@vibeapi/api-helper 0.0.103 → 0.0.105
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 +1 -0
- package/client-config.snapshot.json +16 -1
- package/dist/client-config.snapshot.json +16 -1
- package/dist/commands/config.js +1 -1
- package/dist/lib/program.js +1 -1
- package/dist/lib/tool-manager.d.ts +4 -1
- package/dist/lib/tool-manager.js +1 -1
- package/dist/lib/tools/codex.js +1 -1
- package/dist/lib/tools/types.d.ts +7 -1
- package/dist/lib/wizard.js +1 -1
- package/dist/locales/en_US.json +12 -4
- package/dist/locales/zh_CN.json +12 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,6 +104,7 @@ vibecli config claude-code clear-model # 模型选择被钉住时,交还给
|
|
|
104
104
|
vibecli config <tool> # 配置某工具(选模型 → 应用 / 移除 / 还原)
|
|
105
105
|
vibecli config <tool> restore # 还原该工具到上次更改前
|
|
106
106
|
vibecli config <tool> clear-model # 清掉钉死的模型设置,回到工具自带默认(保留 API Key)
|
|
107
|
+
vibecli config <tool> remove # 移除 VibeAPI 写入的配置(Codex 会退出 API Key 登录,可改用 ChatGPT 订阅)
|
|
107
108
|
vibecli config tool-model set codex gpt-6-astra # 单独给某工具指定模型
|
|
108
109
|
vibecli config profile use work # 切换 profile
|
|
109
110
|
vibecli doctor # 健康巡检(--deep 实发一条请求)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": 1,
|
|
3
|
-
"revision": "2026-10-
|
|
3
|
+
"revision": "2026-10-18T18:25:57Z-6",
|
|
4
4
|
"min_client_version": "",
|
|
5
5
|
"upgrade_message": "",
|
|
6
6
|
"defaults": {
|
|
@@ -657,5 +657,20 @@
|
|
|
657
657
|
"claude-fable-5",
|
|
658
658
|
"claude-fable-5-1"
|
|
659
659
|
]
|
|
660
|
+
},
|
|
661
|
+
"key_groups": {
|
|
662
|
+
"base": [
|
|
663
|
+
"auto"
|
|
664
|
+
],
|
|
665
|
+
"options": [
|
|
666
|
+
{
|
|
667
|
+
"id": "claude-official",
|
|
668
|
+
"label": "包含 Claude 官方满血版",
|
|
669
|
+
"hint": "可以使用高级模型 Fable,并且畅享满血提示词缓存",
|
|
670
|
+
"groups": [
|
|
671
|
+
"Claude 官方满血版"
|
|
672
|
+
]
|
|
673
|
+
}
|
|
674
|
+
]
|
|
660
675
|
}
|
|
661
676
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": 1,
|
|
3
|
-
"revision": "2026-10-
|
|
3
|
+
"revision": "2026-10-18T18:25:57Z-6",
|
|
4
4
|
"min_client_version": "",
|
|
5
5
|
"upgrade_message": "",
|
|
6
6
|
"defaults": {
|
|
@@ -657,5 +657,20 @@
|
|
|
657
657
|
"claude-fable-5",
|
|
658
658
|
"claude-fable-5-1"
|
|
659
659
|
]
|
|
660
|
+
},
|
|
661
|
+
"key_groups": {
|
|
662
|
+
"base": [
|
|
663
|
+
"auto"
|
|
664
|
+
],
|
|
665
|
+
"options": [
|
|
666
|
+
{
|
|
667
|
+
"id": "claude-official",
|
|
668
|
+
"label": "包含 Claude 官方满血版",
|
|
669
|
+
"hint": "可以使用高级模型 Fable,并且畅享满血提示词缓存",
|
|
670
|
+
"groups": [
|
|
671
|
+
"Claude 官方满血版"
|
|
672
|
+
]
|
|
673
|
+
}
|
|
674
|
+
]
|
|
660
675
|
}
|
|
661
676
|
}
|
package/dist/commands/config.js
CHANGED
|
@@ -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
|
|
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.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)}
|
package/dist/lib/program.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Command as e,Option as o}from"commander";import{readFileSync as t}from"fs";import{join as s,dirname as a}from"path";import{fileURLToPath as n}from"url";import{i18n as i}from"./i18n.js";import{wizard as r}from"./wizard.js";import{SUPPORTED_TOOLS as c}from"./tool-manager.js";import{DEFAULT_BASE_URL as l}from"./config.js";import{attachCommandHelp as p,helpConfiguration as u}from"./cli-help.js";import{langCommand as m,authCommand as d,doctorCommand as g,configCommand as f,statusCommand as x,refreshCommand as y}from"../commands/index.js";import{logsCommand as b}from"../commands/logs.js";import{completionCommand as h}from"../commands/completion.js";import{benchCommand as $}from"../commands/bench.js";import{updateCommand as k}from"../commands/update.js";import{upgradeCommand as _}from"../commands/upgrade.js";import{codexSessionsCommand as w}from"../commands/codex-sessions.js";import{setupCommand as v,DEDICATED_KEYS as j}from"../commands/setup.js";import{baseCommand as O}from"../commands/base.js";import{usageError as S}from"./errors.js";import{brand as z,brandEnv as A,CLI_NAME as C}from"./brand.js";const E=(z().gatewayAddresses[1]??z().gatewayAddresses[0]).url,G=(z().gatewayAddresses[2]??z().gatewayAddresses[0]).url;function R(e,o){return i.t(`help.${e}`,o)}function K(e,o){return{command:e,note:R(o)}}function L(e){const o=R(e);return o===`help.${e}`?"":o}function N(e,o=[]){return{when:L(`${e}.when`),prerequisites:L(`${e}.needs`).split("\n").filter(Boolean),alternatives:o.map(([e,o])=>K(e,o))}}function P(e){return e.helpCommand("help [command]",R("help_command"))}export function buildProgram(){const z=new e;z.name(`${C}`).summary(R("root.summary")).description(R("root.description")).configureHelp(u()).allowExcessArguments(!0).optionsGroup(R("group.global_options")).helpOption("-h, --help",R("global.help")).version(function(){try{const e=a(n(import.meta.url));return JSON.parse(t(s(e,"../../package.json"),"utf-8")).version}catch{return"1.0.0"}}(),"-v, --version",R("global.version")).option("--base <url>",R("global.base")).option("--non-interactive",R("global.non_interactive")).option("--json",R("global.json")).option("-y, --yes",R("global.yes")).option("--dry-run",R("global.dry_run")).option("--no-color",R("global.no_color")),z.configureOutput({writeErr:()=>{},outputError:()=>{}}),z.showSuggestionAfterError(),z.exitOverride(e=>{throw e}),z.commandsGroup(R("group.configure"));const L=z.command("setup").summary(R("setup.summary")).description(R("setup.description")).option("--key <key>",R("setup.opt.key"));for(const e of j){const t=new o(`--${e.option} <key>`,R(`setup.opt.${e.option}`));e.hidden&&t.hideHelp(),L.addOption(t)}L.option("--1m",R("setup.opt.one_m")).option("--no-1m",R("setup.opt.no_one_m")).option("--claude-official <on|off>",R("setup.opt.claude_official")).option("--desktop-registry <on|off>",R("setup.opt.desktop_registry")).option("--force",R("setup.opt.force")).option("--install",R("setup.opt.install")).option("--no-install",R("setup.opt.no_install")).option("--all",R("setup.opt.all")).action(async e=>{e.key||j.some(o=>e[o.option])||(e.key=A("SETUP_KEY")?.trim()||void 0);const o=Boolean(e.key||j.some(o=>e[o.option])),t=void 0!==e["1m"]||void 0!==e.claudeOfficial||void 0!==e.desktopRegistry,s="zh_CN"===i.getLocale()?"<你的 Key>":"<your key>";if(!o&&!t)throw S(i.t("setup.usage"),`${C} setup --key ${s}`,"missing_key");if(void 0!==e.claudeOfficial&&!["on","off"].includes(String(e.claudeOfficial).toLowerCase()))throw S(i.t("setup.claude_official_invalid",{value:String(e.claudeOfficial)}),`${C} setup --claude-official on|off`,"invalid_value");if(void 0!==e.desktopRegistry&&!["on","off"].includes(String(e.desktopRegistry).toLowerCase()))throw S(i.t("setup.desktop_registry_invalid",{value:String(e.desktopRegistry)}),`${C} setup --desktop-registry on|off`,"invalid_value");await v({key:e.key,...Object.fromEntries(j.map(o=>[o.option,e[o.option]])),all:e.all,oneMillion:e["1m"],claudeOfficial:e.claudeOfficial,desktopRegistry:e.desktopRegistry,force:e.force,install:e.install})}),p(L,{...N("setup",[[`${C} init`,"setup.alt.init"],[`${C} config <tool>`,"setup.alt.config"],[`${C} auth <key>`,"setup.alt.auth"]]),sections:[{title:R("setup.autodetect_title"),rows:[["Claude",R("setup.autodetect.claude")],["GPT",R("setup.autodetect.gpt")],["Grok",R("setup.autodetect.grok")],["Gemini",R("setup.autodetect.gemini")]]}],examples:[K(`${C} setup --key sk-xxx`,"setup.ex.key"),K(`${C} setup --install --key sk-xxx`,"setup.ex.install"),K(`${C} setup --claudekey sk-a --codexkey sk-b --agykey sk-g`,"setup.ex.split"),K(`${C} setup --force --key sk-xxx`,"setup.ex.force"),K(`${C} setup --base ${E} --key sk-xxx`,"setup.ex.base")]});const T=z.command("init").summary(R("init.summary")).description(R("init.description")).action(async()=>{await r.runFirstTimeSetup()});p(T,{...N("init",[[`${C} setup --key <key>`,"init.alt.setup"],[`${C}`,"init.alt.menu"]]),examples:[K(`${C} init`,"init.ex.run"),K(`${C} init --base ${E}`,"init.ex.base"),K(`${C}`,"init.ex.menu")]});const U=z.command("auth").summary(R("auth.summary")).description(R("auth.description")).argument("[token]",R("auth.arg.token")).action(async e=>{const o=[];e&&o.push(e),await d(o)});P(U);const B=U.command("revoke").description(R("auth.revoke")).action(async()=>{await d(["revoke"])});p(B,{examples:[K(`${C} auth revoke`,"auth.ex.revoke_ask"),K(`${C} auth revoke --yes`,"auth.ex.revoke")]});const H=U.command("reload <tool>").description(R("auth.reload")).action(async e=>{await d(["reload",e])});p(H,{examples:[K(`${C} auth reload claude-code`,"auth.ex.reload"),K(`${C} auth reload claude-code --json`,"auth.ex.reload_json")]}),p(U,{...N("auth",[[`${C} setup --key <key>`,"auth.alt.setup"]]),examples:[K(`${C} auth`,"auth.ex.prompt"),K(`${C} auth sk-xxx --non-interactive`,"auth.ex.save"),K(`${C} auth revoke --yes`,"auth.ex.revoke"),K(`${C} auth reload claude-code`,"auth.ex.reload")]});const M=z.command("config").summary(R("config.summary")).description(R("config.description")).argument("[args...]",R("config.arg.args")).option("-f, --force",R("config.opt.force")).allowUnknownOption(!0).action(async(e=[],o={})=>{await f(o.force?[...e,"--force"]:e)});p(M,{...N("config",[[`${C} setup --force --key <key>`,"config.alt.setup"],[`${C} status`,"config.alt.status"]]),sections:[{title:R("config.subcommands_title"),rows:[["<tool>",R("config.sub.tool")],["<tool> --force",R("config.sub.tool_force")],["<tool> --non-interactive",R("config.sub.tool_non_interactive")],["<tool> restore",R("config.sub.tool_restore")],["<tool> backups",R("config.sub.tool_backups")],["<tool> clear-model",R("config.sub.tool_clear_model")],["tool-model list",R("config.sub.tool_model_list")],["tool-model set <tool> [slot] <model>",R("config.sub.tool_model_set")],["tool-model clear <tool>",R("config.sub.tool_model_clear")],["profile list",R("config.sub.profile_list")],["profile create <name>",R("config.sub.profile_create")],["profile use <name>",R("config.sub.profile_use")],["profile delete <name>",R("config.sub.profile_delete")],["preset list",R("config.sub.preset_list")],["preset save <name>",R("config.sub.preset_save")],["preset use <name>",R("config.sub.preset_use")],["preset delete <name>",R("config.sub.preset_delete")],["backup list",R("config.sub.backup_list")],["backup create [label]",R("config.sub.backup_create")],["backup restore <name>",R("config.sub.backup_restore")]]},{title:R("config.tools_title"),rows:Object.values(c).filter(e=>!e.hidden).map(e=>[e.name,e.displayName])}],examples:[K(`${C} config codex`,"config.ex.menu"),K(`${C} config claude-code --force`,"config.ex.force"),K(`${C} config tool-model set codex gpt-6-astra`,"config.ex.tool_model"),K(`${C} config profile create work`,"config.ex.profile"),K(`${C} config backup create before-upgrade`,"config.ex.backup")]});const q=z.command("base").summary(R("base.summary")).description(R("base.description")).argument("[target]",R("base.arg.target")).action(async e=>{await O(e)});p(q,{...N("base",[[`${C} doctor`,"base.alt.doctor"],[`${C} bench`,"base.alt.bench"]]),sections:[{title:R("base.targets_title"),rows:[[R("base.target.none_term"),R("base.target.none")],[R("base.target.index_term"),R("base.target.index")],[R("base.target.url_term"),R("base.target.url")],["auto",R("base.target.auto")],["default",R("base.target.default",{url:l})]]}],examples:[K(`${C} base`,"base.ex.list"),K(`${C} base auto`,"base.ex.auto"),K(`${C} base 2`,"base.ex.index"),K(`${C} base ${E}`,"base.ex.url"),K(`${C} base default`,"base.ex.default")]}),z.commandsGroup(R("group.diagnose"));const F=z.command("status").summary(R("status.summary")).description(R("status.description")).action(async()=>{await x()});p(F,{...N("status",[[`${C} doctor`,"status.alt.doctor"]]),examples:[K(`${C} status`,"status.ex.show"),K(`${C} status --json`,"status.ex.json")]});const J=z.command("doctor").summary(R("doctor.summary")).description(R("doctor.description")).option("--deep",R("doctor.opt.deep")).action(async e=>{await g({deep:e.deep})});p(J,{...N("doctor",[[`${C} base auto`,"doctor.alt.base"],[`${C} logs tail`,"doctor.alt.logs"]]),examples:[K(`${C} doctor`,"doctor.ex.run"),K(`${C} doctor --deep`,"doctor.ex.deep")]});const Y=z.command("bench").summary(R("bench.summary")).description(R("bench.description")).option("--samples <n>",R("bench.opt.samples"),"5").action(async e=>{const o=[];e.samples&&o.push("--samples",e.samples),await $(o)});p(Y,{...N("bench",[[`${C} base`,"bench.alt.base"]]),examples:[K(`${C} bench`,"bench.ex.run"),K(`${C} bench --samples 3`,"bench.ex.samples"),K(`${C} bench --json`,"bench.ex.json")]});const D=z.command("logs").summary(R("logs.summary")).description(R("logs.description")).argument("[action]",R("logs.arg.action")).argument("[file]",R("logs.arg.file")).action(async(e,o)=>{const t=[];e&&t.push(e),o&&t.push(o),await b(t)});p(D,{...N("logs",[[`${C} doctor`,"logs.alt.doctor"]]),sections:[{title:R("logs.actions_title"),rows:[["list",R("logs.action.list")],["tail [file]",R("logs.action.tail")],["path",R("logs.action.path")]]}],examples:[K(`${C} logs`,"logs.ex.list"),K(`${C} logs tail`,"logs.ex.tail"),K(`${C} logs path`,"logs.ex.path")]}),z.commandsGroup(R("group.maintain"));const I=z.command("upgrade").summary(R("upgrade.summary")).description(R("upgrade.description")).argument("[tools...]",R("upgrade.arg.tools")).action(async(e=[])=>{await _(e)});p(I,{...N("upgrade",[[`${C} update`,"upgrade.alt.update"]]),examples:[K(`${C} upgrade`,"upgrade.ex.all"),K(`${C} upgrade claude-code`,"upgrade.ex.one"),K(`${C} upgrade codex agy`,"upgrade.ex.many")]});const Q=z.command("refresh").summary(R("refresh.summary")).description(R("refresh.description")).action(async()=>{await y()});p(Q,{...N("refresh",[[`${C} setup --key <你的 Key>`,"refresh.alt.setup"]]),examples:[K(`${C} refresh`,"refresh.ex.run"),K(`${C} refresh --base ${G}`,"refresh.ex.base")]});const V=z.command("update").summary(R("update.summary")).description(R("update.description")).action(async()=>{await k()});p(V,{...N("update",[[`${C} upgrade`,"update.alt.upgrade"]]),examples:[K(`${C} update`,"update.ex.check"),K(`${C} update --json`,"update.ex.json")]});const W=z.command("codex").summary(R("codex.summary")).description(R("codex.description"));P(W);const X=W.command("sessions").summary(R("codex_sessions.summary")).description(R("codex_sessions.description")).option("--to <provider>",R("codex_sessions.opt.to")).option("--undo <dir>",R("codex_sessions.opt.undo")).action(async e=>{await w(e)});p(W,{...N("codex"),examples:[K(`${C} codex sessions`,"codex_sessions.ex.move"),K(`${C} codex sessions --undo <dir>`,"codex_sessions.ex.undo")]}),p(X,{...N("codex_sessions",[[`${C} codex sessions --undo <dir>`,"codex_sessions.alt.undo"]]),examples:[K(`${C} codex sessions`,"codex_sessions.ex.move"),K(`${C} codex sessions --to custom`,"codex_sessions.ex.to"),K(`${C} codex sessions --undo <dir>`,"codex_sessions.ex.undo")]});const Z=z.command("lang").summary(R("lang.summary")).description(R("lang.description"));P(Z);const ee=Z.command("show").description(R("lang.show")).action(async()=>{await m(["show"])}),oe=Z.command("set <locale>").description(R("lang.set")).action(async e=>{await m(["set",e])}),te=[K(`${C} lang show`,"lang.ex.show"),K(`${C} lang set en_US`,"lang.ex.set_en"),K(`${C} lang set zh_CN`,"lang.ex.set_zh")];p(Z,{...N("lang",[[`${C} enter lang`,"lang.alt.enter"]]),examples:te}),p(ee,{examples:[te[0],K(`${C} lang show --json`,"lang.ex.show_json")]}),p(oe,{examples:te.slice(1)});const se=z.command("completion").summary(R("completion.summary")).description(R("completion.description")).argument("<shell>",R("completion.arg.shell")).action(async e=>{await h([e])});p(se,{...N("completion"),examples:[K(`${C} completion bash > ~/.${C}-completion.bash`,"completion.ex.bash"),K(`${C} completion zsh > ~/.${C}-completion.zsh`,"completion.ex.zsh"),K(`${C} completion fish > ~/.config/fish/completions/${C}.fish`,"completion.ex.fish")]});const ae=z.command("enter").summary(R("enter.summary")).description(R("enter.description")).argument("[option]",R("enter.arg.option")).action(async e=>{if(e)switch(e){case"lang":case"language":await r.configLanguage();break;case"apikey":case"api-key":await r.configApiKey();break;case"models":await r.configModels();break;default:await f([e])}else await r.run()});p(ae,{...N("enter",[[`${C}`,"enter.alt.menu"],[`${C} config <tool>`,"enter.alt.config"]]),sections:[{title:R("enter.options_title"),rows:[[R("enter.option.none_term"),R("enter.option.none")],["lang",R("enter.option.lang")],["apikey",R("enter.option.apikey")],["models",R("enter.option.models")],["<tool>",R("enter.option.tool")]]}],examples:[K(`${C} enter`,"enter.ex.menu"),K(`${C} enter models`,"enter.ex.models"),K(`${C} enter codex`,"enter.ex.tool")]}),P(z),z.action(async()=>{await r.run()}),p(z,{examples:[K(`${C}`,"root.ex.menu"),K(`${C} setup --key sk-xxx`,"root.ex.setup"),K(`${C} doctor`,"root.ex.doctor"),K(`${C} base auto`,"root.ex.base"),K(`${C} config codex`,"root.ex.config")]});const ne=e=>{for(const o of e.commands)o.helpOption("-h, --help",R("global.help")),ne(o)};return ne(z),z}
|
|
1
|
+
import{Command as e,Option as o}from"commander";import{readFileSync as t}from"fs";import{join as s,dirname as a}from"path";import{fileURLToPath as n}from"url";import{i18n as i}from"./i18n.js";import{wizard as r}from"./wizard.js";import{SUPPORTED_TOOLS as c}from"./tool-manager.js";import{DEFAULT_BASE_URL as l}from"./config.js";import{attachCommandHelp as p,helpConfiguration as m}from"./cli-help.js";import{langCommand as u,authCommand as d,doctorCommand as g,configCommand as f,statusCommand as x,refreshCommand as y}from"../commands/index.js";import{logsCommand as h}from"../commands/logs.js";import{completionCommand as b}from"../commands/completion.js";import{benchCommand as $}from"../commands/bench.js";import{updateCommand as k}from"../commands/update.js";import{upgradeCommand as _}from"../commands/upgrade.js";import{codexSessionsCommand as w}from"../commands/codex-sessions.js";import{setupCommand as v,DEDICATED_KEYS as j}from"../commands/setup.js";import{baseCommand as O}from"../commands/base.js";import{usageError as S}from"./errors.js";import{brand as z,brandEnv as A,CLI_NAME as C}from"./brand.js";const E=(z().gatewayAddresses[1]??z().gatewayAddresses[0]).url,G=(z().gatewayAddresses[2]??z().gatewayAddresses[0]).url;function R(e,o){return i.t(`help.${e}`,o)}function K(e,o){return{command:e,note:R(o)}}function L(e){const o=R(e);return o===`help.${e}`?"":o}function N(e,o=[]){return{when:L(`${e}.when`),prerequisites:L(`${e}.needs`).split("\n").filter(Boolean),alternatives:o.map(([e,o])=>K(e,o))}}function P(e){return e.helpCommand("help [command]",R("help_command"))}export function buildProgram(){const z=new e;z.name(`${C}`).summary(R("root.summary")).description(R("root.description")).configureHelp(m()).allowExcessArguments(!0).optionsGroup(R("group.global_options")).helpOption("-h, --help",R("global.help")).version(function(){try{const e=a(n(import.meta.url));return JSON.parse(t(s(e,"../../package.json"),"utf-8")).version}catch{return"1.0.0"}}(),"-v, --version",R("global.version")).option("--base <url>",R("global.base")).option("--non-interactive",R("global.non_interactive")).option("--json",R("global.json")).option("-y, --yes",R("global.yes")).option("--dry-run",R("global.dry_run")).option("--no-color",R("global.no_color")),z.configureOutput({writeErr:()=>{},outputError:()=>{}}),z.showSuggestionAfterError(),z.exitOverride(e=>{throw e}),z.commandsGroup(R("group.configure"));const L=z.command("setup").summary(R("setup.summary")).description(R("setup.description")).option("--key <key>",R("setup.opt.key"));for(const e of j){const t=new o(`--${e.option} <key>`,R(`setup.opt.${e.option}`));e.hidden&&t.hideHelp(),L.addOption(t)}L.option("--1m",R("setup.opt.one_m")).option("--no-1m",R("setup.opt.no_one_m")).option("--claude-official <on|off>",R("setup.opt.claude_official")).option("--desktop-registry <on|off>",R("setup.opt.desktop_registry")).option("--force",R("setup.opt.force")).option("--install",R("setup.opt.install")).option("--no-install",R("setup.opt.no_install")).option("--all",R("setup.opt.all")).action(async e=>{e.key||j.some(o=>e[o.option])||(e.key=A("SETUP_KEY")?.trim()||void 0);const o=Boolean(e.key||j.some(o=>e[o.option])),t=void 0!==e["1m"]||void 0!==e.claudeOfficial||void 0!==e.desktopRegistry,s="zh_CN"===i.getLocale()?"<你的 Key>":"<your key>";if(!o&&!t)throw S(i.t("setup.usage"),`${C} setup --key ${s}`,"missing_key");if(void 0!==e.claudeOfficial&&!["on","off"].includes(String(e.claudeOfficial).toLowerCase()))throw S(i.t("setup.claude_official_invalid",{value:String(e.claudeOfficial)}),`${C} setup --claude-official on|off`,"invalid_value");if(void 0!==e.desktopRegistry&&!["on","off"].includes(String(e.desktopRegistry).toLowerCase()))throw S(i.t("setup.desktop_registry_invalid",{value:String(e.desktopRegistry)}),`${C} setup --desktop-registry on|off`,"invalid_value");await v({key:e.key,...Object.fromEntries(j.map(o=>[o.option,e[o.option]])),all:e.all,oneMillion:e["1m"],claudeOfficial:e.claudeOfficial,desktopRegistry:e.desktopRegistry,force:e.force,install:e.install})}),p(L,{...N("setup",[[`${C} init`,"setup.alt.init"],[`${C} config <tool>`,"setup.alt.config"],[`${C} auth <key>`,"setup.alt.auth"]]),sections:[{title:R("setup.autodetect_title"),rows:[["Claude",R("setup.autodetect.claude")],["GPT",R("setup.autodetect.gpt")],["Grok",R("setup.autodetect.grok")],["Gemini",R("setup.autodetect.gemini")]]}],examples:[K(`${C} setup --key sk-xxx`,"setup.ex.key"),K(`${C} setup --install --key sk-xxx`,"setup.ex.install"),K(`${C} setup --claudekey sk-a --codexkey sk-b --agykey sk-g`,"setup.ex.split"),K(`${C} setup --force --key sk-xxx`,"setup.ex.force"),K(`${C} setup --base ${E} --key sk-xxx`,"setup.ex.base")]});const T=z.command("init").summary(R("init.summary")).description(R("init.description")).action(async()=>{await r.runFirstTimeSetup()});p(T,{...N("init",[[`${C} setup --key <key>`,"init.alt.setup"],[`${C}`,"init.alt.menu"]]),examples:[K(`${C} init`,"init.ex.run"),K(`${C} init --base ${E}`,"init.ex.base"),K(`${C}`,"init.ex.menu")]});const U=z.command("auth").summary(R("auth.summary")).description(R("auth.description")).argument("[token]",R("auth.arg.token")).action(async e=>{const o=[];e&&o.push(e),await d(o)});P(U);const B=U.command("revoke").description(R("auth.revoke")).action(async()=>{await d(["revoke"])});p(B,{examples:[K(`${C} auth revoke`,"auth.ex.revoke_ask"),K(`${C} auth revoke --yes`,"auth.ex.revoke")]});const H=U.command("reload <tool>").description(R("auth.reload")).action(async e=>{await d(["reload",e])});p(H,{examples:[K(`${C} auth reload claude-code`,"auth.ex.reload"),K(`${C} auth reload claude-code --json`,"auth.ex.reload_json")]}),p(U,{...N("auth",[[`${C} setup --key <key>`,"auth.alt.setup"]]),examples:[K(`${C} auth`,"auth.ex.prompt"),K(`${C} auth sk-xxx --non-interactive`,"auth.ex.save"),K(`${C} auth revoke --yes`,"auth.ex.revoke"),K(`${C} auth reload claude-code`,"auth.ex.reload")]});const M=z.command("config").summary(R("config.summary")).description(R("config.description")).argument("[args...]",R("config.arg.args")).option("-f, --force",R("config.opt.force")).allowUnknownOption(!0).action(async(e=[],o={})=>{await f(o.force?[...e,"--force"]:e)});p(M,{...N("config",[[`${C} setup --force --key <key>`,"config.alt.setup"],[`${C} status`,"config.alt.status"]]),sections:[{title:R("config.subcommands_title"),rows:[["<tool>",R("config.sub.tool")],["<tool> --force",R("config.sub.tool_force")],["<tool> --non-interactive",R("config.sub.tool_non_interactive")],["<tool> remove",R("config.sub.tool_remove")],["<tool> restore",R("config.sub.tool_restore")],["<tool> backups",R("config.sub.tool_backups")],["<tool> clear-model",R("config.sub.tool_clear_model")],["tool-model list",R("config.sub.tool_model_list")],["tool-model set <tool> [slot] <model>",R("config.sub.tool_model_set")],["tool-model clear <tool>",R("config.sub.tool_model_clear")],["profile list",R("config.sub.profile_list")],["profile create <name>",R("config.sub.profile_create")],["profile use <name>",R("config.sub.profile_use")],["profile delete <name>",R("config.sub.profile_delete")],["preset list",R("config.sub.preset_list")],["preset save <name>",R("config.sub.preset_save")],["preset use <name>",R("config.sub.preset_use")],["preset delete <name>",R("config.sub.preset_delete")],["backup list",R("config.sub.backup_list")],["backup create [label]",R("config.sub.backup_create")],["backup restore <name>",R("config.sub.backup_restore")]]},{title:R("config.tools_title"),rows:Object.values(c).filter(e=>!e.hidden).map(e=>[e.name,e.displayName])}],examples:[K(`${C} config codex`,"config.ex.menu"),K(`${C} config claude-code --force`,"config.ex.force"),K(`${C} config tool-model set codex gpt-6-astra`,"config.ex.tool_model"),K(`${C} config profile create work`,"config.ex.profile"),K(`${C} config codex remove`,"config.ex.remove")]});const q=z.command("base").summary(R("base.summary")).description(R("base.description")).argument("[target]",R("base.arg.target")).action(async e=>{await O(e)});p(q,{...N("base",[[`${C} doctor`,"base.alt.doctor"],[`${C} bench`,"base.alt.bench"]]),sections:[{title:R("base.targets_title"),rows:[[R("base.target.none_term"),R("base.target.none")],[R("base.target.index_term"),R("base.target.index")],[R("base.target.url_term"),R("base.target.url")],["auto",R("base.target.auto")],["default",R("base.target.default",{url:l})]]}],examples:[K(`${C} base`,"base.ex.list"),K(`${C} base auto`,"base.ex.auto"),K(`${C} base 2`,"base.ex.index"),K(`${C} base ${E}`,"base.ex.url"),K(`${C} base default`,"base.ex.default")]}),z.commandsGroup(R("group.diagnose"));const F=z.command("status").summary(R("status.summary")).description(R("status.description")).action(async()=>{await x()});p(F,{...N("status",[[`${C} doctor`,"status.alt.doctor"]]),examples:[K(`${C} status`,"status.ex.show"),K(`${C} status --json`,"status.ex.json")]});const J=z.command("doctor").summary(R("doctor.summary")).description(R("doctor.description")).option("--deep",R("doctor.opt.deep")).action(async e=>{await g({deep:e.deep})});p(J,{...N("doctor",[[`${C} base auto`,"doctor.alt.base"],[`${C} logs tail`,"doctor.alt.logs"]]),examples:[K(`${C} doctor`,"doctor.ex.run"),K(`${C} doctor --deep`,"doctor.ex.deep")]});const Y=z.command("bench").summary(R("bench.summary")).description(R("bench.description")).option("--samples <n>",R("bench.opt.samples"),"5").action(async e=>{const o=[];e.samples&&o.push("--samples",e.samples),await $(o)});p(Y,{...N("bench",[[`${C} base`,"bench.alt.base"]]),examples:[K(`${C} bench`,"bench.ex.run"),K(`${C} bench --samples 3`,"bench.ex.samples"),K(`${C} bench --json`,"bench.ex.json")]});const D=z.command("logs").summary(R("logs.summary")).description(R("logs.description")).argument("[action]",R("logs.arg.action")).argument("[file]",R("logs.arg.file")).action(async(e,o)=>{const t=[];e&&t.push(e),o&&t.push(o),await h(t)});p(D,{...N("logs",[[`${C} doctor`,"logs.alt.doctor"]]),sections:[{title:R("logs.actions_title"),rows:[["list",R("logs.action.list")],["tail [file]",R("logs.action.tail")],["path",R("logs.action.path")]]}],examples:[K(`${C} logs`,"logs.ex.list"),K(`${C} logs tail`,"logs.ex.tail"),K(`${C} logs path`,"logs.ex.path")]}),z.commandsGroup(R("group.maintain"));const I=z.command("upgrade").summary(R("upgrade.summary")).description(R("upgrade.description")).argument("[tools...]",R("upgrade.arg.tools")).action(async(e=[])=>{await _(e)});p(I,{...N("upgrade",[[`${C} update`,"upgrade.alt.update"]]),examples:[K(`${C} upgrade`,"upgrade.ex.all"),K(`${C} upgrade claude-code`,"upgrade.ex.one"),K(`${C} upgrade codex agy`,"upgrade.ex.many")]});const Q=z.command("refresh").summary(R("refresh.summary")).description(R("refresh.description")).action(async()=>{await y()});p(Q,{...N("refresh",[[`${C} setup --key <你的 Key>`,"refresh.alt.setup"]]),examples:[K(`${C} refresh`,"refresh.ex.run"),K(`${C} refresh --base ${G}`,"refresh.ex.base")]});const V=z.command("update").summary(R("update.summary")).description(R("update.description")).action(async()=>{await k()});p(V,{...N("update",[[`${C} upgrade`,"update.alt.upgrade"]]),examples:[K(`${C} update`,"update.ex.check"),K(`${C} update --json`,"update.ex.json")]});const W=z.command("codex").summary(R("codex.summary")).description(R("codex.description"));P(W);const X=W.command("sessions").summary(R("codex_sessions.summary")).description(R("codex_sessions.description")).option("--to <provider>",R("codex_sessions.opt.to")).option("--undo <dir>",R("codex_sessions.opt.undo")).action(async e=>{await w(e)});p(W,{...N("codex"),examples:[K(`${C} codex sessions`,"codex_sessions.ex.move"),K(`${C} codex sessions --undo <dir>`,"codex_sessions.ex.undo")]}),p(X,{...N("codex_sessions",[[`${C} codex sessions --undo <dir>`,"codex_sessions.alt.undo"]]),examples:[K(`${C} codex sessions`,"codex_sessions.ex.move"),K(`${C} codex sessions --to custom`,"codex_sessions.ex.to"),K(`${C} codex sessions --undo <dir>`,"codex_sessions.ex.undo")]});const Z=z.command("lang").summary(R("lang.summary")).description(R("lang.description"));P(Z);const ee=Z.command("show").description(R("lang.show")).action(async()=>{await u(["show"])}),oe=Z.command("set <locale>").description(R("lang.set")).action(async e=>{await u(["set",e])}),te=[K(`${C} lang show`,"lang.ex.show"),K(`${C} lang set en_US`,"lang.ex.set_en"),K(`${C} lang set zh_CN`,"lang.ex.set_zh")];p(Z,{...N("lang",[[`${C} enter lang`,"lang.alt.enter"]]),examples:te}),p(ee,{examples:[te[0],K(`${C} lang show --json`,"lang.ex.show_json")]}),p(oe,{examples:te.slice(1)});const se=z.command("completion").summary(R("completion.summary")).description(R("completion.description")).argument("<shell>",R("completion.arg.shell")).action(async e=>{await b([e])});p(se,{...N("completion"),examples:[K(`${C} completion bash > ~/.${C}-completion.bash`,"completion.ex.bash"),K(`${C} completion zsh > ~/.${C}-completion.zsh`,"completion.ex.zsh"),K(`${C} completion fish > ~/.config/fish/completions/${C}.fish`,"completion.ex.fish")]});const ae=z.command("enter").summary(R("enter.summary")).description(R("enter.description")).argument("[option]",R("enter.arg.option")).action(async e=>{if(e)switch(e){case"lang":case"language":await r.configLanguage();break;case"apikey":case"api-key":await r.configApiKey();break;case"models":await r.configModels();break;default:await f([e])}else await r.run()});p(ae,{...N("enter",[[`${C}`,"enter.alt.menu"],[`${C} config <tool>`,"enter.alt.config"]]),sections:[{title:R("enter.options_title"),rows:[[R("enter.option.none_term"),R("enter.option.none")],["lang",R("enter.option.lang")],["apikey",R("enter.option.apikey")],["models",R("enter.option.models")],["<tool>",R("enter.option.tool")]]}],examples:[K(`${C} enter`,"enter.ex.menu"),K(`${C} enter models`,"enter.ex.models"),K(`${C} enter codex`,"enter.ex.tool")]}),P(z),z.action(async()=>{await r.run()}),p(z,{examples:[K(`${C}`,"root.ex.menu"),K(`${C} setup --key sk-xxx`,"root.ex.setup"),K(`${C} doctor`,"root.ex.doctor"),K(`${C} base auto`,"root.ex.base"),K(`${C} config codex`,"root.ex.config")]});const ne=e=>{for(const o of e.commands)o.helpOption("-h, --help",R("global.help")),ne(o)};return ne(z),z}
|
|
@@ -19,6 +19,8 @@ export interface ToolInfo {
|
|
|
19
19
|
configPath: string;
|
|
20
20
|
displayName: string;
|
|
21
21
|
hidden?: boolean;
|
|
22
|
+
/** GUI app (no terminal command to type, e.g. Claude Desktop). */
|
|
23
|
+
gui?: boolean;
|
|
22
24
|
}
|
|
23
25
|
/**
|
|
24
26
|
* Tool metadata keyed by id. Derived from the adapter registry so the list of
|
|
@@ -75,7 +77,8 @@ export declare class ToolManager {
|
|
|
75
77
|
current: string;
|
|
76
78
|
min: string;
|
|
77
79
|
} | null;
|
|
78
|
-
|
|
80
|
+
/** Remove our config from the tool; returns what the user should do next (e.g. sign in with the vendor's account). */
|
|
81
|
+
unloadPrivateConfig(toolName: string): ApplyNote[];
|
|
79
82
|
/**
|
|
80
83
|
* Clear the tool's pinned model, keeping its credentials. Also drops this
|
|
81
84
|
* CLI's own per-tool model override so a later re-apply doesn't pin it back.
|
package/dist/lib/tool-manager.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import e from"inquirer";import r from"chalk";import{logger as i}from"../utils/logger.js";import{configManager as s}from"./config.js";import{getAdapter as l,listAdapters as a,TOOL_ADAPTERS as c}from"./tools/registry.js";import{backupBeforeWrite as d,listBackups as p,restoreBackup as u}from"./tools/backup.js";import{existsSync as
|
|
1
|
+
import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import e from"inquirer";import r from"chalk";import{logger as i}from"../utils/logger.js";import{configManager as s}from"./config.js";import{getAdapter as l,listAdapters as a,TOOL_ADAPTERS as c}from"./tools/registry.js";import{backupBeforeWrite as d,listBackups as p,restoreBackup as u}from"./tools/backup.js";import{existsSync as f,rmSync as m}from"fs";import{join as g}from"path";import{toolHome as h}from"./tools/types.js";import{stringWidth as w}from"../utils/string-width.js";import{resolveModelCatalog as P}from"./model-catalog.js";import{compareVersions as y,getToolMinVersion as T}from"./model-registry.js";import{findInstalls as $,forgetInstalls as k,installLabel as C,mirrorInstallCommand as E}from"./tools/tool-installs.js";import{CLI_NAME as v}from"./brand.js";export{y as compareVersions};function O(o){const t=c[o];return{name:t.name,command:t.command,installCommand:t.installCommand,configPath:t.configPath,displayName:t.displayName,...t.hidden?{hidden:!0}:{},...t.isInstalled?{gui:!0}:{}}}function S(){const o=new Set;for(const t of s.listProfiles()){const n=s.getProfile(t);for(const t of[n.api_key,...Object.values(n.tool_api_keys??{})])t?.trim()&&o.add(t.trim())}return[...o]}export const SUPPORTED_TOOLS=Object.fromEntries(Object.keys(c).map(o=>[o,O(o)]));export class ToolManager{static instance;constructor(){}static getInstance(){return ToolManager.instance||(ToolManager.instance=new ToolManager),ToolManager.instance}isToolInstalled(o){if(!SUPPORTED_TOOLS[o])return!1;const t=l(o);if(t?.isInstalled)try{return t.isInstalled()}catch{return!1}return this.isOnPath(o)||null!==this.nativeLauncher(o)}isOnPath(t){const n=SUPPORTED_TOOLS[t];if(!n)return!1;try{const t="win32"===process.platform?`where ${n.command}`:`which ${n.command}`;return o(t,{stdio:"pipe"}),!0}catch{return!1}}nativeLauncher(o){const t=l(o),n=t?.installSpec?.native?.binDir;if(!t||!n)return null;const e="win32"===process.platform?`${t.command}.exe`:t.command,r=g(h(),...n,e);return f(r)?r:null}async installTool(t){const i=SUPPORTED_TOOLS[t];if(!i)throw new Error(`Unknown tool: ${t}`);const s=l(t)?.installSpec,a=s?E(s):i.installCommand;console.log(r.gray("$ ")+r.white(a));try{return o(a,{stdio:"inherit"}),k(),void console.log(r.green("√ "+n.t("wizard.tool_installed")))}catch(o){if(console.log(r.red("× "+n.t("wizard.install_failed"))),!/EACCES|EPERM|permission denied/i.test(`${o?.message??""}${o?.stderr??""}`)&&243!==o?.status&&!a.startsWith("npm "))throw new Error(`Failed to install ${i.displayName}: ${o}`);console.log(r.yellow(" ! "+("win32"===process.platform?n.t("install.permission_windows",{command:a}):n.t("install.permission_unix",{command:a}))))}const{action:c}=await e.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===c)throw new Error(n.t("install.user_cancelled"));if(k(),!this.isToolInstalled(t))throw console.log(r.red("× "+n.t("install.still_not_installed",{tool:i.displayName}))),new Error(`${i.displayName} is not installed`);console.log(r.green("√ "+n.t("install.verified_success",{tool:i.displayName})))}getToolConfig(o){const t=l(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{return t.getConfig()}catch(t){return i.warn(`Failed to read config for ${o}:`,t),i.logError(`ToolManager.getToolConfig(${o})`,t),null}}updateToolConfig(o,t){const n=l(o);if(!n)throw new Error(`Unknown tool: ${o}`);if(!n.updateConfig)throw new Error(`Tool ${o} does not support raw config updates`);n.updateConfig(t)}forceResetConfig(o){const t=l(o);if(!t)throw new Error(`Unknown tool: ${o}`);const n=t.forceResetPaths?t.forceResetPaths():this.backupPathsFor(t),e=[];for(const o of n)f(o)&&(d(o),m(o,{force:!0}),e.push(o));return e}loadPrivateConfig(o,t,n,e,r={}){const i=l(o);if(!i)throw new Error(`Unknown tool: ${o}`);r.force&&this.forceResetConfig(o),i.loadPrivateConfig({apiKey:t,baseUrl:s.getBaseUrl(),models:n,settings:s.getToolSettings(o),...e?{catalog:e}:{}})}async applyPrivateConfig(o,t,n,e={}){const r=l(o);if(!r)throw new Error(`Unknown tool: ${o}`);const i=r.wantsModelCatalog?await P(t):null;e.force?this.loadPrivateConfig(o,t,n,i??void 0,{force:!0}):i?this.loadPrivateConfig(o,t,n,i):this.loadPrivateConfig(o,t,n)}applyNotes(o){const t=l(o);if(!t)return[];const e=[];try{t.applyNotes&&e.push(...t.applyNotes())}catch(t){i.logError(`ToolManager.applyNotes(${o})`,t)}const r=this.outdatedVersion(o);if(r){e.push({kind:"action",text:n.t("tools.version_outdated",{current:r.current,min:r.min,upgrade:t.installSpec?`${v} upgrade ${o}`:t.upgradeCommand||t.installCommand})});for(const o of t.upgradeHints?.(r.min)??[])e.push({kind:"action",text:o})}const s=t.installSpec?$(t.installSpec):[];return s.length>1&&e.push({kind:"action",text:n.t("upgrade.duplicates_note",{count:String(s.length),active:C(s[0]),others:s.slice(1).map(C).join("、"),tool:o})}),e}printApplied(o,t=16){const n=SUPPORTED_TOOLS[o]?.displayName??o,e=this.applyNotes(o);for(const o of e.filter(o=>"detail"===o.kind))i.record(`${n}: ${o.text}`);const s=e.filter(o=>"summary"===o.kind).map(o=>o.text).join(";"),l=" ".repeat(Math.max(1,t-w(n)));console.log(r.green("√ "+n)+(s?l+s:""));for(const o of e.filter(o=>"action"===o.kind))console.log(r.yellow(" ! "+o.text))}installedVersion(o){const n=l(o);if(!n)return null;if(n.installSpec)return $(n.installSpec)[0]?.version??null;if(n.installedVersion)try{return n.installedVersion()}catch(t){return i.logError(`ToolManager.installedVersion(${o})`,t),null}if(n.isInstalled)return null;try{const o={encoding:"utf-8",timeout:1e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},e=`${("win32"===process.platform?t(`${n.command} --version`,{...o,shell:!0}):t(n.command,["--version"],o)).stdout??""}`.match(/(\d+)\.(\d+)\.(\d+)/);return e?e[0]:null}catch{return null}}outdatedVersion(o){const t=T(o);if(!t)return null;const n=this.installedVersion(o);return n&&y(n,t)<0?{current:n,min:t}:null}unloadPrivateConfig(o){const t=l(o);if(!t)throw new Error(`Unknown tool: ${o}`);t.unloadPrivateConfig({savedKeys:S()});try{return t.unloadNotes?.()??[]}catch(t){return i.logError(`ToolManager.unloadNotes(${o})`,t),[]}}async clearPinnedModels(o){const t=l(o);if(!t)throw new Error(`Unknown tool: ${o}`);if(s.setToolModel(o,null),!t.clearPinnedModels)return[];const n=s.getApiKeyForTool(o),e=t.wantsModelCatalog&&n?await P(n):null;return t.clearPinnedModels(e??void 0)}supportsClearPinnedModels(o){return Boolean(l(o)?.clearPinnedModels)}detectCurrentConfig(o){const t=l(o);if(!t)throw new Error(`Unknown tool: ${o}`);return t.detectCurrentConfig()}backupPathsFor(o){return o.backupPaths?o.backupPaths():[o.configPath]}listToolBackups(o){const t=l(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,backups:p(o)}))}restorePrivateConfig(o){const t=l(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,result:u(o)}))}getInstalledTools(){return Object.keys(SUPPORTED_TOOLS).filter(o=>this.isToolInstalled(o))}getSupportedTools(){return a().filter(o=>!o.hidden).map(o=>O(o.name))}isGitInstalled(){try{const t="win32"===process.platform?"where git":"which git";return o(t,{stdio:"pipe"}),!0}catch{return!1}}}export const toolManager=ToolManager.getInstance();
|
package/dist/lib/tools/codex.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as e,readFileSync as t}from"fs";import{join as
|
|
1
|
+
import{existsSync as e,readFileSync as t,rmSync as o}from"fs";import{join as n}from"path";import*as r from"@iarna/toml";import{logger as i}from"../../utils/logger.js";import{i18n as l}from"../i18n.js";import{backupBeforeWrite as a,atomicWriteFile as s}from"./backup.js";import{pickModel as d,toolHome as c,withV1 as m}from"./types.js";import{getToolDefaultModel as u}from"../model-registry.js";import{buildCodexCatalog as p,codexCatalogPath as _,loadBundledCodexModels as g,loadPreviousCodexModels as f,previousGatewayModelIds as x}from"./codex-catalog.js";import{gatewayModelSpecs as y,modelFamily as h}from"../gateway-models.js";import{mirrorInstallCommand as k,brandInstallScripts as b}from"./tool-installs.js";const j=()=>n(c(),".codex"),w=()=>n(j(),"config.toml"),O=()=>n(j(),"auth.json"),v="OPENAI_API_KEY",C="custom",M=1e6,E=9e5;export const CODEX_ONE_MILLION_CONTEXT_SETTING="one_million_context";function N(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function S(e,t){return N(e[t])||(e[t]={}),e[t]}function A(){if(!e(w()))return{};const o=t(w(),"utf-8");if(!o.trim())return{};try{const e=r.parse(o);if(!N(e))throw new Error("config.toml root must be a TOML table");return e}catch(e){throw new Error(`Existing ~/.codex/config.toml cannot be parsed, back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}}function P(){if(!e(O()))return{};try{const e=JSON.parse(t(O(),"utf-8"));return N(e)?e:{}}catch{return{}}}let T=null;function I(e){const t=e.profiles;if(N(t)){for(const[e,o]of Object.entries(t))N(o)&&2===Object.keys(o).length&&o.model_provider===C&&o.model===e&&delete t[e];0===Object.keys(t).length&&delete e.profiles}}let L=null;function D(o,n,r){const l=!1!==n.settings?.one_million_context;!function(e){e.model_context_window===M&&delete e.model_context_window,e.model_auto_compact_token_limit===E&&delete e.model_auto_compact_token_limit}(o);const d=g()??f();if(!d)return i.logError("codexAdapter.writeModelCatalog",new Error("no Codex binary found; model catalog skipped")),L="skipped",o.model_catalog_json===_()&&delete o.model_catalog_json,void(l&&(o.model_context_window=M,o.model_auto_compact_token_limit=E));const c=n.catalog,m=p({bundled:d,specs:y("codex",c?.clientModels),...c?{keyModels:c.models}:{},gatewayAvailable:c?.models??x(),oneMillion:l,selectedModel:r,..."gateway"===c?.oneMillionSource?{claudeOneMillion:c.oneMillion}:{}});L={listed:m.models.filter(e=>"list"===e.visibility).map(e=>({id:String(e.slug),name:String(e.display_name??e.slug)}))};const u=JSON.stringify(m,null,2)+"\n",h=_();e(h)&&t(h,"utf-8")===u||(a(h),s(h,u)),o.model_catalog_json=h}export function setCodexOneMillionContext(e,t){const o=A(),n=r.stringify(o),i="string"==typeof o.model?o.model:u("codex");D(o,{settings:{[CODEX_ONE_MILLION_CONTEXT_SETTING]:e},catalog:t},i);const l=r.stringify(o);l!==n&&(a(w()),s(w(),l))}const J={command:"codex",npmPackage:"@openai/codex",native:{binDir:"win32"===process.platform?["AppData","Local","Programs","OpenAI","Codex","bin"]:[".local","bin"],updateArgs:["update"],updateTimeoutMs:12e4,dataDirs:[[".codex","packages","standalone"]]},mirrorScript:b("codex"),brew:"codex"};export const codexAdapter={name:"codex",displayName:"Codex",command:"codex",installCommand:k(J),installSpec:J,configPath:w(),wantsModelCatalog:!0,listedModels(){if(A().model_catalog_json!==_())return null;try{return(JSON.parse(t(_(),"utf-8")).models??[]).filter(e=>"list"===e.visibility).map(e=>String(e.slug))}catch{return null}},refreshModelMenu(e){A().model_catalog_json===_()&&setCodexOneMillionContext(!1!==e.settings?.one_million_context,e.catalog)},applyNotes(){if("skipped"===L)return[{kind:"action",text:l.t("tools.codex.catalog_skipped")}];if(!L)return[];const e=new Map;for(const t of L.listed)e.set(h(t.id),(e.get(h(t.id))??0)+1);const t=["gpt","claude","gemini","other","grok"].filter(t=>e.has(t)).map(t=>`${l.t(`tools.model_family.${t}`)} ${e.get(t)}`).join(" · ");return[{kind:"summary",text:l.t("tools.codex.catalog_written",{count:String(L.listed.length),breakdown:t})},{kind:"detail",text:L.listed.map(e=>e.name).join(", ")}]},loadPrivateConfig(e){const t=u("codex"),o=d(e.models,t),n=function(e){return/(?:^|\/)claude(?:-|$)/i.test(e)}(o)?t:o,i=m(e.baseUrl),l=A();l.model=n,l.model_provider=C,l.model_reasoning_effort="high",D(l,e,n);const c=S(l,"model_providers"),p=N(c[C])?{...c[C]}:{};delete p.env_key;const{experimental_bearer_token:_,...g}=p;c[C]={...g,name:"custom",wire_api:"responses",requires_openai_auth:!0,base_url:i},I(l),S(S(l,"tui"),"model_availability_nux")[n]=4;const f=S(l,"features");f.goals=!0,f.js_repl=!1,a(w()),s(w(),r.stringify(l)),function(e){const t=e.trim();if(!t)return;const o={...P(),auth_mode:"apikey",[v]:t};a(O()),s(O(),JSON.stringify(o,null,2)+"\n")}(e.apiKey)},unloadPrivateConfig(t){if(T=function(e){const t=P(),n="string"==typeof t[v]?t[v].trim():"";if(!n)return N(t.tokens)?"chatgpt":null;if(!e.includes(n))return"other_key";const{[v]:r,auth_mode:i,...l}=t;return a(O()),N(l.tokens)?(s(O(),JSON.stringify({...l,auth_mode:"chatgpt"},null,2)+"\n"),"chatgpt"):(o(O(),{force:!0}),"signed_out")}(t?.savedKeys??[]),!e(w()))return;let n;try{n=A()}catch(e){return void i.logError("codexAdapter.unloadPrivateConfig",e)}const l=n.model_providers;N(l)&&(delete l[C],0===Object.keys(l).length&&delete n.model_providers),n.model_provider===C&&delete n.model_provider,n.model_catalog_json===_()&&delete n.model_catalog_json,I(n),a(w()),s(w(),r.stringify(n))},unloadNotes(){switch(T){case"chatgpt":return[{kind:"action",text:l.t("tools.codex.unload_chatgpt_restored")}];case"other_key":return[{kind:"action",text:l.t("tools.codex.unload_other_key")}];default:return[{kind:"action",text:l.t("tools.codex.unload_sign_in")}]}},detectCurrentConfig(){const e=P()[v];return{apiKey:"string"==typeof e&&e.trim()?e.trim():null}},getConfig(){try{return A()}catch(e){return i.logError("codexAdapter.getConfig",e),null}},backupPaths:()=>[w(),O(),_()]};export function codexAuthProblem(){try{const e=A(),t=e.model_providers?.[C];if(e.model_provider!==C||!t)return null;if("string"==typeof t.experimental_bearer_token&&t.experimental_bearer_token)return"stale_bearer";const o=P();return!0===t.requires_openai_auth&&"chatgpt"===o.auth_mode?"chatgpt_login":null}catch{return null}}
|
|
@@ -39,6 +39,10 @@ export interface ApplyNote {
|
|
|
39
39
|
kind: 'summary' | 'action' | 'detail';
|
|
40
40
|
text: string;
|
|
41
41
|
}
|
|
42
|
+
export interface ToolUnloadContext {
|
|
43
|
+
/** Every API key this CLI has saved (all profiles, default and tool-specific): a key in the tool equal to one of these is ours to remove. */
|
|
44
|
+
savedKeys: string[];
|
|
45
|
+
}
|
|
42
46
|
export interface ToolAdapter {
|
|
43
47
|
/** Stable id used on the CLI and as the config key (e.g. `codex`). */
|
|
44
48
|
name: string;
|
|
@@ -108,7 +112,9 @@ export interface ToolAdapter {
|
|
|
108
112
|
/** Write this CLI's provider config into the tool. */
|
|
109
113
|
loadPrivateConfig(ctx: ToolApplyContext): void;
|
|
110
114
|
/** Remove this CLI's provider config from the tool, leaving other config intact. */
|
|
111
|
-
unloadPrivateConfig(): void;
|
|
115
|
+
unloadPrivateConfig(ctx?: ToolUnloadContext): void;
|
|
116
|
+
/** Localized next steps after the last `unloadPrivateConfig` (e.g. how to sign in with the vendor's own account). */
|
|
117
|
+
unloadNotes?(): ApplyNote[];
|
|
112
118
|
/** Read back the api key currently configured for this tool, if any. */
|
|
113
119
|
detectCurrentConfig(): {
|
|
114
120
|
apiKey: string | null;
|
package/dist/lib/wizard.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"inquirer";import t from"chalk";import a from"ora";import{configManager as o,DEFAULT_MODELS as i}from"./config.js";import{getPresets as n,resolvePreset as r,getToolDefaultModel as s}from"./model-registry.js";import{toolManager as l,SUPPORTED_TOOLS as c}from"./tool-manager.js";import{postApplyPrompts as d}from"./post-apply.js";import{i18n as p,detectSystemLang as m}from"./i18n.js";import{createBorderLine as u,createContentLine as _}from"../utils/string-width.js";import{validateApiKey as g,fetchModels as w}from"./api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as f}from"./tools/codex.js";import{CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as y}from"./tools/claude-desktop.js";import{addressesWithCurrent as h,ensureReachableGatewayAddress as z,fastestIndex as v,probeAll as k,probeSummary as x,reasonText as b,savedApiKey as S,switchGatewayAddress as C}from"../commands/base.js";import{readFileSync as M}from"fs";import{dirname as T,join as A}from"path";import{fileURLToPath as K}from"url";import{brand as N}from"./brand.js";const B=T(K(import.meta.url)),W=t.hex("#FF8700");export class Wizard{static instance;BOX_WIDTH=63;validatedApiKeys=new Set;constructor(){}static getInstance(){return Wizard.instance||(Wizard.instance=new Wizard),Wizard.instance}createBox(e){console.log(W.bold("\n"+u("╔","╗","═",this.BOX_WIDTH))),console.log(W.bold(_(e,"║","║",this.BOX_WIDTH,"center"))),console.log(W.bold(u("╚","╝","═",this.BOX_WIDTH))),console.log("")}showOperationHints(){const e=[t.gray(p.t("wizard.hint_navigate")),t.gray(p.t("wizard.hint_confirm"))];console.log(t.gray("💡 ")+e.join(t.gray(" | "))+"\n")}async promptWithHints(t){this.showOperationHints();const a=t.map(e=>"list"!==e.type||e.pageSize?e:{...e,pageSize:20});return e.prompt(a)}printBanner(){const e=60,t=p.t("wizard.banner_subtitle"),a=_(t,"║","║",e,"center"),o=_("","║","║",e,"center"),i=_(`${N().productName} v${function(){try{return JSON.parse(M(A(B,"..","..","package.json"),"utf-8")).version}catch{return"0.0.0"}}()}`,"║","║",e,"center"),n=[String.raw`__ ___ _ ____ _ ___ `,String.raw`\ \ / (_) |__ ___ / ___| | |_ _|`,String.raw` \ \ / /| | '_ \ / _ \ | | | | | `,String.raw` \ V / | | |_) | __/ |___| |___ | | `,String.raw` \_/ |_|_.__/ \___|\____|_____|___|`],r=Math.max(...n.map(e=>e.length)),s=" ".repeat(Math.floor((58-r)/2)),l=n.map(t=>_(s+t,"║","║",e,"left")),c=[u("╔","╗","═",e),o,...l,o,i,a,u("╚","╝","═",e)];console.log(W.bold("\n"+c.join("\n")))}resetScreen(){console.clear(),this.printBanner()}printGoodbye(){const e=l.getSupportedTools().filter(e=>{try{return Boolean(l.detectCurrentConfig(e.name).apiKey)}catch{return!1}});let a;if(e.length>0){const t=e.map(e=>e.command).join(" / ");a=p.t("wizard.goodbye_message_tools",{commands:t}),e.some(e=>"claude-code"===e.name)&&(a+=" "+p.t("wizard.goodbye_claude_hint"))}else a=p.t("wizard.goodbye_message");console.log(t.green("\n👋 "+a))}async runFirstTimeSetup(){const e="zh_CN"===m();e&&(o.setLang("zh_CN"),p.setLocale("zh_CN")),this.resetScreen(),console.log(W.bold("\n"+p.t("wizard.welcome"))),console.log(t.gray(p.t("wizard.privacy_note")+"\n")),e?console.log(t.gray(p.t("wizard.lang_auto_zh")+"\n")):await this.configLanguage(),await z(),await this.configApiKey()&&await this.selectAndConfigureTool(!0)}async configLanguage(){for(;;){this.resetScreen(),this.createBox(p.t("wizard.select_language"));const a=p.getLocale(),{language:i}=await this.promptWithHints([{type:"list",name:"language",message:"✨ "+p.t("wizard.select_language"),choices:[{name:"[EN] English"+("en_US"===a?t.green(" ✓ ("+p.t("wizard.current_active")+")"):""),value:"en_US"},{name:"[CN] 中文"+("zh_CN"===a?t.green(" ✓ ("+p.t("wizard.current_active")+")"):""),value:"zh_CN"},new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"back"},{name:"x "+p.t("wizard.nav_exit"),value:"exit"}],default:"zh_CN"}]);if("exit"===i)this.printGoodbye(),process.exit(0);else if("back"===i)return;return o.setLang(i),void p.setLocale(i)}}buildPresetChoices(){const a=n(),o=a.filter(e=>e.recommended),i=a.filter(e=>!e.recommended),r=e=>({name:(p.t(e.name)!==e.name?p.t(e.name):e.name)+(e.models?t.gray(` [H:${e.models.haiku} S:${e.models.sonnet} O:${e.models.opus}]`):""),value:{type:"preset",preset:e}}),s=[];return o.length>0&&(s.push(new e.Separator(t.hex("#FF8700")("── "+p.t("wizard.recommended")+" ──"))),s.push(...o.map(r))),i.length>0&&(s.push(new e.Separator(t.gray("── "+p.t("wizard.other_models")+" ──"))),s.push(...i.map(r))),s}async handleCustomModelInput(){const a=o.getModels(),{customMode:n}=await e.prompt([{type:"list",name:"customMode",message:p.t("wizard.custom_model_mode"),choices:[{name:p.t("wizard.custom_model_single"),value:"single"},{name:p.t("wizard.custom_model_per_role"),value:"per_role"}]}]);if("single"===n){const{customModel:t}=await e.prompt([{type:"input",name:"customModel",message:p.t("wizard.input_custom_model"),default:i.sonnet}]);o.setModels({haiku:t,sonnet:t,opus:t,reasoning:t})}else{const t=await e.prompt([{type:"input",name:"haiku",message:p.t("wizard.model_haiku"),default:a.haiku},{type:"input",name:"sonnet",message:p.t("wizard.model_sonnet"),default:a.sonnet},{type:"input",name:"opus",message:p.t("wizard.model_opus"),default:a.opus},{type:"input",name:"reasoning",message:p.t("wizard.model_reasoning"),default:a.reasoning}]);o.setModels(t)}console.log(t.green("\n✓ "+p.t("wizard.models_saved")))}async configModels(a){const i=o.getApiKey();if(await this.validatedKeyForConfiguration(i))for(;;){this.resetScreen(),this.createBox(p.t("wizard.config_models"));const i=[...this.buildPresetChoices()];i.push(new e.Separator),i.push({name:"✏️ "+p.t("wizard.custom_model_input"),value:{type:"custom_input"}}),i.push(new e.Separator),i.push({name:"<- "+p.t("wizard.nav_return"),value:{type:"back"}}),i.push({name:"x "+p.t("wizard.nav_exit"),value:{type:"exit"}});const{modelChoice:n}=await this.promptWithHints([{type:"list",name:"modelChoice",message:p.t("wizard.select_model_config"),choices:i}]);if("exit"===n.type)this.printGoodbye(),process.exit(0);else{if("back"===n.type)return;if("custom_input"===n.type)return await this.handleCustomModelInput(),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig());if("preset"===n.type){const e=r(n.preset);return o.setModels(e),console.log(t.green("\n✓ "+p.t("wizard.models_saved"))),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig())}}}else await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}async promptLoadAfterModelConfig(){const{shouldLoad:t}=await e.prompt([{type:"list",name:"shouldLoad",message:p.t("wizard.load_config_now"),choices:[{name:p.t("wizard.load_config_yes"),value:!0},{name:p.t("wizard.load_config_later"),value:!1}]}]);t&&await this.selectAndConfigureTool()}async configBaseUrl(){const i=o.getBaseUrl(),n=h(),r=a(p.t("wizard.base_testing")).start(),s=await k(n,{apiKey:S(),samples:3});r.stop();const l=v(s),c=n.map((e,a)=>{const o=e.url===i?t.cyan(` ← ${p.t("base.current_mark")}`):"";return{name:`${e.url} ${t.gray(e.label)} ${x(s[a],a===l)}${o}`,value:e.url}});c.push(new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"__back__"});const{url:d}=await this.promptWithHints([{type:"list",name:"url",message:p.t("wizard.base_select"),choices:c,default:i}]);if("__back__"===d)return;const m=s[n.findIndex(e=>e.url===d)];m.ok?await C(d):console.log(t.red(p.t("base.unreachable",{url:d,reason:b(m)}))),await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}async configApiKey(){for(;;){this.resetScreen(),this.createBox(p.t("wizard.input_api_key")),console.log(t.gray("\n💡 "+p.t("wizard.api_key_input_hint"))),console.log(t.gray(" "+p.t("wizard.api_key_get_hint",{url:N().links.tokenPage}))),console.log();const{apiKey:i}=await e.prompt([{type:"password",name:"apiKey",message:p.t("wizard.input_your_api_key"),mask:"*"}]);if(!i||""===i.trim()){const{action:t}=await e.prompt([{type:"list",name:"action",message:p.t("wizard.select_action"),choices:[{name:p.t("wizard.retry_input"),value:"retry"},{name:"<- "+p.t("wizard.nav_return"),value:"back"}]}]);if("back"===t)return!1;continue}const n=a(p.t("wizard.validating_api_key")).start(),r=await g(i.trim());if(n.stop(),r.valid)return o.setApiKey(i.trim()),this.validatedApiKeys.add(i.trim()),console.log(t.green("\n✓ "+p.t("wizard.api_key_valid"))),!0;{this.validatedApiKeys.delete(i.trim()),"invalid_api_key"===r.error?console.log(t.red("\n✗ "+p.t("wizard.api_key_invalid"))):console.log(t.red("\n✗ "+p.t("wizard.api_key_network_error")));const{action:a}=await e.prompt([{type:"list",name:"action",message:p.t("wizard.select_action"),choices:[{name:p.t("wizard.retry_input"),value:"retry"},{name:"<- "+p.t("wizard.nav_return"),value:"back"}]}]);if("back"===a)return!1}}}async selectAndConfigureTool(t=!1){for(;;){this.resetScreen(),this.createBox(p.t("wizard.select_tool"));const a=l.getSupportedTools().map(e=>({name:e.displayName,value:e.name})),{tool:o}=await this.promptWithHints([{type:"list",name:"tool",message:"🛠️ "+p.t("wizard.select_tool"),choices:[...a,new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"back"},{name:"x "+p.t("wizard.nav_exit"),value:"exit"}]}]);if("exit"===o)this.printGoodbye(),process.exit(0);else if("back"===o)return;await this.configureTool(o,t)}}async configureTool(a,o=!1){const i=c[a];if(i){if(!l.isToolInstalled(a)){console.log(t.yellow("\n"+p.t("wizard.tool_not_installed",{tool:i.displayName})));const{install:o}=await e.prompt([{type:"confirm",name:"install",message:p.t("wizard.install_tool_confirm"),default:!0}]);if(!o)return;try{await l.installTool(a)}catch{return void console.log(t.red(p.t("wizard.install_failed")))}}o?await this.configureToolModel(a)&&await this.loadConfig(a):await this.showToolMenu(a)}}async showToolMenu(t){for(;;){this.resetScreen();const a=c[t];if(!a)return;this.createBox(a.displayName+" "+p.t("wizard.menu_title"));const o=[{name:"📥 "+p.t("wizard.action_load_config",{tool:a.displayName}),value:"load"},{name:"📤 "+p.t("wizard.action_unload_config",{tool:a.displayName}),value:"unload"}];l.supportsClearPinnedModels(t)&&o.push({name:"🧹 "+p.t("wizard.action_clear_model",{tool:a.displayName}),value:"clear-model"}),o.push({name:"🧨 "+p.t("wizard.action_force_config",{tool:a.displayName}),value:"force"},{name:"↩️ "+p.t("wizard.action_restore_config",{tool:a.displayName}),value:"restore"},new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"back"},{name:"x "+p.t("wizard.nav_exit"),value:"exit"});const{action:i}=await this.promptWithHints([{type:"list",name:"action",message:"⚙️ "+p.t("wizard.select_action"),choices:o}]);if("exit"===i)this.printGoodbye(),process.exit(0);else{if("back"===i)return;"load"===i?await this.configureToolModel(t)&&await this.loadConfig(t):"force"===i?await this.forceConfig(t):"unload"===i?await this.unloadConfig(t):"clear-model"===i?await this.clearPinnedModels(t):"restore"===i&&await this.restoreConfig(t)}}}singleModelOverride(e){const t=e.trim();return/claude/i.test(t)?{opus:t}:{haiku:t,sonnet:t,opus:t,reasoning:t}}hasConfiguredApiKey(){return!!o.getApiKey()?.trim()||o.listToolApiKeys().some(e=>Boolean(o.getApiKeyForTool(e)?.trim()))}async validatedKeyForConfiguration(e){const o=e?.trim();if(!o)return console.log(t.red("\n"+p.t("wizard.api_key_required"))),console.log(t.yellow(p.t("wizard.please_config_api_key_first"))),null;if(this.validatedApiKeys.has(o))return o;const i=a(p.t("wizard.validating_api_key")).start(),n=await g(o);if(n.valid)return this.validatedApiKeys.add(o),i.succeed(p.t("wizard.api_key_valid")),o;this.validatedApiKeys.delete(o);const r="invalid_api_key"===n.error?p.t("wizard.api_key_invalid"):p.t("wizard.api_key_network_error");return i.fail(r),console.log(t.red("\n"+p.t("wizard.please_reconfig_api_key"))),null}async configureToolModel(i){const n=c[i];if(!n)return!1;const l=await this.validatedKeyForConfiguration(o.getApiKeyForTool(i));if(!l)return await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}]),!1;const d="claude-code"===i,m=s(i),u=d||!m?p.t("wizard.model_builtin_default"):m;this.resetScreen(),this.createBox(n.displayName+" · "+p.t("wizard.config_models"));const _=[{name:"✅ "+p.t("wizard.use_default_model",{model:u}),value:{type:"default"}},{name:"🌐 "+p.t("wizard.fetch_models_from_api"),value:{type:"fetch"}},...this.buildPresetChoices(),new e.Separator,{name:"✏️ "+p.t("wizard.input_custom_model"),value:{type:"custom"}},new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:{type:"back"}}],{choice:g}=await this.promptWithHints([{type:"list",name:"choice",message:p.t("wizard.select_tool_model",{tool:n.displayName}),choices:_}]);if("back"===g.type)return!1;if("default"===g.type)o.setToolModel(i,null);else if("preset"===g.type)o.setToolModel(i,r(g.preset));else if("custom"===g.type){const{model:t}=await e.prompt([{type:"input",name:"model",message:p.t("wizard.input_custom_model"),default:!d&&m?m:void 0}]),a=(t||"").trim();o.setToolModel(i,a?this.singleModelOverride(a):null)}else if("fetch"===g.type){const n=a(p.t("wizard.fetching_models")).start(),r=await w(l);let s;if(n.stop(),r.ok&&r.models.length>0){const{model:t}=await e.prompt([{type:"list",name:"model",message:p.t("wizard.select_fetched_model"),pageSize:20,choices:[...r.models,new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"__back__"}]}]);if("__back__"===t)return!1;s=t}else{console.log(t.yellow("\n"+p.t("wizard.fetch_models_failed")));const{model:a}=await e.prompt([{type:"input",name:"model",message:p.t("wizard.input_custom_model"),default:!d&&m?m:void 0}]);s=(a||"").trim()}o.setToolModel(i,s?this.singleModelOverride(s):null)}if("codex"===i){const t=o.getToolSetting(i,f),{enableOneMillionContext:a}=await e.prompt([{type:"confirm",name:"enableOneMillionContext",message:p.t("wizard.codex_enable_1m_context"),default:!1!==t}]);o.setToolSetting(i,f,Boolean(a))}if("claude-desktop"===i){const t=o.getToolSetting(i,y),{hideOfficialLogin:a}=await e.prompt([{type:"confirm",name:"hideOfficialLogin",message:p.t("wizard.desktop_hide_official_login"),default:!1!==t}]);o.setToolSetting(i,y,Boolean(a))}return console.log(t.green("\n✓ "+p.t("wizard.models_saved"))),d&&console.log(t.gray("💡 "+p.t("wizard.claude_model_hint"))),!0}async forceConfig(t){const a=c[t]?.displayName||t,{confirm:o}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("config.confirm_force",{tool:a}),default:!1}]);o&&await this.loadConfig(t,{force:!0})}async loadConfig(i,n={}){const r=o.getModelsForTool(i),s=await this.validatedKeyForConfiguration(o.getApiKeyForTool(i));if(!s)return void await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}]);const m=a(p.t("wizard.loading_config")).start();try{await l.applyPrivateConfig(i,s,r,n),m.stop(),l.printApplied(i),await d([i]),n.force&&console.log(t.yellow(p.t("config.force_done",{tool:c[i]?.displayName||i})));const a=c[i]?.command;a&&console.log(t.green("\n"+p.t("wizard.run_tool_hint",{command:a})));const{nextAction:o}=await e.prompt([{type:"list",name:"nextAction",message:p.t("wizard.what_next"),choices:[{name:p.t("wizard.exit_and_start"),value:"exit"},{name:p.t("wizard.continue_config"),value:"continue"}]}]);"exit"===o&&(this.printGoodbye(),process.exit(0))}catch(a){m.fail(p.t("wizard.config_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}}async clearPinnedModels(a){const o=c[a]?.displayName||a,{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("wizard.confirm_clear_model",{tool:o}),default:!1}]);if(i){try{const e=await l.clearPinnedModels(a);0===e.length?console.log(t.yellow("\n"+p.t("config.clear_model_none",{tool:o}))):(console.log(t.green("\n✓ "+p.t("config.clear_model_done",{tool:o}))),e.forEach(e=>console.log(t.gray(` - ${e}`))),console.log(t.gray(p.t("config.clear_model_restart_hint",{tool:o}))))}catch(e){console.log(t.red("\n"+(e instanceof Error?e.message:String(e))))}await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}}async unloadConfig(o){const{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("wizard.confirm_unload_config",{tool:c[o]?.displayName||o}),default:!1}]);if(!i)return;const n=a(p.t("wizard.unloading_config")).start();try{l.unloadPrivateConfig(o),n.succeed(p.t("wizard.config_unloaded"));const{nextAction:t}=await e.prompt([{type:"list",name:"nextAction",message:p.t("wizard.what_next"),choices:[{name:p.t("wizard.exit_and_start"),value:"exit"},{name:p.t("wizard.continue_config"),value:"continue"}]}]);"exit"===t&&(this.printGoodbye(),process.exit(0))}catch(a){n.fail(p.t("wizard.config_unload_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}}async restoreConfig(o){const i=c[o]?.displayName||o,{confirm:n}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("wizard.confirm_restore_config",{tool:i}),default:!1}]);if(!n)return;const r=a(p.t("wizard.restoring_config")).start();try{const e=l.restorePrivateConfig(o).filter(e=>e.result.restored);0===e.length?r.warn(p.t("wizard.restore_no_backup")):(r.succeed(p.t("wizard.config_restored",{tool:i})),e.forEach(e=>console.log(t.gray(` ${e.file} ← ${e.result.from}`))))}catch(e){r.fail(p.t("wizard.config_restore_failed")),console.log(t.red(e instanceof Error?e.message:String(e)))}await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}async run(){await this.showMainMenu()}async showMainMenu(){if(this.hasConfiguredApiKey())for(;;){this.resetScreen();const a=o.getApiKey()||"",i=a.length>4?"sk-****"+a.slice(-4):"****";console.log(t.gray(` 🔑 API Key: ${i}`)+t.green(" ✓")),console.log("");const n=l.getSupportedTools().map(e=>({name:"🛠️ "+e.displayName,value:{type:"tool",tool:e.name}})),r=[new e.Separator(W("── "+p.t("wizard.select_tool")+" ──")),...n,new e.Separator(t.gray("── "+p.t("wizard.settings")+" ──")),{name:"🔑 "+p.t("wizard.menu_change_api_key"),value:{type:"apikey"}},{name:"🔗 "+p.t("wizard.menu_base_url",{url:o.getBaseUrl()}),value:{type:"base"}},{name:"🌐 "+p.t("wizard.menu_config_language"),value:{type:"language"}},new e.Separator,{name:"x "+p.t("wizard.nav_exit"),value:{type:"exit"}}],{action:s}=await this.promptWithHints([{type:"list",name:"action",message:"🛠️ "+p.t("wizard.select_tool"),choices:r}]);"exit"===s.type?(this.printGoodbye(),process.exit(0)):"tool"===s.type?await this.configureTool(s.tool):"apikey"===s.type?await this.configApiKey():"base"===s.type?await this.configBaseUrl():"language"===s.type&&await this.configLanguage()}else await this.runFirstTimeSetup()}}export const wizard=Wizard.getInstance();
|
|
1
|
+
import e from"inquirer";import t from"chalk";import a from"ora";import{configManager as o,DEFAULT_MODELS as i}from"./config.js";import{getPresets as n,resolvePreset as r,getToolDefaultModel as s}from"./model-registry.js";import{toolManager as l,SUPPORTED_TOOLS as c}from"./tool-manager.js";import{postApplyPrompts as d}from"./post-apply.js";import{i18n as p,detectSystemLang as m}from"./i18n.js";import{createBorderLine as u,createContentLine as _}from"../utils/string-width.js";import{validateApiKey as g,fetchModels as w}from"./api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as f}from"./tools/codex.js";import{CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as y}from"./tools/claude-desktop.js";import{addressesWithCurrent as h,ensureReachableGatewayAddress as z,fastestIndex as v,probeAll as k,probeSummary as x,reasonText as b,savedApiKey as S,switchGatewayAddress as C}from"../commands/base.js";import{readFileSync as M}from"fs";import{dirname as T,join as A}from"path";import{fileURLToPath as K}from"url";import{brand as N}from"./brand.js";const B=T(K(import.meta.url)),W=t.hex("#FF8700");export class Wizard{static instance;BOX_WIDTH=63;validatedApiKeys=new Set;constructor(){}static getInstance(){return Wizard.instance||(Wizard.instance=new Wizard),Wizard.instance}createBox(e){console.log(W.bold("\n"+u("╔","╗","═",this.BOX_WIDTH))),console.log(W.bold(_(e,"║","║",this.BOX_WIDTH,"center"))),console.log(W.bold(u("╚","╝","═",this.BOX_WIDTH))),console.log("")}showOperationHints(){const e=[t.gray(p.t("wizard.hint_navigate")),t.gray(p.t("wizard.hint_confirm"))];console.log(t.gray("💡 ")+e.join(t.gray(" | "))+"\n")}async promptWithHints(t){this.showOperationHints();const a=t.map(e=>"list"!==e.type||e.pageSize?e:{...e,pageSize:20});return e.prompt(a)}printBanner(){const e=60,t=p.t("wizard.banner_subtitle"),a=_(t,"║","║",e,"center"),o=_("","║","║",e,"center"),i=_(`${N().productName} v${function(){try{return JSON.parse(M(A(B,"..","..","package.json"),"utf-8")).version}catch{return"0.0.0"}}()}`,"║","║",e,"center"),n=[String.raw`__ ___ _ ____ _ ___ `,String.raw`\ \ / (_) |__ ___ / ___| | |_ _|`,String.raw` \ \ / /| | '_ \ / _ \ | | | | | `,String.raw` \ V / | | |_) | __/ |___| |___ | | `,String.raw` \_/ |_|_.__/ \___|\____|_____|___|`],r=Math.max(...n.map(e=>e.length)),s=" ".repeat(Math.floor((58-r)/2)),l=n.map(t=>_(s+t,"║","║",e,"left")),c=[u("╔","╗","═",e),o,...l,o,i,a,u("╚","╝","═",e)];console.log(W.bold("\n"+c.join("\n")))}resetScreen(){console.clear(),this.printBanner()}printGoodbye(){const e=l.getSupportedTools().filter(e=>{if(e.gui)return!1;try{return Boolean(l.detectCurrentConfig(e.name).apiKey)}catch{return!1}});let a;if(e.length>0){const t=e.map(e=>e.command).join(" / ");a=p.t("wizard.goodbye_message_tools",{commands:t}),e.some(e=>"claude-code"===e.name)&&(a+=" "+p.t("wizard.goodbye_claude_hint"))}else a=p.t("wizard.goodbye_message");console.log(t.green("\n👋 "+a))}async runFirstTimeSetup(){const e="zh_CN"===m();e&&(o.setLang("zh_CN"),p.setLocale("zh_CN")),this.resetScreen(),console.log(W.bold("\n"+p.t("wizard.welcome"))),console.log(t.gray(p.t("wizard.privacy_note")+"\n")),e?console.log(t.gray(p.t("wizard.lang_auto_zh")+"\n")):await this.configLanguage(),await z(),await this.configApiKey()&&await this.selectAndConfigureTool(!0)}async configLanguage(){for(;;){this.resetScreen(),this.createBox(p.t("wizard.select_language"));const a=p.getLocale(),{language:i}=await this.promptWithHints([{type:"list",name:"language",message:"✨ "+p.t("wizard.select_language"),choices:[{name:"[EN] English"+("en_US"===a?t.green(" ✓ ("+p.t("wizard.current_active")+")"):""),value:"en_US"},{name:"[CN] 中文"+("zh_CN"===a?t.green(" ✓ ("+p.t("wizard.current_active")+")"):""),value:"zh_CN"},new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"back"},{name:"x "+p.t("wizard.nav_exit"),value:"exit"}],default:"zh_CN"}]);if("exit"===i)this.printGoodbye(),process.exit(0);else if("back"===i)return;return o.setLang(i),void p.setLocale(i)}}buildPresetChoices(){const a=n(),o=a.filter(e=>e.recommended),i=a.filter(e=>!e.recommended),r=e=>({name:(p.t(e.name)!==e.name?p.t(e.name):e.name)+(e.models?t.gray(` [H:${e.models.haiku} S:${e.models.sonnet} O:${e.models.opus}]`):""),value:{type:"preset",preset:e}}),s=[];return o.length>0&&(s.push(new e.Separator(t.hex("#FF8700")("── "+p.t("wizard.recommended")+" ──"))),s.push(...o.map(r))),i.length>0&&(s.push(new e.Separator(t.gray("── "+p.t("wizard.other_models")+" ──"))),s.push(...i.map(r))),s}async handleCustomModelInput(){const a=o.getModels(),{customMode:n}=await e.prompt([{type:"list",name:"customMode",message:p.t("wizard.custom_model_mode"),choices:[{name:p.t("wizard.custom_model_single"),value:"single"},{name:p.t("wizard.custom_model_per_role"),value:"per_role"}]}]);if("single"===n){const{customModel:t}=await e.prompt([{type:"input",name:"customModel",message:p.t("wizard.input_custom_model"),default:i.sonnet}]);o.setModels({haiku:t,sonnet:t,opus:t,reasoning:t})}else{const t=await e.prompt([{type:"input",name:"haiku",message:p.t("wizard.model_haiku"),default:a.haiku},{type:"input",name:"sonnet",message:p.t("wizard.model_sonnet"),default:a.sonnet},{type:"input",name:"opus",message:p.t("wizard.model_opus"),default:a.opus},{type:"input",name:"reasoning",message:p.t("wizard.model_reasoning"),default:a.reasoning}]);o.setModels(t)}console.log(t.green("\n✓ "+p.t("wizard.models_saved")))}async configModels(a){const i=o.getApiKey();if(await this.validatedKeyForConfiguration(i))for(;;){this.resetScreen(),this.createBox(p.t("wizard.config_models"));const i=[...this.buildPresetChoices()];i.push(new e.Separator),i.push({name:"✏️ "+p.t("wizard.custom_model_input"),value:{type:"custom_input"}}),i.push(new e.Separator),i.push({name:"<- "+p.t("wizard.nav_return"),value:{type:"back"}}),i.push({name:"x "+p.t("wizard.nav_exit"),value:{type:"exit"}});const{modelChoice:n}=await this.promptWithHints([{type:"list",name:"modelChoice",message:p.t("wizard.select_model_config"),choices:i}]);if("exit"===n.type)this.printGoodbye(),process.exit(0);else{if("back"===n.type)return;if("custom_input"===n.type)return await this.handleCustomModelInput(),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig());if("preset"===n.type){const e=r(n.preset);return o.setModels(e),console.log(t.green("\n✓ "+p.t("wizard.models_saved"))),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig())}}}else await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}async promptLoadAfterModelConfig(){const{shouldLoad:t}=await e.prompt([{type:"list",name:"shouldLoad",message:p.t("wizard.load_config_now"),choices:[{name:p.t("wizard.load_config_yes"),value:!0},{name:p.t("wizard.load_config_later"),value:!1}]}]);t&&await this.selectAndConfigureTool()}async configBaseUrl(){const i=o.getBaseUrl(),n=h(),r=a(p.t("wizard.base_testing")).start(),s=await k(n,{apiKey:S(),samples:3});r.stop();const l=v(s),c=n.map((e,a)=>{const o=e.url===i?t.cyan(` ← ${p.t("base.current_mark")}`):"";return{name:`${e.url} ${t.gray(e.label)} ${x(s[a],a===l)}${o}`,value:e.url}});c.push(new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"__back__"});const{url:d}=await this.promptWithHints([{type:"list",name:"url",message:p.t("wizard.base_select"),choices:c,default:i}]);if("__back__"===d)return;const m=s[n.findIndex(e=>e.url===d)];m.ok?await C(d):console.log(t.red(p.t("base.unreachable",{url:d,reason:b(m)}))),await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}async configApiKey(){for(;;){this.resetScreen(),this.createBox(p.t("wizard.input_api_key")),console.log(t.gray("\n💡 "+p.t("wizard.api_key_input_hint"))),console.log(t.gray(" "+p.t("wizard.api_key_get_hint",{url:N().links.tokenPage}))),console.log();const{apiKey:i}=await e.prompt([{type:"password",name:"apiKey",message:p.t("wizard.input_your_api_key"),mask:"*"}]);if(!i||""===i.trim()){const{action:t}=await e.prompt([{type:"list",name:"action",message:p.t("wizard.select_action"),choices:[{name:p.t("wizard.retry_input"),value:"retry"},{name:"<- "+p.t("wizard.nav_return"),value:"back"}]}]);if("back"===t)return!1;continue}const n=a(p.t("wizard.validating_api_key")).start(),r=await g(i.trim());if(n.stop(),r.valid)return o.setApiKey(i.trim()),this.validatedApiKeys.add(i.trim()),console.log(t.green("\n✓ "+p.t("wizard.api_key_valid"))),!0;{this.validatedApiKeys.delete(i.trim()),"invalid_api_key"===r.error?console.log(t.red("\n✗ "+p.t("wizard.api_key_invalid"))):console.log(t.red("\n✗ "+p.t("wizard.api_key_network_error")));const{action:a}=await e.prompt([{type:"list",name:"action",message:p.t("wizard.select_action"),choices:[{name:p.t("wizard.retry_input"),value:"retry"},{name:"<- "+p.t("wizard.nav_return"),value:"back"}]}]);if("back"===a)return!1}}}async selectAndConfigureTool(t=!1){for(;;){this.resetScreen(),this.createBox(p.t("wizard.select_tool"));const a=l.getSupportedTools().map(e=>({name:e.displayName,value:e.name})),{tool:o}=await this.promptWithHints([{type:"list",name:"tool",message:"🛠️ "+p.t("wizard.select_tool"),choices:[...a,new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"back"},{name:"x "+p.t("wizard.nav_exit"),value:"exit"}]}]);if("exit"===o)this.printGoodbye(),process.exit(0);else if("back"===o)return;await this.configureTool(o,t)}}async configureTool(a,o=!1){const i=c[a];if(i){if(!l.isToolInstalled(a)){console.log(t.yellow("\n"+p.t("wizard.tool_not_installed",{tool:i.displayName})));const{install:o}=await e.prompt([{type:"confirm",name:"install",message:p.t("wizard.install_tool_confirm"),default:!0}]);if(!o)return;try{await l.installTool(a)}catch{return void console.log(t.red(p.t("wizard.install_failed")))}}o?await this.configureToolModel(a)&&await this.loadConfig(a):await this.showToolMenu(a)}}async showToolMenu(t){for(;;){this.resetScreen();const a=c[t];if(!a)return;this.createBox(a.displayName+" "+p.t("wizard.menu_title"));const o=[{name:"📥 "+p.t("wizard.action_load_config",{tool:a.displayName}),value:"load"},{name:"📤 "+p.t("wizard.action_unload_config",{tool:a.displayName}),value:"unload"}];l.supportsClearPinnedModels(t)&&o.push({name:"🧹 "+p.t("wizard.action_clear_model",{tool:a.displayName}),value:"clear-model"}),o.push({name:"🧨 "+p.t("wizard.action_force_config",{tool:a.displayName}),value:"force"},{name:"↩️ "+p.t("wizard.action_restore_config",{tool:a.displayName}),value:"restore"},new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"back"},{name:"x "+p.t("wizard.nav_exit"),value:"exit"});const{action:i}=await this.promptWithHints([{type:"list",name:"action",message:"⚙️ "+p.t("wizard.select_action"),choices:o}]);if("exit"===i)this.printGoodbye(),process.exit(0);else{if("back"===i)return;"load"===i?await this.configureToolModel(t)&&await this.loadConfig(t):"force"===i?await this.forceConfig(t):"unload"===i?await this.unloadConfig(t):"clear-model"===i?await this.clearPinnedModels(t):"restore"===i&&await this.restoreConfig(t)}}}singleModelOverride(e){const t=e.trim();return/claude/i.test(t)?{opus:t}:{haiku:t,sonnet:t,opus:t,reasoning:t}}hasConfiguredApiKey(){return!!o.getApiKey()?.trim()||o.listToolApiKeys().some(e=>Boolean(o.getApiKeyForTool(e)?.trim()))}async validatedKeyForConfiguration(e){const o=e?.trim();if(!o)return console.log(t.red("\n"+p.t("wizard.api_key_required"))),console.log(t.yellow(p.t("wizard.please_config_api_key_first"))),null;if(this.validatedApiKeys.has(o))return o;const i=a(p.t("wizard.validating_api_key")).start(),n=await g(o);if(n.valid)return this.validatedApiKeys.add(o),i.succeed(p.t("wizard.api_key_valid")),o;this.validatedApiKeys.delete(o);const r="invalid_api_key"===n.error?p.t("wizard.api_key_invalid"):p.t("wizard.api_key_network_error");return i.fail(r),console.log(t.red("\n"+p.t("wizard.please_reconfig_api_key"))),null}async configureToolModel(i){const n=c[i];if(!n)return!1;const l=await this.validatedKeyForConfiguration(o.getApiKeyForTool(i));if(!l)return await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}]),!1;const d="claude-code"===i,m=s(i),u=d||!m?p.t("wizard.model_builtin_default"):m;this.resetScreen(),this.createBox(n.displayName+" · "+p.t("wizard.config_models"));const _=[{name:"✅ "+p.t("wizard.use_default_model",{model:u}),value:{type:"default"}},{name:"🌐 "+p.t("wizard.fetch_models_from_api"),value:{type:"fetch"}},...this.buildPresetChoices(),new e.Separator,{name:"✏️ "+p.t("wizard.input_custom_model"),value:{type:"custom"}},new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:{type:"back"}}],{choice:g}=await this.promptWithHints([{type:"list",name:"choice",message:p.t("wizard.select_tool_model",{tool:n.displayName}),choices:_}]);if("back"===g.type)return!1;if("default"===g.type)o.setToolModel(i,null);else if("preset"===g.type)o.setToolModel(i,r(g.preset));else if("custom"===g.type){const{model:t}=await e.prompt([{type:"input",name:"model",message:p.t("wizard.input_custom_model"),default:!d&&m?m:void 0}]),a=(t||"").trim();o.setToolModel(i,a?this.singleModelOverride(a):null)}else if("fetch"===g.type){const n=a(p.t("wizard.fetching_models")).start(),r=await w(l);let s;if(n.stop(),r.ok&&r.models.length>0){const{model:t}=await e.prompt([{type:"list",name:"model",message:p.t("wizard.select_fetched_model"),pageSize:20,choices:[...r.models,new e.Separator,{name:"<- "+p.t("wizard.nav_return"),value:"__back__"}]}]);if("__back__"===t)return!1;s=t}else{console.log(t.yellow("\n"+p.t("wizard.fetch_models_failed")));const{model:a}=await e.prompt([{type:"input",name:"model",message:p.t("wizard.input_custom_model"),default:!d&&m?m:void 0}]);s=(a||"").trim()}o.setToolModel(i,s?this.singleModelOverride(s):null)}if("codex"===i){const t=o.getToolSetting(i,f),{enableOneMillionContext:a}=await e.prompt([{type:"confirm",name:"enableOneMillionContext",message:p.t("wizard.codex_enable_1m_context"),default:!1!==t}]);o.setToolSetting(i,f,Boolean(a))}if("claude-desktop"===i){const t=o.getToolSetting(i,y),{hideOfficialLogin:a}=await e.prompt([{type:"confirm",name:"hideOfficialLogin",message:p.t("wizard.desktop_hide_official_login"),default:!1!==t}]);o.setToolSetting(i,y,Boolean(a))}return console.log(t.green("\n✓ "+p.t("wizard.models_saved"))),d&&console.log(t.gray("💡 "+p.t("wizard.claude_model_hint"))),!0}async forceConfig(t){const a=c[t]?.displayName||t,{confirm:o}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("config.confirm_force",{tool:a}),default:!1}]);o&&await this.loadConfig(t,{force:!0})}async loadConfig(i,n={}){const r=o.getModelsForTool(i),s=await this.validatedKeyForConfiguration(o.getApiKeyForTool(i));if(!s)return void await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}]);const m=a(p.t("wizard.loading_config")).start();try{await l.applyPrivateConfig(i,s,r,n),m.stop(),l.printApplied(i),await d([i]),n.force&&console.log(t.yellow(p.t("config.force_done",{tool:c[i]?.displayName||i})));const a=c[i]?.command;a&&console.log(t.green("\n"+p.t("wizard.run_tool_hint",{command:a})));const{nextAction:o}=await e.prompt([{type:"list",name:"nextAction",message:p.t("wizard.what_next"),choices:[{name:p.t("wizard.exit_and_start"),value:"exit"},{name:p.t("wizard.continue_config"),value:"continue"}]}]);"exit"===o&&(this.printGoodbye(),process.exit(0))}catch(a){m.fail(p.t("wizard.config_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}}async clearPinnedModels(a){const o=c[a]?.displayName||a,{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("wizard.confirm_clear_model",{tool:o}),default:!1}]);if(i){try{const e=await l.clearPinnedModels(a);0===e.length?console.log(t.yellow("\n"+p.t("config.clear_model_none",{tool:o}))):(console.log(t.green("\n✓ "+p.t("config.clear_model_done",{tool:o}))),e.forEach(e=>console.log(t.gray(` - ${e}`))),console.log(t.gray(p.t("config.clear_model_restart_hint",{tool:o}))))}catch(e){console.log(t.red("\n"+(e instanceof Error?e.message:String(e))))}await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}}async unloadConfig(o){const{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("wizard.confirm_unload_config",{tool:c[o]?.displayName||o}),default:!1}]);if(!i)return;const n=a(p.t("wizard.unloading_config")).start();try{const a=l.unloadPrivateConfig(o);n.succeed(p.t("wizard.config_unloaded")),a.forEach(e=>console.log(t.yellow(" ! "+e.text)));const{nextAction:i}=await e.prompt([{type:"list",name:"nextAction",message:p.t("wizard.what_next"),choices:[{name:p.t("wizard.exit_and_start"),value:"exit"},{name:p.t("wizard.continue_config"),value:"continue"}]}]);"exit"===i&&(this.printGoodbye(),process.exit(0))}catch(a){n.fail(p.t("wizard.config_unload_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}}async restoreConfig(o){const i=c[o]?.displayName||o,{confirm:n}=await e.prompt([{type:"confirm",name:"confirm",message:p.t("wizard.confirm_restore_config",{tool:i}),default:!1}]);if(!n)return;const r=a(p.t("wizard.restoring_config")).start();try{const e=l.restorePrivateConfig(o).filter(e=>e.result.restored);0===e.length?r.warn(p.t("wizard.restore_no_backup")):(r.succeed(p.t("wizard.config_restored",{tool:i})),e.forEach(e=>console.log(t.gray(` ${e.file} ← ${e.result.from}`))))}catch(e){r.fail(p.t("wizard.config_restore_failed")),console.log(t.red(e instanceof Error?e.message:String(e)))}await e.prompt([{type:"input",name:"continue",message:p.t("wizard.press_enter")}])}async run(){await this.showMainMenu()}async showMainMenu(){if(this.hasConfiguredApiKey())for(;;){this.resetScreen();const a=o.getApiKey()||"",i=a.length>4?"sk-****"+a.slice(-4):"****";console.log(t.gray(` 🔑 API Key: ${i}`)+t.green(" ✓")),console.log("");const n=l.getSupportedTools().map(e=>({name:"🛠️ "+e.displayName,value:{type:"tool",tool:e.name}})),r=[new e.Separator(W("── "+p.t("wizard.select_tool")+" ──")),...n,new e.Separator(t.gray("── "+p.t("wizard.settings")+" ──")),{name:"🔑 "+p.t("wizard.menu_change_api_key"),value:{type:"apikey"}},{name:"🔗 "+p.t("wizard.menu_base_url",{url:o.getBaseUrl()}),value:{type:"base"}},{name:"🌐 "+p.t("wizard.menu_config_language"),value:{type:"language"}},new e.Separator,{name:"x "+p.t("wizard.nav_exit"),value:{type:"exit"}}],{action:s}=await this.promptWithHints([{type:"list",name:"action",message:"🛠️ "+p.t("wizard.select_tool"),choices:r}]);"exit"===s.type?(this.printGoodbye(),process.exit(0)):"tool"===s.type?await this.configureTool(s.tool):"apikey"===s.type?await this.configApiKey():"base"===s.type?await this.configBaseUrl():"language"===s.type&&await this.configLanguage()}else await this.runFirstTimeSetup()}}export const wizard=Wizard.getInstance();
|
package/dist/locales/en_US.json
CHANGED
|
@@ -287,7 +287,10 @@
|
|
|
287
287
|
"clear_model_unsupported": "{{tool}} does not support clearing model settings",
|
|
288
288
|
"clear_model_restart_hint": "Restart {{tool}} to apply (your API key, hooks and MCP config were left untouched)",
|
|
289
289
|
"confirm_force": "Reset {{tool}}? Its config files are snapshotted, deleted, and rewritten from the recommended configuration (fields you added by hand are lost; undo with restore)",
|
|
290
|
-
"force_done": "Reset {{tool}}'s config files (originals snapshotted; undo with `{{cli}} config {{tool}} restore`)"
|
|
290
|
+
"force_done": "Reset {{tool}}'s config files (originals snapshotted; undo with `{{cli}} config {{tool}} restore`)",
|
|
291
|
+
"confirm_remove": "Remove the {{brand}} configuration from {{tool}}? (The current state is backed up first; {{cli}} config {{name}} restore brings it back)",
|
|
292
|
+
"remove_dry_run": "Would remove the {{brand}} provider, key and model settings from {{tool}}, keeping everything else",
|
|
293
|
+
"remove_done": "Removed the {{brand}} configuration from {{tool}}"
|
|
291
294
|
},
|
|
292
295
|
"logs": {
|
|
293
296
|
"directory": "Logs directory: {{dir}}",
|
|
@@ -384,7 +387,10 @@
|
|
|
384
387
|
},
|
|
385
388
|
"codex": {
|
|
386
389
|
"catalog_written": "{{count}} models in the menu ({{breakdown}}); reopen the Codex desktop app to see them",
|
|
387
|
-
"catalog_skipped": "Couldn't read Codex's built-in model list (not installed, or older than 0.122), so the menu has GPT models only; run {{cli}} upgrade codex, then {{cli}} config codex --non-interactive"
|
|
390
|
+
"catalog_skipped": "Couldn't read Codex's built-in model list (not installed, or older than 0.122), so the menu has GPT models only; run {{cli}} upgrade codex, then {{cli}} config codex --non-interactive",
|
|
391
|
+
"unload_sign_in": "Codex is no longer signed in with an API key. To use your ChatGPT subscription, run codex login; quit the Codex desktop app completely, reopen it and sign in",
|
|
392
|
+
"unload_chatgpt_restored": "Codex is back on your ChatGPT sign-in; quit the Codex desktop app completely and reopen it",
|
|
393
|
+
"unload_other_key": "Codex is still signed in with another API key (not the {{brand}} key, left as is). To use your ChatGPT subscription, run codex logout, then codex login"
|
|
388
394
|
},
|
|
389
395
|
"claude_desktop": {
|
|
390
396
|
"restart_hint": "Fully quit Claude Desktop and reopen it for the change to take effect",
|
|
@@ -665,7 +671,8 @@
|
|
|
665
671
|
"preset_delete": "Delete a preset",
|
|
666
672
|
"backup_list": "List backups of the {{product}} config",
|
|
667
673
|
"backup_create": "Back up the {{product}} config (optional label)",
|
|
668
|
-
"backup_restore": "Restore the {{product}} config from a backup"
|
|
674
|
+
"backup_restore": "Restore the {{product}} config from a backup",
|
|
675
|
+
"tool_remove": "Remove the provider, key and model settings {{brand}} wrote, keeping everything else"
|
|
669
676
|
},
|
|
670
677
|
"tools_title": "Tool names:",
|
|
671
678
|
"ex": {
|
|
@@ -673,7 +680,8 @@
|
|
|
673
680
|
"force": "Rewrite the whole Claude Code config",
|
|
674
681
|
"tool_model": "Use a specific model in Codex only",
|
|
675
682
|
"profile": "Create a profile named work",
|
|
676
|
-
"backup": "Back up the {{product}} config before upgrading"
|
|
683
|
+
"backup": "Back up the {{product}} config before upgrading",
|
|
684
|
+
"remove": "Stop Codex using {{brand}} (e.g. go back to your ChatGPT subscription)"
|
|
677
685
|
},
|
|
678
686
|
"when": "To adjust one tool (models, rewrite or restore its config), or manage profiles, presets and backups.",
|
|
679
687
|
"needs": "Save a key before writing tool configs: {{cli}} auth <key> or {{cli}} setup --key <key>",
|
package/dist/locales/zh_CN.json
CHANGED
|
@@ -287,7 +287,10 @@
|
|
|
287
287
|
"clear_model_unsupported": "{{tool}} 不支持清除模型设置",
|
|
288
288
|
"clear_model_restart_hint": "请重启 {{tool}} 后生效(API Key 与你的 hooks / MCP 配置未改动)",
|
|
289
289
|
"confirm_force": "确认重置 {{tool}} 的配置吗?会先快照、再删掉它的配置文件,用推荐配置整份重写(您自行添加的字段会丢失,可用 restore 撤销)",
|
|
290
|
-
"force_done": "已重置 {{tool}} 的配置文件(原文件已快照,`{{cli}} config {{tool}} restore` 可撤销)"
|
|
290
|
+
"force_done": "已重置 {{tool}} 的配置文件(原文件已快照,`{{cli}} config {{tool}} restore` 可撤销)",
|
|
291
|
+
"confirm_remove": "确定从 {{tool}} 移除 {{brand}} 的配置吗?(当前状态会先自动备份,可用 {{cli}} config {{name}} restore 还原)",
|
|
292
|
+
"remove_dry_run": "将从 {{tool}} 移除 {{brand}} 的服务商、Key 和模型设置,其它设置保留",
|
|
293
|
+
"remove_done": "已从 {{tool}} 移除 {{brand}} 的配置"
|
|
291
294
|
},
|
|
292
295
|
"logs": {
|
|
293
296
|
"directory": "日志目录: {{dir}}",
|
|
@@ -384,7 +387,10 @@
|
|
|
384
387
|
},
|
|
385
388
|
"codex": {
|
|
386
389
|
"catalog_written": "模型菜单 {{count}} 个({{breakdown}}),Codex 桌面版重开后生效",
|
|
387
|
-
"catalog_skipped": "没读到 Codex 自带的模型列表(未安装或版本低于 0.122),模型菜单只有 GPT;运行 {{cli}} upgrade codex 后再运行 {{cli}} config codex --non-interactive"
|
|
390
|
+
"catalog_skipped": "没读到 Codex 自带的模型列表(未安装或版本低于 0.122),模型菜单只有 GPT;运行 {{cli}} upgrade codex 后再运行 {{cli}} config codex --non-interactive",
|
|
391
|
+
"unload_sign_in": "Codex 已退出 API Key 登录。改用 ChatGPT 订阅:终端运行 codex login;Codex 桌面版完全退出后重开,按提示登录",
|
|
392
|
+
"unload_chatgpt_restored": "Codex 已改回你的 ChatGPT 登录;Codex 桌面版完全退出后重开即可",
|
|
393
|
+
"unload_other_key": "Codex 仍在用另一个 API Key 登录(不是 {{brand}} 的 Key,没有动它)。改用 ChatGPT 订阅:运行 codex logout,再运行 codex login"
|
|
388
394
|
},
|
|
389
395
|
"claude_desktop": {
|
|
390
396
|
"restart_hint": "完全退出 Claude 桌面端再重新打开才会生效",
|
|
@@ -665,7 +671,8 @@
|
|
|
665
671
|
"preset_delete": "删除预设",
|
|
666
672
|
"backup_list": "列出 {{product}} 配置的备份",
|
|
667
673
|
"backup_create": "备份 {{product}} 配置(可加标签)",
|
|
668
|
-
"backup_restore": "从备份还原 {{product}} 配置"
|
|
674
|
+
"backup_restore": "从备份还原 {{product}} 配置",
|
|
675
|
+
"tool_remove": "移除 {{brand}} 写入的服务商、Key 和模型设置,其它设置保留"
|
|
669
676
|
},
|
|
670
677
|
"tools_title": "工具名:",
|
|
671
678
|
"ex": {
|
|
@@ -673,7 +680,8 @@
|
|
|
673
680
|
"force": "把 Claude Code 的配置整份重写",
|
|
674
681
|
"tool_model": "Codex 单独用某个模型",
|
|
675
682
|
"profile": "新建一个叫 work 的 profile",
|
|
676
|
-
"backup": "升级前备份 {{product}} 配置"
|
|
683
|
+
"backup": "升级前备份 {{product}} 配置",
|
|
684
|
+
"remove": "不再让 Codex 用 {{brand}}(例如改回 ChatGPT 订阅登录)"
|
|
677
685
|
},
|
|
678
686
|
"when": "调整单个工具(换模型、重写或还原配置),或管理 profile、模型预设和备份时。",
|
|
679
687
|
"needs": "写工具配置前要先保存 Key:{{cli}} auth <key> 或 {{cli}} setup --key <key>",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeapi/api-helper",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.105",
|
|
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",
|