@vibeapi/cli 0.0.53 → 0.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/config.js +1 -1
- package/dist/commands/setup.js +1 -1
- package/dist/lib/claude-code-manager.js +1 -1
- package/dist/lib/config.js +1 -1
- package/dist/lib/gateway-models.d.ts +5 -0
- package/dist/lib/gateway-models.js +1 -1
- package/dist/lib/model-registry.d.ts +4 -0
- package/dist/lib/model-registry.js +1 -1
- package/dist/lib/tool-manager.d.ts +7 -1
- package/dist/lib/tool-manager.js +1 -1
- package/dist/lib/tools/claude-code.d.ts +1 -1
- package/dist/lib/tools/claude-code.js +1 -1
- package/dist/lib/tools/claude-desktop.d.ts +5 -0
- package/dist/lib/tools/claude-desktop.js +1 -1
- package/dist/lib/tools/codex-catalog.js +1 -1
- package/dist/lib/tools/codex.js +1 -1
- package/dist/lib/tools/types.d.ts +11 -6
- package/dist/lib/wizard.js +1 -1
- package/dist/locales/en_US.json +19 -12
- package/dist/locales/zh_CN.json +19 -12
- package/dist/models.json +6 -2
- package/dist/settings-template.json +1 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +1 -1
- package/models.json +6 -2
- package/package.json +1 -1
- package/settings-template.json +1 -0
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 s}from"../lib/config.js";import{confirmAction as a,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 _(s,f,d){if(!l[s])return void console.log(e.red(i.t("config.unknown_tool",{tool:s})));const g=(f[0]||"").toLowerCase();if("backups"!==g&&"list-backups"!==g){if("restore"===g){if(!await a({message:i.t("config.confirm_restore",{tool:l[s].displayName}),defaultValue:!1}))return;return void p(s,"restore")}if("clear-model"===g||"clear-models"===g){const o=l[s].displayName;return n.supportsClearPinnedModels(s)?void await c({description:i.t("config.clear_model_dry_run",{tool:o}),json:{action:"clear_model",tool:s},apply:async()=>{const t=await n.clearPinnedModels(s);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(s)){if(d.nonInteractive)return void console.log(e.yellow(i.t("wizard.tool_not_installed",{tool:l[s].displayName})));console.log(e.yellow(i.t("wizard.tool_not_installed",{tool:l[s].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(s)}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(s);if(!o)return void console.log(e.red(i.t("wizard.api_key_required")));if(d.force&&!d.nonInteractive&&!await a({message:i.t("config.confirm_force",{tool:l[s].displayName}),defaultValue:!1}))return;return await n.applyPrivateConfig(s,o,r.getModelsForTool(s),{force:d.force}),d.force&&console.log(e.yellow(i.t("config.force_done",{tool:l[s].displayName}))),
|
|
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 s}from"../lib/config.js";import{confirmAction as a,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 _(s,f,d){if(!l[s])return void console.log(e.red(i.t("config.unknown_tool",{tool:s})));const g=(f[0]||"").toLowerCase();if("backups"!==g&&"list-backups"!==g){if("restore"===g){if(!await a({message:i.t("config.confirm_restore",{tool:l[s].displayName}),defaultValue:!1}))return;return void p(s,"restore")}if("clear-model"===g||"clear-models"===g){const o=l[s].displayName;return n.supportsClearPinnedModels(s)?void await c({description:i.t("config.clear_model_dry_run",{tool:o}),json:{action:"clear_model",tool:s},apply:async()=>{const t=await n.clearPinnedModels(s);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(s)){if(d.nonInteractive)return void console.log(e.yellow(i.t("wizard.tool_not_installed",{tool:l[s].displayName})));console.log(e.yellow(i.t("wizard.tool_not_installed",{tool:l[s].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(s)}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(s);if(!o)return void console.log(e.red(i.t("wizard.api_key_required")));if(d.force&&!d.nonInteractive&&!await a({message:i.t("config.confirm_force",{tool:l[s].displayName}),defaultValue:!1}))return;return await n.applyPrivateConfig(s,o,r.getModelsForTool(s),{force:d.force}),d.force&&console.log(e.yellow(i.t("config.force_done",{tool:l[s].displayName}))),void n.printApplied(s)}await t.showToolMenu(s)}else p(s,"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===s&&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 a({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",s=(o.length>=4?o[3]:o[2]||"").trim();return l[t]?s&&g.test(n)?(r.setToolModel(t,{[n]:s}),void console.log(e.green(i.t("config.tool_model_set",{tool:t,slot:n,model:s})))):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 a({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/commands/setup.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"chalk";import{
|
|
1
|
+
import e from"chalk";import{getAdapter as o}from"../lib/tools/registry.js";import{i18n as t}from"../lib/i18n.js";import{configManager as s}from"../lib/config.js";import{toolManager as l,SUPPORTED_TOOLS as a}from"../lib/tool-manager.js";import{validateApiKey as i,fetchModels as n}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as d,setCodexOneMillionContext as r}from"../lib/tools/codex.js";import{resolveModelCatalog as p}from"../lib/model-catalog.js";import{CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as c}from"../lib/tools/claude-desktop.js";async function u(e){const o=await n(e);if(!o.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,probed:!1};const t=o.models.map(e=>e.toLowerCase());return{hasClaude:t.some(e=>e.includes("claude")),hasGpt:t.some(e=>e.startsWith("gpt")||e.includes("gpt-")||/^o\d/.test(e)),hasGrok:t.some(e=>e.includes("grok")),probed:!0}}function f(e,o){return"claude"===o?e.hasClaude:"gpt"===o?e.hasGpt:e.hasGrok}export function parseOnOff(e){const o=(e??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(o)||!["off","false","hide","0","no","n"].includes(o)&&void 0}function m(o){console.log(e.green(o))}function g(o){console.log(e.yellow(o))}function y(o){console.error(e.red(o))}async function k(o,s){console.log(e.gray(t.t("setup.validating",{label:o})));const l=await i(s);return!!l.valid||(y(t.t("setup.invalid_key",{label:o,reason:l.message||l.error||"invalid"})),!1)}async function _(o,i,n,r,p){const u=a[o];try{"codex"===o&&void 0!==n&&s.setToolSetting("codex",d,n),"claude-desktop"===o&&void 0!==r&&s.setToolSetting("claude-desktop",c,!r),await l.applyPrivateConfig(o,i,s.getModelsForTool(o),{force:p})}catch(e){const o=(e instanceof Error?e.message:String(e)).replace(/\s+/g," ").trim();return y("× "+t.t("setup.apply_failed",{tool:u.displayName,reason:o})),!1}return l.printApplied(o),p&&console.log(e.gray(" "+t.t("config.force_done",{tool:u.displayName}))),"codex"===o&&void 0!==n&&console.log(e.gray(" "+t.t(n?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),l.isToolInstalled(o)||console.log(e.yellow(" ! "+t.t("setup.install_hint",{tool:u.displayName,install:u.installCommand}))),!0}export async function setupCommand(e){const i=e.key?.trim(),n=e.claudekey?.trim(),c=e.codexkey?.trim(),b=e.grokkey?.trim(),h=e.desktopkey?.trim(),x=void 0!==e.oneMillion,v=void 0!==e.claudeOfficial;let C;if(v&&(C=parseOnOff(e.claudeOfficial),void 0===C))return y(t.t("setup.claude_official_invalid",{value:String(e.claudeOfficial)})),void(process.exitCode=1);const w=Boolean(i||n||c||b||h);if(!w&&(x||v)){if(x){const o=s.getApiKeyForTool("codex");if(o)try{const l=!0===e.oneMillion;s.setToolSetting("codex",d,l);const a=await p(o);r(l,a??void 0),m(t.t(l?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(e){y(t.t("setup.apply_failed",{tool:a.codex.displayName,reason:e instanceof Error?e.message:String(e)})),process.exitCode=1}else y(t.t("setup.codex_1m_missing_key")),process.exitCode=1}if(v){const o=s.getApiKeyForTool("claude-desktop");o?await _("claude-desktop",o,void 0,C,e.force)||(process.exitCode=1):(y(t.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!w)return y(t.t("setup.usage")),void(process.exitCode=1);let K=0,G=0;const M=new Set,j=[];n&&j.push({tool:"claude-code",label:"--claudekey",apiKey:n,need:"claude"}),c&&j.push({tool:"codex",label:"--codexkey",apiKey:c,need:"gpt"}),b&&j.push({tool:"grok",label:"--grokkey",apiKey:b,need:"grok"}),h&&j.push({tool:"claude-desktop",label:"--desktopkey",apiKey:h,need:"claude"});for(const o of j){if(!await k(o.label,o.apiKey)){G+=1;continue}const l=await u(o.apiKey);!l.probed||f(l,o.need)?(l.probed||g(t.t("setup.probe_failed",{label:o.label})),s.setToolApiKey(o.tool,o.apiKey),await _(o.tool,o.apiKey,e.oneMillion,C,e.force)?(K+=1,M.add(o.tool)):G+=1):(y(t.t(`setup.key_no_${o.need}`,{label:o.label,tool:a[o.tool].displayName})),G+=1)}if(i){if(!await k("--key",i))return void(process.exitCode=1);s.setApiKey(i);const o=await u(i);if(o.probed||g(t.t("setup.probe_failed",{label:"--key"})),o.probed&&!o.hasClaude&&!o.hasGpt&&!o.hasGrok)return y(t.t("setup.key_no_family")),void(process.exitCode=1);const a=[{tool:"claude-code",capable:o.hasClaude,skipMsg:t.t("setup.skip_no_claude")},{tool:"codex",capable:o.hasGpt,skipMsg:t.t("setup.skip_no_gpt")},{tool:"grok",capable:o.hasGrok,skipMsg:t.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:o.hasClaude&&l.isToolInstalled("claude-desktop"),skipMsg:t.t("setup.skip_desktop_not_installed"),quiet:!o.hasClaude}];for(const o of a)M.has(o.tool)||(o.capable?await _(o.tool,i,e.oneMillion,C,e.force)?(K+=1,M.add(o.tool)):G+=1:o.quiet||g(o.skipMsg))}if(K>0){const e=[...M].filter(e=>!o(e)?.isInstalled).map(e=>a[e]?.command).filter(Boolean).join(" / "),s=t.t("setup.done",{count:String(K)});m("\n"+(e?`${s}${t.t("setup.done_commands",{commands:e})}`:s))}G>0&&y(t.t("setup.failed_summary",{count:String(G)})),(G>0||0===K)&&(process.exitCode=1)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as e,mkdirSync as t,readFileSync as n,writeFileSync as o,renameSync as s,unlinkSync as i}from"fs";import{join as r,dirname as a}from"path";import{
|
|
1
|
+
import{existsSync as e,mkdirSync as t,readFileSync as n,writeFileSync as o,renameSync as s,unlinkSync as i}from"fs";import{join as r,dirname as a}from"path";import{toolHome as l}from"./tools/types.js";import{logger as c}from"../utils/logger.js";import{configManager as d,DEFAULT_MODELS as g}from"./config.js";import{loadSettingsTemplate as m}from"./settings-template.js";import{cleanupAnthropicEnvVars as C}from"./env-cleanup.js";import{getClaudeCodeTierChains as f,getGatewayModelRules as O}from"./model-registry.js";import{autoCompactTokens as h,prettyModelName as u}from"./gateway-models.js";import{baseModelId as _}from"./model-catalog.js";export const MODEL_ENV_VARS=["ANTHROPIC_DEFAULT_HAIKU_MODEL","ANTHROPIC_DEFAULT_SONNET_MODEL","ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_DEFAULT_FABLE_MODEL","ANTHROPIC_MODEL","ANTHROPIC_REASONING_MODEL"];const p={opus:"ANTHROPIC_DEFAULT_OPUS_MODEL",sonnet:"ANTHROPIC_DEFAULT_SONNET_MODEL",haiku:"ANTHROPIC_DEFAULT_HAIKU_MODEL",fable:"ANTHROPIC_DEFAULT_FABLE_MODEL"},E="CLAUDE_CODE_MAX_CONTEXT_TOKENS";function T(e,t=[]){if(!e||"object"!=typeof e)return!1;const{options:n,replaceBuiltInOptions:o}=e;if(!Array.isArray(n)||o)return!1;const s=new Set([...O().models.map(e=>e.id),...t]);return n.every(e=>e&&"object"==typeof e&&s.has(e.model))}export function applyGatewayModels(e,t){if(void 0===t)return e;const n={...e};if(void 0!==n.modelPicker&&!T(n.modelPicker,t.map(e=>e.id)))return n;const o=T(n.modelPicker)?n.modelPicker.options.map(e=>e.model):[],s={...n.env||{}},i={...n.modelSettings||{}};for(const e of o){if(!i[e])continue;const{autoCompactWindow:t,...n}=i[e];Object.keys(n).length>0?i[e]=n:delete i[e]}const r=t.map(e=>e.contextWindow).filter(e=>"number"==typeof e&&e>0);if(0===t.length)delete n.modelPicker,delete s[E];else{n.modelPicker={options:t.map(e=>({model:e.id,label:e.name||u(e.id),...e.description?{description:e.description}:{}}))},r.length>0&&(s[E]=String(Math.min(...r)));for(const e of t){if(!e.contextWindow)continue;const t=h(e.contextWindow,e.autoCompactTokens);i[e.id]={...i[e.id],autoCompactWindow:Math.min(Math.max(t,1e5),1e6)}}}return Object.keys(i).length>0?n.modelSettings=i:delete n.modelSettings,Object.keys(s).length>0?n.env=s:delete n.env,n}export function resolveTierFallbacks(e){if(!e||0===e.length)return[];const t=new Set(e.map(_)),n=[];for(const[e,o]of Object.entries(f())){const s=p[e],[i,...r]=o;if(!s||!i||t.has(i))continue;const a=r.find(e=>t.has(e));a&&n.push({tier:e,envVar:s,from:i,to:a})}return n}export class ClaudeCodeManager{static instance;settingsPath;mcpConfigPath;lastTierFallbacks=[];constructor(){this.settingsPath=r(l(),".claude","settings.json"),this.mcpConfigPath=r(l(),".claude.json")}static getInstance(){return ClaudeCodeManager.instance||(ClaudeCodeManager.instance=new ClaudeCodeManager),ClaudeCodeManager.instance}ensureConfigDir(n){const o=a(n);e(o)||t(o,{recursive:!0})}atomicWrite(t,n){const r=`${t}.tmp`;try{o(r,n,"utf-8"),s(r,t)}catch(t){if(e(r))try{i(r)}catch{}throw t}}getSettings(){try{if(e(this.settingsPath)){const e=n(this.settingsPath,"utf-8");return JSON.parse(e)}}catch(e){c.warn("Failed to read Claude Code settings:",e),c.logError("ClaudeCodeManager.getSettings",e)}return{}}saveSettings(e){try{this.ensureConfigDir(this.settingsPath),this.atomicWrite(this.settingsPath,JSON.stringify(e,null,2))}catch(e){throw new Error(`Failed to save Claude Code settings: ${e}`)}}getMCPConfig(){try{if(e(this.mcpConfigPath)){const e=n(this.mcpConfigPath,"utf-8");return JSON.parse(e)}}catch(e){c.warn("Failed to read Claude Code MCP config:",e),c.logError("ClaudeCodeManager.getMCPConfig",e)}return{}}saveMCPConfig(e){try{this.ensureConfigDir(this.mcpConfigPath),this.atomicWrite(this.mcpConfigPath,JSON.stringify(e,null,2))}catch(e){throw new Error(`Failed to save Claude Code MCP config: ${e}`)}}loadPrivateConfig(e,t,n,o){this.ensureOnboardingCompleted(),C();const s=m(),i=s.env||{},{env:r,...a}=s,l=this.getSettings(),{ANTHROPIC_API_KEY:c,...f}=l.env||{},O={...f};for(const e of MODEL_ENV_VARS)delete O[e];const h={},u=e=>{const n=(t[e]||"").trim();return n&&n!==g[e]?n:null},_=u("haiku"),p=u("sonnet"),E=u("opus"),T=new Set([_&&"haiku",p&&"sonnet",E&&"opus"].filter(Boolean));this.lastTierFallbacks=resolveTierFallbacks(n).filter(e=>!T.has(e.tier));for(const e of this.lastTierFallbacks)h[e.envVar]=e.to;_&&(h.ANTHROPIC_DEFAULT_HAIKU_MODEL=_),p&&(h.ANTHROPIC_DEFAULT_SONNET_MODEL=p),E&&(h.ANTHROPIC_DEFAULT_OPUS_MODEL=E,h.ANTHROPIC_MODEL=E);const A={...l};for(const[e,t]of Object.entries(a))e in A||(A[e]=t);A.showThinkingSummaries=!0;const P={...A,env:{...O,...Object.fromEntries(Object.entries(i).filter(([e])=>!(e in O))),ANTHROPIC_AUTH_TOKEN:e,ANTHROPIC_BASE_URL:d.getBaseUrl(),...h}};E?P.model=E:Object.prototype.hasOwnProperty.call(a,"model")?P.model=a.model:delete P.model,this.saveSettings(applyGatewayModels(P,o))}ensureOnboardingCompleted(){try{const e=this.getMCPConfig();e.hasCompletedOnboarding||this.saveMCPConfig({...e,hasCompletedOnboarding:!0})}catch(e){c.warn("Failed to ensure onboarding completed:",e),c.logError("ClaudeCodeManager.ensureOnboardingCompleted",e)}}unloadPrivateConfig(){const e=this.getSettings();if(!e.env){if(void 0!==e.model){const{model:t,...n}=e;this.saveSettings(n)}return}const{ANTHROPIC_AUTH_TOKEN:t,ANTHROPIC_BASE_URL:n,API_TIMEOUT_MS:o,CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:s,CLAUDE_CODE_AUTO_MODE_SERVER:i,...r}=e.env,a={...r};for(const e of MODEL_ENV_VARS)delete a[e];const l={...applyGatewayModels({...e,env:a},[])};l.env=l.env||{},delete l.model,l.env&&0===Object.keys(l.env).length&&delete l.env,this.saveSettings(l)}clearPinnedModels(e){const t=this.getSettings(),n=t.env,o=n?.ANTHROPIC_AUTH_TOKEN?Object.fromEntries(resolveTierFallbacks(e).map(e=>[e.envVar,e.to])):{},s=[];for(const e of MODEL_ENV_VARS)n&&e in n&&n[e]!==o[e]&&s.push(e);void 0!==t.model&&s.push("model");const i=Object.entries(o).some(([e,t])=>n?.[e]!==t);if(0===s.length&&!i)return[];const r={...t};if(delete r.model,n){const e={...n};for(const t of MODEL_ENV_VARS)delete e[t];Object.assign(e,o),0===Object.keys(e).length?delete r.env:r.env=e}return this.saveSettings(r),s}getLastTierFallbacks(){return[...this.lastTierFallbacks]}detectCurrentConfig(){try{const e=this.getSettings();return e.env&&e.env.ANTHROPIC_AUTH_TOKEN?{apiKey:e.env.ANTHROPIC_AUTH_TOKEN}:{apiKey:null}}catch{return{apiKey:null}}}getExperimentalFeature(e){const t=this.getSettings();return t.env?.[e]}setExperimentalFeature(e,t){const n=this.getSettings(),o=n.env||{},s={...n,env:{...o,[e]:t}};this.saveSettings(s)}removeExperimentalFeature(e){const t=this.getSettings();if(!t.env)return;const{[e]:n,...o}=t.env,s={...t,env:o};this.saveSettings(s)}}export const claudeCodeManager=ClaudeCodeManager.getInstance();
|
package/dist/lib/config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as e,mkdirSync as t,readFileSync as i,writeFileSync as o,renameSync as s,unlinkSync as r,readdirSync as n,rmdirSync as a,statSync as c,chmodSync as l}from"fs";import{join as f,dirname as g}from"path";import{homedir as h}from"os";import{createHash as p}from"crypto";import*as m from"js-yaml";import{logger as u}from"../utils/logger.js";import{getDefaultModels as y}from"./model-registry.js";import{readLegacySecretsFile as d}from"./secret-store.js";export const DEFAULT_BASE_URL="https://www.vibeapi.cn";export const DEFAULT_MODELS=y();export const DEFAULT_PROFILE_NAME="default";const _="plaintext";export class ConfigManager{static instance;configDir;configPath;config;runtimeBaseUrl;constructor(){this.configDir=this.resolveConfigDir(),this.migrateLegacyConfigDir(),this.configPath=f(this.configDir,"config.yaml"),this.config=this.loadConfig()}migrateLegacyConfigDir(){try{const t=f(g(this.configDir),".chelper");if(t===this.configDir||!e(t))return;if(["config.yaml","secrets.enc"].some(t=>e(f(this.configDir,t))))return;if(e(this.configDir)){for(const i of n(t)){const o=f(this.configDir,i);e(o)||s(f(t,i),o)}0===n(t).length&&a(t)}else s(t,this.configDir);u.info(`Migrated config dir: ${t} -> ${this.configDir}`)}catch(e){u.warn("Failed to migrate legacy .chelper config dir:",e)}}resolveConfigDir(){const e=process.env.VIBECLI_CONFIG_DIR;if(e&&e.trim())return e.trim();const t=process.env.VIBECLI_TEST_HOME;return t&&t.trim()?f(t.trim(),".vibecli"):f(h(),".vibecli")}createDefaultConfig(){return this.syncLegacyFields({lang:"en_US",active_profile:"default",profiles:{[DEFAULT_PROFILE_NAME]:{}},presets:{}})}normalizeModels(e){const t={haiku:e?.haiku?.trim()||DEFAULT_MODELS.haiku,sonnet:e?.sonnet?.trim()||DEFAULT_MODELS.sonnet,opus:e?.opus?.trim()||DEFAULT_MODELS.opus,reasoning:e?.reasoning?.trim()||DEFAULT_MODELS.reasoning};if(e&&"object"==typeof e)for(const[i,o]of Object.entries(e))i in t||"string"==typeof o&&o.trim()&&(t[i]=o.trim());return t}normalizeToolModels(e){if(!e||"object"!=typeof e)return{};const t=Object.entries(e).flatMap(([e,t])=>{if(!e||"string"!=typeof e||!t||"object"!=typeof t)return[];const i={};for(const[e,o]of Object.entries(t))"string"==typeof o&&o.trim()&&(i[e]=o.trim());return Object.keys(i).length>0?[[e,i]]:[]});return Object.fromEntries(t)}normalizeToolSettings(e){if(!e||"object"!=typeof e||Array.isArray(e))return{};const t=Object.entries(e).flatMap(([e,t])=>{if(!e||!t||"object"!=typeof t||Array.isArray(t))return[];const i=Object.fromEntries(Object.entries(t).filter(([,e])=>"string"==typeof e||"boolean"==typeof e||"number"==typeof e&&Number.isFinite(e)));return Object.keys(i).length>0?[[e,i]]:[]});return Object.fromEntries(t)}normalizeStringRecord(e){return!e||"object"!=typeof e||Array.isArray(e)?{}:Object.fromEntries(Object.entries(e).filter(e=>"string"==typeof e[1]&&Boolean(e[1].trim())).map(([e,t])=>[e,t.trim()]))}normalizeProfile(e){if(!e)return{};const t=this.normalizeToolModels(e.tool_models),i=this.normalizeToolSettings(e.tool_settings),o=this.normalizeStringRecord(e.tool_api_keys);return{..."string"==typeof e.api_key&&e.api_key?{api_key:e.api_key}:{},...Object.keys(o).length>0?{tool_api_keys:o}:{},..."string"==typeof e.base_url&&e.base_url?{base_url:e.base_url}:{},...e.models?{models:this.normalizeModels(e.models)}:{},...Object.keys(t).length>0?{tool_models:t}:{},...Object.keys(i).length>0?{tool_settings:i}:{}}}normalizeProfiles(e){if(!e||"object"!=typeof e)return{};const t=Object.entries(e).flatMap(([e,t])=>e&&"string"==typeof e&&t&&"object"==typeof t?[[e,this.normalizeProfile(t)]]:[]);return Object.fromEntries(t)}normalizePresets(e){if(!e||"object"!=typeof e)return{};const t=Object.entries(e).flatMap(([e,t])=>{if(!e||"string"!=typeof e||!t||"object"!=typeof t)return[];const i=t;return i.models?[[e,{models:this.normalizeModels(i.models),updated_at:i.updated_at||new Date(0).toISOString()}]]:[]});return Object.fromEntries(t)}getResolvedActiveProfile(e){const t=e.active_profile||"default";return e.profiles?.[t]||{}}syncLegacyFields(e){const t=this.normalizeProfiles(e.profiles),i=e.active_profile?.trim()||Object.keys(t)[0]||"default",o=t[i]?t:{...t,[i]:{}},s=this.getResolvedActiveProfile({...e,profiles:o,active_profile:i});return{...e,lang:e.lang||"en_US",active_profile:i,profiles:o,presets:this.normalizePresets(e.presets),api_key:s.api_key,base_url:s.base_url,models:s.models?this.normalizeModels(s.models):DEFAULT_MODELS}}sanitizeBackupLabel(e){return(e||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40)}getBackupDir(){return f(this.configDir,"backups")}getLegacySecretsPath(){return f(this.configDir,"secrets.enc")}getSecretsBackupPath(e){return e.replace(/\.yaml$/,".secrets.enc")}static getInstance(){return ConfigManager.instance||(ConfigManager.instance=new ConfigManager),ConfigManager.instance}ensureConfigDir(){e(this.configDir)||t(this.configDir,{recursive:!0})}loadConfig(){try{if(e(this.configPath)){const t=i(this.configPath,"utf-8"),o=m.load(t);let s=this.migrateOldConfig(o||{lang:"en_US"}),n=!1;const a=this.getLegacySecretsPath();if(e(a)&&o?.credential_store!==_)try{s=this.mergeLegacySecrets(s,d(a)),n=!0}catch(e){u.warn("Legacy secrets.enc is unreadable on this host; it was kept for recovery and will not block new credentials."),u.logError("ConfigManager.migrateLegacySecrets",e)}if((this.needsMigration(o)||n)&&(this.backupConfig(),this.atomicWrite(this.configPath,m.dump(this.prepareForPersistence(s))),n))try{r(a)}catch(e){u.logError("ConfigManager.removeLegacySecrets",e)}try{l(this.configPath,384)}catch{}return s}const t=this.getLegacySecretsPath();if(e(t))try{const e=this.mergeLegacySecrets(this.createDefaultConfig(),d(t));this.ensureConfigDir(),this.atomicWrite(this.configPath,m.dump(this.prepareForPersistence(e)));try{r(t)}catch(e){u.logError("ConfigManager.removeLegacySecrets",e)}return e}catch(e){u.warn("Legacy secrets.enc is unreadable on this host; it was kept for recovery and will not block new credentials."),u.logError("ConfigManager.migrateLegacySecretsWithoutConfig",e)}}catch(e){u.warn("Failed to load config, using defaults:",e),u.logError("ConfigManager.loadConfig",e)}return this.createDefaultConfig()}needsMigration(e){return!(!e||"object"!=typeof e)&&("plan"in e||!("profiles"in e)||!("active_profile"in e)||!("presets"in e))}migrateOldConfig(e){if(!e||"object"!=typeof e)return this.createDefaultConfig();const t=e,{plan:i,...o}=t,s=this.normalizeProfiles(o.profiles),r=this.normalizeProfile({api_key:"string"==typeof o.api_key?o.api_key:void 0,base_url:"string"==typeof o.base_url?o.base_url:void 0,models:o.models}),n=Object.keys(s).length>0?s:{[DEFAULT_PROFILE_NAME]:r},a="string"==typeof o.active_profile&&o.active_profile.trim()?o.active_profile.trim():Object.keys(n)[0]||"default";return this.syncLegacyFields({lang:"string"==typeof o.lang&&o.lang?o.lang:"en_US",...o.credential_store===_?{credential_store:_}:{},active_profile:a,profiles:n,presets:this.normalizePresets(o.presets)})}atomicWrite(t,i){const n=`${t}.tmp`;try{o(n,i,{encoding:"utf-8",mode:384}),s(n,t);try{l(t,384)}catch{}}catch(t){if(e(n))try{r(n)}catch{}throw t}}backupConfig(){if(!e(this.configPath))return;const s=this.getBackupDir();e(s)||t(s,{recursive:!0});const r=(new Date).toISOString().replace(/[:.]/g,"-"),n=f(s,`config-${r}.yaml`);try{const e=i(this.configPath,"utf-8");o(n,e,{encoding:"utf-8",mode:384}),this.rotateBackups(s,10,30)}catch(e){u.logError("ConfigManager.backupConfig",e)}}rotateBackups(t,i,o){try{const s=Date.now()-24*o*60*60*1e3,a=n(t).filter(e=>e.startsWith("config-")&&e.endsWith(".yaml")).map(e=>({name:e,path:f(t,e),mtime:c(f(t,e)).mtime})).sort((e,t)=>t.mtime.getTime()-e.mtime.getTime()),l=new Set;a.slice(i).forEach(e=>l.add(e.path)),a.forEach(e=>{e.mtime.getTime()<s&&l.add(e.path)});for(const t of l){let i=!1;try{r(t),i=!0}catch(e){u.logError("ConfigManager.rotateBackups",e)}if(i){const i=this.getSecretsBackupPath(t);if(e(i))try{r(i)}catch(e){u.logError("ConfigManager.rotateBackups.secrets",e)}}}}catch(e){u.logError("ConfigManager.rotateBackups",e)}}saveConfig(e){try{this.ensureConfigDir(),this.backupConfig();const t=this.syncLegacyFields(this.migrateOldConfig(e||this.config)),i=this.prepareForPersistence(t),o=m.dump(i);this.atomicWrite(this.configPath,o),this.config=t}catch(e){throw u.error("Failed to save config:",e),u.logError("ConfigManager.saveConfig",e),e}}prepareForPersistence(e){const t={...e,credential_store:_};return delete t.api_key,delete t.base_url,delete t.models,t}mergeLegacySecrets(e,t){const i={...e.profiles||{}},o=new Set([...Object.keys(t.api_keys||{}),...Object.keys(t.tool_api_keys||{})]);for(const e of o){const o=i[e]||{},s=o.api_key||t.api_keys?.[e],r={...t.tool_api_keys?.[e]||{},...o.tool_api_keys||{}};i[e]={...o,...s?{api_key:s}:{},...Object.keys(r).length>0?{tool_api_keys:r}:{}}}return this.syncLegacyFields({...e,profiles:i})}getConfig(){return this.syncLegacyFields({...this.config})}updateConfig(e){this.saveConfig({...this.config,...e})}isFirstRun(){return!e(this.configPath)}getLang(){return this.config.lang||"en_US"}setLang(e){this.updateConfig({lang:e})}getActiveProfileName(){return this.config.active_profile||"default"}listProfiles(){return Object.keys(this.config.profiles||{}).sort()}getProfile(e=this.getActiveProfileName()){const t=this.config.profiles?.[e]||{};return{...t.api_key?{api_key:t.api_key}:{},...t.tool_api_keys&&Object.keys(t.tool_api_keys).length>0?{tool_api_keys:this.normalizeStringRecord(t.tool_api_keys)}:{},...t.base_url?{base_url:t.base_url}:{},models:t.models?this.normalizeModels(t.models):DEFAULT_MODELS,...t.tool_models&&Object.keys(t.tool_models).length>0?{tool_models:this.normalizeToolModels(t.tool_models)}:{},...t.tool_settings&&Object.keys(t.tool_settings).length>0?{tool_settings:this.normalizeToolSettings(t.tool_settings)}:{}}}createProfile(e,t=this.getActiveProfileName()){const i=this.getProfile(t),o={...this.config.profiles||{},[e]:{...i.api_key?{api_key:i.api_key}:{},...i.base_url?{base_url:i.base_url}:{},models:this.normalizeModels(i.models)}};this.saveConfig({...this.config,profiles:o})}setActiveProfile(e){if(!this.config.profiles?.[e])throw new Error(`Profile not found: ${e}`);this.saveConfig({...this.config,active_profile:e})}updateProfile(e,t){const i=this.config.profiles?.[e]||{},o=t.models?this.normalizeModels({...i.models,...t.models}):i.models?this.normalizeModels(i.models):void 0,s={...i,...void 0!==t.api_key?{api_key:t.api_key}:{},...void 0!==t.base_url?{base_url:t.base_url}:{},...o?{models:o}:{}},r={...this.config.profiles||{},[e]:s};this.saveConfig({...this.config,profiles:r})}deleteProfile(e){const t={...this.config.profiles||{}};if(!t[e])return;const i=Object.keys(t).filter(t=>t!==e);if(0===i.length)throw new Error("At least one profile must remain");delete t[e];const o=this.getActiveProfileName()===e?i[0]:this.getActiveProfileName();this.saveConfig({...this.config,profiles:t,active_profile:o})}getApiKey(){return this.config.profiles?.[this.getActiveProfileName()]?.api_key}setApiKey(e){this.updateProfile(this.getActiveProfileName(),{api_key:e})}revokeApiKey(){const e=this.config.profiles?.[this.getActiveProfileName()]||{},{api_key:t,tool_api_keys:i,...o}=e,s={...this.config.profiles||{},[this.getActiveProfileName()]:o};this.saveConfig({...this.config,profiles:s})}getApiKeyFingerprint(){const e=this.getApiKey();return e?p("sha256").update(e).digest("hex").slice(0,12):""}getApiKeyForTool(e){const t=this.config.profiles?.[this.getActiveProfileName()];return t?.tool_api_keys?.[e]||t?.api_key||void 0}setToolApiKey(e,t){const i=this.getActiveProfileName(),o=this.config.profiles?.[i]||{},s={...this.config.profiles||{},[i]:{...o,tool_api_keys:{...o.tool_api_keys||{},[e]:t}}};this.saveConfig({...this.config,profiles:s})}clearToolApiKey(e){const t=this.getActiveProfileName(),i=this.config.profiles?.[t]||{},{[e]:o,...s}=i.tool_api_keys||{},r={...i};Object.keys(s).length>0?r.tool_api_keys=s:delete r.tool_api_keys,this.saveConfig({...this.config,profiles:{...this.config.profiles||{},[t]:r}})}listToolApiKeys(){return Object.keys(this.config.profiles?.[this.getActiveProfileName()]?.tool_api_keys||{}).sort()}getToolApiKeyFingerprint(e){const t=this.config.profiles?.[this.getActiveProfileName()]?.tool_api_keys?.[e];return t?p("sha256").update(t).digest("hex").slice(0,12):""}getModels(){const e=this.config.profiles?.[this.getActiveProfileName()]?.models;return e?this.normalizeModels(e):DEFAULT_MODELS}setModels(e){this.updateProfile(this.getActiveProfileName(),{models:this.normalizeModels(e)})}updateModels(e){this.setModels(this.normalizeModels({...this.getModels(),...e}))}getModelsForTool(e){const t=this.getModels(),i=this.config.profiles?.[this.getActiveProfileName()]?.tool_models?.[e];return i?this.normalizeModels({...t,...i}):t}setToolModel(e,t){const i=this.getActiveProfileName(),o=this.config.profiles?.[i]||{},s={...o.tool_models||{}};t&&0!==Object.keys(t).length?s[e]=t:delete s[e];const r={...o};Object.keys(s).length>0?r.tool_models=s:delete r.tool_models;const n={...this.config.profiles||{},[i]:r};this.saveConfig({...this.config,profiles:n})}getToolSettings(e){const t=this.config.profiles?.[this.getActiveProfileName()]?.tool_settings?.[e];return t?{...t}:{}}getToolSetting(e,t){return this.config.profiles?.[this.getActiveProfileName()]?.tool_settings?.[e]?.[t]}setToolSetting(e,t,i){if(this.getToolSetting(e,t)===i)return;const o=this.getActiveProfileName(),s=this.config.profiles?.[o]||{},r={...s.tool_settings||{}};r[e]={...r[e]||{},[t]:i};const n={...this.config.profiles||{},[o]:{...s,tool_settings:r}};this.saveConfig({...this.config,profiles:n})}getCustomPresets(){return{...this.config.presets||{}}}saveCustomPreset(e,t){const i={...this.config.presets||{},[e]:{models:this.normalizeModels(t),updated_at:(new Date).toISOString()}};this.saveConfig({...this.config,presets:i})}deleteCustomPreset(e){const t={...this.config.presets||{}};t[e]&&(delete t[e],this.saveConfig({...this.config,presets:t}))}listBackups(){const t=this.getBackupDir();return e(t)?n(t).filter(e=>e.startsWith("config-")&&e.endsWith(".yaml")).map(e=>{const i=f(t,e);return{name:e,path:i,mtimeMs:c(i).mtimeMs}}).sort((e,t)=>t.mtimeMs-e.mtimeMs):[]}createBackup(s){this.ensureConfigDir();const r=this.getBackupDir();e(r)||t(r,{recursive:!0});const n=(new Date).toISOString().replace(/[:.]/g,"-"),a=this.sanitizeBackupLabel(s),c=f(r,a?`config-${n}-${a}.yaml`:`config-${n}.yaml`),l=e(this.configPath)?i(this.configPath,"utf-8"):m.dump(this.prepareForPersistence(this.getConfig()));return o(c,l,{encoding:"utf-8",mode:384}),this.rotateBackups(r,10,30),c}restoreBackup(t){if(!t||"."===t||".."===t||/[/\\]|\.\./.test(t))throw new Error(`Invalid backup name: ${t}`);const o=this.getBackupDir(),s=f(o,t);if(!e(s))throw new Error(`Backup not found: ${t}`);const r=i(s,"utf-8"),n=m.load(r),a=this.getSecretsBackupPath(s);let c=this.migrateOldConfig(n||this.createDefaultConfig());if(n?.credential_store!==_&&e(a))try{c=this.mergeLegacySecrets(c,d(a))}catch(e){throw new Error(`Legacy backup credentials could not be decrypted: ${a}`,{cause:e})}this.saveConfig(c)}getBaseUrl(){return this.runtimeBaseUrl||this.config.profiles?.[this.getActiveProfileName()]?.base_url||DEFAULT_BASE_URL}setBaseUrl(e,t=!1){this.runtimeBaseUrl=e,t&&this.updateProfile(this.getActiveProfileName(),{base_url:e})}resetBaseUrl(){this.runtimeBaseUrl=void 0;const e=this.config.profiles?.[this.getActiveProfileName()]||{},{base_url:t,...i}=e,o={...this.config.profiles||{},[this.getActiveProfileName()]:i};this.saveConfig({...this.config,profiles:o})}}export const configManager=ConfigManager.getInstance();
|
|
1
|
+
import{existsSync as e,mkdirSync as t,readFileSync as i,writeFileSync as o,renameSync as s,unlinkSync as r,readdirSync as n,rmdirSync as a,statSync as c,chmodSync as l}from"fs";import{join as f,dirname as g}from"path";import{homedir as h}from"os";import{createHash as p}from"crypto";import*as m from"js-yaml";import{logger as u}from"../utils/logger.js";import{getDefaultModels as y,isRetiredDefaultModel as d}from"./model-registry.js";import{readLegacySecretsFile as _}from"./secret-store.js";export const DEFAULT_BASE_URL="https://www.vibeapi.cn";export const DEFAULT_MODELS=y();export const DEFAULT_PROFILE_NAME="default";const k="plaintext";export class ConfigManager{static instance;configDir;configPath;config;runtimeBaseUrl;constructor(){this.configDir=this.resolveConfigDir(),this.migrateLegacyConfigDir(),this.configPath=f(this.configDir,"config.yaml"),this.config=this.loadConfig()}migrateLegacyConfigDir(){try{const t=f(g(this.configDir),".chelper");if(t===this.configDir||!e(t))return;if(["config.yaml","secrets.enc"].some(t=>e(f(this.configDir,t))))return;if(e(this.configDir)){for(const i of n(t)){const o=f(this.configDir,i);e(o)||s(f(t,i),o)}0===n(t).length&&a(t)}else s(t,this.configDir);u.record(`Migrated config dir: ${t} -> ${this.configDir}`)}catch(e){u.warn("Failed to migrate legacy .chelper config dir:",e)}}resolveConfigDir(){const e=process.env.VIBECLI_CONFIG_DIR;if(e&&e.trim())return e.trim();const t=process.env.VIBECLI_TEST_HOME;return t&&t.trim()?f(t.trim(),".vibecli"):f(h(),".vibecli")}createDefaultConfig(){return this.syncLegacyFields({lang:"en_US",active_profile:"default",profiles:{[DEFAULT_PROFILE_NAME]:{}},presets:{}})}normalizeModels(e){const t=t=>{const i=e?.[t]?.trim();return i&&!d(t,i)?i:DEFAULT_MODELS[t]},i={haiku:t("haiku"),sonnet:t("sonnet"),opus:t("opus"),reasoning:t("reasoning")};if(e&&"object"==typeof e)for(const[t,o]of Object.entries(e))t in i||"string"==typeof o&&o.trim()&&(i[t]=o.trim());return i}normalizeToolModels(e){if(!e||"object"!=typeof e)return{};const t=Object.entries(e).flatMap(([e,t])=>{if(!e||"string"!=typeof e||!t||"object"!=typeof t)return[];const i={};for(const[e,o]of Object.entries(t))"string"==typeof o&&o.trim()&&(i[e]=o.trim());return Object.keys(i).length>0?[[e,i]]:[]});return Object.fromEntries(t)}normalizeToolSettings(e){if(!e||"object"!=typeof e||Array.isArray(e))return{};const t=Object.entries(e).flatMap(([e,t])=>{if(!e||!t||"object"!=typeof t||Array.isArray(t))return[];const i=Object.fromEntries(Object.entries(t).filter(([,e])=>"string"==typeof e||"boolean"==typeof e||"number"==typeof e&&Number.isFinite(e)));return Object.keys(i).length>0?[[e,i]]:[]});return Object.fromEntries(t)}normalizeStringRecord(e){return!e||"object"!=typeof e||Array.isArray(e)?{}:Object.fromEntries(Object.entries(e).filter(e=>"string"==typeof e[1]&&Boolean(e[1].trim())).map(([e,t])=>[e,t.trim()]))}normalizeProfile(e){if(!e)return{};const t=this.normalizeToolModels(e.tool_models),i=this.normalizeToolSettings(e.tool_settings),o=this.normalizeStringRecord(e.tool_api_keys);return{..."string"==typeof e.api_key&&e.api_key?{api_key:e.api_key}:{},...Object.keys(o).length>0?{tool_api_keys:o}:{},..."string"==typeof e.base_url&&e.base_url?{base_url:e.base_url}:{},...e.models?{models:this.normalizeModels(e.models)}:{},...Object.keys(t).length>0?{tool_models:t}:{},...Object.keys(i).length>0?{tool_settings:i}:{}}}normalizeProfiles(e){if(!e||"object"!=typeof e)return{};const t=Object.entries(e).flatMap(([e,t])=>e&&"string"==typeof e&&t&&"object"==typeof t?[[e,this.normalizeProfile(t)]]:[]);return Object.fromEntries(t)}normalizePresets(e){if(!e||"object"!=typeof e)return{};const t=Object.entries(e).flatMap(([e,t])=>{if(!e||"string"!=typeof e||!t||"object"!=typeof t)return[];const i=t;return i.models?[[e,{models:this.normalizeModels(i.models),updated_at:i.updated_at||new Date(0).toISOString()}]]:[]});return Object.fromEntries(t)}getResolvedActiveProfile(e){const t=e.active_profile||"default";return e.profiles?.[t]||{}}syncLegacyFields(e){const t=this.normalizeProfiles(e.profiles),i=e.active_profile?.trim()||Object.keys(t)[0]||"default",o=t[i]?t:{...t,[i]:{}},s=this.getResolvedActiveProfile({...e,profiles:o,active_profile:i});return{...e,lang:e.lang||"en_US",active_profile:i,profiles:o,presets:this.normalizePresets(e.presets),api_key:s.api_key,base_url:s.base_url,models:s.models?this.normalizeModels(s.models):DEFAULT_MODELS}}sanitizeBackupLabel(e){return(e||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40)}getBackupDir(){return f(this.configDir,"backups")}getLegacySecretsPath(){return f(this.configDir,"secrets.enc")}getSecretsBackupPath(e){return e.replace(/\.yaml$/,".secrets.enc")}static getInstance(){return ConfigManager.instance||(ConfigManager.instance=new ConfigManager),ConfigManager.instance}ensureConfigDir(){e(this.configDir)||t(this.configDir,{recursive:!0})}loadConfig(){try{if(e(this.configPath)){const t=i(this.configPath,"utf-8"),o=m.load(t);let s=this.migrateOldConfig(o||{lang:"en_US"}),n=!1;const a=this.getLegacySecretsPath();if(e(a)&&o?.credential_store!==k)try{s=this.mergeLegacySecrets(s,_(a)),n=!0}catch(e){u.warn("Legacy secrets.enc is unreadable on this host; it was kept for recovery and will not block new credentials."),u.logError("ConfigManager.migrateLegacySecrets",e)}if((this.needsMigration(o)||n)&&(this.backupConfig(),this.atomicWrite(this.configPath,m.dump(this.prepareForPersistence(s))),n))try{r(a)}catch(e){u.logError("ConfigManager.removeLegacySecrets",e)}try{l(this.configPath,384)}catch{}return s}const t=this.getLegacySecretsPath();if(e(t))try{const e=this.mergeLegacySecrets(this.createDefaultConfig(),_(t));this.ensureConfigDir(),this.atomicWrite(this.configPath,m.dump(this.prepareForPersistence(e)));try{r(t)}catch(e){u.logError("ConfigManager.removeLegacySecrets",e)}return e}catch(e){u.warn("Legacy secrets.enc is unreadable on this host; it was kept for recovery and will not block new credentials."),u.logError("ConfigManager.migrateLegacySecretsWithoutConfig",e)}}catch(e){u.warn("Failed to load config, using defaults:",e),u.logError("ConfigManager.loadConfig",e)}return this.createDefaultConfig()}needsMigration(e){return!(!e||"object"!=typeof e)&&("plan"in e||!("profiles"in e)||!("active_profile"in e)||!("presets"in e))}migrateOldConfig(e){if(!e||"object"!=typeof e)return this.createDefaultConfig();const t=e,{plan:i,...o}=t,s=this.normalizeProfiles(o.profiles),r=this.normalizeProfile({api_key:"string"==typeof o.api_key?o.api_key:void 0,base_url:"string"==typeof o.base_url?o.base_url:void 0,models:o.models}),n=Object.keys(s).length>0?s:{[DEFAULT_PROFILE_NAME]:r},a="string"==typeof o.active_profile&&o.active_profile.trim()?o.active_profile.trim():Object.keys(n)[0]||"default";return this.syncLegacyFields({lang:"string"==typeof o.lang&&o.lang?o.lang:"en_US",...o.credential_store===k?{credential_store:k}:{},active_profile:a,profiles:n,presets:this.normalizePresets(o.presets)})}atomicWrite(t,i){const n=`${t}.tmp`;try{o(n,i,{encoding:"utf-8",mode:384}),s(n,t);try{l(t,384)}catch{}}catch(t){if(e(n))try{r(n)}catch{}throw t}}backupConfig(){if(!e(this.configPath))return;const s=this.getBackupDir();e(s)||t(s,{recursive:!0});const r=(new Date).toISOString().replace(/[:.]/g,"-"),n=f(s,`config-${r}.yaml`);try{const e=i(this.configPath,"utf-8");o(n,e,{encoding:"utf-8",mode:384}),this.rotateBackups(s,10,30)}catch(e){u.logError("ConfigManager.backupConfig",e)}}rotateBackups(t,i,o){try{const s=Date.now()-24*o*60*60*1e3,a=n(t).filter(e=>e.startsWith("config-")&&e.endsWith(".yaml")).map(e=>({name:e,path:f(t,e),mtime:c(f(t,e)).mtime})).sort((e,t)=>t.mtime.getTime()-e.mtime.getTime()),l=new Set;a.slice(i).forEach(e=>l.add(e.path)),a.forEach(e=>{e.mtime.getTime()<s&&l.add(e.path)});for(const t of l){let i=!1;try{r(t),i=!0}catch(e){u.logError("ConfigManager.rotateBackups",e)}if(i){const i=this.getSecretsBackupPath(t);if(e(i))try{r(i)}catch(e){u.logError("ConfigManager.rotateBackups.secrets",e)}}}}catch(e){u.logError("ConfigManager.rotateBackups",e)}}saveConfig(e){try{this.ensureConfigDir(),this.backupConfig();const t=this.syncLegacyFields(this.migrateOldConfig(e||this.config)),i=this.prepareForPersistence(t),o=m.dump(i);this.atomicWrite(this.configPath,o),this.config=t}catch(e){throw u.error("Failed to save config:",e),u.logError("ConfigManager.saveConfig",e),e}}prepareForPersistence(e){const t={...e,credential_store:k};return delete t.api_key,delete t.base_url,delete t.models,t}mergeLegacySecrets(e,t){const i={...e.profiles||{}},o=new Set([...Object.keys(t.api_keys||{}),...Object.keys(t.tool_api_keys||{})]);for(const e of o){const o=i[e]||{},s=o.api_key||t.api_keys?.[e],r={...t.tool_api_keys?.[e]||{},...o.tool_api_keys||{}};i[e]={...o,...s?{api_key:s}:{},...Object.keys(r).length>0?{tool_api_keys:r}:{}}}return this.syncLegacyFields({...e,profiles:i})}getConfig(){return this.syncLegacyFields({...this.config})}updateConfig(e){this.saveConfig({...this.config,...e})}isFirstRun(){return!e(this.configPath)}getLang(){return this.config.lang||"en_US"}setLang(e){this.updateConfig({lang:e})}getActiveProfileName(){return this.config.active_profile||"default"}listProfiles(){return Object.keys(this.config.profiles||{}).sort()}getProfile(e=this.getActiveProfileName()){const t=this.config.profiles?.[e]||{};return{...t.api_key?{api_key:t.api_key}:{},...t.tool_api_keys&&Object.keys(t.tool_api_keys).length>0?{tool_api_keys:this.normalizeStringRecord(t.tool_api_keys)}:{},...t.base_url?{base_url:t.base_url}:{},models:t.models?this.normalizeModels(t.models):DEFAULT_MODELS,...t.tool_models&&Object.keys(t.tool_models).length>0?{tool_models:this.normalizeToolModels(t.tool_models)}:{},...t.tool_settings&&Object.keys(t.tool_settings).length>0?{tool_settings:this.normalizeToolSettings(t.tool_settings)}:{}}}createProfile(e,t=this.getActiveProfileName()){const i=this.getProfile(t),o={...this.config.profiles||{},[e]:{...i.api_key?{api_key:i.api_key}:{},...i.base_url?{base_url:i.base_url}:{},models:this.normalizeModels(i.models)}};this.saveConfig({...this.config,profiles:o})}setActiveProfile(e){if(!this.config.profiles?.[e])throw new Error(`Profile not found: ${e}`);this.saveConfig({...this.config,active_profile:e})}updateProfile(e,t){const i=this.config.profiles?.[e]||{},o=t.models?this.normalizeModels({...i.models,...t.models}):i.models?this.normalizeModels(i.models):void 0,s={...i,...void 0!==t.api_key?{api_key:t.api_key}:{},...void 0!==t.base_url?{base_url:t.base_url}:{},...o?{models:o}:{}},r={...this.config.profiles||{},[e]:s};this.saveConfig({...this.config,profiles:r})}deleteProfile(e){const t={...this.config.profiles||{}};if(!t[e])return;const i=Object.keys(t).filter(t=>t!==e);if(0===i.length)throw new Error("At least one profile must remain");delete t[e];const o=this.getActiveProfileName()===e?i[0]:this.getActiveProfileName();this.saveConfig({...this.config,profiles:t,active_profile:o})}getApiKey(){return this.config.profiles?.[this.getActiveProfileName()]?.api_key}setApiKey(e){this.updateProfile(this.getActiveProfileName(),{api_key:e})}revokeApiKey(){const e=this.config.profiles?.[this.getActiveProfileName()]||{},{api_key:t,tool_api_keys:i,...o}=e,s={...this.config.profiles||{},[this.getActiveProfileName()]:o};this.saveConfig({...this.config,profiles:s})}getApiKeyFingerprint(){const e=this.getApiKey();return e?p("sha256").update(e).digest("hex").slice(0,12):""}getApiKeyForTool(e){const t=this.config.profiles?.[this.getActiveProfileName()];return t?.tool_api_keys?.[e]||t?.api_key||void 0}setToolApiKey(e,t){const i=this.getActiveProfileName(),o=this.config.profiles?.[i]||{},s={...this.config.profiles||{},[i]:{...o,tool_api_keys:{...o.tool_api_keys||{},[e]:t}}};this.saveConfig({...this.config,profiles:s})}clearToolApiKey(e){const t=this.getActiveProfileName(),i=this.config.profiles?.[t]||{},{[e]:o,...s}=i.tool_api_keys||{},r={...i};Object.keys(s).length>0?r.tool_api_keys=s:delete r.tool_api_keys,this.saveConfig({...this.config,profiles:{...this.config.profiles||{},[t]:r}})}listToolApiKeys(){return Object.keys(this.config.profiles?.[this.getActiveProfileName()]?.tool_api_keys||{}).sort()}getToolApiKeyFingerprint(e){const t=this.config.profiles?.[this.getActiveProfileName()]?.tool_api_keys?.[e];return t?p("sha256").update(t).digest("hex").slice(0,12):""}getModels(){const e=this.config.profiles?.[this.getActiveProfileName()]?.models;return e?this.normalizeModels(e):DEFAULT_MODELS}setModels(e){this.updateProfile(this.getActiveProfileName(),{models:this.normalizeModels(e)})}updateModels(e){this.setModels(this.normalizeModels({...this.getModels(),...e}))}getModelsForTool(e){const t=this.getModels(),i=this.config.profiles?.[this.getActiveProfileName()]?.tool_models?.[e];return i?this.normalizeModels({...t,...i}):t}setToolModel(e,t){const i=this.getActiveProfileName(),o=this.config.profiles?.[i]||{},s={...o.tool_models||{}};t&&0!==Object.keys(t).length?s[e]=t:delete s[e];const r={...o};Object.keys(s).length>0?r.tool_models=s:delete r.tool_models;const n={...this.config.profiles||{},[i]:r};this.saveConfig({...this.config,profiles:n})}getToolSettings(e){const t=this.config.profiles?.[this.getActiveProfileName()]?.tool_settings?.[e];return t?{...t}:{}}getToolSetting(e,t){return this.config.profiles?.[this.getActiveProfileName()]?.tool_settings?.[e]?.[t]}setToolSetting(e,t,i){if(this.getToolSetting(e,t)===i)return;const o=this.getActiveProfileName(),s=this.config.profiles?.[o]||{},r={...s.tool_settings||{}};r[e]={...r[e]||{},[t]:i};const n={...this.config.profiles||{},[o]:{...s,tool_settings:r}};this.saveConfig({...this.config,profiles:n})}getCustomPresets(){return{...this.config.presets||{}}}saveCustomPreset(e,t){const i={...this.config.presets||{},[e]:{models:this.normalizeModels(t),updated_at:(new Date).toISOString()}};this.saveConfig({...this.config,presets:i})}deleteCustomPreset(e){const t={...this.config.presets||{}};t[e]&&(delete t[e],this.saveConfig({...this.config,presets:t}))}listBackups(){const t=this.getBackupDir();return e(t)?n(t).filter(e=>e.startsWith("config-")&&e.endsWith(".yaml")).map(e=>{const i=f(t,e);return{name:e,path:i,mtimeMs:c(i).mtimeMs}}).sort((e,t)=>t.mtimeMs-e.mtimeMs):[]}createBackup(s){this.ensureConfigDir();const r=this.getBackupDir();e(r)||t(r,{recursive:!0});const n=(new Date).toISOString().replace(/[:.]/g,"-"),a=this.sanitizeBackupLabel(s),c=f(r,a?`config-${n}-${a}.yaml`:`config-${n}.yaml`),l=e(this.configPath)?i(this.configPath,"utf-8"):m.dump(this.prepareForPersistence(this.getConfig()));return o(c,l,{encoding:"utf-8",mode:384}),this.rotateBackups(r,10,30),c}restoreBackup(t){if(!t||"."===t||".."===t||/[/\\]|\.\./.test(t))throw new Error(`Invalid backup name: ${t}`);const o=this.getBackupDir(),s=f(o,t);if(!e(s))throw new Error(`Backup not found: ${t}`);const r=i(s,"utf-8"),n=m.load(r),a=this.getSecretsBackupPath(s);let c=this.migrateOldConfig(n||this.createDefaultConfig());if(n?.credential_store!==k&&e(a))try{c=this.mergeLegacySecrets(c,_(a))}catch(e){throw new Error(`Legacy backup credentials could not be decrypted: ${a}`,{cause:e})}this.saveConfig(c)}getBaseUrl(){return this.runtimeBaseUrl||this.config.profiles?.[this.getActiveProfileName()]?.base_url||DEFAULT_BASE_URL}setBaseUrl(e,t=!1){this.runtimeBaseUrl=e,t&&this.updateProfile(this.getActiveProfileName(),{base_url:e})}resetBaseUrl(){this.runtimeBaseUrl=void 0;const e=this.config.profiles?.[this.getActiveProfileName()]||{},{base_url:t,...i}=e,o={...this.config.profiles||{},[this.getActiveProfileName()]:i};this.saveConfig({...this.config,profiles:o})}}export const configManager=ConfigManager.getInstance();
|
|
@@ -21,3 +21,8 @@ export declare function gatewayModelSpecs(tool: GatewayModelTool, clientModels?:
|
|
|
21
21
|
* `claude-opus-5-5` → `Claude Opus 5.5`, `qwen3.8-max` → `Qwen 3.8 Max`.
|
|
22
22
|
*/
|
|
23
23
|
export declare function prettyModelName(id: string): string;
|
|
24
|
+
/** Vendor names in first-seen order: `glm-5.3`, `glm-5.2`, `kimi-k3` → `GLM`, `Kimi`. */
|
|
25
|
+
export declare function vendorNames(ids: string[]): string[];
|
|
26
|
+
export type ModelFamily = 'gpt' | 'claude' | 'grok' | 'other';
|
|
27
|
+
/** Coarse family for a summary line; everything that isn't GPT, Claude or Grok counts as other (domestic). */
|
|
28
|
+
export declare function modelFamily(id: string): ModelFamily;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getGatewayModelRules as
|
|
1
|
+
import{getGatewayModelRules as t}from"./model-registry.js";export function autoCompactTokens(e,o){return o&&o>0?Math.min(o,e):Math.floor(e*t().autoCompactRatio)}export function gatewayModelSpecs(e,o){const n=t().models.filter(t=>function(t,e){return"codex"===t||!e.id.startsWith("claude-")&&!1!==e.claudeCode}(e,t));if(!o)return n;const r=new Map(n.map(t=>[t.id,t])),s="codex"===e?[...o.codex??[],...(o.claude??[]).filter(t=>t.id.startsWith("claude-")&&r.has(t.id))]:(o.claude??[]).filter(t=>!t.id.startsWith("claude-")&&(r.get(t.id)?.claudeCode??!0));if(0===s.length)return n;const a=new Set,i=[];for(const t of s)a.has(t.id)||(a.add(t.id),i.push({...r.get(t.id),...t}));return i}const e={gpt:"GPT",glm:"GLM",deepseek:"DeepSeek",minimax:"MiniMax",qwen:"Qwen"};export function prettyModelName(t){const o=t.replace(/^([a-z]+)(\d)/i,"$1 $2").split(/[-_\s]+/).filter(Boolean),n=[];for(const t of o){const o=n[n.length-1];if(/^\d+$/.test(t)&&o&&/^\d+$/.test(o)&&t.length<=2&&!/^\d{8}$/.test(t)){n[n.length-1]=`${o}.${t}`;continue}const r=t.toLowerCase();n.push(e[r]??(/^[a-z]\d/i.test(t)?t.toUpperCase():t[0].toUpperCase()+t.slice(1)))}return n.join(" ")}export function vendorNames(t){return[...new Set(t.map(t=>prettyModelName(t).split(" ")[0]))]}export function modelFamily(t){const e=t.toLowerCase();return e.startsWith("claude-")?"claude":e.startsWith("grok")?"grok":/^(gpt|o\d|codex)/.test(e)?"gpt":"other"}
|
|
@@ -60,6 +60,8 @@ export interface CodexRules {
|
|
|
60
60
|
}
|
|
61
61
|
export interface ModelRegistryData {
|
|
62
62
|
defaultModels: Models;
|
|
63
|
+
/** Earlier `defaultModels` values per slot; a profile still holding one follows the current default. */
|
|
64
|
+
retiredDefaultModels?: Record<string, string[]>;
|
|
63
65
|
/** Default model for non-Claude tools (Codex/OpenCode/OpenClaw/Hermes/AtomCode/Grok). */
|
|
64
66
|
defaultToolModel?: string;
|
|
65
67
|
/** Per-tool default model. Empty string (e.g. claude-code) means "use the tool's built-in default". */
|
|
@@ -73,6 +75,8 @@ export interface ModelRegistryData {
|
|
|
73
75
|
toolMinVersions?: Record<string, string>;
|
|
74
76
|
}
|
|
75
77
|
export declare function getDefaultModels(): Models;
|
|
78
|
+
/** Earlier default for this slot, saved into a profile by the wizard's prefilled inputs. */
|
|
79
|
+
export declare function isRetiredDefaultModel(slot: string, model: string): boolean;
|
|
76
80
|
/** The model non-Claude tools use unless the user configured something else. */
|
|
77
81
|
export declare function getDefaultToolModel(): string;
|
|
78
82
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dirname as
|
|
1
|
+
import{dirname as e,join as o}from"path";import{fileURLToPath as t}from"url";import{existsSync as n,readFileSync as r}from"fs";const l=e(t(import.meta.url));let s=null;function u(){return s||(s=function(){const e=[o(l,"..","..","models.json"),o(l,"..","models.json"),o(l,"models.json")];for(const o of e)if(n(o))return JSON.parse(r(o,"utf-8"));throw new Error(`models.json not found, searched: ${e.join(", ")}`)}()),s}export function getDefaultModels(){return{...u().defaultModels}}export function isRetiredDefaultModel(e,o){return u().retiredDefaultModels?.[e]?.includes(o)??!1}export function getDefaultToolModel(){return u().defaultToolModel?.trim()||"gpt-5.5"}export function getToolDefaultModel(e){const o=u().toolDefaults;return o&&Object.prototype.hasOwnProperty.call(o,e)?(o[e]??"").trim():getDefaultToolModel()}export function getPresets(){return[...u().presets]}export function resolvePreset(e){return e.models?{...e.models}:e.model?{haiku:e.model,sonnet:e.model,opus:e.model,reasoning:e.model}:getDefaultModels()}export function getClaudeCodeTierChains(){const e=u().claudeCode?.tierChains??{};return Object.fromEntries(Object.entries(e).map(([e,o])=>[e,[...o]]))}export function getClaudeDesktopRules(){const e=u().claudeDesktop??{};return{oneMillionFallback:[...e.oneMillionFallback??[]],oneMillionExclusions:(e.oneMillionExclusions??[]).map(e=>({...e,models:[...e.models]}))}}export function getGatewayModelRules(){const e=u().gatewayModels??{};return{autoCompactRatio:e.autoCompactRatio??.8,models:(e.models??[]).map(e=>({...e}))}}export function getCodexRules(){return{standardContextWindow:u().codex?.standardContextWindow??272e3}}export function getToolMinVersion(e){return u().toolMinVersions?.[e]?.trim()||null}export function reloadRegistry(){s=null}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type VibecliModels } from './config.js';
|
|
2
2
|
import { type BackupEntry, type RestoreResult } from './tools/backup.js';
|
|
3
|
+
import type { ApplyNote } from './tools/types.js';
|
|
3
4
|
import { type ModelCatalog } from './model-catalog.js';
|
|
4
5
|
export interface ToolRestoreEntry {
|
|
5
6
|
file: string;
|
|
@@ -51,7 +52,12 @@ export declare class ToolManager {
|
|
|
51
52
|
force?: boolean;
|
|
52
53
|
}): Promise<void>;
|
|
53
54
|
/** Post-apply follow-ups the adapter wants shown to the user (may be empty). */
|
|
54
|
-
applyNotes(toolName: string):
|
|
55
|
+
applyNotes(toolName: string): ApplyNote[];
|
|
56
|
+
/**
|
|
57
|
+
* The one place a configured tool is reported: `√ <name> <summary>`, then the
|
|
58
|
+
* things the user has to do. Details go to the log file only.
|
|
59
|
+
*/
|
|
60
|
+
printApplied(toolName: string, nameWidth?: number): void;
|
|
55
61
|
/** `<command> --version` of the installed tool, as `x.y.z`; null when absent or unparsable. */
|
|
56
62
|
installedVersion(toolName: string): string | null;
|
|
57
63
|
/** The installed and required versions when the tool is older than `models.json` → `toolMinVersions`. */
|
package/dist/lib/tool-manager.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execSync as o,spawnSync as
|
|
1
|
+
import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import l from"inquirer";import e from"chalk";import s from"terminal-link";import i from"ora";import{logger as r}from"../utils/logger.js";import{configManager as a}from"./config.js";import{getAdapter as c,listAdapters as d,TOOL_ADAPTERS as u}from"./tools/registry.js";import{backupBeforeWrite as g,listBackups as m,restoreBackup as p}from"./tools/backup.js";import{existsSync as f,rmSync as w}from"fs";import{stringWidth as h}from"../utils/string-width.js";import{resolveModelCatalog as _}from"./model-catalog.js";import{getToolMinVersion as y}from"./model-registry.js";function P(o){const t=u[o];return{name:t.name,command:t.command,installCommand:t.installCommand,configPath:t.configPath,displayName:t.displayName,...t.hidden?{hidden:!0}:{}}}export const SUPPORTED_TOOLS=Object.fromEntries(Object.keys(u).map(o=>[o,P(o)]));export class ToolManager{static instance;constructor(){}static getInstance(){return ToolManager.instance||(ToolManager.instance=new ToolManager),ToolManager.instance}isToolInstalled(t){const n=SUPPORTED_TOOLS[t];if(!n)return!1;const l=c(t);if(l?.isInstalled)try{return l.isInstalled()}catch{return!1}try{const t="win32"===process.platform?`where ${n.command}`:`which ${n.command}`;return o(t,{stdio:"pipe"}),!0}catch{return!1}}async installTool(t){const a=SUPPORTED_TOOLS[t];if(!a)throw new Error(`Unknown tool: ${t}`);const c=i(n.t("wizard.installing_tool")).start();try{c.info(e.gray("$ ")+e.white(a.installCommand)),c.stop(),o(a.installCommand,{stdio:"inherit"}),c.succeed(n.t("wizard.tool_installed"))}catch(i){c.fail(n.t("wizard.install_failed"));const d=(i.message||"")+(i.stderr?.toString()||"")+(i.stdout?.toString()||"");if(!(d.includes("EACCES")||d.includes("permission denied")||d.includes("EPERM")||243===i.status))throw new Error(`Failed to install ${a.displayName}: ${i}`);if(console.log("\n⚠️ "+n.t("install.permission_detected")+"\n"),"win32"===process.platform)try{const t=a.installCommand.replace("npm install -g","npm install -g --force");return console.log("🔧 "+n.t("install.trying_solution",{num:"1",desc:n.t("install.using_force")})),console.log(e.gray("$ ")+e.white(t)),o(t,{stdio:"inherit"}),void console.log("\n✅ "+n.t("install.permission_fixed"))}catch(o){r.warn("Retry install failed:",o),console.log("\n❌ "+n.t("install.auto_fix_failed")),console.log(e.yellow("\n📌 "+n.t("install.windows_solutions"))),console.log(""),console.log(e.cyan.bold(n.t("install.windows_solution_1_title"))),console.log(e.gray(" "+n.t("install.windows_solution_1_step1"))),console.log(e.gray(" "+n.t("install.windows_solution_1_step2"))),console.log(e.gray(" "+n.t("install.windows_solution_1_step3"))),console.log(e.white(` ${a.installCommand}`)),console.log(""),console.log(e.cyan.bold(n.t("install.windows_solution_2_title"))),console.log(e.gray(" "+n.t("install.windows_solution_2_command"))),console.log(e.white(` ${a.installCommand.replace("npm install -g","npm install -g --prefix=%APPDATA%\\npm")}`)),console.log("");const{action:s}=await l.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"===s)throw new Error(n.t("install.user_cancelled"));if(!this.isToolInstalled(t))throw console.log(e.red("\n❌ "+n.t("install.still_not_installed",{tool:a.displayName}))),new Error(`${a.displayName} is not installed`);return void console.log(e.green("\n✅ "+n.t("install.verified_success",{tool:a.displayName})))}console.log(e.yellow("\n📌 "+n.t("install.unix_solutions"))),console.log(""),console.log(e.cyan.bold(n.t("install.unix_solution_1_title"))),console.log(e.gray(" "+n.t("install.unix_solution_1_desc"))),console.log(e.white(` sudo ${a.installCommand}`)),console.log("");const u="https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally",g=s(u,u,{fallback:()=>u});console.log(e.cyan.bold(n.t("install.unix_solution_2_title"))),console.log(e.gray(" "+n.t("install.unix_solution_2_desc"))),console.log(e.blue(" 📖 "+n.t("install.npm_docs_link")+": ")+g),console.log("");const{action:m}=await l.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"===m)throw new Error(n.t("install.user_cancelled"));if(!this.isToolInstalled(t))throw console.log(e.red("\n❌ "+n.t("install.still_not_installed",{tool:a.displayName}))),new Error(`${a.displayName} is not installed`);console.log(e.green("\n✅ "+n.t("install.verified_success",{tool:a.displayName})))}}getToolConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{return t.getConfig()}catch(t){return r.warn(`Failed to read config for ${o}:`,t),r.logError(`ToolManager.getToolConfig(${o})`,t),null}}updateToolConfig(o,t){const n=c(o);if(!n)throw new Error(`Unknown tool: ${o}`);if(!n.updateConfig)throw new Error(`Tool ${o} does not support raw config updates`);n.updateConfig(t)}forceResetConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);const n=t.forceResetPaths?t.forceResetPaths():this.backupPathsFor(t),l=[];for(const o of n)f(o)&&(g(o),w(o,{force:!0}),l.push(o));return l}loadPrivateConfig(o,t,n,l,e={}){const s=c(o);if(!s)throw new Error(`Unknown tool: ${o}`);e.force&&this.forceResetConfig(o),s.loadPrivateConfig({apiKey:t,baseUrl:a.getBaseUrl(),models:n,settings:a.getToolSettings(o),...l?{catalog:l}:{}})}async applyPrivateConfig(o,t,n,l={}){const e=c(o);if(!e)throw new Error(`Unknown tool: ${o}`);const s=e.wantsModelCatalog?await _(t):null;l.force?this.loadPrivateConfig(o,t,n,s??void 0,{force:!0}):s?this.loadPrivateConfig(o,t,n,s):this.loadPrivateConfig(o,t,n)}applyNotes(o){const t=c(o);if(!t)return[];const l=[];try{t.applyNotes&&l.push(...t.applyNotes())}catch(t){r.logError(`ToolManager.applyNotes(${o})`,t)}const e=this.outdatedVersion(o);return e&&l.push({kind:"action",text:n.t("tools.version_outdated",{current:e.current,min:e.min,upgrade:t.upgradeCommand||t.installCommand})}),l}printApplied(o,t=16){const n=SUPPORTED_TOOLS[o]?.displayName??o,l=this.applyNotes(o);for(const o of l.filter(o=>"detail"===o.kind))r.record(`${n}: ${o.text}`);const s=l.filter(o=>"summary"===o.kind).map(o=>o.text).join(";"),i=" ".repeat(Math.max(1,t-h(n)));console.log(e.green("√ "+n)+(s?i+s:""));for(const o of l.filter(o=>"action"===o.kind))console.log(e.yellow(" ! "+o.text))}installedVersion(o){const n=c(o);if(!n)return null;if(n.installedVersion)try{return n.installedVersion()}catch(t){return r.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"]},l=`${("win32"===process.platform?t(`${n.command} --version`,{...o,shell:!0}):t(n.command,["--version"],o)).stdout??""}`.match(/(\d+)\.(\d+)\.(\d+)/);return l?l[0]:null}catch{return null}}outdatedVersion(o){const t=y(o);if(!t)return null;const n=this.installedVersion(o);return n&&compareVersions(n,t)<0?{current:n,min:t}:null}unloadPrivateConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);t.unloadPrivateConfig()}async clearPinnedModels(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);if(a.setToolModel(o,null),!t.clearPinnedModels)return[];const n=a.getApiKeyForTool(o),l=t.wantsModelCatalog&&n?await _(n):null;return t.clearPinnedModels(l??void 0)}supportsClearPinnedModels(o){return Boolean(c(o)?.clearPinnedModels)}detectCurrentConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);return t.detectCurrentConfig()}backupPathsFor(o){return o.backupPaths?o.backupPaths():[o.configPath]}listToolBackups(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,backups:m(o)}))}restorePrivateConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,result:p(o)}))}getInstalledTools(){return Object.keys(SUPPORTED_TOOLS).filter(o=>this.isToolInstalled(o))}getSupportedTools(){return d().filter(o=>!o.hidden).map(o=>P(o.name))}isGitInstalled(){try{const t="win32"===process.platform?"where git":"which git";return o(t,{stdio:"pipe"}),!0}catch{return!1}}}export function compareVersions(o,t){const n=o.split(".").map(o=>parseInt(o,10)||0),l=t.split(".").map(o=>parseInt(o,10)||0);for(let o=0;o<Math.max(n.length,l.length);o++){const t=(n[o]??0)-(l[o]??0);if(0!==t)return t}return 0}export const toolManager=ToolManager.getInstance();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{join as e}from"path";import{
|
|
1
|
+
import{join as e}from"path";import{claudeCodeManager as t}from"../claude-code-manager.js";import{backupBeforeWrite as o}from"./backup.js";import{i18n as a}from"../i18n.js";import{gatewayModelSpecs as n,prettyModelName as d,vendorNames as i}from"../gateway-models.js";import{toolHome as s}from"./types.js";const l=e(s(),".claude","settings.json"),r=e(s(),".claude.json");let c;export const claudeCodeAdapter={name:"claude-code",displayName:"Claude Code",command:"claude",installCommand:"npm install -g @anthropic-ai/claude-code",upgradeCommand:"claude update",configPath:l,wantsModelCatalog:!0,loadPrivateConfig(e){o(l),o(r),c=function(e){if(!e)return;const t=new Set(e.models);return n("claude-code",e.clientModels).filter(e=>t.has(e.id))}(e.catalog),t.loadPrivateConfig(e.apiKey,e.models,e.catalog?.models,c)},unloadPrivateConfig(){o(l),t.unloadPrivateConfig()},detectCurrentConfig:()=>t.detectCurrentConfig(),getConfig:()=>({settings:t.getSettings(),mcp:t.getMCPConfig()}),updateConfig(e){const o=e||{};o.settings&&t.saveSettings(o.settings),o.mcp&&t.saveMCPConfig(o.mcp)},clearPinnedModels:e=>(o(l),t.clearPinnedModels(e?.models)),applyNotes(){const e=[];c&&c.length>0&&(e.push({kind:"summary",text:a.t("tools.claude_code.gateway_models",{count:String(c.length),vendors:i(c.map(e=>e.id)).join(" / ")})}),e.push({kind:"detail",text:c.map(e=>e.name||d(e.id)).join(", ")}));for(const o of t.getLastTierFallbacks())e.push({kind:"detail",text:a.t("tools.claude_code.tier_fallback",{tier:o.tier,from:o.from,to:o.to})});return e},backupPaths:()=>[l,r],forceResetPaths:()=>[l]};
|
|
@@ -37,6 +37,11 @@ export declare function humanizeModelId(base: string): string;
|
|
|
37
37
|
* Order: the profile's main model first (Claude Desktop treats the first entry
|
|
38
38
|
* as the default), then by family (opus, fable, sonnet, haiku) newest-first.
|
|
39
39
|
* Each family's default is the model the profile slot points at, else its newest.
|
|
40
|
+
*
|
|
41
|
+
* Claude only: the desktop drops any `inferenceModels` entry whose name matches its
|
|
42
|
+
* built-in list of non-Anthropic vendors (deepseek, glm, kimi, qwen, minimax, …) and
|
|
43
|
+
* shows a "configuration may need attention" warning, so domestic models stay in
|
|
44
|
+
* Claude Code's `/model` menu.
|
|
40
45
|
*/
|
|
41
46
|
export declare function buildInferenceModels(models: VibecliModels, catalog?: ModelCatalog): InferenceModel[];
|
|
42
47
|
type RegRunner = (args: string[]) => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{chmodSync as e,existsSync as t,mkdirSync as o,readdirSync as n,readFileSync as r,rmSync as s}from"fs";import{dirname as i}from"path";import{join as a}from"path";import{randomUUID as l}from"crypto";import{execFileSync as c}from"child_process";import{userInfo as p}from"os";import{logger as d}from"../../utils/logger.js";import{i18n as u}from"../i18n.js";import{BRAND_NAME as f}from"../brand.js";import{backupBeforeWrite as m,atomicWriteFile as g}from"./backup.js";import{toolHome as h}from"./types.js";import{baseModelId as y,isClaudeModel as b}from"../model-catalog.js";import{gatewayModelSpecs as C,prettyModelName as k}from"../gateway-models.js";const A=f;export const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING="hide_official_login";const w=["Claude_pzs8sxrjxfjjc","AnthropicPBC.Claude_fnn82j28hfe8t"],_=/^[a-f0-9-]{36}$/;function D(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}export function claudeDesktopUserDataDir(){const e=process.env.CLAUDE_USER_DATA_DIR?.trim();if(e)return e;const o=h(),n=Boolean(process.env.VIBECLI_TEST_HOME?.trim());switch(process.platform){case"darwin":return a(o,"Library","Application Support","Claude-3p");case"win32":{const e=!n&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:a(o,"AppData","Local");return w.map(t=>a(e,"Packages",t,"LocalCache","Local","Claude-3p")).find(e=>t(e))??a(e,"Claude-3p")}default:{const e=!n&&process.env.XDG_CONFIG_HOME?process.env.XDG_CONFIG_HOME:a(o,".config");return a(e,"Claude-3p")}}}const E=()=>a(claudeDesktopUserDataDir(),"configLibrary"),M=()=>a(E(),"_meta.json"),v=e=>a(E(),`${e}.json`),O=()=>a(claudeDesktopUserDataDir(),"claude_desktop_config.json");function P(e){if(!t(e))return null;const o=r(e,"utf-8");if(!o.trim())return null;try{const e=JSON.parse(o);return D(e)?e:null}catch(t){throw new Error(`Existing ${e} cannot be parsed, back it up and fix it first: ${t instanceof Error?t.message:String(t)}`)}}function S(n,r){const s=i(n);t(s)||o(s,{recursive:!0,mode:448}),m(n),g(n,JSON.stringify(r,null,2)+"\n");try{e(n,384)}catch(e){d.logError("claude-desktop.writeJson.chmod",e)}}function j(){const e=P(M());if(!e)return null;const t=Array.isArray(e.entries)?e.entries.filter(e=>D(e)&&"string"==typeof e.id&&"string"==typeof e.name):[];return{...e,appliedId:"string"==typeof e.appliedId?e.appliedId:"",entries:t}}function x(e){return e?.entries.find(e=>e.name===A&&_.test(e.id))}const I={opus:0,fable:1,sonnet:2,haiku:3};function L(e){let t=/^claude-(opus|sonnet|haiku|fable)-(\d+(?:-\d+)*)/i.exec(e);return t?{family:t[1].toLowerCase(),version:t[2].split("-").map(Number)}:(t=/^claude-(\d+(?:-\d+)*)-(opus|sonnet|haiku)/i.exec(e),t?{family:t[2].toLowerCase(),version:t[1].split("-").map(Number)}:null)}export function humanizeModelId(e){const t=L(e);return t?`${t.family[0].toUpperCase()+t.family.slice(1)} ${t.version.filter(e=>e<1e7).slice(0,2).join(".")}`:e}function T(e){return L(e)?.family}export function buildInferenceModels(e,t){const{primary:o,bySlot:n}=function(e){const t=["opus","sonnet","haiku","reasoning"].map(t=>y(e[t]||"")).filter(Boolean);return{primary:t[0]??"",bySlot:t}}(e),r=new Set,s=t?.labels??{};let i;if(t&&t.models.some(b)){i=[...new Set(t.models.filter(b).map(y))];for(const e of t.oneMillion)r.add(e)}else{i=[];for(const t of["opus","sonnet","haiku","reasoning"]){const o=(e[t]||"").trim(),n=y(o);n&&(i.includes(n)||i.push(n),/\[1m\]/i.test(o)&&r.add(n))}}const a=e=>I[T(e)??""]??9;i.sort((e,t)=>{if(e===o)return-1;if(t===o)return 1;const n=a(e)-a(t);if(0!==n)return n;const r=L(e),s=L(t);return r&&s?function(e,t){const o=Math.max(e.length,t.length);for(let n=0;n<o;n++){const o=(t[n]??0)-(e[n]??0);if(0!==o)return o}return 0}(r.version,s.version):e.localeCompare(t)});const l=new Set,c=new Map;for(const e of n){const t=T(e);t&&i.includes(e)&&!c.has(t)&&c.set(t,e)}const p=[...i.map(e=>{const t=T(e),o={name:e,labelOverride:s[e]||humanizeModelId(e)};if(r.has(e)&&(o.supports1m=!0,o.prefer1m=!0),t){o.anthropicFamilyTier=t;const n=c.get(t);n&&n!==e||l.has(t)||(o.isFamilyDefault=!0,l.add(t))}return o}),...$(t)],d=p.findIndex(e=>e.name===o);return d>0&&p.unshift(...p.splice(d,1)),p}function $(e){if(!e)return[];const t=new Set(e.models.map(y));return C("claude-code",e.clientModels).filter(e=>t.has(e.id)).map(e=>{const t={name:e.id,labelOverride:e.name||k(e.id)};return(e.contextWindow??0)>=1e6&&(t.supports1m=!0,t.prefer1m=!0),t})}let G=null,N=null;function U(e){return{inferenceProvider:"gateway",inferenceCredentialKind:"static",inferenceGatewayBaseUrl:(e.baseUrl||"").trim().replace(/\/+$/,""),inferenceGatewayApiKey:e.apiKey,inferenceModels:buildInferenceModels(e.models,e.catalog),disableDeploymentModeChooser:!1!==e.settings?.hide_official_login,chatTabEnabled:!0,chatAdvancedFileAnalysisEnabled:!0,autoModeEnabled:!0,coworkEgressAllowedHosts:["*"],disableEssentialTelemetry:!0,disableNonessentialTelemetry:!0,disableNonessentialServices:!1}}const F={modelPrefer1mContext:!0,skipWebFetchPreflight:!0,toolSearchEnabled:!0,builtinBrowserEnabled:!0,isDesktopExtensionEnabled:!0,sshHostAllowlist:["*"],claudeAiImport:{enabled:!0,automatic3pImport:!0,exportEnabled:!0},coworkVmIpv6Enabled:!0,mcpToolTimeoutSec:3600,updateViaUpdatesHost:!0};function R(e){return Object.fromEntries(Object.entries(F).filter(([t])=>!e(t)))}const K="HKCU\\SOFTWARE\\Policies\\Claude",H="HKLM\\SOFTWARE\\Policies\\Claude",B="vibecli-claude-policy.reg",W=e=>c("reg",e,{stdio:["ignore","pipe","pipe"]}).toString();let V=W;export function setRegRunnerForTests(e){V=e??W}function z(){return"win32"===process.platform}function J(e){let t;try{t=V(["query",e])}catch{return null}const o=new Map;for(const e of t.split(/\r?\n/)){const t=/^\s{2,}(\S+)\s+(REG_[A-Z_]+)\s*(.*)$/.exec(e);t&&o.set(t[1],t[3])}return o}function Z(){if(null===J(K))return;const e=a(claudeDesktopUserDataDir(),B);try{t(i(e))||o(i(e),{recursive:!0,mode:448}),m(e),V(["export",K,e,"/y"])}catch(e){d.logError("claude-desktop.snapshotPolicy",e)}}const X=[...Object.keys(U({apiKey:"",baseUrl:"",models:{haiku:"",sonnet:"",opus:"",reasoning:""}})),...Object.keys(F)];export function detectManagedConfig(){try{if("darwin"===process.platform){let e="";try{e=p().username}catch{}return[e?`/Library/Managed Preferences/${e}/com.anthropic.claudefordesktop.plist`:"","/Library/Managed Preferences/com.anthropic.claudefordesktop.plist"].filter(Boolean).find(e=>t(e))??null}if("win32"===process.platform)return J(H)?H:null;const e="/etc/claude-desktop/managed-settings.json";return t(e)?e:null}catch(e){return d.logError("claude-desktop.detectManagedConfig",e),null}}const q=/\d+\.\d+\.\d+/;function Q(e){const t=e=>e.split(".").map(Number);return e.sort((e,o)=>{const[n,r]=[t(e),t(o)];for(let e=0;e<3;e++)if(n[e]!==r[e])return r[e]-n[e];return 0})[0]??null}const Y="darwin"===process.platform?"open -a Claude":"win32"===process.platform?"Claude":"claude-desktop",ee="darwin"===process.platform||"win32"===process.platform?"https://cnb.cool/vibeapi/claude-desktop/-/releases/latest":"https://claude.ai/download",te="darwin"===process.platform?`open ${ee}`:"win32"===process.platform?`start ${ee}`:`xdg-open ${ee}`;export const claudeDesktopAdapter={name:"claude-desktop",displayName:"Claude Desktop",command:Y,installCommand:te,configPath:M(),isInstalled:function(){const e=h();let o;switch(process.platform){case"darwin":o=["/Applications/Claude.app",a(e,"Applications","Claude.app")];break;case"win32":{const t=process.env.LOCALAPPDATA||a(e,"AppData","Local");o=[a(t,"AnthropicClaude"),a(t,"Programs","Claude"),...w.map(e=>a(t,"Packages",e))];break}default:o=["/usr/lib/claude-desktop","/opt/Claude","/usr/bin/claude-desktop",a(e,".local","bin","claude-desktop")]}return o.push(claudeDesktopUserDataDir(),a(claudeDesktopUserDataDir(),"..","Claude")),o.some(e=>t(e))},installedVersion:function(){if("darwin"===process.platform){for(const e of["/Applications/Claude.app",a(h(),"Applications","Claude.app")]){const o=a(e,"Contents","Info.plist");if(!t(o))continue;const n=/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(r(o,"utf-8")),s=n?q.exec(n[1])?.[0]:void 0;if(s)return s}return null}if("win32"===process.platform){const e=a(process.env.LOCALAPPDATA||a(h(),"AppData","Local"),"AnthropicClaude");if(t(e)){const t=n(e).map(e=>/^app-(\d+\.\d+\.\d+)$/.exec(e)?.[1]).filter(e=>!!e);if(t.length>0)return Q(t)}const o=w.map(e=>`'${e}'`).join(",");return Q(c("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${o}) -contains $_.PackageFamilyName } | ForEach-Object { $_.Version.ToString() }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"]}).split(/\r?\n/).flatMap(e=>q.exec(e)?.[0]??[]))}return null},wantsModelCatalog:!0,loadPrivateConfig(e){const t=j()??{appliedId:"",entries:[]};let o=x(t);o||(o={id:l(),name:A},t.entries.push(o));const n=U(e);N=!0===n.disableDeploymentModeChooser,G={models:n.inferenceModels,source:e.catalog?e.catalog.oneMillionSource:"slots",groups:e.catalog?.matchedGroups??[]};const r=P(v(o.id))??{};S(v(o.id),{...R(e=>e in r),...r,...n}),t.appliedId=o.id,S(M(),t);const s=P(O())??{};if("3p"!==s.deploymentMode&&S(O(),{...s,deploymentMode:"3p"}),z()){const e=J(K);!function(e){Z();for(const[t,o]of Object.entries(e)){const[e,n]="boolean"==typeof o?["REG_DWORD",o?"1":"0"]:"number"==typeof o?["REG_DWORD",String(o)]:"string"==typeof o?["REG_SZ",o]:["REG_SZ",JSON.stringify(o)];V(["add",K,"/v",t,"/t",e,"/d",n,"/f"])}}({...R(t=>e?.has(t)??!1),...n})}},unloadPrivateConfig(){z()&&function(e){const t=J(K);if(!t)return;Z();let o=t.size;for(const n of e)t.has(n)&&(V(["delete",K,"/v",n,"/f"]),o-=1);o<=0&&V(["delete",K,"/f"])}(X);const e=j(),t=x(e);if(!e||!t)return;m(v(t.id)),s(v(t.id),{force:!0});const o=e.entries.filter(e=>e.id!==t.id);0===o.length?(m(M()),s(M(),{force:!0})):S(M(),{...e,entries:o,appliedId:e.appliedId===t.id?o[0].id:e.appliedId})},detectCurrentConfig(){try{if(z()){const e=J(K)?.get("inferenceGatewayApiKey");if(e)return{apiKey:e}}const e=x(j());if(!e)return{apiKey:null};const t=P(v(e.id)),o=t?.inferenceGatewayApiKey;return{apiKey:"string"==typeof o&&o?o:null}}catch(e){return d.logError("claude-desktop.detectCurrentConfig",e),{apiKey:null}}},getConfig(){try{const e=j(),t=x(e);return{meta:e,applied:t?P(v(t.id)):null,desktop:P(O()),...z()?{policy:Object.fromEntries(J(K)??[])}:{}}}catch(e){return d.logError("claude-desktop.getConfig",e),null}},clearPinnedModels(){let e=!1;z()&&J(K)?.has("inferenceModels")&&(Z(),V(["delete",K,"/v","inferenceModels","/f"]),e=!0);const t=x(j()),o=t?P(v(t.id)):null;if(t&&o&&void 0!==o.inferenceModels){const{inferenceModels:n,...r}=o;S(v(t.id),r),e=!0}return e?["inferenceModels"]:[]},applyNotes(){const e=[];if(G){const t=G.models.map(e=>`${e.labelOverride}${e.supports1m?" (1M)":""}`).join(", ");e.push(u.t(`tools.claude_desktop.models_written_${G.source}`,{count:String(G.models.length),list:t,groups:G.groups.join(" / ")}))}null!==N&&e.push(u.t(N?"tools.claude_desktop.official_login_hidden":"tools.claude_desktop.official_login_shown")),e.push(u.t("tools.claude_desktop.restart_hint")),z()&&e.push(u.t("tools.claude_desktop.registry_written",{key:K}));const t=detectManagedConfig();return t&&e.push(u.t("tools.claude_desktop.managed_conflict",{path:t})),e},forceResetPaths(){const e=[M(),O()];try{const t=x(j());t&&e.push(v(t.id))}catch{}return e},backupPaths(){const e=[M(),O()];z()&&e.push(a(claudeDesktopUserDataDir(),B));try{const t=x(j());t&&e.push(v(t.id))}catch{}return e}};
|
|
1
|
+
import{chmodSync as e,existsSync as t,mkdirSync as o,readdirSync as n,readFileSync as r,rmSync as s}from"fs";import{dirname as i}from"path";import{join as a}from"path";import{randomUUID as l}from"crypto";import{execFileSync as c}from"child_process";import{userInfo as d}from"os";import{logger as p}from"../../utils/logger.js";import{i18n as u}from"../i18n.js";import{BRAND_NAME as f}from"../brand.js";import{backupBeforeWrite as m,atomicWriteFile as g}from"./backup.js";import{toolHome as h}from"./types.js";import{baseModelId as y,isClaudeModel as k}from"../model-catalog.js";const b=f;export const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING="hide_official_login";const C=["Claude_pzs8sxrjxfjjc","AnthropicPBC.Claude_fnn82j28hfe8t"],_=/^[a-f0-9-]{36}$/;function A(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}export function claudeDesktopUserDataDir(){const e=process.env.CLAUDE_USER_DATA_DIR?.trim();if(e)return e;const o=h(),n=Boolean(process.env.VIBECLI_TEST_HOME?.trim());switch(process.platform){case"darwin":return a(o,"Library","Application Support","Claude-3p");case"win32":{const e=!n&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:a(o,"AppData","Local");return C.map(t=>a(e,"Packages",t,"LocalCache","Local","Claude-3p")).find(e=>t(e))??a(e,"Claude-3p")}default:{const e=!n&&process.env.XDG_CONFIG_HOME?process.env.XDG_CONFIG_HOME:a(o,".config");return a(e,"Claude-3p")}}}const w=()=>a(claudeDesktopUserDataDir(),"configLibrary"),D=()=>a(w(),"_meta.json"),E=e=>a(w(),`${e}.json`),M=()=>a(claudeDesktopUserDataDir(),"claude_desktop_config.json");function x(e){if(!t(e))return null;const o=r(e,"utf-8");if(!o.trim())return null;try{const e=JSON.parse(o);return A(e)?e:null}catch(t){throw new Error(`Existing ${e} cannot be parsed, back it up and fix it first: ${t instanceof Error?t.message:String(t)}`)}}function v(n,r){const s=i(n);t(s)||o(s,{recursive:!0,mode:448}),m(n),g(n,JSON.stringify(r,null,2)+"\n");try{e(n,384)}catch(e){p.logError("claude-desktop.writeJson.chmod",e)}}function P(){const e=x(D());if(!e)return null;const t=Array.isArray(e.entries)?e.entries.filter(e=>A(e)&&"string"==typeof e.id&&"string"==typeof e.name):[];return{...e,appliedId:"string"==typeof e.appliedId?e.appliedId:"",entries:t}}function S(e){return e?.entries.find(e=>e.name===b&&_.test(e.id))}const O={opus:0,fable:1,sonnet:2,haiku:3};function j(e){let t=/^claude-(opus|sonnet|haiku|fable)-(\d+(?:-\d+)*)/i.exec(e);return t?{family:t[1].toLowerCase(),version:t[2].split("-").map(Number)}:(t=/^claude-(\d+(?:-\d+)*)-(opus|sonnet|haiku)/i.exec(e),t?{family:t[2].toLowerCase(),version:t[1].split("-").map(Number)}:null)}export function humanizeModelId(e){const t=j(e);return t?`${t.family[0].toUpperCase()+t.family.slice(1)} ${t.version.filter(e=>e<1e7).slice(0,2).join(".")}`:e}function I(e){return j(e)?.family}export function buildInferenceModels(e,t){const{primary:o,bySlot:n}=function(e){const t=["opus","sonnet","haiku","reasoning"].map(t=>y(e[t]||"")).filter(Boolean);return{primary:t[0]??"",bySlot:t}}(e),r=new Set,s=t?.labels??{};let i;if(t&&t.models.some(k)){i=[...new Set(t.models.filter(k).map(y))];for(const e of t.oneMillion)r.add(e)}else{i=[];for(const t of["opus","sonnet","haiku","reasoning"]){const o=(e[t]||"").trim(),n=y(o);n&&(i.includes(n)||i.push(n),/\[1m\]/i.test(o)&&r.add(n))}}const a=e=>O[I(e)??""]??9;i.sort((e,t)=>{if(e===o)return-1;if(t===o)return 1;const n=a(e)-a(t);if(0!==n)return n;const r=j(e),s=j(t);return r&&s?function(e,t){const o=Math.max(e.length,t.length);for(let n=0;n<o;n++){const o=(t[n]??0)-(e[n]??0);if(0!==o)return o}return 0}(r.version,s.version):e.localeCompare(t)});const l=new Set,c=new Map;for(const e of n){const t=I(e);t&&i.includes(e)&&!c.has(t)&&c.set(t,e)}return i.map(e=>{const t=I(e),o={name:e,labelOverride:s[e]||humanizeModelId(e)};if(r.has(e)&&(o.supports1m=!0,o.prefer1m=!0),t){o.anthropicFamilyTier=t;const n=c.get(t);n&&n!==e||l.has(t)||(o.isFamilyDefault=!0,l.add(t))}return o})}let L=null,T=null,$=null;function G(e){return{inferenceProvider:"gateway",inferenceCredentialKind:"static",inferenceGatewayBaseUrl:(e.baseUrl||"").trim().replace(/\/+$/,""),inferenceGatewayApiKey:e.apiKey,inferenceModels:buildInferenceModels(e.models,e.catalog),disableDeploymentModeChooser:!1!==e.settings?.hide_official_login,chatTabEnabled:!0,chatAdvancedFileAnalysisEnabled:!0,autoModeEnabled:!0,coworkEgressAllowedHosts:["*"],disableEssentialTelemetry:!0,disableNonessentialTelemetry:!0,disableNonessentialServices:!1}}const N={defaultModelEffort:"medium",modelPrefer1mContext:!0,skipWebFetchPreflight:!0,toolSearchEnabled:!0,builtinBrowserEnabled:!0,isDesktopExtensionEnabled:!0,sshHostAllowlist:["*"],claudeAiImport:{enabled:!0,automatic3pImport:!0,exportEnabled:!0},coworkVmIpv6Enabled:!0,mcpToolTimeoutSec:3600,updateViaUpdatesHost:!0};function U(e){return Object.fromEntries(Object.entries(N).filter(([t])=>!e(t)))}const F="HKCU\\SOFTWARE\\Policies\\Claude",R="HKLM\\SOFTWARE\\Policies\\Claude",K="vibecli-claude-policy.reg",H=e=>c("reg",e,{stdio:["ignore","pipe","pipe"]}).toString();let B=H;export function setRegRunnerForTests(e){B=e??H}function V(){return"win32"===process.platform}function W(e){let t;try{t=B(["query",e])}catch{return null}const o=new Map;for(const e of t.split(/\r?\n/)){const t=/^\s{2,}(\S+)\s+(REG_[A-Z_]+)\s*(.*)$/.exec(e);t&&o.set(t[1],t[3])}return o}function z(){if(null===W(F))return;const e=a(claudeDesktopUserDataDir(),K);try{t(i(e))||o(i(e),{recursive:!0,mode:448}),m(e),B(["export",F,e,"/y"])}catch(e){p.logError("claude-desktop.snapshotPolicy",e)}}const J=[...Object.keys(G({apiKey:"",baseUrl:"",models:{haiku:"",sonnet:"",opus:"",reasoning:""}})),...Object.keys(N)];export function detectManagedConfig(){try{if("darwin"===process.platform){let e="";try{e=d().username}catch{}return[e?`/Library/Managed Preferences/${e}/com.anthropic.claudefordesktop.plist`:"","/Library/Managed Preferences/com.anthropic.claudefordesktop.plist"].filter(Boolean).find(e=>t(e))??null}if("win32"===process.platform)return W(R)?R:null;const e="/etc/claude-desktop/managed-settings.json";return t(e)?e:null}catch(e){return p.logError("claude-desktop.detectManagedConfig",e),null}}const Z=/\d+\.\d+\.\d+/;function X(e){const t=e=>e.split(".").map(Number);return e.sort((e,o)=>{const[n,r]=[t(e),t(o)];for(let e=0;e<3;e++)if(n[e]!==r[e])return r[e]-n[e];return 0})[0]??null}const q="darwin"===process.platform?"open -a Claude":"win32"===process.platform?"Claude":"claude-desktop",Q="darwin"===process.platform||"win32"===process.platform?"https://cnb.cool/vibeapi/claude-desktop/-/releases/latest":"https://claude.ai/download",Y="darwin"===process.platform?`open ${Q}`:"win32"===process.platform?`start ${Q}`:`xdg-open ${Q}`;export const claudeDesktopAdapter={name:"claude-desktop",displayName:"Claude Desktop",command:q,installCommand:Y,configPath:D(),isInstalled:function(){const e=h();let o;switch(process.platform){case"darwin":o=["/Applications/Claude.app",a(e,"Applications","Claude.app")];break;case"win32":{const t=process.env.LOCALAPPDATA||a(e,"AppData","Local");o=[a(t,"AnthropicClaude"),a(t,"Programs","Claude"),...C.map(e=>a(t,"Packages",e))];break}default:o=["/usr/lib/claude-desktop","/opt/Claude","/usr/bin/claude-desktop",a(e,".local","bin","claude-desktop")]}return o.push(claudeDesktopUserDataDir(),a(claudeDesktopUserDataDir(),"..","Claude")),o.some(e=>t(e))},installedVersion:function(){if("darwin"===process.platform){for(const e of["/Applications/Claude.app",a(h(),"Applications","Claude.app")]){const o=a(e,"Contents","Info.plist");if(!t(o))continue;const n=/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(r(o,"utf-8")),s=n?Z.exec(n[1])?.[0]:void 0;if(s)return s}return null}if("win32"===process.platform){const e=a(process.env.LOCALAPPDATA||a(h(),"AppData","Local"),"AnthropicClaude");if(t(e)){const t=n(e).map(e=>/^app-(\d+\.\d+\.\d+)$/.exec(e)?.[1]).filter(e=>!!e);if(t.length>0)return X(t)}const o=C.map(e=>`'${e}'`).join(",");return X(c("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${o}) -contains $_.PackageFamilyName } | ForEach-Object { $_.Version.ToString() }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"]}).split(/\r?\n/).flatMap(e=>Z.exec(e)?.[0]??[]))}return null},wantsModelCatalog:!0,loadPrivateConfig(e){const t=P()??{appliedId:"",entries:[]};let o=S(t);o||(o={id:l(),name:b},t.entries.push(o));const n=G(e);T=!0===n.disableDeploymentModeChooser,L={models:n.inferenceModels,source:e.catalog?e.catalog.oneMillionSource:"slots",groups:e.catalog?.matchedGroups??[]};const r=x(E(o.id))??{};v(E(o.id),{...U(e=>e in r),...r,...n}),t.appliedId=o.id,v(D(),t);const s=x(M())??{};if("3p"!==s.deploymentMode&&v(M(),{...s,deploymentMode:"3p"}),$=null,V())try{const e=W(F);!function(e){z();for(const[t,o]of Object.entries(e)){const[e,n]="boolean"==typeof o?["REG_DWORD",o?"1":"0"]:"number"==typeof o?["REG_DWORD",String(o)]:"string"==typeof o?["REG_SZ",o]:["REG_SZ",JSON.stringify(o)];B(["add",F,"/v",t,"/t",e,"/d",n,"/f"])}}({...U(t=>e?.has(t)??!1),...n})}catch(e){p.logError("claude-desktop.writePolicy",e),$=e instanceof Error?e.message.trim():String(e)}},unloadPrivateConfig(){if(V())try{!function(e){const t=W(F);if(!t)return;z();let o=t.size;for(const n of e)t.has(n)&&(B(["delete",F,"/v",n,"/f"]),o-=1);o<=0&&B(["delete",F,"/f"])}(J)}catch(e){p.logError("claude-desktop.removePolicy",e)}const e=P(),t=S(e);if(!e||!t)return;m(E(t.id)),s(E(t.id),{force:!0});const o=e.entries.filter(e=>e.id!==t.id);0===o.length?(m(D()),s(D(),{force:!0})):v(D(),{...e,entries:o,appliedId:e.appliedId===t.id?o[0].id:e.appliedId})},detectCurrentConfig(){try{if(V()){const e=W(F)?.get("inferenceGatewayApiKey");if(e)return{apiKey:e}}const e=S(P());if(!e)return{apiKey:null};const t=x(E(e.id)),o=t?.inferenceGatewayApiKey;return{apiKey:"string"==typeof o&&o?o:null}}catch(e){return p.logError("claude-desktop.detectCurrentConfig",e),{apiKey:null}}},getConfig(){try{const e=P(),t=S(e);return{meta:e,applied:t?x(E(t.id)):null,desktop:x(M()),...V()?{policy:Object.fromEntries(W(F)??[])}:{}}}catch(e){return p.logError("claude-desktop.getConfig",e),null}},clearPinnedModels(){let e=!1;V()&&W(F)?.has("inferenceModels")&&(z(),B(["delete",F,"/v","inferenceModels","/f"]),e=!0);const t=S(P()),o=t?x(E(t.id)):null;if(t&&o&&void 0!==o.inferenceModels){const{inferenceModels:n,...r}=o;v(E(t.id),r),e=!0}return e?["inferenceModels"]:[]},applyNotes(){const e=[];if(L&&L.models.length>0){const{models:t,source:o,groups:n}=L;e.push({kind:"summary",text:u.t("tools.claude_desktop.models_summary",{count:String(t.length),default:t[0].labelOverride??t[0].name})}),e.push({kind:"detail",text:u.t(`tools.claude_desktop.models_written_${o}`,{count:String(t.length),list:t.map(e=>`${e.labelOverride}${e.supports1m?" (1M)":""}`).join(", "),groups:n.join(" / ")})})}null!==T&&e.push({kind:"detail",text:u.t(T?"tools.claude_desktop.official_login_hidden":"tools.claude_desktop.official_login_shown")}),e.push({kind:"action",text:u.t("tools.claude_desktop.restart_hint")}),$?(e.push({kind:"action",text:u.t("tools.claude_desktop.registry_denied")}),e.push({kind:"detail",text:$})):V()&&e.push({kind:"detail",text:u.t("tools.claude_desktop.registry_written",{key:F})});const t=detectManagedConfig();return t&&e.push({kind:"action",text:u.t("tools.claude_desktop.managed_conflict",{path:t})}),e},forceResetPaths(){const e=[D(),M()];try{const t=S(P());t&&e.push(E(t.id))}catch{}return e},backupPaths(){const e=[D(),M()];V()&&e.push(a(claudeDesktopUserDataDir(),K));try{const t=S(P());t&&e.push(E(t.id))}catch{}return e}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{spawnSync as t}from"child_process";import{existsSync as e,readFileSync as o}from"fs";import{dirname as n,join as i}from"path";import{fileURLToPath as s}from"url";import{logger as r}from"../../utils/logger.js";import{getCodexRules as l}from"../model-registry.js";import{autoCompactTokens as u,prettyModelName as a}from"../gateway-models.js";import{toolHome as d}from"./types.js";const c=n(s(import.meta.url));export const CODEX_CATALOG_FILE="vibeapi-model-catalog.json";export const codexCatalogPath=()=>i(d(),".codex",CODEX_CATALOG_FILE);function p(t){return!!t&&"object"==typeof t&&!Array.isArray(t)}function _(t){try{const e=JSON.parse(t),o=p(e)&&Array.isArray(e.models)?e.models.filter(p):[];return o.length>0?o:null}catch{return null}}export function loadBundledCodexModels(){for(const o of function(){const t=process.env.VIBECLI_CODEX_BIN;if(void 0!==t)return t.trim()?[t.trim()]:[];const e=["codex"];if("darwin"===process.platform)for(const t of["/Applications",i(d(),"Applications")])e.push(i(t,"ChatGPT.app/Contents/Resources/codex-cli/bin/codex")),e.push(i(t,"Codex.app/Contents/Resources/codex"));return e}()){if("codex"!==o&&!e(o))continue;const n=
|
|
1
|
+
import{spawnSync as t}from"child_process";import{existsSync as e,readFileSync as o}from"fs";import{dirname as n,join as i}from"path";import{fileURLToPath as s}from"url";import{logger as r}from"../../utils/logger.js";import{getCodexRules as l}from"../model-registry.js";import{autoCompactTokens as u,prettyModelName as a}from"../gateway-models.js";import{toolHome as d}from"./types.js";const c=n(s(import.meta.url));export const CODEX_CATALOG_FILE="vibeapi-model-catalog.json";export const codexCatalogPath=()=>i(d(),".codex",CODEX_CATALOG_FILE);function p(t){return!!t&&"object"==typeof t&&!Array.isArray(t)}function _(t){try{const e=JSON.parse(t),o=p(e)&&Array.isArray(e.models)?e.models.filter(p):[];return o.length>0?o:null}catch{return null}}export function loadBundledCodexModels(){for(const o of function(){const t=process.env.VIBECLI_CODEX_BIN;if(void 0!==t)return t.trim()?[t.trim()]:[];const e=["codex"];if("darwin"===process.platform)for(const t of["/Applications",i(d(),"Applications")])e.push(i(t,"ChatGPT.app/Contents/Resources/codex-cli/bin/codex")),e.push(i(t,"Codex.app/Contents/Resources/codex"));return e}()){if("codex"!==o&&!e(o))continue;const n={encoding:"utf-8",timeout:2e4,maxBuffer:67108864,windowsHide:!0,stdio:["ignore","pipe","pipe"]},i="win32"===process.platform&&"codex"===o?t("codex debug models --bundled",{...n,shell:!0}):t(o,["debug","models","--bundled"],n);if(0===i.status&&i.stdout){const t=_(i.stdout);if(t)return t}(i.error||0!==i.status)&&r.logError("loadBundledCodexModels",i.error??new Error(`${o} exited ${i.status}`))}return null}export function loadPreviousCodexModels(){const t=m()?.filter(t=>!f(t));return t&&t.length>0?t:null}export function previousGatewayModelIds(){return(m()??[]).filter(f).map(t=>String(t.slug))}function m(){return e(codexCatalogPath())?_(o(codexCatalogPath(),"utf-8")):null}function f(t){return"number"==typeof t.priority&&t.priority>=1e3}let x=null;function w(){if(null!==x)return x;const t=[i(c,"..","..","..","codex-base-instructions.md"),i(c,"..","..","codex-base-instructions.md"),i(c,"codex-base-instructions.md")],n=t.find(t=>e(t));if(!n)throw new Error(`codex-base-instructions.md not found, searched: ${t.join(", ")}`);return x=o(n,"utf-8"),x}function g(t){return"number"==typeof t&&Number.isFinite(t)&&t>0?t:void 0}function h(t,e,o,n){const i=o?t:Math.min(t,e);return{window:i,compact:u(i,n)}}function y(t,e,o,n){const{standardContextWindow:i}=l();let s=g(t.contextWindow)??i;n&&t.id.startsWith("claude-")&&(s=n.has(t.id)?Math.max(s,1e6):Math.min(s,2e5));const{window:r,compact:u}=h(s,i,o,g(t.autoCompactTokens));return{slug:t.id,display_name:t.name||a(t.id),description:t.description??null,supported_reasoning_levels:[],shell_type:"unified_exec",visibility:"list",supported_in_api:!0,priority:e,additional_speed_tiers:[],service_tiers:[],availability_nux:null,upgrade:null,model_messages:{instructions_template:w()},base_instructions:w(),supports_reasoning_summaries:!0,supports_parallel_tool_calls:!1,prefer_websockets:!1,include_skills_usage_instructions:!1,include_plugin_usage_instructions:!1,include_apps_usage_instructions:!1,default_reasoning_summary:"auto",support_verbosity:!1,default_verbosity:null,apply_patch_tool_type:null,web_search_tool_type:"text",truncation_policy:{mode:"bytes",limit:1e4},supports_image_detail_original:!1,context_window:r,max_context_window:r,auto_compact_token_limit:u,effective_context_window_percent:95,experimental_supported_tools:[],input_modalities:["text","image"],supports_search_tool:!1,supports_experimental_context:!1,use_responses_lite:!1,supports_reasoning_effort_updates:!1,node_repl_auto_review_required:!1,node_repl_disabled:!1}}function b(t,e,o){if("list"!==t.visibility)return t;const n=g(t.context_window);if(!n)return t;const i=g(t.max_context_window)??n,s=o?Math.min(g(e?.contextWindow)??i,i):n,{window:r,compact:l}=h(s,n,!0,g(e?.autoCompactTokens));return{...t,context_window:r,auto_compact_token_limit:l}}export function buildCodexCatalog(t){const{bundled:e,specs:o,oneMillion:n,selectedModel:i}=t,s=t.claudeOneMillion?new Set(t.claudeOneMillion):void 0,r=t.keyModels?new Set(t.keyModels):null,l=new Set(t.gatewayAvailable),u=t=>!r||r.has(t)||t===i,a=t=>l.has(t)||t===i,d=new Map(o.map(t=>[t.id,t])),c=[],p=new Set;for(const t of e){const e="string"==typeof t.slug?t.slug:"";e&&!p.has(e)&&("list"!==t.visibility||u(e))&&(p.add(e),c.push(b(t,d.get(e),n)))}const _=[...o];i&&!d.has(i)&&_.push({id:i});for(const t of _)!p.has(t.id)&&a(t.id)&&(p.add(t.id),c.push(y(t,1e3+c.length,n,s)));return{models:c}}
|
package/dist/lib/tools/codex.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as o,readFileSync as
|
|
1
|
+
import{existsSync as o,readFileSync as t}from"fs";import{join as e}from"path";import*as n from"@iarna/toml";import{logger as r}from"../../utils/logger.js";import{i18n as i}from"../i18n.js";import{backupBeforeWrite as l,atomicWriteFile as a}from"./backup.js";import{pickModel as s,toolHome as d,withV1 as c}from"./types.js";import{getToolDefaultModel as m}from"../model-registry.js";import{buildCodexCatalog as p,codexCatalogPath as u,loadBundledCodexModels as f,loadPreviousCodexModels as g,previousGatewayModelIds as _}from"./codex-catalog.js";import{gatewayModelSpecs as x,modelFamily as y}from"../gateway-models.js";const w=()=>e(d(),".codex"),k=()=>e(w(),"config.toml"),C=()=>e(w(),"auth.json"),h="OPENAI_API_KEY",j="custom",E=1e6,b=9e5;export const CODEX_ONE_MILLION_CONTEXT_SETTING="one_million_context";function v(o){return!!o&&"object"==typeof o&&!Array.isArray(o)}function O(o,t){return v(o[t])||(o[t]={}),o[t]}function M(){if(!o(k()))return{};const e=t(k(),"utf-8");if(!e.trim())return{};try{const o=n.parse(e);if(!v(o))throw new Error("config.toml root must be a TOML table");return o}catch(o){throw new Error(`Existing ~/.codex/config.toml cannot be parsed, back it up and fix it first: ${o instanceof Error?o.message:String(o)}`)}}function N(){if(!o(C()))return{};try{const o=JSON.parse(t(C(),"utf-8"));return v(o)?o:{}}catch{return{}}}let S=null;function A(e,n,i){const s=!1!==n.settings?.one_million_context;!function(o){o.model_context_window===E&&delete o.model_context_window,o.model_auto_compact_token_limit===b&&delete o.model_auto_compact_token_limit}(e);const d=f()??g();if(!d)return r.logError("codexAdapter.writeModelCatalog",new Error("no Codex binary found; model catalog skipped")),S="skipped",e.model_catalog_json===u()&&delete e.model_catalog_json,void(s&&(e.model_context_window=E,e.model_auto_compact_token_limit=b));const c=n.catalog,m=p({bundled:d,specs:x("codex",c?.clientModels),...c?{keyModels:c.models}:{},gatewayAvailable:c?.models??_(),oneMillion:s,selectedModel:i,..."gateway"===c?.oneMillionSource?{claudeOneMillion:c.oneMillion}:{}});S={listed:m.models.filter(o=>"list"===o.visibility).map(o=>({id:String(o.slug),name:String(o.display_name??o.slug)}))};const y=JSON.stringify(m,null,2)+"\n",w=u();o(w)&&t(w,"utf-8")===y||(l(w),a(w,y)),e.model_catalog_json=w}export function setCodexOneMillionContext(o,t){const e=M(),r=n.stringify(e),i="string"==typeof e.model?e.model:m("codex");A(e,{settings:{[CODEX_ONE_MILLION_CONTEXT_SETTING]:o},catalog:t},i);const s=n.stringify(e);s!==r&&(l(k()),a(k(),s))}export const codexAdapter={name:"codex",displayName:"Codex",command:"codex",installCommand:"npm install -g @openai/codex",upgradeCommand:"npm install -g @openai/codex@latest",configPath:k(),wantsModelCatalog:!0,applyNotes(){if("skipped"===S)return[{kind:"action",text:i.t("tools.codex.catalog_skipped")}];if(!S)return[];const o=new Map;for(const t of S.listed)o.set(y(t.id),(o.get(y(t.id))??0)+1);const t=["gpt","claude","other","grok"].filter(t=>o.has(t)).map(t=>`${i.t(`tools.model_family.${t}`)} ${o.get(t)}`).join(" · ");return[{kind:"summary",text:i.t("tools.codex.catalog_written",{count:String(S.listed.length),breakdown:t})},{kind:"detail",text:S.listed.map(o=>o.name).join(", ")}]},loadPrivateConfig(o){const t=m("codex"),e=s(o.models,t),r=function(o){return/(?:^|\/)claude(?:-|$)/i.test(o)}(e)?t:e,i=c(o.baseUrl),d=M();d.model=r,d.model_provider=j,d.model_reasoning_effort="xhigh",A(d,o,r);const p=O(d,"model_providers"),u=v(p[j])?{...p[j]}:{};delete u.env_key,p[j]={...u,name:"custom",wire_api:"responses",requires_openai_auth:!0,base_url:i};const f=O(d,"profiles"),g=v(f[r])?{...f[r]}:{};f[r]={...g,model_provider:j,model:r},O(O(d,"tui"),"model_availability_nux")[r]=4;const _=O(d,"features");_.goals=!0,_.js_repl=!1,l(k()),a(k(),n.stringify(d)),function(o){const t=o.trim();if(!t)return;const e={...N(),auth_mode:"apikey",[h]:t};l(C()),a(C(),JSON.stringify(e,null,2)+"\n")}(o.apiKey)},unloadPrivateConfig(){if(!o(k()))return;let t;try{t=M()}catch(o){return void r.logError("codexAdapter.unloadPrivateConfig",o)}const e=t.model_providers;v(e)&&(delete e[j],0===Object.keys(e).length&&delete t.model_providers),t.model_provider===j&&delete t.model_provider,t.model_catalog_json===u()&&delete t.model_catalog_json,l(k()),a(k(),n.stringify(t))},detectCurrentConfig(){const o=N()[h];return{apiKey:"string"==typeof o&&o.trim()?o.trim():null}},getConfig(){try{return M()}catch(o){return r.logError("codexAdapter.getConfig",o),null}},backupPaths:()=>[k(),C(),u()]};
|
|
@@ -29,6 +29,15 @@ export interface ToolApplyContext {
|
|
|
29
29
|
* these and registering it in `registry.ts` — no more editing `if (toolName === ...)`
|
|
30
30
|
* branches scattered across ToolManager.
|
|
31
31
|
*/
|
|
32
|
+
/**
|
|
33
|
+
* One line of feedback after a tool is configured. `summary` is what got set up
|
|
34
|
+
* (printed next to the tool name), `action` is something the user has to do
|
|
35
|
+
* (upgrade, reopen the app), `detail` is diagnostics that only go to the log file.
|
|
36
|
+
*/
|
|
37
|
+
export interface ApplyNote {
|
|
38
|
+
kind: 'summary' | 'action' | 'detail';
|
|
39
|
+
text: string;
|
|
40
|
+
}
|
|
32
41
|
export interface ToolAdapter {
|
|
33
42
|
/** Stable id used on the CLI and as the config key (e.g. `codex`). */
|
|
34
43
|
name: string;
|
|
@@ -59,12 +68,8 @@ export interface ToolAdapter {
|
|
|
59
68
|
* omitted, ToolManager runs `which`/`where` on `command`.
|
|
60
69
|
*/
|
|
61
70
|
isInstalled?(): boolean;
|
|
62
|
-
/**
|
|
63
|
-
|
|
64
|
-
* (e.g. "quit and reopen the app", "a managed policy overrides this").
|
|
65
|
-
* Already localized; callers just print them.
|
|
66
|
-
*/
|
|
67
|
-
applyNotes?(): string[];
|
|
71
|
+
/** Localized feedback about the last successful `loadPrivateConfig`; see {@link ApplyNote}. */
|
|
72
|
+
applyNotes?(): ApplyNote[];
|
|
68
73
|
/** Write this CLI's provider config into the tool. */
|
|
69
74
|
loadPrivateConfig(ctx: ToolApplyContext): void;
|
|
70
75
|
/** Remove this CLI's provider config from the tool, leaving other config intact. */
|
package/dist/lib/wizard.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"inquirer";import t from"chalk";import o from"ora";import{configManager as a,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{i18n as d,detectSystemLang as p}from"./i18n.js";import{createBorderLine as m,createContentLine as u}from"../utils/string-width.js";import{validateApiKey as g,fetchModels as w}from"./api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as _}from"./tools/codex.js";import{CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as f}from"./tools/claude-desktop.js";import{readFileSync as y}from"fs";import{dirname as h,join as z}from"path";import{fileURLToPath as v}from"url";const k=h(v(import.meta.url)),x=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(x.bold("\n"+m("╔","╗","═",this.BOX_WIDTH))),console.log(x.bold(u(e,"║","║",this.BOX_WIDTH,"center"))),console.log(x.bold(m("╚","╝","═",this.BOX_WIDTH))),console.log("")}showOperationHints(){const e=[t.gray(d.t("wizard.hint_navigate")),t.gray(d.t("wizard.hint_confirm"))];console.log(t.gray("💡 ")+e.join(t.gray(" | "))+"\n")}async promptWithHints(t){this.showOperationHints();const o=t.map(e=>"list"!==e.type||e.pageSize?e:{...e,pageSize:20});return e.prompt(o)}printBanner(){const e=65,t=d.t("wizard.banner_subtitle"),o=u(t,"║","║",e,"center"),a=u("","║","║",e,"center"),i=u(`API Helper v${function(){try{return JSON.parse(y(z(k,"..","..","package.json"),"utf-8")).version}catch{return"0.0.0"}}()}`,"║","║",e,"center"),n=[" ▄▀▄ █▀▄ █ █▄█ ██▀ █ █▀▄ ██▀ █▀▄ "," █▀█ █▀ █ █ █ █▄▄ █▄▄ █▀ █▄▄ █▀▄ "].map(t=>u(t,"║","║",e,"center")),r=[m("╔","╗","═",e),a,...n,a,i,o,m("╚","╝","═",e)];console.log(x.bold("\n"+r.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 o;if(e.length>0){const t=e.map(e=>e.command).join(" / ");o=d.t("wizard.goodbye_message_tools",{commands:t}),e.some(e=>"claude-code"===e.name)&&(o+=" "+d.t("wizard.goodbye_claude_hint"))}else o=d.t("wizard.goodbye_message");console.log(t.green("\n👋 "+o))}async runFirstTimeSetup(){const e="zh_CN"===p();e&&(a.setLang("zh_CN"),d.setLocale("zh_CN")),this.resetScreen(),console.log(x.bold("\n"+d.t("wizard.welcome"))),console.log(t.gray(d.t("wizard.privacy_note")+"\n")),e?console.log(t.gray(d.t("wizard.lang_auto_zh")+"\n")):await this.configLanguage(),await this.configApiKey()&&await this.selectAndConfigureTool(!0)}async configLanguage(){for(;;){this.resetScreen(),this.createBox(d.t("wizard.select_language"));const o=d.getLocale(),{language:i}=await this.promptWithHints([{type:"list",name:"language",message:"✨ "+d.t("wizard.select_language"),choices:[{name:"[EN] English"+("en_US"===o?t.green(" ✓ ("+d.t("wizard.current_active")+")"):""),value:"en_US"},{name:"[CN] 中文"+("zh_CN"===o?t.green(" ✓ ("+d.t("wizard.current_active")+")"):""),value:"zh_CN"},new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"back"},{name:"x "+d.t("wizard.nav_exit"),value:"exit"}],default:"zh_CN"}]);if("exit"===i)this.printGoodbye(),process.exit(0);else if("back"===i)return;return a.setLang(i),void d.setLocale(i)}}buildPresetChoices(){const o=n(),a=o.filter(e=>e.recommended),i=o.filter(e=>!e.recommended),r=e=>({name:(d.t(e.name)!==e.name?d.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 a.length>0&&(s.push(new e.Separator(t.hex("#FF8700")("── "+d.t("wizard.recommended")+" ──"))),s.push(...a.map(r))),i.length>0&&(s.push(new e.Separator(t.gray("── "+d.t("wizard.other_models")+" ──"))),s.push(...i.map(r))),s}async handleCustomModelInput(){const o=a.getModels(),{customMode:n}=await e.prompt([{type:"list",name:"customMode",message:d.t("wizard.custom_model_mode"),choices:[{name:d.t("wizard.custom_model_single"),value:"single"},{name:d.t("wizard.custom_model_per_role"),value:"per_role"}]}]);if("single"===n){const{customModel:t}=await e.prompt([{type:"input",name:"customModel",message:d.t("wizard.input_custom_model"),default:i.sonnet}]);a.setModels({haiku:t,sonnet:t,opus:t,reasoning:t})}else{const t=await e.prompt([{type:"input",name:"haiku",message:d.t("wizard.model_haiku"),default:o.haiku},{type:"input",name:"sonnet",message:d.t("wizard.model_sonnet"),default:o.sonnet},{type:"input",name:"opus",message:d.t("wizard.model_opus"),default:o.opus},{type:"input",name:"reasoning",message:d.t("wizard.model_reasoning"),default:o.reasoning}]);a.setModels(t)}console.log(t.green("\n✓ "+d.t("wizard.models_saved")))}async configModels(o){const i=a.getApiKey();if(await this.validatedKeyForConfiguration(i))for(;;){this.resetScreen(),this.createBox(d.t("wizard.config_models"));const i=[...this.buildPresetChoices()];i.push(new e.Separator),i.push({name:"✏️ "+d.t("wizard.custom_model_input"),value:{type:"custom_input"}}),i.push(new e.Separator),i.push({name:"<- "+d.t("wizard.nav_return"),value:{type:"back"}}),i.push({name:"x "+d.t("wizard.nav_exit"),value:{type:"exit"}});const{modelChoice:n}=await this.promptWithHints([{type:"list",name:"modelChoice",message:d.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(o?.skipLoadPrompt||await this.promptLoadAfterModelConfig());if("preset"===n.type){const e=r(n.preset);return a.setModels(e),console.log(t.green("\n✓ "+d.t("wizard.models_saved"))),void(o?.skipLoadPrompt||await this.promptLoadAfterModelConfig())}}}else await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}async promptLoadAfterModelConfig(){const{shouldLoad:t}=await e.prompt([{type:"list",name:"shouldLoad",message:d.t("wizard.load_config_now"),choices:[{name:d.t("wizard.load_config_yes"),value:!0},{name:d.t("wizard.load_config_later"),value:!1}]}]);t&&await this.selectAndConfigureTool()}async configApiKey(){for(;;){this.resetScreen(),this.createBox(d.t("wizard.input_api_key")),console.log(t.gray("\n💡 "+d.t("wizard.api_key_input_hint"))),console.log(t.gray(" "+d.t("wizard.api_key_get_hint",{url:"https://www.vibeapi.cn/console/token"}))),console.log();const{apiKey:i}=await e.prompt([{type:"password",name:"apiKey",message:d.t("wizard.input_your_api_key"),mask:"*"}]);if(!i||""===i.trim()){const{action:t}=await e.prompt([{type:"list",name:"action",message:d.t("wizard.select_action"),choices:[{name:d.t("wizard.retry_input"),value:"retry"},{name:"<- "+d.t("wizard.nav_return"),value:"back"}]}]);if("back"===t)return!1;continue}const n=o(d.t("wizard.validating_api_key")).start(),r=await g(i.trim());if(n.stop(),r.valid)return a.setApiKey(i.trim()),this.validatedApiKeys.add(i.trim()),console.log(t.green("\n✓ "+d.t("wizard.api_key_valid"))),!0;{this.validatedApiKeys.delete(i.trim()),"invalid_api_key"===r.error?console.log(t.red("\n✗ "+d.t("wizard.api_key_invalid"))):console.log(t.red("\n✗ "+d.t("wizard.api_key_network_error")));const{action:o}=await e.prompt([{type:"list",name:"action",message:d.t("wizard.select_action"),choices:[{name:d.t("wizard.retry_input"),value:"retry"},{name:"<- "+d.t("wizard.nav_return"),value:"back"}]}]);if("back"===o)return!1}}}async selectAndConfigureTool(t=!1){for(;;){this.resetScreen(),this.createBox(d.t("wizard.select_tool"));const o=l.getSupportedTools().map(e=>({name:e.displayName,value:e.name})),{tool:a}=await this.promptWithHints([{type:"list",name:"tool",message:"🛠️ "+d.t("wizard.select_tool"),choices:[...o,new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"back"},{name:"x "+d.t("wizard.nav_exit"),value:"exit"}]}]);if("exit"===a)this.printGoodbye(),process.exit(0);else if("back"===a)return;await this.configureTool(a,t)}}async configureTool(o,a=!1){const i=c[o];if(i){if(!l.isToolInstalled(o)){console.log(t.yellow("\n"+d.t("wizard.tool_not_installed",{tool:i.displayName})));const{install:a}=await e.prompt([{type:"confirm",name:"install",message:d.t("wizard.install_tool_confirm"),default:!0}]);if(!a)return;try{await l.installTool(o)}catch{return void console.log(t.red(d.t("wizard.install_failed")))}}a?await this.configureToolModel(o)&&await this.loadConfig(o):await this.showToolMenu(o)}}async showToolMenu(t){for(;;){this.resetScreen();const o=c[t];if(!o)return;this.createBox(o.displayName+" "+d.t("wizard.menu_title"));const a=[{name:"📥 "+d.t("wizard.action_load_config",{tool:o.displayName}),value:"load"},{name:"📤 "+d.t("wizard.action_unload_config",{tool:o.displayName}),value:"unload"}];l.supportsClearPinnedModels(t)&&a.push({name:"🧹 "+d.t("wizard.action_clear_model",{tool:o.displayName}),value:"clear-model"}),a.push({name:"🧨 "+d.t("wizard.action_force_config",{tool:o.displayName}),value:"force"},{name:"↩️ "+d.t("wizard.action_restore_config",{tool:o.displayName}),value:"restore"},new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"back"},{name:"x "+d.t("wizard.nav_exit"),value:"exit"});const{action:i}=await this.promptWithHints([{type:"list",name:"action",message:"⚙️ "+d.t("wizard.select_action"),choices:a}]);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!!a.getApiKey()?.trim()||a.listToolApiKeys().some(e=>Boolean(a.getApiKeyForTool(e)?.trim()))}async validatedKeyForConfiguration(e){const a=e?.trim();if(!a)return console.log(t.red("\n"+d.t("wizard.api_key_required"))),console.log(t.yellow(d.t("wizard.please_config_api_key_first"))),null;if(this.validatedApiKeys.has(a))return a;const i=o(d.t("wizard.validating_api_key")).start(),n=await g(a);if(n.valid)return this.validatedApiKeys.add(a),i.succeed(d.t("wizard.api_key_valid")),a;this.validatedApiKeys.delete(a);const r="invalid_api_key"===n.error?d.t("wizard.api_key_invalid"):d.t("wizard.api_key_network_error");return i.fail(r),console.log(t.red("\n"+d.t("wizard.please_reconfig_api_key"))),null}async configureToolModel(i){const n=c[i];if(!n)return!1;const l=await this.validatedKeyForConfiguration(a.getApiKeyForTool(i));if(!l)return await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}]),!1;const p="claude-code"===i,m=s(i),u=p||!m?d.t("wizard.model_builtin_default"):m;this.resetScreen(),this.createBox(n.displayName+" · "+d.t("wizard.config_models"));const g=[{name:"✅ "+d.t("wizard.use_default_model",{model:u}),value:{type:"default"}},{name:"🌐 "+d.t("wizard.fetch_models_from_api"),value:{type:"fetch"}},...this.buildPresetChoices(),new e.Separator,{name:"✏️ "+d.t("wizard.input_custom_model"),value:{type:"custom"}},new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:{type:"back"}}],{choice:y}=await this.promptWithHints([{type:"list",name:"choice",message:d.t("wizard.select_tool_model",{tool:n.displayName}),choices:g}]);if("back"===y.type)return!1;if("default"===y.type)a.setToolModel(i,null);else if("preset"===y.type)a.setToolModel(i,r(y.preset));else if("custom"===y.type){const{model:t}=await e.prompt([{type:"input",name:"model",message:d.t("wizard.input_custom_model"),default:!p&&m?m:void 0}]),o=(t||"").trim();a.setToolModel(i,o?this.singleModelOverride(o):null)}else if("fetch"===y.type){const n=o(d.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:d.t("wizard.select_fetched_model"),pageSize:20,choices:[...r.models,new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"__back__"}]}]);if("__back__"===t)return!1;s=t}else{console.log(t.yellow("\n"+d.t("wizard.fetch_models_failed")));const{model:o}=await e.prompt([{type:"input",name:"model",message:d.t("wizard.input_custom_model"),default:!p&&m?m:void 0}]);s=(o||"").trim()}a.setToolModel(i,s?this.singleModelOverride(s):null)}if("codex"===i){const t=a.getToolSetting(i,_),{enableOneMillionContext:o}=await e.prompt([{type:"confirm",name:"enableOneMillionContext",message:d.t("wizard.codex_enable_1m_context"),default:!1!==t}]);a.setToolSetting(i,_,Boolean(o))}if("claude-desktop"===i){const t=a.getToolSetting(i,f),{hideOfficialLogin:o}=await e.prompt([{type:"confirm",name:"hideOfficialLogin",message:d.t("wizard.desktop_hide_official_login"),default:!1!==t}]);a.setToolSetting(i,f,Boolean(o))}return console.log(t.green("\n✓ "+d.t("wizard.models_saved"))),p&&console.log(t.gray("💡 "+d.t("wizard.claude_model_hint"))),!0}async forceConfig(t){const o=c[t]?.displayName||t,{confirm:a}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("config.confirm_force",{tool:o}),default:!1}]);a&&await this.loadConfig(t,{force:!0})}async loadConfig(i,n={}){const r=a.getModelsForTool(i),s=await this.validatedKeyForConfiguration(a.getApiKeyForTool(i));if(!s)return void await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}]);const p=o(d.t("wizard.loading_config")).start();try{await l.applyPrivateConfig(i,s,r,n),p.succeed(d.t("wizard.config_loaded",{tool:c[i]?.displayName||i})),n.force&&console.log(t.yellow(d.t("config.force_done",{tool:c[i]?.displayName||i})));const o=c[i]?.command;o&&console.log(t.green("\n"+d.t("wizard.run_tool_hint",{command:o})));for(const e of l.applyNotes(i))console.log(t.yellow("💡 "+e));const{nextAction:a}=await e.prompt([{type:"list",name:"nextAction",message:d.t("wizard.what_next"),choices:[{name:d.t("wizard.exit_and_start"),value:"exit"},{name:d.t("wizard.continue_config"),value:"continue"}]}]);"exit"===a&&(this.printGoodbye(),process.exit(0))}catch(o){p.fail(d.t("wizard.config_failed")),console.log(t.red(o instanceof Error?o.message:String(o))),await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}}async clearPinnedModels(o){const a=c[o]?.displayName||o,{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("wizard.confirm_clear_model",{tool:a}),default:!1}]);if(i){try{const e=await l.clearPinnedModels(o);0===e.length?console.log(t.yellow("\n"+d.t("config.clear_model_none",{tool:a}))):(console.log(t.green("\n✓ "+d.t("config.clear_model_done",{tool:a}))),e.forEach(e=>console.log(t.gray(` - ${e}`))),console.log(t.gray(d.t("config.clear_model_restart_hint",{tool:a}))))}catch(e){console.log(t.red("\n"+(e instanceof Error?e.message:String(e))))}await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}}async unloadConfig(a){const{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("wizard.confirm_unload_config",{tool:c[a]?.displayName||a}),default:!1}]);if(!i)return;const n=o(d.t("wizard.unloading_config")).start();try{l.unloadPrivateConfig(a),n.succeed(d.t("wizard.config_unloaded"));const{nextAction:t}=await e.prompt([{type:"list",name:"nextAction",message:d.t("wizard.what_next"),choices:[{name:d.t("wizard.exit_and_start"),value:"exit"},{name:d.t("wizard.continue_config"),value:"continue"}]}]);"exit"===t&&(this.printGoodbye(),process.exit(0))}catch(o){n.fail(d.t("wizard.config_unload_failed")),console.log(t.red(o instanceof Error?o.message:String(o))),await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}}async restoreConfig(a){const i=c[a]?.displayName||a,{confirm:n}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("wizard.confirm_restore_config",{tool:i}),default:!1}]);if(!n)return;const r=o(d.t("wizard.restoring_config")).start();try{const e=l.restorePrivateConfig(a).filter(e=>e.result.restored);0===e.length?r.warn(d.t("wizard.restore_no_backup")):(r.succeed(d.t("wizard.config_restored",{tool:i})),e.forEach(e=>console.log(t.gray(` ${e.file} ← ${e.result.from}`))))}catch(e){r.fail(d.t("wizard.config_restore_failed")),console.log(t.red(e instanceof Error?e.message:String(e)))}await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}async run(){await this.showMainMenu()}async showMainMenu(){if(this.hasConfiguredApiKey())for(;;){this.resetScreen();const o=a.getApiKey()||"",i=o.length>4?"sk-****"+o.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(x("── "+d.t("wizard.select_tool")+" ──")),...n,new e.Separator(t.gray("── "+d.t("wizard.settings")+" ──")),{name:"🔑 "+d.t("wizard.menu_change_api_key"),value:{type:"apikey"}},{name:"🌐 "+d.t("wizard.menu_config_language"),value:{type:"language"}},new e.Separator,{name:"x "+d.t("wizard.nav_exit"),value:{type:"exit"}}],{action:s}=await this.promptWithHints([{type:"list",name:"action",message:"🛠️ "+d.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():"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 o from"ora";import{configManager as a,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{i18n as d,detectSystemLang as p}from"./i18n.js";import{createBorderLine as m,createContentLine as u}from"../utils/string-width.js";import{validateApiKey as g,fetchModels as w}from"./api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as _}from"./tools/codex.js";import{CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as f}from"./tools/claude-desktop.js";import{readFileSync as y}from"fs";import{dirname as h,join as z}from"path";import{fileURLToPath as v}from"url";const k=h(v(import.meta.url)),x=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(x.bold("\n"+m("╔","╗","═",this.BOX_WIDTH))),console.log(x.bold(u(e,"║","║",this.BOX_WIDTH,"center"))),console.log(x.bold(m("╚","╝","═",this.BOX_WIDTH))),console.log("")}showOperationHints(){const e=[t.gray(d.t("wizard.hint_navigate")),t.gray(d.t("wizard.hint_confirm"))];console.log(t.gray("💡 ")+e.join(t.gray(" | "))+"\n")}async promptWithHints(t){this.showOperationHints();const o=t.map(e=>"list"!==e.type||e.pageSize?e:{...e,pageSize:20});return e.prompt(o)}printBanner(){const e=65,t=d.t("wizard.banner_subtitle"),o=u(t,"║","║",e,"center"),a=u("","║","║",e,"center"),i=u(`API Helper v${function(){try{return JSON.parse(y(z(k,"..","..","package.json"),"utf-8")).version}catch{return"0.0.0"}}()}`,"║","║",e,"center"),n=[" ▄▀▄ █▀▄ █ █▄█ ██▀ █ █▀▄ ██▀ █▀▄ "," █▀█ █▀ █ █ █ █▄▄ █▄▄ █▀ █▄▄ █▀▄ "].map(t=>u(t,"║","║",e,"center")),r=[m("╔","╗","═",e),a,...n,a,i,o,m("╚","╝","═",e)];console.log(x.bold("\n"+r.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 o;if(e.length>0){const t=e.map(e=>e.command).join(" / ");o=d.t("wizard.goodbye_message_tools",{commands:t}),e.some(e=>"claude-code"===e.name)&&(o+=" "+d.t("wizard.goodbye_claude_hint"))}else o=d.t("wizard.goodbye_message");console.log(t.green("\n👋 "+o))}async runFirstTimeSetup(){const e="zh_CN"===p();e&&(a.setLang("zh_CN"),d.setLocale("zh_CN")),this.resetScreen(),console.log(x.bold("\n"+d.t("wizard.welcome"))),console.log(t.gray(d.t("wizard.privacy_note")+"\n")),e?console.log(t.gray(d.t("wizard.lang_auto_zh")+"\n")):await this.configLanguage(),await this.configApiKey()&&await this.selectAndConfigureTool(!0)}async configLanguage(){for(;;){this.resetScreen(),this.createBox(d.t("wizard.select_language"));const o=d.getLocale(),{language:i}=await this.promptWithHints([{type:"list",name:"language",message:"✨ "+d.t("wizard.select_language"),choices:[{name:"[EN] English"+("en_US"===o?t.green(" ✓ ("+d.t("wizard.current_active")+")"):""),value:"en_US"},{name:"[CN] 中文"+("zh_CN"===o?t.green(" ✓ ("+d.t("wizard.current_active")+")"):""),value:"zh_CN"},new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"back"},{name:"x "+d.t("wizard.nav_exit"),value:"exit"}],default:"zh_CN"}]);if("exit"===i)this.printGoodbye(),process.exit(0);else if("back"===i)return;return a.setLang(i),void d.setLocale(i)}}buildPresetChoices(){const o=n(),a=o.filter(e=>e.recommended),i=o.filter(e=>!e.recommended),r=e=>({name:(d.t(e.name)!==e.name?d.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 a.length>0&&(s.push(new e.Separator(t.hex("#FF8700")("── "+d.t("wizard.recommended")+" ──"))),s.push(...a.map(r))),i.length>0&&(s.push(new e.Separator(t.gray("── "+d.t("wizard.other_models")+" ──"))),s.push(...i.map(r))),s}async handleCustomModelInput(){const o=a.getModels(),{customMode:n}=await e.prompt([{type:"list",name:"customMode",message:d.t("wizard.custom_model_mode"),choices:[{name:d.t("wizard.custom_model_single"),value:"single"},{name:d.t("wizard.custom_model_per_role"),value:"per_role"}]}]);if("single"===n){const{customModel:t}=await e.prompt([{type:"input",name:"customModel",message:d.t("wizard.input_custom_model"),default:i.sonnet}]);a.setModels({haiku:t,sonnet:t,opus:t,reasoning:t})}else{const t=await e.prompt([{type:"input",name:"haiku",message:d.t("wizard.model_haiku"),default:o.haiku},{type:"input",name:"sonnet",message:d.t("wizard.model_sonnet"),default:o.sonnet},{type:"input",name:"opus",message:d.t("wizard.model_opus"),default:o.opus},{type:"input",name:"reasoning",message:d.t("wizard.model_reasoning"),default:o.reasoning}]);a.setModels(t)}console.log(t.green("\n✓ "+d.t("wizard.models_saved")))}async configModels(o){const i=a.getApiKey();if(await this.validatedKeyForConfiguration(i))for(;;){this.resetScreen(),this.createBox(d.t("wizard.config_models"));const i=[...this.buildPresetChoices()];i.push(new e.Separator),i.push({name:"✏️ "+d.t("wizard.custom_model_input"),value:{type:"custom_input"}}),i.push(new e.Separator),i.push({name:"<- "+d.t("wizard.nav_return"),value:{type:"back"}}),i.push({name:"x "+d.t("wizard.nav_exit"),value:{type:"exit"}});const{modelChoice:n}=await this.promptWithHints([{type:"list",name:"modelChoice",message:d.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(o?.skipLoadPrompt||await this.promptLoadAfterModelConfig());if("preset"===n.type){const e=r(n.preset);return a.setModels(e),console.log(t.green("\n✓ "+d.t("wizard.models_saved"))),void(o?.skipLoadPrompt||await this.promptLoadAfterModelConfig())}}}else await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}async promptLoadAfterModelConfig(){const{shouldLoad:t}=await e.prompt([{type:"list",name:"shouldLoad",message:d.t("wizard.load_config_now"),choices:[{name:d.t("wizard.load_config_yes"),value:!0},{name:d.t("wizard.load_config_later"),value:!1}]}]);t&&await this.selectAndConfigureTool()}async configApiKey(){for(;;){this.resetScreen(),this.createBox(d.t("wizard.input_api_key")),console.log(t.gray("\n💡 "+d.t("wizard.api_key_input_hint"))),console.log(t.gray(" "+d.t("wizard.api_key_get_hint",{url:"https://www.vibeapi.cn/console/token"}))),console.log();const{apiKey:i}=await e.prompt([{type:"password",name:"apiKey",message:d.t("wizard.input_your_api_key"),mask:"*"}]);if(!i||""===i.trim()){const{action:t}=await e.prompt([{type:"list",name:"action",message:d.t("wizard.select_action"),choices:[{name:d.t("wizard.retry_input"),value:"retry"},{name:"<- "+d.t("wizard.nav_return"),value:"back"}]}]);if("back"===t)return!1;continue}const n=o(d.t("wizard.validating_api_key")).start(),r=await g(i.trim());if(n.stop(),r.valid)return a.setApiKey(i.trim()),this.validatedApiKeys.add(i.trim()),console.log(t.green("\n✓ "+d.t("wizard.api_key_valid"))),!0;{this.validatedApiKeys.delete(i.trim()),"invalid_api_key"===r.error?console.log(t.red("\n✗ "+d.t("wizard.api_key_invalid"))):console.log(t.red("\n✗ "+d.t("wizard.api_key_network_error")));const{action:o}=await e.prompt([{type:"list",name:"action",message:d.t("wizard.select_action"),choices:[{name:d.t("wizard.retry_input"),value:"retry"},{name:"<- "+d.t("wizard.nav_return"),value:"back"}]}]);if("back"===o)return!1}}}async selectAndConfigureTool(t=!1){for(;;){this.resetScreen(),this.createBox(d.t("wizard.select_tool"));const o=l.getSupportedTools().map(e=>({name:e.displayName,value:e.name})),{tool:a}=await this.promptWithHints([{type:"list",name:"tool",message:"🛠️ "+d.t("wizard.select_tool"),choices:[...o,new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"back"},{name:"x "+d.t("wizard.nav_exit"),value:"exit"}]}]);if("exit"===a)this.printGoodbye(),process.exit(0);else if("back"===a)return;await this.configureTool(a,t)}}async configureTool(o,a=!1){const i=c[o];if(i){if(!l.isToolInstalled(o)){console.log(t.yellow("\n"+d.t("wizard.tool_not_installed",{tool:i.displayName})));const{install:a}=await e.prompt([{type:"confirm",name:"install",message:d.t("wizard.install_tool_confirm"),default:!0}]);if(!a)return;try{await l.installTool(o)}catch{return void console.log(t.red(d.t("wizard.install_failed")))}}a?await this.configureToolModel(o)&&await this.loadConfig(o):await this.showToolMenu(o)}}async showToolMenu(t){for(;;){this.resetScreen();const o=c[t];if(!o)return;this.createBox(o.displayName+" "+d.t("wizard.menu_title"));const a=[{name:"📥 "+d.t("wizard.action_load_config",{tool:o.displayName}),value:"load"},{name:"📤 "+d.t("wizard.action_unload_config",{tool:o.displayName}),value:"unload"}];l.supportsClearPinnedModels(t)&&a.push({name:"🧹 "+d.t("wizard.action_clear_model",{tool:o.displayName}),value:"clear-model"}),a.push({name:"🧨 "+d.t("wizard.action_force_config",{tool:o.displayName}),value:"force"},{name:"↩️ "+d.t("wizard.action_restore_config",{tool:o.displayName}),value:"restore"},new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"back"},{name:"x "+d.t("wizard.nav_exit"),value:"exit"});const{action:i}=await this.promptWithHints([{type:"list",name:"action",message:"⚙️ "+d.t("wizard.select_action"),choices:a}]);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!!a.getApiKey()?.trim()||a.listToolApiKeys().some(e=>Boolean(a.getApiKeyForTool(e)?.trim()))}async validatedKeyForConfiguration(e){const a=e?.trim();if(!a)return console.log(t.red("\n"+d.t("wizard.api_key_required"))),console.log(t.yellow(d.t("wizard.please_config_api_key_first"))),null;if(this.validatedApiKeys.has(a))return a;const i=o(d.t("wizard.validating_api_key")).start(),n=await g(a);if(n.valid)return this.validatedApiKeys.add(a),i.succeed(d.t("wizard.api_key_valid")),a;this.validatedApiKeys.delete(a);const r="invalid_api_key"===n.error?d.t("wizard.api_key_invalid"):d.t("wizard.api_key_network_error");return i.fail(r),console.log(t.red("\n"+d.t("wizard.please_reconfig_api_key"))),null}async configureToolModel(i){const n=c[i];if(!n)return!1;const l=await this.validatedKeyForConfiguration(a.getApiKeyForTool(i));if(!l)return await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}]),!1;const p="claude-code"===i,m=s(i),u=p||!m?d.t("wizard.model_builtin_default"):m;this.resetScreen(),this.createBox(n.displayName+" · "+d.t("wizard.config_models"));const g=[{name:"✅ "+d.t("wizard.use_default_model",{model:u}),value:{type:"default"}},{name:"🌐 "+d.t("wizard.fetch_models_from_api"),value:{type:"fetch"}},...this.buildPresetChoices(),new e.Separator,{name:"✏️ "+d.t("wizard.input_custom_model"),value:{type:"custom"}},new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:{type:"back"}}],{choice:y}=await this.promptWithHints([{type:"list",name:"choice",message:d.t("wizard.select_tool_model",{tool:n.displayName}),choices:g}]);if("back"===y.type)return!1;if("default"===y.type)a.setToolModel(i,null);else if("preset"===y.type)a.setToolModel(i,r(y.preset));else if("custom"===y.type){const{model:t}=await e.prompt([{type:"input",name:"model",message:d.t("wizard.input_custom_model"),default:!p&&m?m:void 0}]),o=(t||"").trim();a.setToolModel(i,o?this.singleModelOverride(o):null)}else if("fetch"===y.type){const n=o(d.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:d.t("wizard.select_fetched_model"),pageSize:20,choices:[...r.models,new e.Separator,{name:"<- "+d.t("wizard.nav_return"),value:"__back__"}]}]);if("__back__"===t)return!1;s=t}else{console.log(t.yellow("\n"+d.t("wizard.fetch_models_failed")));const{model:o}=await e.prompt([{type:"input",name:"model",message:d.t("wizard.input_custom_model"),default:!p&&m?m:void 0}]);s=(o||"").trim()}a.setToolModel(i,s?this.singleModelOverride(s):null)}if("codex"===i){const t=a.getToolSetting(i,_),{enableOneMillionContext:o}=await e.prompt([{type:"confirm",name:"enableOneMillionContext",message:d.t("wizard.codex_enable_1m_context"),default:!1!==t}]);a.setToolSetting(i,_,Boolean(o))}if("claude-desktop"===i){const t=a.getToolSetting(i,f),{hideOfficialLogin:o}=await e.prompt([{type:"confirm",name:"hideOfficialLogin",message:d.t("wizard.desktop_hide_official_login"),default:!1!==t}]);a.setToolSetting(i,f,Boolean(o))}return console.log(t.green("\n✓ "+d.t("wizard.models_saved"))),p&&console.log(t.gray("💡 "+d.t("wizard.claude_model_hint"))),!0}async forceConfig(t){const o=c[t]?.displayName||t,{confirm:a}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("config.confirm_force",{tool:o}),default:!1}]);a&&await this.loadConfig(t,{force:!0})}async loadConfig(i,n={}){const r=a.getModelsForTool(i),s=await this.validatedKeyForConfiguration(a.getApiKeyForTool(i));if(!s)return void await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}]);const p=o(d.t("wizard.loading_config")).start();try{await l.applyPrivateConfig(i,s,r,n),p.stop(),l.printApplied(i),n.force&&console.log(t.yellow(d.t("config.force_done",{tool:c[i]?.displayName||i})));const o=c[i]?.command;o&&console.log(t.green("\n"+d.t("wizard.run_tool_hint",{command:o})));const{nextAction:a}=await e.prompt([{type:"list",name:"nextAction",message:d.t("wizard.what_next"),choices:[{name:d.t("wizard.exit_and_start"),value:"exit"},{name:d.t("wizard.continue_config"),value:"continue"}]}]);"exit"===a&&(this.printGoodbye(),process.exit(0))}catch(o){p.fail(d.t("wizard.config_failed")),console.log(t.red(o instanceof Error?o.message:String(o))),await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}}async clearPinnedModels(o){const a=c[o]?.displayName||o,{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("wizard.confirm_clear_model",{tool:a}),default:!1}]);if(i){try{const e=await l.clearPinnedModels(o);0===e.length?console.log(t.yellow("\n"+d.t("config.clear_model_none",{tool:a}))):(console.log(t.green("\n✓ "+d.t("config.clear_model_done",{tool:a}))),e.forEach(e=>console.log(t.gray(` - ${e}`))),console.log(t.gray(d.t("config.clear_model_restart_hint",{tool:a}))))}catch(e){console.log(t.red("\n"+(e instanceof Error?e.message:String(e))))}await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}}async unloadConfig(a){const{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("wizard.confirm_unload_config",{tool:c[a]?.displayName||a}),default:!1}]);if(!i)return;const n=o(d.t("wizard.unloading_config")).start();try{l.unloadPrivateConfig(a),n.succeed(d.t("wizard.config_unloaded"));const{nextAction:t}=await e.prompt([{type:"list",name:"nextAction",message:d.t("wizard.what_next"),choices:[{name:d.t("wizard.exit_and_start"),value:"exit"},{name:d.t("wizard.continue_config"),value:"continue"}]}]);"exit"===t&&(this.printGoodbye(),process.exit(0))}catch(o){n.fail(d.t("wizard.config_unload_failed")),console.log(t.red(o instanceof Error?o.message:String(o))),await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}}async restoreConfig(a){const i=c[a]?.displayName||a,{confirm:n}=await e.prompt([{type:"confirm",name:"confirm",message:d.t("wizard.confirm_restore_config",{tool:i}),default:!1}]);if(!n)return;const r=o(d.t("wizard.restoring_config")).start();try{const e=l.restorePrivateConfig(a).filter(e=>e.result.restored);0===e.length?r.warn(d.t("wizard.restore_no_backup")):(r.succeed(d.t("wizard.config_restored",{tool:i})),e.forEach(e=>console.log(t.gray(` ${e.file} ← ${e.result.from}`))))}catch(e){r.fail(d.t("wizard.config_restore_failed")),console.log(t.red(e instanceof Error?e.message:String(e)))}await e.prompt([{type:"input",name:"continue",message:d.t("wizard.press_enter")}])}async run(){await this.showMainMenu()}async showMainMenu(){if(this.hasConfiguredApiKey())for(;;){this.resetScreen();const o=a.getApiKey()||"",i=o.length>4?"sk-****"+o.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(x("── "+d.t("wizard.select_tool")+" ──")),...n,new e.Separator(t.gray("── "+d.t("wizard.settings")+" ──")),{name:"🔑 "+d.t("wizard.menu_change_api_key"),value:{type:"apikey"}},{name:"🌐 "+d.t("wizard.menu_config_language"),value:{type:"language"}},new e.Separator,{name:"x "+d.t("wizard.nav_exit"),value:{type:"exit"}}],{action:s}=await this.promptWithHints([{type:"list",name:"action",message:"🛠️ "+d.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():"language"===s.type&&await this.configLanguage()}else await this.runFirstTimeSetup()}}export const wizard=Wizard.getInstance();
|
package/dist/locales/en_US.json
CHANGED
|
@@ -65,7 +65,6 @@
|
|
|
65
65
|
"action_exit": "Exit",
|
|
66
66
|
"goodbye": "Goodbye!",
|
|
67
67
|
"loading_config": "Applying configuration...",
|
|
68
|
-
"config_loaded": "Configuration applied — you can use {{tool}} for coding now.",
|
|
69
68
|
"run_tool_hint": "✅ Now run `{{command}}` to start using your config",
|
|
70
69
|
"config_failed": "Failed to load configuration",
|
|
71
70
|
"confirm_unload_config": "Are you sure you want to remove configuration from {{tool}}?",
|
|
@@ -254,7 +253,6 @@
|
|
|
254
253
|
"backup_restore_aborted": "Backup restore cancelled",
|
|
255
254
|
"unknown_command": "Unknown command: {{command}}",
|
|
256
255
|
"usage_hint": "Usage: vibecli config [profile|preset|backup|tool-model|<tool-name>] [...]",
|
|
257
|
-
"tool_config_loaded": "{{tool}} configuration loaded",
|
|
258
256
|
"unknown_action": "Unknown action: {{action}}",
|
|
259
257
|
"unknown_tool": "Unknown tool: {{tool}}",
|
|
260
258
|
"empty_list": "no entries",
|
|
@@ -332,33 +330,42 @@
|
|
|
332
330
|
"skip_no_claude": "This key has no Claude model group; skipped Claude Code",
|
|
333
331
|
"skip_no_gpt": "This key has no GPT model group; skipped Codex",
|
|
334
332
|
"skip_no_grok": "This key has no Grok model group; skipped Grok Build",
|
|
335
|
-
"configured": "√ {{tool}} configured (run `{{command}}` to start)",
|
|
336
333
|
"apply_failed": "Failed to write {{tool}} config: {{reason}}",
|
|
337
|
-
"install_hint": "
|
|
338
|
-
"done": "Done: {{count}} tool(s) configured.
|
|
334
|
+
"install_hint": "{{tool}} not found; install it with {{install}}",
|
|
335
|
+
"done": "Done: {{count}} tool(s) configured. ",
|
|
339
336
|
"skip_desktop_not_installed": "Claude Desktop is not installed; skipped (after installing, run vibecli setup --desktopkey sk-xxx or use the wizard)",
|
|
340
337
|
"desktop_official_login_missing_key": "No saved Claude Desktop API key found; run --key or --desktopkey first",
|
|
341
|
-
"claude_official_invalid": "Invalid value for --claude-official: {{value}} (expected on or off)"
|
|
338
|
+
"claude_official_invalid": "Invalid value for --claude-official: {{value}} (expected on or off)",
|
|
339
|
+
"done_commands": "Type {{commands}} in your terminal to start",
|
|
340
|
+
"failed_summary": "{{count}} tool(s) failed; see above"
|
|
342
341
|
},
|
|
343
342
|
"tools": {
|
|
344
|
-
"version_outdated": "
|
|
343
|
+
"version_outdated": "version {{current}} is too old (needs {{min}} or later); upgrade with {{upgrade}}",
|
|
345
344
|
"codex": {
|
|
346
|
-
"catalog_written": "
|
|
347
|
-
"catalog_skipped": "
|
|
345
|
+
"catalog_written": "{{count}} models in the menu ({{breakdown}}); reopen the Codex desktop app to see them",
|
|
346
|
+
"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; install or upgrade Codex and run this again"
|
|
348
347
|
},
|
|
349
348
|
"claude_desktop": {
|
|
350
|
-
"restart_hint": "
|
|
349
|
+
"restart_hint": "Fully quit Claude Desktop and reopen it for the change to take effect",
|
|
351
350
|
"managed_conflict": "Managed configuration found at {{path}}; Claude Desktop prefers it and ignores local settings. Remove that profile / policy first, then relaunch",
|
|
352
351
|
"registry_written": "Also written to the registry policy {{key}} as a backstop (same as the downloadable .reg); the in-app \"Configure Third-Party Inference\" window will show as managed, and unloading removes it too",
|
|
353
352
|
"models_written_gateway": "Wrote {{count}} models (1M flags from the gateway group table, matched groups: {{groups}}): {{list}}",
|
|
354
353
|
"models_written_fallback": "Wrote {{count}} models (gateway group table unavailable or no group matched; 1M flags from built-in rules): {{list}}",
|
|
355
354
|
"models_written_slots": "Wrote {{count}} models (offline: from the profile's model slots, gateway model list not fetched): {{list}}",
|
|
356
355
|
"official_login_hidden": "The official Claude.ai sign-in entry is hidden; the desktop is gateway-only. Run vibecli setup --claude-official on to bring it back",
|
|
357
|
-
"official_login_shown": "The official Claude.ai sign-in entry stays visible, so users can switch between the gateway and their own account. Run vibecli setup --claude-official off to hide it"
|
|
356
|
+
"official_login_shown": "The official Claude.ai sign-in entry stays visible, so users can switch between the gateway and their own account. Run vibecli setup --claude-official off to hide it",
|
|
357
|
+
"models_summary": "{{count}} Claude models, default {{default}}",
|
|
358
|
+
"registry_denied": "Not elevated, so the registry backstop was skipped (the local config is written and usually enough); if the reopened app doesn't use VibeAPI, run this again from an administrator terminal"
|
|
358
359
|
},
|
|
359
360
|
"claude_code": {
|
|
360
|
-
"gateway_models": "
|
|
361
|
+
"gateway_models": "{{count}} Chinese models added to /model ({{vendors}})",
|
|
361
362
|
"tier_fallback": "This key can't use Claude Code's default {{from}}; the {{tier}} alias now uses {{to}}"
|
|
363
|
+
},
|
|
364
|
+
"model_family": {
|
|
365
|
+
"gpt": "GPT",
|
|
366
|
+
"claude": "Claude",
|
|
367
|
+
"other": "Chinese",
|
|
368
|
+
"grok": "Grok"
|
|
362
369
|
}
|
|
363
370
|
}
|
|
364
371
|
}
|
package/dist/locales/zh_CN.json
CHANGED
|
@@ -65,7 +65,6 @@
|
|
|
65
65
|
"action_exit": "退出",
|
|
66
66
|
"goodbye": "再见!",
|
|
67
67
|
"loading_config": "正在应用配置...",
|
|
68
|
-
"config_loaded": "配置已应用,现在就能用 {{tool}} 写代码了。",
|
|
69
68
|
"run_tool_hint": "✅ 现在运行 `{{command}}` 就能用上你的配置了",
|
|
70
69
|
"config_failed": "配置装载失败",
|
|
71
70
|
"confirm_unload_config": "确认从 {{tool}} 移除配置吗?",
|
|
@@ -254,7 +253,6 @@
|
|
|
254
253
|
"backup_restore_aborted": "已取消恢复备份",
|
|
255
254
|
"unknown_command": "未知命令: {{command}}",
|
|
256
255
|
"usage_hint": "用法: vibecli config [profile|preset|backup|tool-model|<tool-name>] [...]",
|
|
257
|
-
"tool_config_loaded": "{{tool}} 配置已加载",
|
|
258
256
|
"unknown_action": "未知操作: {{action}}",
|
|
259
257
|
"unknown_tool": "未知工具: {{tool}}",
|
|
260
258
|
"empty_list": "暂无条目",
|
|
@@ -332,33 +330,42 @@
|
|
|
332
330
|
"skip_no_claude": "该 Key 未开通 Claude 模型分组,已跳过 Claude Code",
|
|
333
331
|
"skip_no_gpt": "该 Key 未开通 GPT 模型分组,已跳过 Codex",
|
|
334
332
|
"skip_no_grok": "该 Key 未开通 Grok 模型分组,已跳过 Grok Build",
|
|
335
|
-
"configured": "√ {{tool}} 配置完成(运行 `{{command}}` 即可使用)",
|
|
336
333
|
"apply_failed": "{{tool}} 配置写入失败: {{reason}}",
|
|
337
|
-
"install_hint": "
|
|
338
|
-
"done": "
|
|
334
|
+
"install_hint": "没检测到 {{tool}},运行 {{install}} 安装",
|
|
335
|
+
"done": "完成:已配置 {{count}} 个工具。",
|
|
339
336
|
"skip_desktop_not_installed": "未检测到已安装的 Claude Desktop,已跳过(装好后运行 vibecli setup --desktopkey sk-xxx 或在向导里配置)",
|
|
340
337
|
"desktop_official_login_missing_key": "未找到已保存的 Claude Desktop API Key;请先用 --key 或 --desktopkey 完成配置",
|
|
341
|
-
"claude_official_invalid": "--claude-official 的值无效: {{value}}(只接受 on / off)"
|
|
338
|
+
"claude_official_invalid": "--claude-official 的值无效: {{value}}(只接受 on / off)",
|
|
339
|
+
"done_commands": "在终端输入 {{commands}} 开始使用",
|
|
340
|
+
"failed_summary": "{{count}} 个工具没有配好,原因见上方"
|
|
342
341
|
},
|
|
343
342
|
"tools": {
|
|
344
|
-
"version_outdated": "
|
|
343
|
+
"version_outdated": "版本 {{current}} 过旧,需要 {{min}} 及以上,运行 {{upgrade}} 升级",
|
|
345
344
|
"codex": {
|
|
346
|
-
"catalog_written": "
|
|
347
|
-
"catalog_skipped": "
|
|
345
|
+
"catalog_written": "模型菜单 {{count}} 个({{breakdown}}),Codex 桌面版重开后生效",
|
|
346
|
+
"catalog_skipped": "没读到 Codex 自带的模型列表(未安装或版本低于 0.122),模型菜单只有 GPT;安装或升级 Codex 后再运行一次"
|
|
348
347
|
},
|
|
349
348
|
"claude_desktop": {
|
|
350
|
-
"restart_hint": "Claude
|
|
349
|
+
"restart_hint": "完全退出 Claude 桌面端再重新打开才会生效",
|
|
351
350
|
"managed_conflict": "检测到托管配置 {{path}},Claude Desktop 会优先使用它并忽略本地配置;请先移除该描述文件 / 策略再重启",
|
|
352
351
|
"registry_written": "已同步写入注册表 {{key}} 作为兜底(与官网下载的 .reg 等效);应用内「Configure Third-Party Inference」窗口会显示为托管状态,移除配置时会一并清理",
|
|
353
352
|
"models_written_gateway": "已写入 {{count}} 个模型(1M 标记依据网关分组表,匹配分组:{{groups}}):{{list}}",
|
|
354
353
|
"models_written_fallback": "已写入 {{count}} 个模型(网关分组表不可用或未匹配到分组,1M 标记按内置规则):{{list}}",
|
|
355
354
|
"models_written_slots": "已写入 {{count}} 个模型(离线:按当前 profile 的模型槽位,未拉取网关模型列表):{{list}}",
|
|
356
355
|
"official_login_hidden": "官方登录(Claude.ai 账号)入口已隐藏,桌面端只走网关;要恢复运行 vibecli setup --claude-official on",
|
|
357
|
-
"official_login_shown": "官方登录(Claude.ai 账号)入口保持可见,用户可在网关与官方账号间切换;要隐藏运行 vibecli setup --claude-official off"
|
|
356
|
+
"official_login_shown": "官方登录(Claude.ai 账号)入口保持可见,用户可在网关与官方账号间切换;要隐藏运行 vibecli setup --claude-official off",
|
|
357
|
+
"models_summary": "{{count}} 个 Claude 模型,默认 {{default}}",
|
|
358
|
+
"registry_denied": "没有管理员权限,跳过了注册表兜底(本地配置已写好,通常不影响);如果重开桌面端后没有走 VibeAPI,用管理员身份打开终端再运行一次"
|
|
358
359
|
},
|
|
359
360
|
"claude_code": {
|
|
360
|
-
"gateway_models": "
|
|
361
|
+
"gateway_models": "/model 菜单加入 {{count}} 个国产模型({{vendors}})",
|
|
361
362
|
"tier_fallback": "当前 Key 用不了 Claude Code 默认的 {{from}},{{tier}} 档已改用 {{to}}"
|
|
363
|
+
},
|
|
364
|
+
"model_family": {
|
|
365
|
+
"gpt": "GPT",
|
|
366
|
+
"claude": "Claude",
|
|
367
|
+
"other": "国产",
|
|
368
|
+
"grok": "Grok"
|
|
362
369
|
}
|
|
363
370
|
}
|
|
364
371
|
}
|
package/dist/models.json
CHANGED
|
@@ -2,8 +2,12 @@
|
|
|
2
2
|
"defaultModels": {
|
|
3
3
|
"haiku": "claude-haiku-4-5-20251001",
|
|
4
4
|
"sonnet": "claude-sonnet-5[1m]",
|
|
5
|
-
"opus": "claude-opus-
|
|
6
|
-
"reasoning": "claude-opus-
|
|
5
|
+
"opus": "claude-opus-5-5[1m]",
|
|
6
|
+
"reasoning": "claude-opus-5-5[1m]"
|
|
7
|
+
},
|
|
8
|
+
"retiredDefaultModels": {
|
|
9
|
+
"opus": ["claude-opus-4-8[1m]"],
|
|
10
|
+
"reasoning": ["claude-opus-4-8[1m]"]
|
|
7
11
|
},
|
|
8
12
|
"defaultToolModel": "gpt-5.5",
|
|
9
13
|
"toolDefaults": {
|
package/dist/utils/logger.d.ts
CHANGED
|
@@ -49,6 +49,8 @@ export declare class Logger {
|
|
|
49
49
|
setFileLogLevel(level: LogLevel): void;
|
|
50
50
|
setFileLoggingEnabled(enabled: boolean): void;
|
|
51
51
|
debug(message: string, ...args: any[]): void;
|
|
52
|
+
/** Log-file only (never the console): diagnostics users don't need to read. */
|
|
53
|
+
record(message: string): void;
|
|
52
54
|
info(message: string, ...args: any[]): void;
|
|
53
55
|
warn(message: string, ...args: any[]): void;
|
|
54
56
|
error(message: string, ...args: any[]): void;
|
package/dist/utils/logger.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as e,mkdirSync as t,appendFileSync as i,readdirSync as o,statSync as r,unlinkSync as s}from"fs";import{join as g}from"path";import{homedir as n}from"os";export var LogLevel;!function(e){e[e.DEBUG=0]="DEBUG",e[e.INFO=1]="INFO",e[e.WARN=2]="WARN",e[e.ERROR=3]="ERROR"}(LogLevel||(LogLevel={}));const l=["token","apikey","api_key","api-key","auth_token","auth-token","authorization","password","secret","credential","anthropic_auth_token","anthropic_api_key","z_ai_api_key"],a=[/eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,/\b[a-zA-Z0-9]{32,}\b/g,/Bearer\s+[A-Za-z0-9._-]+/gi];export class Logger{static instance;logLevel=LogLevel.INFO;fileLogLevel=LogLevel.WARN;logDir;fileLoggingEnabled=!0;retentionDays=14;constructor(){this.logDir=g(n(),".vibecli"),this.ensureLogDir(),this.rotateOldLogs()}static getInstance(){return Logger.instance||(Logger.instance=new Logger),Logger.instance}ensureLogDir(){try{e(this.logDir)||t(this.logDir,{recursive:!0})}catch{this.fileLoggingEnabled=!1}}getLogFilePath(){const e=(new Date).toISOString().split("T")[0];return g(this.logDir,`${e}.log`)}rotateOldLogs(){if(this.fileLoggingEnabled&&e(this.logDir))try{const e=Date.now()-24*this.retentionDays*60*60*1e3,t=o(this.logDir).filter(e=>/^\d{4}-\d{2}-\d{2}\.log$/.test(e));for(const i of t){const t=g(this.logDir,i);try{r(t).mtimeMs<e&&s(t)}catch{}}}catch{}}setRetentionDays(e){e>=0&&Number.isFinite(e)&&(this.retentionDays=Math.floor(e),this.rotateOldLogs())}sanitizeValue(e){if(null==e)return e;if("string"==typeof e){let t=e;for(const e of a)t=t.replace(e,"[REDACTED]");return t}if(Array.isArray(e))return e.map(e=>this.sanitizeValue(e));if("object"==typeof e){const t={};for(const[i,o]of Object.entries(e)){const e=i.toLowerCase(),r=l.some(t=>e.includes(t));t[i]=r?"[REDACTED]":this.sanitizeValue(o)}return t}return e}sanitize(e,t){return{message:this.sanitizeValue(e),args:t.map(e=>this.sanitizeValue(e))}}formatArgs(e){return 0===e.length?"":" "+e.map(e=>{if("object"==typeof e)try{return JSON.stringify(e)}catch{return String(e)}return String(e)}).join(" ")}writeToFile(e,t,o){if(this.fileLoggingEnabled)try{const{message:r,args:s}=this.sanitize(t,o),g=`${(new Date).toISOString()} [${e}] ${r}${this.formatArgs(s)}\n`;i(this.getLogFilePath(),g,"utf-8")}catch{}}setLogLevel(e){this.logLevel=e}setFileLogLevel(e){this.fileLogLevel=e}setFileLoggingEnabled(e){this.fileLoggingEnabled=e}debug(e,...t){this.logLevel<=LogLevel.DEBUG&&console.debug(`[DEBUG] ${e}`,...t),this.fileLoggingEnabled&&this.fileLogLevel<=LogLevel.DEBUG&&this.writeToFile("DEBUG",e,t)}info(e,...t){this.logLevel<=LogLevel.INFO&&console.info(`[INFO] ${e}`,...t),this.fileLoggingEnabled&&this.fileLogLevel<=LogLevel.INFO&&this.writeToFile("INFO",e,t)}warn(e,...t){this.logLevel<=LogLevel.WARN&&console.warn(`[WARN] ${e}`,...t),this.fileLoggingEnabled&&this.fileLogLevel<=LogLevel.WARN&&this.writeToFile("WARN",e,t)}error(e,...t){this.logLevel<=LogLevel.ERROR&&console.error(`[ERROR] ${e}`,...t),this.fileLoggingEnabled&&this.fileLogLevel<=LogLevel.ERROR&&this.writeToFile("ERROR",e,t)}logError(e,t){const i=t instanceof Error?t.message:String(t),o=t instanceof Error?t.stack:void 0;this.writeToFile("ERROR",`[${e}] ${i}`,o?[{stack:o}]:[])}getLogDir(){return this.logDir}}export const logger=Logger.getInstance();
|
|
1
|
+
import{existsSync as e,mkdirSync as t,appendFileSync as i,readdirSync as o,statSync as r,unlinkSync as s}from"fs";import{join as g}from"path";import{homedir as n}from"os";export var LogLevel;!function(e){e[e.DEBUG=0]="DEBUG",e[e.INFO=1]="INFO",e[e.WARN=2]="WARN",e[e.ERROR=3]="ERROR"}(LogLevel||(LogLevel={}));const l=["token","apikey","api_key","api-key","auth_token","auth-token","authorization","password","secret","credential","anthropic_auth_token","anthropic_api_key","z_ai_api_key"],a=[/eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,/\b[a-zA-Z0-9]{32,}\b/g,/Bearer\s+[A-Za-z0-9._-]+/gi];export class Logger{static instance;logLevel=LogLevel.INFO;fileLogLevel=LogLevel.WARN;logDir;fileLoggingEnabled=!0;retentionDays=14;constructor(){this.logDir=g(n(),".vibecli"),this.ensureLogDir(),this.rotateOldLogs()}static getInstance(){return Logger.instance||(Logger.instance=new Logger),Logger.instance}ensureLogDir(){try{e(this.logDir)||t(this.logDir,{recursive:!0})}catch{this.fileLoggingEnabled=!1}}getLogFilePath(){const e=(new Date).toISOString().split("T")[0];return g(this.logDir,`${e}.log`)}rotateOldLogs(){if(this.fileLoggingEnabled&&e(this.logDir))try{const e=Date.now()-24*this.retentionDays*60*60*1e3,t=o(this.logDir).filter(e=>/^\d{4}-\d{2}-\d{2}\.log$/.test(e));for(const i of t){const t=g(this.logDir,i);try{r(t).mtimeMs<e&&s(t)}catch{}}}catch{}}setRetentionDays(e){e>=0&&Number.isFinite(e)&&(this.retentionDays=Math.floor(e),this.rotateOldLogs())}sanitizeValue(e){if(null==e)return e;if("string"==typeof e){let t=e;for(const e of a)t=t.replace(e,"[REDACTED]");return t}if(Array.isArray(e))return e.map(e=>this.sanitizeValue(e));if("object"==typeof e){const t={};for(const[i,o]of Object.entries(e)){const e=i.toLowerCase(),r=l.some(t=>e.includes(t));t[i]=r?"[REDACTED]":this.sanitizeValue(o)}return t}return e}sanitize(e,t){return{message:this.sanitizeValue(e),args:t.map(e=>this.sanitizeValue(e))}}formatArgs(e){return 0===e.length?"":" "+e.map(e=>{if("object"==typeof e)try{return JSON.stringify(e)}catch{return String(e)}return String(e)}).join(" ")}writeToFile(e,t,o){if(this.fileLoggingEnabled)try{const{message:r,args:s}=this.sanitize(t,o),g=`${(new Date).toISOString()} [${e}] ${r}${this.formatArgs(s)}\n`;i(this.getLogFilePath(),g,"utf-8")}catch{}}setLogLevel(e){this.logLevel=e}setFileLogLevel(e){this.fileLogLevel=e}setFileLoggingEnabled(e){this.fileLoggingEnabled=e}debug(e,...t){this.logLevel<=LogLevel.DEBUG&&console.debug(`[DEBUG] ${e}`,...t),this.fileLoggingEnabled&&this.fileLogLevel<=LogLevel.DEBUG&&this.writeToFile("DEBUG",e,t)}record(e){this.fileLoggingEnabled&&this.writeToFile("INFO",e,[])}info(e,...t){this.logLevel<=LogLevel.INFO&&console.info(`[INFO] ${e}`,...t),this.fileLoggingEnabled&&this.fileLogLevel<=LogLevel.INFO&&this.writeToFile("INFO",e,t)}warn(e,...t){this.logLevel<=LogLevel.WARN&&console.warn(`[WARN] ${e}`,...t),this.fileLoggingEnabled&&this.fileLogLevel<=LogLevel.WARN&&this.writeToFile("WARN",e,t)}error(e,...t){this.logLevel<=LogLevel.ERROR&&console.error(`[ERROR] ${e}`,...t),this.fileLoggingEnabled&&this.fileLogLevel<=LogLevel.ERROR&&this.writeToFile("ERROR",e,t)}logError(e,t){const i=t instanceof Error?t.message:String(t),o=t instanceof Error?t.stack:void 0;this.writeToFile("ERROR",`[${e}] ${i}`,o?[{stack:o}]:[])}getLogDir(){return this.logDir}}export const logger=Logger.getInstance();
|
package/models.json
CHANGED
|
@@ -2,8 +2,12 @@
|
|
|
2
2
|
"defaultModels": {
|
|
3
3
|
"haiku": "claude-haiku-4-5-20251001",
|
|
4
4
|
"sonnet": "claude-sonnet-5[1m]",
|
|
5
|
-
"opus": "claude-opus-
|
|
6
|
-
"reasoning": "claude-opus-
|
|
5
|
+
"opus": "claude-opus-5-5[1m]",
|
|
6
|
+
"reasoning": "claude-opus-5-5[1m]"
|
|
7
|
+
},
|
|
8
|
+
"retiredDefaultModels": {
|
|
9
|
+
"opus": ["claude-opus-4-8[1m]"],
|
|
10
|
+
"reasoning": ["claude-opus-4-8[1m]"]
|
|
7
11
|
},
|
|
8
12
|
"defaultToolModel": "gpt-5.5",
|
|
9
13
|
"toolDefaults": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeapi/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.55",
|
|
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",
|