@vibeapi/api-helper 0.0.115 → 0.0.118
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/setup.js +1 -1
- package/dist/lib/tool-manager.d.ts +7 -0
- package/dist/lib/tool-manager.js +1 -1
- package/dist/lib/tool-upgrade.d.ts +18 -4
- package/dist/lib/tool-upgrade.js +1 -1
- package/dist/lib/tools/codex.js +1 -1
- package/dist/lib/tools/grok.js +1 -1
- package/dist/lib/windows-env.d.ts +5 -0
- package/dist/lib/windows-env.js +1 -1
- package/dist/locales/en_US.json +4 -1
- package/dist/locales/zh_CN.json +4 -1
- package/package.json +1 -1
package/dist/commands/setup.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import o from"chalk";import{getAdapter as e}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{ensureReachableGatewayAddress as i}from"./base.js";import{i18n as s}from"../lib/i18n.js";import{configManager as l}from"../lib/config.js";import{toolManager as a,SUPPORTED_TOOLS as n}from"../lib/tool-manager.js";import{validateApiKey as r,fetchModels as p}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as d,setCodexOneMillionContext as c}from"../lib/tools/codex.js";import{resolveModelCatalog as u}from"../lib/model-catalog.js";import{CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING as m,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as f}from"../lib/tools/claude-desktop.js";import{operationError as g,authenticationError as y,networkError as k,EXIT_CODES as _}from"../lib/errors.js";import{isJsonMode as h,isNonInteractive as b,shouldAutoConfirm as w}from"../lib/runtime-options.js";import v from"inquirer";import{logger as x}from"../utils/logger.js";import{forgetInstalls as C}from"../lib/tools/tool-installs.js";import{CLI_NAME as j,brandEnv as K}from"../lib/brand.js";export const DEDICATED_KEYS=[{option:"claudekey",tool:"claude-code",need:"claude"},{option:"codexkey",tool:"codex",need:"gpt"},{option:"grokkey",tool:"grok",need:"grok"},{option:"desktopkey",tool:"claude-desktop",need:"claude"},{option:"agykey",tool:"agy",need:"gemini"},{option:"openclawkey",tool:"openclaw",need:"any",hidden:!0},{option:"hermeskey",tool:"hermes",need:"any",hidden:!0},{option:"atomcodekey",tool:"atomcode",need:"any",hidden:!0}];async function T(o){const e=await p(o);if(!e.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,hasGemini:!0,probed:!1};const t=e.models.map(o=>o.toLowerCase());return{hasClaude:t.some(o=>o.includes("claude")),hasGpt:t.some(o=>o.startsWith("gpt")||o.includes("gpt-")||/^o\d/.test(o)),hasGrok:t.some(o=>o.includes("grok")),hasGemini:t.some(o=>o.startsWith("gemini")),probed:!0}}function $(o,e){switch(e){case"claude":return o.hasClaude;case"gpt":return o.hasGpt;case"grok":return o.hasGrok;case"gemini":return o.hasGemini;default:return!0}}export function parseOnOff(o){const e=(o??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(e)||!["off","false","hide","0","no","n"].includes(e)&&void 0}function G(e){console.log(o.green(e))}function
|
|
1
|
+
import o from"chalk";import{getAdapter as e}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{ensureReachableGatewayAddress as i}from"./base.js";import{i18n as s}from"../lib/i18n.js";import{configManager as l}from"../lib/config.js";import{toolManager as a,SUPPORTED_TOOLS as n}from"../lib/tool-manager.js";import{validateApiKey as r,fetchModels as p}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as d,setCodexOneMillionContext as c}from"../lib/tools/codex.js";import{resolveModelCatalog as u}from"../lib/model-catalog.js";import{CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING as m,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as f}from"../lib/tools/claude-desktop.js";import{operationError as g,authenticationError as y,networkError as k,EXIT_CODES as _}from"../lib/errors.js";import{isJsonMode as h,isNonInteractive as b,shouldAutoConfirm as w}from"../lib/runtime-options.js";import v from"inquirer";import{logger as x}from"../utils/logger.js";import{forgetInstalls as C}from"../lib/tools/tool-installs.js";import{CLI_NAME as j,brandEnv as K}from"../lib/brand.js";export const DEDICATED_KEYS=[{option:"claudekey",tool:"claude-code",need:"claude"},{option:"codexkey",tool:"codex",need:"gpt"},{option:"grokkey",tool:"grok",need:"grok"},{option:"desktopkey",tool:"claude-desktop",need:"claude"},{option:"agykey",tool:"agy",need:"gemini"},{option:"openclawkey",tool:"openclaw",need:"any",hidden:!0},{option:"hermeskey",tool:"hermes",need:"any",hidden:!0},{option:"atomcodekey",tool:"atomcode",need:"any",hidden:!0}];async function T(o){const e=await p(o);if(!e.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,hasGemini:!0,probed:!1};const t=e.models.map(o=>o.toLowerCase());return{hasClaude:t.some(o=>o.includes("claude")),hasGpt:t.some(o=>o.startsWith("gpt")||o.includes("gpt-")||/^o\d/.test(o)),hasGrok:t.some(o=>o.includes("grok")),hasGemini:t.some(o=>o.startsWith("gemini")),probed:!0}}function $(o,e){switch(e){case"claude":return o.hasClaude;case"gpt":return o.hasGpt;case"grok":return o.hasGrok;case"gemini":return o.hasGemini;default:return!0}}export function parseOnOff(o){const e=(o??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(e)||!["off","false","hide","0","no","n"].includes(e)&&void 0}function G(e){console.log(o.green(e))}function N(e){console.log(o.yellow(e))}function M(e){console.error(o.red(e))}let S=null;function E(o){const e={operation:1,authentication:2,network:3};(!S||e[o]>e[S])&&(S=o)}async function O(e,t){h()||console.log(o.gray(s.t("setup.validating",{label:e})));const i=await r(t);if(i.valid)return!0;const a="zh_CN"===s.getLocale()?"<你的 Key>":"<your key>",n="--key"===e?`${j} setup --key ${a}`:`${j} setup ${e} ${a}`;let p;if("network_error"===i.error?(E("network"),p=k(s.t("setup.unreachable",{url:l.getBaseUrl(),reason:i.message||"network error"}),`${j} base auto`,"network_error")):"invalid_api_key"===i.error?(E("authentication"),p=y(s.t("setup.invalid_key",{label:e,reason:i.message||"invalid"}),n,"invalid_api_key")):(E("operation"),p=g(s.t("setup.invalid_key",{label:e,reason:i.message||i.error||"unknown"}),n,i.error)),h())throw p;return M(p.message),console.log(o.gray(s.t("errors.next_step",{command:p.hint}))),!1}async function A(t,i,r={}){const{oneMillion:p,officialLogin:c,desktopRegistry:u,force:y}=r,k=n[t];try{"claude-desktop"===t&&void 0!==u&&l.setToolSetting("claude-desktop",m,u),"codex"===t&&void 0!==p&&l.setToolSetting("codex",d,p),"claude-desktop"===t&&void 0!==c&&l.setToolSetting("claude-desktop",f,!c),await a.applyPrivateConfig(t,i,l.getModelsForTool(t),{force:y})}catch(o){if(h())throw g(o instanceof Error?o.message:String(o),`${j} setup --key ${"zh_CN"===s.getLocale()?"<你的 Key>":"<your key>"}`,"config_write_failed");const e=(o instanceof Error?o.message:String(o)).replace(/\s+/g," ").trim();return M("× "+s.t("setup.apply_failed",{tool:k.displayName,reason:e})),!1}return a.printApplied(t),y&&console.log(o.gray(" "+s.t("config.force_done",{tool:k.displayName}))),"codex"===t&&void 0!==p&&console.log(o.gray(" "+s.t(p?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),e(t)?.isInstalled&&!a.isToolInstalled(t)&&console.log(o.yellow(" ! "+s.t("setup.gui_preconfigured",{tool:k.displayName,install:k.installCommand}))),!0}export async function setupCommand(r){S=null;const p=r.key?.trim(),m=DEDICATED_KEYS.map(o=>({...o,apiKey:r[o.option]?.trim()})).filter(o=>Boolean(o.apiKey)),f=void 0!==r.oneMillion,g=void 0!==r.claudeOfficial;let y;if(g&&(y=parseOnOff(r.claudeOfficial),void 0===y))return M(s.t("setup.claude_official_invalid",{value:String(r.claudeOfficial)})),void(process.exitCode=1);const k=void 0!==r.desktopRegistry;let E;if(k&&(E=parseOnOff(r.desktopRegistry),void 0===E))return M(s.t("setup.desktop_registry_invalid",{value:String(r.desktopRegistry)})),void(process.exitCode=1);const I=g||k,L=Boolean(p||m.length>0),D={oneMillion:r.oneMillion,officialLogin:y,desktopRegistry:E,force:r.force};if(!L&&(f||I)){if(f){const o=l.getApiKeyForTool("codex");if(o)try{const e=!0===r.oneMillion;l.setToolSetting("codex",d,e);const t=await u(o);c(e,t??void 0),G(s.t(e?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(o){M(s.t("setup.apply_failed",{tool:n.codex.displayName,reason:o instanceof Error?o.message:String(o)})),process.exitCode=1}else M(s.t("setup.codex_1m_missing_key")),process.exitCode=1}if(I){const o=l.getApiKeyForTool("claude-desktop");o?await A("claude-desktop",o,{...D,oneMillion:void 0})?await t(["claude-desktop"]):process.exitCode=1:(M(s.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!L)return M(s.t("setup.usage")),void(process.exitCode=1);await i(p||m[0].apiKey);let R=0,B=0;const F=new Set,P=m.map(o=>({tool:o.tool,label:`--${o.option}`,apiKey:o.apiKey,need:o.need}));for(const o of P){if(!await O(o.label,o.apiKey)){B+=1;continue}const e=await T(o.apiKey);!e.probed||$(e,o.need)?(e.probed||N(s.t("setup.probe_failed",{label:o.label})),l.setToolApiKey(o.tool,o.apiKey),await A(o.tool,o.apiKey,D)?(R+=1,F.add(o.tool)):B+=1):(M(s.t(`setup.key_no_${o.need}`,{label:o.label,tool:n[o.tool].displayName})),B+=1)}if(p){if(!await O("--key",p))return void(process.exitCode=_[S??"operation"]);l.setApiKey(p);const o=await T(p);if(o.probed||N(s.t("setup.probe_failed",{label:"--key"})),o.probed&&!o.hasClaude&&!o.hasGpt&&!o.hasGrok&&!o.hasGemini)return M(s.t("setup.key_no_family")),void(process.exitCode=1);const e=[{tool:"claude-code",capable:o.hasClaude,skipMsg:s.t("setup.skip_no_claude")},{tool:"codex",capable:o.hasGpt,skipMsg:s.t("setup.skip_no_gpt")},{tool:"grok",capable:o.hasGrok,skipMsg:s.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:o.hasClaude&&("darwin"===process.platform||"win32"===process.platform),skipMsg:"",quiet:!0},{tool:"agy",capable:o.hasGemini,skipMsg:s.t("setup.skip_no_gemini")}];for(const o of e)F.has(o.tool)||(o.capable?await A(o.tool,p,D)?(R+=1,F.add(o.tool)):B+=1:o.quiet||N(o.skipMsg))}if(R>0){const t=await async function(t,i,r){const p=t.filter(o=>!e(o)?.isInstalled&&!a.isToolInstalled(o));if(0===p.length)return[];const d=p.map(o=>n[o].displayName).join(s.t("setup.list_separator"));let c=i;if(void 0!==c||h()||(w()?c=!b():process.stdin.isTTY&&(console.log(""),c=(await v.prompt([{type:"confirm",name:"go",message:s.t("setup.install_confirm",{tools:d}),default:!0}])).go)),!c){console.log("");for(const e of p)console.log(o.yellow("! "+s.t("setup.install_hint",{tool:n[e].displayName,install:n[e].installCommand})));return h()||console.log(o.gray(s.t("setup.install_all_hint",{cli:j}))),p}const u=[];for(const e of p){console.log(o.bold(`\n${n[e].displayName}`));try{await a.installTool(e)}catch(o){x.logError(`setup: install ${e}`,o)}C(),a.isToolInstalled(e)||u.push(e)}const m=p.filter(o=>!u.includes(o));m.length>0&&console.log("");for(const o of m){const e=l.getApiKeyForTool(o);e&&await A(o,e,{...r,oneMillion:void 0,force:void 0})}return u}([...F],r.install,D),i=[...F].filter(o=>!e(o)?.isInstalled&&!t.includes(o)),p=i.map(o=>n[o]?.command).filter(Boolean).join(" / "),d=s.t("setup.done",{count:String(R)});G("\n"+(p?`${d}${s.t("setup.done_commands",{commands:p})}`:d)),t.length>0&&N(s.t("setup.still_missing",{tools:t.map(o=>n[o].displayName).join(s.t("setup.list_separator"))}));for(const o of i){const e=a.ensureNativeOnPath(o);e&&G(s.t("setup.path_added",{tool:n[o].displayName,dir:e}))}const c=i.filter(o=>!a.isOnPath(o));if(c.length>0&&!h()&&"1"!==K("PATH_HINT_BY_CALLER")){const e=c.map(o=>n[o].command).join(" / ");console.log(o.yellow(" ! "+s.t("win32"===process.platform?"setup.path_reload_windows":"setup.path_reload",{commands:e})))}}B>0&&(M(s.t("setup.failed_summary",{count:String(B)})),h()||console.error(`${j} setup --key ${"zh_CN"===s.getLocale()?"<你的 Key>":"<your key>"}`)),await t([...F]),(B>0||0===R)&&(process.exitCode=_[S??"operation"])}
|
|
@@ -40,6 +40,13 @@ export declare class ToolManager {
|
|
|
40
40
|
* `curl | sh` installers can only add the directory to PATH for new terminals.
|
|
41
41
|
*/
|
|
42
42
|
nativeLauncher(toolName: string): string | null;
|
|
43
|
+
/**
|
|
44
|
+
* Windows: a native install found by `nativeLauncher` whose directory isn't on PATH (Claude Code's own
|
|
45
|
+
* installer leaves that to the user) counts as installed but `claude` doesn't run. Put the directory on
|
|
46
|
+
* the user PATH so new terminals, and the one-command bootstrap after it refreshes PATH, find it.
|
|
47
|
+
* Returns the directory when it was added.
|
|
48
|
+
*/
|
|
49
|
+
ensureNativeOnPath(toolName: string): string | null;
|
|
43
50
|
installTool(toolName: string): Promise<void>;
|
|
44
51
|
private installToolNow;
|
|
45
52
|
getToolConfig(toolName: string): any;
|
package/dist/lib/tool-manager.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import e from"inquirer";import r from"chalk";import{logger as
|
|
1
|
+
import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import e from"inquirer";import r from"chalk";import{logger as i}from"../utils/logger.js";import{configManager as l}from"./config.js";import{getAdapter as s,listAdapters as a,TOOL_ADAPTERS as c}from"./tools/registry.js";import{backupBeforeWrite as d,listBackups as p,restoreBackup as u}from"./tools/backup.js";import{existsSync as m,rmSync as f}from"fs";import{dirname as g,join as h}from"path";import{toolHome as w}from"./tools/types.js";import{stringWidth as y}from"../utils/string-width.js";import{resolveModelCatalog as P}from"./model-catalog.js";import{compareVersions as $,getToolMinVersion as T}from"./model-registry.js";import{findInstalls as v,forgetInstalls as k,installLabel as C,mirrorInstallCommand as E,npmMirrorInstallCommand as _}from"./tools/tool-installs.js";import{mirrorInstall as O}from"./tool-upgrade.js";import{CLI_NAME as S}from"./brand.js";import{track as N,trackStep as M}from"./telemetry.js";import{addUserPathDir as j,broadcastEnvChange as U}from"./windows-env.js";export{$ as compareVersions};function b(o){const t=c[o];return{name:t.name,command:t.command,installCommand:t.installCommand,configPath:t.configPath,displayName:t.displayName,...t.hidden?{hidden:!0}:{},...t.isInstalled?{gui:!0}:{}}}function x(){const o=new Set;for(const t of l.listProfiles()){const n=l.getProfile(t);for(const t of[n.api_key,...Object.values(n.tool_api_keys??{})])t?.trim()&&o.add(t.trim())}return[...o]}export const SUPPORTED_TOOLS=Object.fromEntries(Object.keys(c).map(o=>[o,b(o)]));export class ToolManager{static instance;constructor(){}static getInstance(){return ToolManager.instance||(ToolManager.instance=new ToolManager),ToolManager.instance}isToolInstalled(o){if(!SUPPORTED_TOOLS[o])return!1;const t=s(o);if(t?.isInstalled)try{return t.isInstalled()}catch{return!1}return this.isOnPath(o)||null!==this.nativeLauncher(o)}isOnPath(t){const n=SUPPORTED_TOOLS[t];if(!n)return!1;try{const t="win32"===process.platform?`where ${n.command}`:`which ${n.command}`;return o(t,{stdio:"pipe"}),!0}catch{return!1}}nativeLauncher(o){const t=s(o),n=t?.installSpec?.native?.binDir;if(!t||!n)return null;const e="win32"===process.platform?`${t.command}.exe`:t.command,r=h(w(),...n,e);return m(r)?r:null}ensureNativeOnPath(o){if("win32"!==process.platform||this.isOnPath(o))return null;const t=this.nativeLauncher(o);if(!t)return null;const n=g(t);try{if(!j(n))return null}catch(t){return i.logError(`ensureNativeOnPath: ${o}`,t),null}return U(),process.env.Path=`${process.env.Path??""};${n}`,n}async installTool(o){return M(`install:${o}`,()=>this.installToolNow(o))}async installToolNow(t){const i=SUPPORTED_TOOLS[t];if(!i)throw new Error(`Unknown tool: ${t}`);const l=s(t)?.installSpec;if(l&&(l.mirrorScript||l.npmPackage)){const o=E(l);if(await O(l)&&(k(),this.isToolInstalled(t)))return void console.log(r.green("√ "+n.t("wizard.tool_installed")));throw console.log(r.red("× "+n.t("wizard.install_failed"))),console.log(r.yellow(" ! "+n.t("install.manual_command",{tool:i.displayName,command:o}))),l.mirrorScript&&l.npmPackage&&console.log(r.yellow(" ! "+n.t("install.manual_npm",{command:_(l)}))),new Error(`Failed to install ${i.displayName}`)}const a=i.installCommand;console.log(r.gray("$ ")+r.white(a));try{return o(a,{stdio:"inherit"}),k(),void console.log(r.green("√ "+n.t("wizard.tool_installed")))}catch(o){if(console.log(r.red("× "+n.t("wizard.install_failed"))),!/EACCES|EPERM|permission denied/i.test(`${o?.message??""}${o?.stderr??""}`)&&243!==o?.status&&!a.startsWith("npm "))throw new Error(`Failed to install ${i.displayName}: ${o}`);console.log(r.yellow(" ! "+("win32"===process.platform?n.t("install.permission_windows",{command:a}):n.t("install.permission_unix",{command:a}))))}const{action:c}=await e.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===c)throw new Error(n.t("install.user_cancelled"));if(k(),!this.isToolInstalled(t))throw console.log(r.red("× "+n.t("install.still_not_installed",{tool:i.displayName}))),new Error(`${i.displayName} is not installed`);console.log(r.green("√ "+n.t("install.verified_success",{tool:i.displayName})))}getToolConfig(o){const t=s(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{return t.getConfig()}catch(t){return i.warn(`Failed to read config for ${o}:`,t),i.logError(`ToolManager.getToolConfig(${o})`,t),null}}updateToolConfig(o,t){const n=s(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=s(o);if(!t)throw new Error(`Unknown tool: ${o}`);const n=t.forceResetPaths?t.forceResetPaths():this.backupPathsFor(t),e=[];for(const o of n)m(o)&&(d(o),f(o,{force:!0}),e.push(o));return e}loadPrivateConfig(o,t,n,e,r={}){const i=s(o);if(!i)throw new Error(`Unknown tool: ${o}`);r.force&&this.forceResetConfig(o),i.loadPrivateConfig({apiKey:t,baseUrl:l.getBaseUrl(),models:n,settings:l.getToolSettings(o),...e?{catalog:e}:{}})}async applyPrivateConfig(o,t,n,e={}){const r=this.installedVersion(o);return M(`apply:${o}`,()=>this.applyPrivateConfigNow(o,t,n,e),{...r?{tool_version:r}:{},...e.force?{force:!0}:{}})}async applyPrivateConfigNow(o,t,n,e){const r=s(o);if(!r)throw new Error(`Unknown tool: ${o}`);const i=r.wantsModelCatalog?await P(t):null;e.force?this.loadPrivateConfig(o,t,n,i??void 0,{force:!0}):i?this.loadPrivateConfig(o,t,n,i):this.loadPrivateConfig(o,t,n)}applyNotes(o){const t=s(o);if(!t)return[];const e=[];try{t.applyNotes&&e.push(...t.applyNotes())}catch(t){i.logError(`ToolManager.applyNotes(${o})`,t)}const r=this.outdatedVersion(o);if(r){e.push({kind:"action",text:n.t("tools.version_outdated",{current:r.current,min:r.min,upgrade:t.installSpec?`${S} upgrade ${o}`:t.upgradeCommand||t.installCommand})});for(const o of t.upgradeHints?.(r.min)??[])e.push({kind:"action",text:o})}const l=t.installSpec?v(t.installSpec):[];return l.length>1&&e.push({kind:"action",text:n.t("upgrade.duplicates_note",{count:String(l.length),active:C(l[0]),others:l.slice(1).map(C).join("、"),tool:o})}),e}printApplied(o,t=16){const n=SUPPORTED_TOOLS[o]?.displayName??o,e=this.applyNotes(o);for(const o of e.filter(o=>"detail"===o.kind))i.record(`${n}: ${o.text}`);const l=e.filter(o=>"summary"===o.kind).map(o=>o.text).join(";"),s=" ".repeat(Math.max(1,t-y(n)));console.log(r.green("√ "+n)+(l?s+l:""));for(const o of e.filter(o=>"action"===o.kind))console.log(r.yellow(" ! "+o.text))}installedVersion(o){const n=s(o);if(!n)return null;if(n.installSpec)return v(n.installSpec)[0]?.version??null;if(n.installedVersion)try{return n.installedVersion()}catch(t){return i.logError(`ToolManager.installedVersion(${o})`,t),null}if(n.isInstalled)return null;try{const o={encoding:"utf-8",timeout:1e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},e=`${("win32"===process.platform?t(`${n.command} --version`,{...o,shell:!0}):t(n.command,["--version"],o)).stdout??""}`.match(/(\d+)\.(\d+)\.(\d+)/);return e?e[0]:null}catch{return null}}outdatedVersion(o){const t=T(o);if(!t)return null;const n=this.installedVersion(o);return n&&$(n,t)<0?{current:n,min:t}:null}unloadPrivateConfig(o){const t=s(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{t.unloadPrivateConfig({savedKeys:x()}),N(`remove:${o}`,"ok")}catch(t){throw N(`remove:${o}`,"fail",{error:t}),t}let e=[];try{e=t.unloadNotes?.()??[]}catch(t){i.logError(`ToolManager.unloadNotes(${o})`,t)}return e.length>0?e:[{kind:"action",text:n.t("config.reopen_hint",{tool:t.displayName})}]}async clearPinnedModels(o){const t=s(o);if(!t)throw new Error(`Unknown tool: ${o}`);if(l.setToolModel(o,null),!t.clearPinnedModels)return[];const n=l.getApiKeyForTool(o),e=t.wantsModelCatalog&&n?await P(n):null;return t.clearPinnedModels(e??void 0)}supportsClearPinnedModels(o){return Boolean(s(o)?.clearPinnedModels)}detectCurrentConfig(o){const t=s(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=s(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,backups:p(o)}))}restorePrivateConfig(o){const t=s(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,result:u(o)}))}getInstalledTools(){return Object.keys(SUPPORTED_TOOLS).filter(o=>this.isToolInstalled(o))}getSupportedTools(){return a().filter(o=>!o.hidden).map(o=>b(o.name))}isGitInstalled(){try{const t="win32"===process.platform?"where git":"which git";return o(t,{stdio:"pipe"}),!0}catch{return!1}}}export const toolManager=ToolManager.getInstance();
|
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
import { type ToolInstallSpec } from './tools/tool-installs.js';
|
|
2
|
+
/** How the last runCommand ended (for the support events and the fallback message). */
|
|
3
|
+
export type RunOutcome = 'ok' | 'fail' | 'timeout' | 'stalled';
|
|
4
|
+
export interface RunLimits {
|
|
5
|
+
/** Stop after this long in total. */
|
|
6
|
+
timeoutMs?: number;
|
|
7
|
+
/** Stop once the command has printed nothing for this long (download progress counts as output). */
|
|
8
|
+
idleMs?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Runs a command with its output passed through to the terminal, stopping it once it goes quiet
|
|
12
|
+
* for `idleMs`: a slow network keeps printing download progress and gets all the time it needs,
|
|
13
|
+
* one that can't connect prints nothing.
|
|
14
|
+
*/
|
|
15
|
+
export declare function runWatched(command: string, args: string[], limits: RunLimits): Promise<RunOutcome>;
|
|
2
16
|
/** Tests replace the process runner. */
|
|
3
|
-
export declare function setUpgradeRunnerForTests(fake: (command: string, args: string[],
|
|
17
|
+
export declare function setUpgradeRunnerForTests(fake: (command: string, args: string[], limits?: RunLimits) => boolean | RunOutcome | Promise<boolean | RunOutcome>): void;
|
|
4
18
|
/**
|
|
5
19
|
* Fresh install / last-resort fallback: our install script when the tool has one, else npm
|
|
6
|
-
* from npmmirror. A script that fails or
|
|
7
|
-
*
|
|
20
|
+
* from npmmirror. A script that fails or stalls falls back to npm when the tool is on npm
|
|
21
|
+
* (it reaches npmmirror through npm's own proxy settings, which often work where
|
|
8
22
|
* PowerShell / curl don't).
|
|
9
23
|
*/
|
|
10
|
-
export declare function mirrorInstall(spec: ToolInstallSpec): boolean
|
|
24
|
+
export declare function mirrorInstall(spec: ToolInstallSpec): Promise<boolean>;
|
|
11
25
|
/**
|
|
12
26
|
* `vibecli upgrade <tool>`: upgrade the copy PATH runs the way it was installed
|
|
13
27
|
* (vendor updater / npm via npmmirror / Homebrew). When the vendor updater
|
package/dist/lib/tool-upgrade.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{spawnSync as
|
|
1
|
+
import{spawn as t,spawnSync as e}from"child_process";import{rmSync as o}from"fs";import{join as r}from"path";import n from"chalk";import i from"inquirer";import{i18n as a}from"./i18n.js";import{logger as s}from"../utils/logger.js";import{compareVersions as l,getToolMinVersion as c}from"./model-registry.js";import{getAdapter as p}from"./tools/registry.js";import{findInstalls as u,forgetInstalls as m,installLabel as d,npmMirrorInstallCommand as g,npmUninstallCommand as f}from"./tools/tool-installs.js";import{toolHome as w}from"./tools/types.js";import{isNonInteractive as y,shouldAutoConfirm as h}from"./runtime-options.js";import{track as _}from"./telemetry.js";let v="ok",k=async(t,o,r={})=>(console.log(n.gray("$ ")+[t,...o].join(" ")),v=r.idleMs?await runWatched(t,o,r):function(t,o,r){const n=b(t)?e($(t,o),{stdio:"inherit",shell:!0,timeout:r}):e(t,o,{stdio:"inherit",timeout:r});return n.error&&s.logError(`upgrade: ${t}`,n.error),"ETIMEDOUT"===n.error?.code?"timeout":0===n.status?"ok":"fail"}(t,o,r.timeoutMs),"ok"===v);const b=t=>"win32"===process.platform&&!/\.exe$/i.test(t),$=(t,e)=>[t,...e].map(t=>/\s/.test(t)?`"${t}"`:t).join(" ");export function runWatched(e,o,r){return new Promise(n=>{const i=b(e)?t($(e,o),{stdio:["inherit","pipe","pipe"],shell:!0}):t(e,o,{stdio:["inherit","pipe","pipe"]});let a;const l=t=>{a=t,i.kill()};let c;const p=()=>{clearTimeout(c),r.idleMs&&(c=setTimeout(()=>l("stalled"),r.idleMs))},u=r.timeoutMs?setTimeout(()=>l("timeout"),r.timeoutMs):void 0;p(),i.stdout?.on("data",t=>{process.stdout.write(t),p()}),i.stderr?.on("data",t=>{process.stderr.write(t),p()});const m=t=>{clearTimeout(c),clearTimeout(u),n(t)};i.on("error",t=>{s.logError(`upgrade: ${e}`,t),m(a??"fail")}),i.on("close",t=>{a&&process.stdout.write("\n"),m(a??(0===t?"ok":"fail"))})})}export function setUpgradeRunnerForTests(t){k=async(e,o,r)=>{const n=await t(e,o,r);return v="string"==typeof n?n:n?"ok":"fail","ok"===v}}const T={ok:"install.script_failed_npm",fail:"install.script_failed_npm",stalled:"install.script_stalled_npm",timeout:"install.script_timeout_npm"};export async function mirrorInstall(t){if(!t.mirrorScript)return j(t);console.log(n.gray(a.t("install.downloading")));const e=`install-script:${t.command}`,o=Date.now();_(e,"start");const r={idleMs:18e4,timeoutMs:36e5},i="win32"===process.platform?await k("powershell.exe",["-NoProfile","-ExecutionPolicy","Bypass","-Command",`irm ${t.mirrorScript.ps1} -TimeoutSec 30 | iex`],r):await k("sh",["-c",`script=$(curl -fsSL --connect-timeout 15 --max-time 60 ${t.mirrorScript.sh}) && printf '%s\\n' "$script" | sh`],r),s=v;return _(e,"stalled"===s?"timeout":s,{duration_ms:Date.now()-o,..."stalled"===s||"timeout"===s?{detail:{reason:s}}:{}}),i||!t.npmPackage?i:(console.log(n.yellow(" ! "+a.t(T[s],{minutes:String(3)}))),_(e,"fallback"),j(t))}async function j(t){const[e,...o]=g(t).split(" "),r=`install-npm:${t.command}`,i=Date.now();_(r,"start");const s=await k(e,o);return _(r,s?"ok":"fail",{duration_ms:Date.now()-i}),s||"win32"===process.platform||console.log(n.yellow(" ! "+a.t("upgrade.npm_permission",{command:g(t)}))),s}async function M(t,e){switch(e.kind){case"npm":t.npmPackage&&await k("npm",["uninstall","-g",t.npmPackage]);break;case"brew":t.brew&&await k("brew",["uninstall",t.brew]);break;case"native":try{o(e.path,{force:!0});for(const e of t.native?.dataDirs??[])o(r(w(),...e),{recursive:!0,force:!0})}catch(t){s.logError("upgrade: remove native copy",t)}break;default:return!1}return m(),!u(t).some(t=>t.path===e.path)}function D(t,e){switch(e.kind){case"npm":return f(t);case"brew":return`brew uninstall ${t.brew}`;case"native":return a.t("upgrade.delete_paths",{paths:[e.path,...(t.native?.dataDirs??[]).map(t=>r(w(),...t))].join("、")});default:return a.t("upgrade.delete_paths",{paths:e.path})}}export async function upgradeTool(t){const e=Date.now();_(`upgrade:${t}`,"start");try{const o=await async function(t){const e=p(t),o=e?.installSpec;if(!e||!o)throw new Error(a.t("upgrade.unsupported",{tool:t}));const r=e.displayName;m();const g=u(o);if(console.log(n.bold(`\n${r}`)),0===g.length)console.log(a.t("upgrade.not_installed_installing",{tool:r})),await mirrorInstall(o);else{const t=g[0];console.log(n.gray(" "+a.t("upgrade.current",{copy:d(t)})));const e=await async function(t,e){switch(e.kind){case"native":return k(e.path,t.native?.updateArgs??["update"],{timeoutMs:t.native?.updateTimeoutMs});case"npm":return j(t);case"brew":return!!t.brew&&k("brew",["upgrade",t.brew]);default:return!1}}(o,t);e||"other"!==t.kind?e||"npm"===t.kind||"native"===t.kind&&await async function(t){const e=t.native?.mirrorUpdate;if(!e)return!1;console.log(n.yellow(" ! "+a.t("upgrade.native_mirror_trying")));try{const{version:t,manifestVerified:o}=await e();return console.log(n.green(" √ "+a.t(o?"upgrade.native_mirror_done_verified":"upgrade.native_mirror_done",{version:t}))),!0}catch(t){return s.logError("upgrade: native mirror",t),console.log(n.yellow(" ! "+a.t("upgrade.native_mirror_failed",{reason:t instanceof Error?t.message:String(t)}))),!1}}(o)||(console.log(n.yellow(" ! "+a.t("upgrade.fallback_mirror"))),await mirrorInstall(o)):console.log(n.yellow(" ! "+a.t("upgrade.unknown_install",{path:t.path})))}m(),await async function(t,e){const o=u(t);if(o.length<2)return;const r=function(t){return t.reduce((t,e)=>e.version&&(!t.version||l(e.version,t.version)>0)?e:t)}(o),s=o.filter(t=>t!==r);console.log(n.yellow(" ! "+a.t("upgrade.duplicates",{tool:e,keep:d(r),others:s.map(d).join("、")})));let c=h();c||y()||!process.stdin.isTTY||(c=(await i.prompt([{type:"confirm",name:"remove",message:a.t("upgrade.confirm_remove"),default:!0}])).remove);for(const e of s)c&&await M(t,e)?console.log(n.green(" √ "+a.t("upgrade.removed",{copy:d(e)}))):console.log(n.yellow(" ! "+a.t("upgrade.remove_by_hand",{how:D(t,e)})))}(o,r),m();const f=u(o)[0];if(!f)return console.log(n.red(" × "+a.t("upgrade.still_missing",{tool:r}))),!1;const w=c(t);if(w&&f.version&&l(f.version,w)<0){console.log(n.yellow(" ! "+a.t("upgrade.still_old",{copy:d(f),min:w})));for(const t of e.upgradeHints?.(w)??[])console.log(n.yellow(" ! "+t));return!1}return console.log(n.green(" √ "+a.t("upgrade.done",{copy:d(f)}))),!0}(t);return _(`upgrade:${t}`,o?"ok":"fail",{duration_ms:Date.now()-e}),o}catch(o){throw _(`upgrade:${t}`,"fail",{duration_ms:Date.now()-e,error:o}),o}}
|
package/dist/lib/tools/codex.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash as e}from"crypto";import{existsSync as t,mkdirSync as o,readFileSync as n,rmSync as r,statSync as i,writeFileSync as l}from"fs";import{join as a}from"path";import*as s from"@iarna/toml";import{logger as c}from"../../utils/logger.js";import{i18n as d}from"../i18n.js";import{backupBeforeWrite as u,atomicWriteFile as m}from"./backup.js";import{pickModel as f,toolHome as p,withV1 as g}from"./types.js";import{getToolDefaultModel as _}from"../model-registry.js";import{configManager as x}from"../config.js";import{maskHome as y,track as h}from"../telemetry.js";import{buildCodexCatalog as k,catalogRejections as b,codexCatalogPath as j,fillFromOlderEntries as v,installedCodexBinaries as w,loadBundledCodexModels as O,loadPreviousCodexModels as C,previousGatewayModelIds as M}from"./codex-catalog.js";import{gatewayModelSpecs as E,modelFamily as N}from"../gateway-models.js";import{
|
|
1
|
+
import{createHash as e}from"crypto";import{existsSync as t,mkdirSync as o,readFileSync as n,rmSync as r,statSync as i,writeFileSync as l}from"fs";import{join as a}from"path";import*as s from"@iarna/toml";import{logger as c}from"../../utils/logger.js";import{i18n as d}from"../i18n.js";import{backupBeforeWrite as u,atomicWriteFile as m}from"./backup.js";import{pickModel as f,toolHome as p,withV1 as g}from"./types.js";import{getToolDefaultModel as _}from"../model-registry.js";import{configManager as x}from"../config.js";import{maskHome as y,track as h}from"../telemetry.js";import{buildCodexCatalog as k,catalogRejections as b,codexCatalogPath as j,fillFromOlderEntries as v,installedCodexBinaries as w,loadBundledCodexModels as O,loadPreviousCodexModels as C,previousGatewayModelIds as M}from"./codex-catalog.js";import{gatewayModelSpecs as E,modelFamily as N}from"../gateway-models.js";import{findInstalls as S,mirrorInstallCommand as A,brandInstallScripts as P}from"./tool-installs.js";const T=()=>a(p(),".codex"),D=()=>a(T(),"config.toml"),I=()=>a(T(),"auth.json"),$="OPENAI_API_KEY",J="custom",L=1e6,K=9e5;export const CODEX_ONE_MILLION_CONTEXT_SETTING="one_million_context";function X(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function B(e,t){return X(e[t])||(e[t]={}),e[t]}function q(){if(!t(D()))return{};const e=n(D(),"utf-8");if(!e.trim())return{};try{const t=s.parse(e);if(!X(t))throw new Error("config.toml root must be a TOML table");return t}catch(e){throw new Error(`Existing ~/.codex/config.toml cannot be parsed, back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}}function G(){if(!t(I()))return{};try{const e=JSON.parse(n(I(),"utf-8"));return X(e)?e:{}}catch{return{}}}let z=null;function R(e){const t=e.profiles;if(X(t)){for(const[e,o]of Object.entries(t))X(o)&&2===Object.keys(o).length&&o.model_provider===J&&o.model===e&&delete t[e];0===Object.keys(t).length&&delete e.profiles}}let U=null;const Y=()=>a(x.getConfigDir(),"codex-catalog-check.json");function F(e){const o=j();t(o)&&n(o,"utf-8")===e||(u(o),m(o,e))}function H(t,r){if(0===r.length)return[];const a=function(t,o){const n=e("sha256").update(t);for(const e of o)try{const t=i(e);n.update(`\0${e}\0${t.size}\0${t.mtimeMs}`)}catch{n.update(`\0${e}`)}return n.digest("hex")}(t,r);if(function(e){try{return JSON.parse(n(Y(),"utf-8")).signature===e}catch{return!1}}(a))return[];const s=b(j(),r);return 0===s.length&&function(e){try{o(x.getConfigDir(),{recursive:!0}),l(Y(),JSON.stringify({signature:e})+"\n")}catch(e){c.logError("codexAdapter.rememberAccepted",e)}}(a),s}function Q(e,t,o){const n=!1!==t.settings?.one_million_context;!function(e){e.model_context_window===L&&delete e.model_context_window,e.model_auto_compact_token_limit===K&&delete e.model_auto_compact_token_limit}(e);const i=()=>{e.model_catalog_json===j()&&delete e.model_catalog_json,n&&(e.model_context_window=L,e.model_auto_compact_token_limit=K)},l=O()??C();if(!l)return c.logError("codexAdapter.writeModelCatalog",new Error("no Codex binary found; model catalog skipped")),U="skipped",void i();const a=t.catalog,s=e=>k({bundled:e,specs:E("codex",a?.clientModels),...a?{keyModels:a.models}:{},gatewayAvailable:a?.models??M(),oneMillion:n,selectedModel:o,..."gateway"===a?.oneMillionSource?{claudeOneMillion:a.oneMillion}:{}}),d=e=>JSON.stringify(e,null,2)+"\n";let u=s(l);F(d(u));const m=w(),f=H(d(u),m);if(f.length>0){const e=Date.now();let t=!1;for(const e of f){const o=O(e.bin);if(o){for(const e of[{models:v(u.models,o)},{models:v(s(o).models,o)}])if(F(d(e)),0===H(d(e),m).length){u=e,t=!0;break}if(t)break}}if(h("codex-catalog",t?"fallback":"fail",{duration_ms:Date.now()-e,error:f[0].error,detail:{rejected_by:f.map(e=>({version:e.version,path:y(e.bin)}))}}),!t)return U={rejectedBy:f[0]},r(j(),{force:!0}),void i()}U={listed:u.models.filter(e=>"list"===e.visibility).map(e=>({id:String(e.slug),name:String(e.display_name??e.slug)}))},e.model_catalog_json=j()}export function codexCatalogRejection(){let e;try{e=q()}catch{return null}return e.model_catalog_json===j()&&t(j())?b(j())[0]??null:null}export function setCodexOneMillionContext(e,t){const o=q(),n=s.stringify(o),r="string"==typeof o.model?o.model:_("codex");Q(o,{settings:{[CODEX_ONE_MILLION_CONTEXT_SETTING]:e},catalog:t},r);const i=s.stringify(o);i!==n&&(u(D()),m(D(),i))}const V={command:"codex",npmPackage:"@openai/codex",native:{binDir:"win32"===process.platform?["AppData","Local","Programs","OpenAI","Codex","bin"]:[".local","bin"],updateArgs:["update"],updateTimeoutMs:12e4,dataDirs:[[".codex","packages","standalone"]]},mirrorScript:P("codex"),brew:"codex"};export const codexAdapter={name:"codex",displayName:"Codex",command:"codex",installCommand:A(V),installSpec:V,configPath:D(),wantsModelCatalog:!0,listedModels(){if(q().model_catalog_json!==j())return null;try{return(JSON.parse(n(j(),"utf-8")).models??[]).filter(e=>"list"===e.visibility).map(e=>String(e.slug))}catch{return null}},refreshModelMenu(e){q().model_catalog_json===j()&&setCodexOneMillionContext(!1!==e.settings?.one_million_context,e.catalog)},applyNotes(){if("skipped"===U)return 0===S(V).length?[]:[{kind:"action",text:d.t("tools.codex.catalog_skipped")}];if(!U)return[];if("rejectedBy"in U){const{bin:e,version:t}=U.rejectedBy;return[{kind:"action",text:d.t("tools.codex.catalog_rejected",{path:e,version:t??"?"})}]}const e=new Map;for(const t of U.listed)e.set(N(t.id),(e.get(N(t.id))??0)+1);const t=["gpt","claude","gemini","other","grok"].filter(t=>e.has(t)).map(t=>`${d.t(`tools.model_family.${t}`)} ${e.get(t)}`).join(" · ");return[{kind:"summary",text:d.t("tools.codex.catalog_written",{count:String(U.listed.length),breakdown:t})},{kind:"detail",text:U.listed.map(e=>e.name).join(", ")}]},loadPrivateConfig(e){const t=_("codex"),o=f(e.models,t),n=function(e){return/(?:^|\/)claude(?:-|$)/i.test(e)}(o)?t:o,r=g(e.baseUrl),i=q();i.model=n,i.model_provider=J,i.model_reasoning_effort="high",Q(i,e,n);const l=B(i,"model_providers"),a=X(l[J])?{...l[J]}:{};delete a.env_key;const{experimental_bearer_token:c,...d}=a;l[J]={...d,name:"custom",wire_api:"responses",requires_openai_auth:!0,base_url:r},R(i),B(B(i,"tui"),"model_availability_nux")[n]=4;const p=B(i,"features");p.goals=!0,p.js_repl=!1,u(D()),m(D(),s.stringify(i)),function(e){const t=e.trim();if(!t)return;const o={...G(),auth_mode:"apikey",[$]:t};u(I()),m(I(),JSON.stringify(o,null,2)+"\n",384)}(e.apiKey)},unloadPrivateConfig(e){if(z=function(e){const t=G(),o="string"==typeof t[$]?t[$].trim():"";if(!o)return X(t.tokens)?"chatgpt":null;if(!e.includes(o))return"other_key";const{[$]:n,auth_mode:i,...l}=t;return u(I()),X(l.tokens)?(m(I(),JSON.stringify({...l,auth_mode:"chatgpt"},null,2)+"\n",384),"chatgpt"):(r(I(),{force:!0}),"signed_out")}(e?.savedKeys??[]),!t(D()))return;let o;try{o=q()}catch(e){return void c.logError("codexAdapter.unloadPrivateConfig",e)}const n=o.model_providers;X(n)&&(delete n[J],0===Object.keys(n).length&&delete o.model_providers),o.model_provider===J&&delete o.model_provider,o.model_catalog_json===j()&&delete o.model_catalog_json,R(o),u(D()),m(D(),s.stringify(o))},unloadNotes(){switch(z){case"chatgpt":return[{kind:"action",text:d.t("tools.codex.unload_chatgpt_restored")}];case"other_key":return[{kind:"action",text:d.t("tools.codex.unload_other_key")}];default:return[{kind:"action",text:d.t("tools.codex.unload_sign_in")}]}},detectCurrentConfig(){const e=G()[$];return{apiKey:"string"==typeof e&&e.trim()?e.trim():null}},getConfig(){try{return q()}catch(e){return c.logError("codexAdapter.getConfig",e),null}},backupPaths:()=>[D(),I(),j()]};export function codexAuthProblem(){try{const e=q(),t=e.model_providers?.[J];if(e.model_provider!==J||!t)return null;if("string"==typeof t.experimental_bearer_token&&t.experimental_bearer_token)return"stale_bearer";const o=G();return!0===t.requires_openai_auth&&"chatgpt"===o.auth_mode?"chatgpt_login":null}catch{return null}}
|
package/dist/lib/tools/grok.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as e,readFileSync as t}from"fs";import{join as o}from"path";import*as r from"@iarna/toml";import{logger as n}from"../../utils/logger.js";import{PROVIDER_KEY as i}from"../brand.js";import{backupBeforeWrite as s,atomicWriteFile as l}from"./backup.js";import{pickModel as
|
|
1
|
+
import{existsSync as e,readFileSync as t}from"fs";import{join as o}from"path";import*as r from"@iarna/toml";import{logger as n}from"../../utils/logger.js";import{PROVIDER_KEY as i}from"../brand.js";import{backupBeforeWrite as s,atomicWriteFile as l}from"./backup.js";import{pickModel as d,toolHome as a,withV1 as m}from"./types.js";import{i18n as f}from"../i18n.js";import{getToolDefaultModel as g}from"../model-registry.js";import{gatewayModelSpecs as u,modelBlurb as c,modelFamily as p,prettyModelName as y}from"../gateway-models.js";import{brandInstallScripts as k,mirrorInstallCommand as b}from"./tool-installs.js";import{OFFICIAL_PLUGINS as h}from"./claude-plugins.js";const j=()=>o(o(a(),".grok"),"config.toml"),_=i,w=`${i}-`,A=["low","medium","high","xhigh"];let v=null;const C=e=>`${w}${e}`,x=e=>e===_||e.startsWith(w),M={command:"grok",npmPackage:"@xai-official/grok",mirrorScript:k("grok"),native:{binDir:[".grok","bin"],updateArgs:["update"],updateTimeoutMs:12e4,dataDirs:[[".grok","downloads"]]}};function S(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function E(e,t){return S(e[t])||(e[t]={}),e[t]}function O(){if(!e(j()))return{};const o=t(j(),"utf-8");if(!o.trim())return{};try{const e=r.parse(o);if(!S(e))throw new Error("config.toml root must be a TOML table");return e}catch(e){throw new Error(`Existing ~/.grok/config.toml cannot be parsed, back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}}function P(e){return S(e.model)?Object.entries(e.model).filter(e=>x(e[0])&&S(e[1])):[]}function N(e,t){let o=u("grok",e.catalog?.clientModels);if(e.catalog){const t=new Set(e.catalog.models);o=o.filter(e=>t.has(e.id))}return o.some(e=>e.id===t)?o:[{id:t},...o]}function $(e,t,o){E(e,"endpoints").models_base_url=m(t.baseUrl);const r=E(e,"model"),n=new Map(P(e));for(const e of n.keys())delete r[e];for(const e of o){const o=C(e.id),i={...n.get(o)??{},name:e.name??y(e.id),model:e.id,base_url:m(t.baseUrl),api_key:t.apiKey,context_window:e.contextWindow??5e5,api_backend:"responses",reasoning_summary:"concise"};"grok"===p(e.id)&&(i.supports_reasoning_effort=!0,i.reasoning_efforts=A);const s=c(e.description);s?i.description=s:delete i.description,r[o]=i}}export const grokAdapter={name:"grok",displayName:"Grok Build",command:"grok",installCommand:b(M),installSpec:M,configPath:j(),wantsModelCatalog:!0,loadPrivateConfig(e){const t=O(),o=d(e.models,g("grok")),n=N(e,o);$(t,e,n);const i=e=>e.name??y(e.id);v={names:n.map(i),defaultName:i(n.find(e=>e.id===o))},E(t,"models").default=C(o),function(e){const t=E(e,"plugins"),o=e=>Array.isArray(e)?e.map(String):[],r=o(t.enabled),n=o(t.disabled),i=h.filter(e=>!r.includes(e)&&!n.includes(e));i.length>0&&(t.disabled=[...n,...i])}(t),s(j()),l(j(),r.stringify(t))},unloadPrivateConfig(){if(!e(j()))return;let t;try{t=O()}catch(e){return void n.logError("grokAdapter.unloadPrivateConfig",e)}if(S(t.model)){for(const[e]of P(t))delete t.model[e];0===Object.keys(t.model).length&&delete t.model}S(t.models)&&"string"==typeof t.models.default&&x(t.models.default)&&(delete t.models.default,0===Object.keys(t.models).length&&delete t.models),S(t.endpoints)&&(delete t.endpoints.models_base_url,0===Object.keys(t.endpoints).length&&delete t.endpoints),function(e){if(!S(e.plugins)||!Array.isArray(e.plugins.disabled))return;const t=e.plugins.disabled.filter(e=>!h.includes(e));t.length>0?e.plugins.disabled=t:delete e.plugins.disabled,0===Object.keys(e.plugins).length&&delete e.plugins}(t),s(j()),l(j(),r.stringify(t))},detectCurrentConfig(){try{const e=O(),t=P(e),o=S(e.models)?e.models.default:void 0,r=t.find(([e])=>e===o)?.[1]??t[0]?.[1],n=r?r.api_key:null;return{apiKey:"string"==typeof n&&n.trim()?n:null}}catch{return{apiKey:null}}},listedModels(){try{const e=P(O());return e.length>0?e.map(([,e])=>String(e.model)):null}catch{return null}},refreshModelMenu(e){const t=O(),o=E(t,"models"),n="string"==typeof o.default?o.default:void 0,i=n?P(t).find(([e])=>e===n)?.[1].model:void 0,a="string"==typeof i&&n!==_&&e.catalog.models.includes(i)?i:d(e.models,g("grok")),m=r.stringify(t);$(t,e,N(e,a)),(void 0===n||x(n))&&(o.default=C(a)),r.stringify(t)!==m&&(s(j()),l(j(),r.stringify(t)))},applyNotes:()=>v?[{kind:"summary",text:f.t("tools.grok.menu_written",{count:String(v.names.length),list:v.names.join(f.t("tools.grok.list_separator")),default:v.defaultName})}]:[],getConfig(){try{return O()}catch(e){return n.logError("grokAdapter.getConfig",e),null}}};
|
|
@@ -10,6 +10,11 @@ type RegRunner = (args: string[]) => string;
|
|
|
10
10
|
export declare function setWindowsEnvRunnersForTests(runner: RegRunner | null, onBroadcast?: () => void): void;
|
|
11
11
|
/** 读注册表里的值;不存在时为 undefined(reg query 以非零退出)。 */
|
|
12
12
|
export declare function readWindowsEnv(scope: EnvScope, name: string): string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* 把一个目录加到用户级 Path 末尾(已有就不动),保留原来的值类型:Path 通常是 REG_EXPAND_SZ,
|
|
15
|
+
* 写成 REG_SZ 会让里面的 %USERPROFILE% 之类不再展开。返回是否改了。
|
|
16
|
+
*/
|
|
17
|
+
export declare function addUserPathDir(dir: string): boolean;
|
|
13
18
|
export declare function setUserEnv(name: string, value: string): void;
|
|
14
19
|
/** 删除一个值;系统级没有管理员权限时 reg.exe 拒绝,异常交给调用方。 */
|
|
15
20
|
export declare function deleteWindowsEnv(scope: EnvScope, name: string): void;
|
package/dist/lib/windows-env.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execFileSync as e,spawn as
|
|
1
|
+
import{execFileSync as e,spawn as r}from"child_process";import{logger as n}from"../utils/logger.js";import{brandEnvName as t}from"./brand.js";const o={user:"HKCU\\Environment",machine:"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"},s=r=>e("reg.exe",r,{encoding:"utf-8",windowsHide:!0,timeout:15e3,stdio:["ignore","pipe","pipe"]}),i=()=>{const e=r("powershell.exe",["-NoProfile","-NonInteractive","-Command",`[Environment]::SetEnvironmentVariable('${t("ENV_REFRESH")}',$null,'User')`],{detached:!0,stdio:"ignore",windowsHide:!0});e.on("error",e=>n.logError("windowsEnv.broadcast",e)),e.unref()};let a=s,d=i;export function setWindowsEnvRunnersForTests(e,r){a=e??s,d=e?r??(()=>{}):i}export function readWindowsEnv(e,r){let n;try{n=a(["query",o[e],"/v",r])}catch{return}const t=n.match(new RegExp(String.raw`^\s*${r}\s+REG_(?:EXPAND_)?SZ\s+(.*?)\r?$`,"im"));return t?t[1]:void 0}export function addUserPathDir(e){let r="REG_EXPAND_SZ",n="";try{const e=a(["query",o.user,"/v","Path"]).match(/^\s*Path\s+(REG_(?:EXPAND_)?SZ)\s+(.*?)\r?$/im);e&&([,r,n]=e)}catch{}const t=e=>(e=>e.replace(/%([^%]+)%/g,(e,r)=>process.env[r]??e))(e).replace(/[\\/]+$/,"").toLowerCase();return!n.split(";").some(r=>r&&t(r)===t(e))&&(a(["add",o.user,"/v","Path","/t",r,"/d",n?`${n.replace(/;+$/,"")};${e}`:e,"/f"]),!0)}export function setUserEnv(e,r){a(["add",o.user,"/v",e,"/t","REG_SZ","/d",r,"/f"])}export function deleteWindowsEnv(e,r){a(["delete",o[e],"/v",r,"/f"])}export function broadcastEnvChange(){d()}
|
package/dist/locales/en_US.json
CHANGED
|
@@ -378,6 +378,7 @@
|
|
|
378
378
|
"install_all_hint": "Or run {{cli}} setup --key <your key> --install to install them all",
|
|
379
379
|
"still_missing": "{{tools}} still not installed; run the commands above to install",
|
|
380
380
|
"path_reload": "Run exec \"$SHELL\" -l in this window (or open a new terminal) to use {{commands}}",
|
|
381
|
+
"path_added": "{{tool}} is installed in {{dir}}, which was not on PATH; added it to your user PATH",
|
|
381
382
|
"path_reload_windows": "Open a new terminal to use {{commands}}",
|
|
382
383
|
"list_separator": ", ",
|
|
383
384
|
"gui_preconfigured": "{{tool}} is not installed yet; its config is written already, so it works once you install and open it (download: {{install}})"
|
|
@@ -476,7 +477,9 @@
|
|
|
476
477
|
"verified_success": "Found {{tool}}, continuing",
|
|
477
478
|
"install_failed_detail": "Installation did not finish; see the output above or {{cli}} logs tail",
|
|
478
479
|
"downloading": "Downloading and installing (tens of MB up to about 130 MB); usually done within a minute or two",
|
|
479
|
-
"script_failed_npm": "The install script did not finish
|
|
480
|
+
"script_failed_npm": "The install script did not finish; installing with npm from the China mirror instead",
|
|
481
|
+
"script_stalled_npm": "The install script made no progress for {{minutes}} minutes (the download server is unreachable); installing with npm from the China mirror instead",
|
|
482
|
+
"script_timeout_npm": "The install script was still running after an hour; installing with npm from the China mirror instead",
|
|
480
483
|
"manual_command": "{{tool}} was not installed; when the network is better, run: {{command}}",
|
|
481
484
|
"manual_npm": "or install with npm: {{command}}"
|
|
482
485
|
},
|
package/dist/locales/zh_CN.json
CHANGED
|
@@ -378,6 +378,7 @@
|
|
|
378
378
|
"install_all_hint": "也可以运行 {{cli}} setup --key <你的 Key> --install 一次装好",
|
|
379
379
|
"still_missing": "{{tools}} 还没装好,按上方的命令安装后就能用",
|
|
380
380
|
"path_reload": "在当前窗口运行 exec \"$SHELL\" -l(或新开一个终端)后就能用 {{commands}}",
|
|
381
|
+
"path_added": "{{tool}} 已装在 {{dir}},但这个目录不在 PATH 里,已加入用户 PATH",
|
|
381
382
|
"path_reload_windows": "新开一个终端后就能用 {{commands}}",
|
|
382
383
|
"list_separator": "、",
|
|
383
384
|
"gui_preconfigured": "{{tool}} 还没装,配置已先写好,装好后打开就能用(下载:{{install}})"
|
|
@@ -476,7 +477,9 @@
|
|
|
476
477
|
"verified_success": "已找到 {{tool}},继续配置",
|
|
477
478
|
"install_failed_detail": "安装没有完成,详情见上面的输出或 {{cli}} logs tail",
|
|
478
479
|
"downloading": "正在下载安装,大约几十到一百多 MB,网络正常时一两分钟内完成",
|
|
479
|
-
"script_failed_npm": "
|
|
480
|
+
"script_failed_npm": "安装脚本没能完成,改用 npm 从国内镜像安装",
|
|
481
|
+
"script_stalled_npm": "安装脚本 {{minutes}} 分钟没有任何进展,网络连不上下载地址,改用 npm 从国内镜像安装",
|
|
482
|
+
"script_timeout_npm": "安装脚本运行 1 小时仍未完成,改用 npm 从国内镜像安装",
|
|
480
483
|
"manual_command": "{{tool}} 没装上,网络好的时候可以手动运行:{{command}}",
|
|
481
484
|
"manual_npm": "或者用 npm 安装:{{command}}"
|
|
482
485
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeapi/api-helper",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.118",
|
|
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",
|