@vibeapi/cli 0.0.158 → 0.0.159
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -8
- package/components.json +14 -0
- package/dist/commands/setup.d.ts +8 -0
- package/dist/commands/setup.js +1 -1
- package/dist/components.json +14 -0
- package/dist/lib/client-config.d.ts +21 -0
- package/dist/lib/client-config.js +1 -1
- package/dist/lib/gateway-models.d.ts +1 -1
- package/dist/lib/gateway-models.js +1 -1
- package/dist/lib/model-registry.d.ts +9 -1
- package/dist/lib/program.js +1 -1
- package/dist/lib/tools/codebuddy-models.d.ts +62 -0
- package/dist/lib/tools/codebuddy-models.js +1 -0
- package/dist/lib/tools/codebuddy.d.ts +2 -0
- package/dist/lib/tools/codebuddy.js +1 -0
- package/dist/lib/tools/registry.js +1 -1
- package/dist/lib/tools/workbuddy.d.ts +2 -0
- package/dist/lib/tools/workbuddy.js +1 -0
- package/dist/locales/en_US.json +16 -2
- package/dist/locales/zh_CN.json +16 -2
- package/dist/models.json +3 -1
- package/models.json +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# VibeCLI(@vibeapi/api-helper)
|
|
2
2
|
|
|
3
|
-
> 一条命令,为 Claude Code、Claude Desktop、Codex、Grok Build、Antigravity CLI 配置 VibeAPI 的令牌和模型;也能从国内镜像安装和升级这些工具,以及 Node.js、Git、uv、Claude Desktop、ChatGPT 桌面版(`vibecli list` / `install` / `upgrade`)。
|
|
3
|
+
> 一条命令,为 Claude Code、Claude Desktop、Codex、Grok Build、Antigravity CLI、CodeBuddy Code、WorkBuddy 配置 VibeAPI 的令牌和模型;也能从国内镜像安装和升级这些工具,以及 Node.js、Git、uv、Claude Desktop、ChatGPT 桌面版(`vibecli list` / `install` / `upgrade`)。
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@vibeapi/api-helper)
|
|
6
6
|
[](https://nodejs.org)
|
|
@@ -60,12 +60,13 @@ vibecli setup --key sk-xxx
|
|
|
60
60
|
|
|
61
61
|
`--key` 按令牌能用的模型自动选择工具:
|
|
62
62
|
|
|
63
|
-
| 令牌能用的模型 | 配置的工具
|
|
64
|
-
| -------------- |
|
|
65
|
-
| Claude | Claude Code、Claude Desktop
|
|
66
|
-
| GPT | Codex
|
|
67
|
-
| Grok | Grok Build
|
|
68
|
-
| Gemini | Antigravity CLI(`agy`)
|
|
63
|
+
| 令牌能用的模型 | 配置的工具 |
|
|
64
|
+
| -------------- | ----------------------------------------- |
|
|
65
|
+
| Claude | Claude Code、Claude Desktop |
|
|
66
|
+
| GPT | Codex |
|
|
67
|
+
| Grok | Grok Build |
|
|
68
|
+
| Gemini | Antigravity CLI(`agy`) |
|
|
69
|
+
| 任意 | CodeBuddy Code、WorkBuddy(已安装才配置) |
|
|
69
70
|
|
|
70
71
|
Claude Desktop 在 macOS 和 Windows 上即使还没有安装也会先写好配置,安装后打开即可使用;Linux 上只配置已安装的官方版。
|
|
71
72
|
|
|
@@ -137,7 +138,7 @@ vibecli config claude-code clear-model
|
|
|
137
138
|
|
|
138
139
|
## 功能
|
|
139
140
|
|
|
140
|
-
- **一次配置多个工具**:把当前的令牌和模型写入 Claude Code、Claude Desktop(第三方推理模式,写入应用的本地配置库,不需要管理员权限或描述文件)、Codex、Grok Build、Antigravity CLI
|
|
141
|
+
- **一次配置多个工具**:把当前的令牌和模型写入 Claude Code、Claude Desktop(第三方推理模式,写入应用的本地配置库,不需要管理员权限或描述文件)、Codex、Grok Build、Antigravity CLI、CodeBuddy Code、WorkBuddy(腾讯)。OpenCode 暂时下架,`vibecli config opencode` 仍可使用。
|
|
141
142
|
- **每个工具单独选模型**:可以用默认模型、从 API 实时获取、选内置预设或手动输入,每个工具可以用不同的模型。
|
|
142
143
|
- Claude Code 使用默认模型时不写 `ANTHROPIC_*_MODEL` 环境变量,顶层 `model` 取 `settings-template.json` 的值(当前为 `opus[1m]`);显式选择其他模型时覆盖这个值。你在 Claude Code / Codex 里用 `/model` 换过的模型和思考强度,之后再运行 setup 也保留(VibeCLI 只更新它自己写过、你没改过的值)。Codex 默认 `gpt-6-astra`,Grok Build 默认 `grok-4.6`,其余工具默认 `gpt-5.5`。
|
|
143
144
|
- Codex(命令行版与桌面版)的模型菜单除了自带的 GPT 模型,还列出网关的 Claude、Gemini、Grok 和国产模型;Claude Code 的 `/model` 菜单在内置档位之后列出 GPT、Gemini、Grok 和国产模型。两边都只列令牌能用的模型。每个模型按自己的上下文窗口设置,用到窗口的 80% 时自动压缩。Codex 默认开启 1M 上下文,交互配置时可以关闭(关闭后窗口不超过 272K)。需要 Codex 0.122 及以上;Codex 或 Claude Code 版本过旧时,配置完成后会给出升级命令。
|
package/components.json
CHANGED
|
@@ -116,6 +116,20 @@
|
|
|
116
116
|
"check": ["agy", "--version"],
|
|
117
117
|
"requires": []
|
|
118
118
|
},
|
|
119
|
+
{
|
|
120
|
+
"id": "codebuddy",
|
|
121
|
+
"name": "CodeBuddy Code",
|
|
122
|
+
"category": "cli",
|
|
123
|
+
"aliases": ["codebuddy-code"],
|
|
124
|
+
"platforms": ["darwin", "linux", "win32"],
|
|
125
|
+
"adapter": "codebuddy",
|
|
126
|
+
"latest": { "type": "npm", "package": "@tencent-ai/codebuddy-code" },
|
|
127
|
+
"sources": { "all": "npmmirror 的 @tencent-ai/codebuddy-code(与 npmjs 同一份)" },
|
|
128
|
+
"verify": { "checksum": "npm sha512", "signature": "—" },
|
|
129
|
+
"install": { "type": "adapter" },
|
|
130
|
+
"check": ["codebuddy", "--version"],
|
|
131
|
+
"requires": ["node"]
|
|
132
|
+
},
|
|
119
133
|
{
|
|
120
134
|
"id": "claude-desktop",
|
|
121
135
|
"name": "Claude Desktop",
|
package/dist/commands/setup.d.ts
CHANGED
|
@@ -69,6 +69,14 @@ export declare const DEDICATED_KEYS: readonly [{
|
|
|
69
69
|
readonly tool: "atomcode";
|
|
70
70
|
readonly need: "any";
|
|
71
71
|
readonly hidden: true;
|
|
72
|
+
}, {
|
|
73
|
+
readonly option: "codebuddykey";
|
|
74
|
+
readonly tool: "codebuddy";
|
|
75
|
+
readonly need: "any";
|
|
76
|
+
}, {
|
|
77
|
+
readonly option: "workbuddykey";
|
|
78
|
+
readonly tool: "workbuddy";
|
|
79
|
+
readonly need: "any";
|
|
72
80
|
}];
|
|
73
81
|
export type DedicatedKeyOption = (typeof DEDICATED_KEYS)[number]['option'];
|
|
74
82
|
export interface SetupCommandOptions extends Partial<Record<DedicatedKeyOption, string>> {
|
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 l}from"../lib/i18n.js";import{configManager as s}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 f,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as m}from"../lib/tools/claude-desktop.js";import{operationError as g,authenticationError as y,networkError as _,EXIT_CODES as k}from"../lib/errors.js";import{canPrompt as h,emitJson as b,isColorEnabled as v,isDryRun as w,isJsonMode as x,isNonInteractive as C,shouldAutoConfirm as j}from"../lib/runtime-options.js";import{appsForTools as K,appUpgradeCommand as $,getApp as T}from"../lib/app-update.js";import{join as M}from"path";import{asksBeforeWriting as G,confirmWritePlan as O,printWritePlan as S,toolWritePlan as I}from"../lib/write-plan.js";import N from"inquirer";import{logger as E}from"../utils/logger.js";import{forgetInstalls as A}from"../lib/tools/tool-installs.js";import{CLI_NAME as B,brandEnv as D}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 F(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 L(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 R(e){console.log(o.green(e))}function P(e){console.log(o.yellow(e))}function Y(e){console.error(o.red(e))}let q=null;function z(o){const e={operation:1,authentication:2,network:3};(!q||e[o]>e[q])&&(q=o)}async function H(e,t){x()||console.log(o.gray(l.t("setup.validating",{label:e})));const i=await r(t);if(i.valid)return!0;const a=l.t("errors.key_placeholder"),n="--key"===e?`${B} setup --key ${a}`:`${B} setup ${e} ${a}`;let p;if("network_error"===i.error?(z("network"),p=_(l.t("setup.unreachable",{url:s.getBaseUrl(),reason:i.message||"network error"}),`${B} base auto`,"network_error")):"invalid_api_key"===i.error?(z("authentication"),p=y(l.t("setup.invalid_key",{label:e,reason:i.message||"invalid"}),n,"invalid_api_key")):(z("operation"),p=g(l.t("setup.validate_failed",{label:e,reason:i.message||i.error||"unknown"}),n,i.error)),x())throw p;return Y(p.message),console.log(o.gray(l.t("errors.next_step",{command:p.hint}))),!1}async function W(t,i,r={}){const{oneMillion:p,officialLogin:c,desktopRegistry:u,force:y,takeOver:_}=r,k=n[t];try{"claude-desktop"===t&&void 0!==u&&s.setToolSetting("claude-desktop",f,u),"codex"===t&&void 0!==p&&s.setToolSetting("codex",d,p),"claude-desktop"===t&&void 0!==c&&s.setToolSetting("claude-desktop",m,!c),await a.applyPrivateConfig(t,i,s.getModelsForTool(t),{force:y,takeOver:_})}catch(o){if(x())throw g(o instanceof Error?o.message:String(o),`${B} setup --key ${l.t("errors.key_placeholder")}`,"config_write_failed");const e=(o instanceof Error?o.message:String(o)).replace(/\s+/g," ").trim();return Y("× "+l.t("setup.apply_failed",{tool:k.displayName,reason:e})),!1}return a.printApplied(t),y&&console.log(o.gray(" "+l.t("config.force_done",{tool:k.displayName,name:t}))),"codex"===t&&void 0!==p&&console.log(o.gray(" "+l.t(p?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),e(t)?.isInstalled&&!a.isToolInstalled(t)&&console.log(o.yellow(" ! "+l.t("setup.gui_preconfigured",{tool:k.displayName,install:k.installCommand}))),!0}function U(o){return!e(o)?.isInstalled&&!a.isToolInstalled(o)}export async function installMissingApps(e,t){const i=K(e).filter(o=>{const e=T(o)?.appInstaller;try{return Boolean(e&&!e.blocker()&&!e.installedPath())}catch(e){return E.logError(`setup: app installed? ${o}`,e),!1}});if(0===i.length)return!1;const s=o=>T(o)?.displayName??o;let a=t;if(void 0===a&&!x())if(j())a=!C();else if(h()){const o=i.map(s).join(l.t("setup.list_separator")),e=i.reduce((o,e)=>o+(T(e)?.appInstaller.sizeMb()??0),0);console.log(""),a=(await N.prompt([{type:"confirm",name:"go",message:l.t("setup.install_app_confirm",{tools:o,size:String(e)}),default:!0}])).go}if(!a&&!x())for(const e of i)console.log(o.gray(l.t("setup.install_app_hint",{tool:s(e),command:$(e)})));return Boolean(a)}function J(o){P(l.t("setup.still_missing",{tools:o.map(o=>n[o].displayName).join(l.t("setup.list_separator")),commands:o.map(o=>`${B} config ${o} --yes`).join(l.t("setup.list_separator"))}))}function Q(e,t,i=[]){const a=I(e),n=M(s.getConfigDir(),"config.yaml");if(x())b({dry_run:!0,tools:a,install_first:i,key_file:t?n:null});else{if(0===a.length&&0===i.length){const e=(v()?o.cyan:o=>o)(l.t("runtime.dry_run_label"));return void console.log(`${e} ${l.t("setup.dry_run_none")}`)}S(a,{label:l.t("runtime.dry_run_label"),keyFile:t?n:void 0,installFirst:i})}}function V(){return"darwin"===process.platform||"win32"===process.platform||a.isToolInstalled("claude-desktop")}export async function setupCommand(r){q=null;const p=r.key?.trim(),f=DEDICATED_KEYS.map(o=>({...o,apiKey:r[o.option]?.trim()})).filter(o=>Boolean(o.apiKey)),m=void 0!==r.oneMillion,g=void 0!==r.claudeOfficial;let y;if(g&&(y=parseOnOff(r.claudeOfficial),void 0===y))return Y(l.t("setup.claude_official_invalid",{value:String(r.claudeOfficial)})),void(process.exitCode=1);const _=void 0!==r.desktopRegistry;let h;if(_&&(h=parseOnOff(r.desktopRegistry),void 0===h))return Y(l.t("setup.desktop_registry_invalid",{value:String(r.desktopRegistry)})),void(process.exitCode=1);const b=g||_,v=Boolean(p||f.length>0),K={oneMillion:r.oneMillion,officialLogin:y,desktopRegistry:h,force:r.force};if(!v&&(m||b)&&w())return void Q([...m?["codex"]:[],...b?["claude-desktop"]:[]],!1);if(!v&&(m||b)){if(m){const o=s.getApiKeyForTool("codex");if(o)try{const e=!0===r.oneMillion;s.setToolSetting("codex",d,e);const t=await u(o);c(e,t??void 0),R(l.t(e?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(o){Y(l.t("setup.apply_failed",{tool:n.codex.displayName,reason:o instanceof Error?o.message:String(o)})),process.exitCode=1}else Y(l.t("setup.codex_1m_missing_key")),process.exitCode=1}if(b){const o=s.getApiKeyForTool("claude-desktop");o?await W("claude-desktop",o,{...K,oneMillion:void 0,takeOver:!0})?await t(["claude-desktop"],{apps:{install:!1}}):process.exitCode=1:(Y(l.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!v)return Y(l.t("setup.usage")),void(process.exitCode=1);const $=w();$||await i(p||f[0].apiKey);const T=[],S=[];let I,z=0,X=0;const Z=new Set,oo=f.map(o=>({tool:o.tool,label:`--${o.option}`,apiKey:o.apiKey,need:o.need}));for(const o of oo){if(!await H(o.label,o.apiKey)){X+=1;continue}const e=await F(o.apiKey);!e.probed||L(e,o.need)?(e.probed||P(l.t("setup.probe_failed",{label:o.label})),T.push({tool:o.tool,apiKey:o.apiKey,dedicated:!0}),Z.add(o.tool)):(Y(l.t(`setup.key_no_${o.need}`,{label:o.label,tool:n[o.tool].displayName})),X+=1)}const eo=!!p&&await H("--key",p);p&&!eo&&(I=k[q??"operation"]);const to=p&&eo?await F(p):void 0;if(p&&to&&!to.probed&&P(l.t("setup.probe_failed",{label:"--key"})),!(p&&to&&to.probed)||to.hasClaude||to.hasGpt||to.hasGrok||to.hasGemini||(Y(l.t("setup.key_no_family")),I=1),p&&to&&void 0===I){const o=[{tool:"claude-code",capable:to.hasClaude,skipMsg:l.t(V()?"setup.skip_no_claude_desktop":"setup.skip_no_claude")},{tool:"codex",capable:to.hasGpt,skipMsg:l.t("setup.skip_no_gpt")},{tool:"grok",capable:to.hasGrok,skipMsg:l.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:to.hasClaude&&V(),skipMsg:"",quiet:!0},{tool:"agy",capable:to.hasGemini,skipMsg:l.t("setup.skip_no_gemini")}];for(const e of o)Z.has(e.tool)||(e.capable?(T.push({tool:e.tool,apiKey:p,dedicated:!1}),Z.add(e.tool)):e.quiet||P(e.skipMsg))}const io=Boolean(p&&eo&&void 0===I);if($)return Q(T.filter(o=>!U(o.tool)).map(o=>o.tool),T.length>0,T.filter(o=>U(o.tool)).map(o=>o.tool)),void((X>0||void 0!==I)&&(process.exitCode=I??k[q??"operation"]));const lo=T.filter(o=>!U(o.tool)),so=io||T.some(o=>o.dedicated),ao=!r.fromInstaller&&G();if((T.length>0||so)&&!r.fromInstaller&&!await O(lo.map(o=>o.tool),{keyFile:so?M(s.getConfigDir(),"config.yaml"):void 0,installFirst:T.filter(o=>U(o.tool)).map(o=>o.tool)}))return void(process.exitCode=k.cancelled);io&&p&&s.setApiKey(p);for(const o of T)o.dedicated&&s.setToolApiKey(o.tool,o.apiKey),U(o.tool)?S.push({tool:o.tool,apiKey:o.apiKey}):await W(o.tool,o.apiKey,{...K,takeOver:o.dedicated||ao})?z+=1:(X+=1,Z.delete(o.tool));if(void 0!==I)return S.length>0&&J(S.map(o=>o.tool)),void(process.exitCode=I);let no=[];if(S.length>0){const e=await async function(e,t,i){const s=e.map(o=>o.tool);if(0===s.length)return{still:[],applied:[],failed:[]};const r=s.map(o=>n[o].displayName).join(l.t("setup.list_separator"));let p=t;if(void 0!==p||x()||(j()?p=!C():process.stdin.isTTY&&(console.log(""),p=(await N.prompt([{type:"confirm",name:"go",message:l.t("setup.install_confirm",{tools:r}),default:!0}])).go)),!p){console.log("");for(const e of s)console.log(o.yellow("! "+l.t("setup.install_hint",{tool:n[e].displayName,install:n[e].installCommand})));return x()||console.log(o.gray(l.t("setup.install_all_hint",{cli:B}))),{still:s,applied:[],failed:[]}}const d=[];for(const e of s){console.log(o.bold(`\n${n[e].displayName}`));try{await a.installTool(e)}catch(o){E.logError(`setup: install ${e}`,o)}A(),a.isToolInstalled(e)||d.push(e)}const c=s.filter(o=>!d.includes(o));c.length>0&&console.log("");const u=[],f=[];for(const{tool:o,apiKey:t}of e.filter(o=>c.includes(o.tool)))await W(o,t,i)?u.push(o):f.push(o);return{still:d,applied:u,failed:f}}(S,r.install,K);no=e.still,z+=e.applied.length,X+=e.failed.length;for(const o of[...no,...e.failed])Z.delete(o)}if(z>0){const t=[...Z].filter(o=>!e(o)?.isInstalled&&!no.includes(o)),i=t.map(o=>n[o]?.command).filter(Boolean).join(" / "),s=l.t("setup.done",{count:String(z)});R("\n"+(i?`${s}${l.t("setup.done_commands",{commands:i})}`:s)),no.length>0&&J(no);for(const o of t){const e=a.ensureNativeOnPath(o);e&&R(l.t("setup.path_added",{tool:n[o].displayName,dir:e}))}const r=t.filter(o=>!a.isOnPath(o));if(r.length>0&&!x()&&"1"!==D("PATH_HINT_BY_CALLER")){const e=r.map(o=>n[o].command).join(" / ");console.log(o.yellow(" ! "+l.t("win32"===process.platform?"setup.path_reload_windows":"setup.path_reload",{commands:e})))}}0===z&&no.length>0&&J(no),X>0&&(Y(l.t("setup.failed_summary",{count:String(X)})),x()||console.error(`${B} setup --key ${l.t("errors.key_placeholder")}`)),await t([...Z],{apps:{install:await installMissingApps([...Z],r.install)}}),(X>0||0===z&&0===no.length)&&(process.exitCode=k[q??"operation"])}
|
|
1
|
+
import o from"chalk";import{getAdapter as e}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{ensureReachableGatewayAddress as i}from"./base.js";import{i18n as l}from"../lib/i18n.js";import{configManager as s}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 f,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as m}from"../lib/tools/claude-desktop.js";import{operationError as g,authenticationError as y,networkError as k,EXIT_CODES as _}from"../lib/errors.js";import{canPrompt as h,emitJson as b,isColorEnabled as w,isDryRun as v,isJsonMode as x,isNonInteractive as C,shouldAutoConfirm as j}from"../lib/runtime-options.js";import{appsForTools as K,appUpgradeCommand as T,getApp as $}from"../lib/app-update.js";import{join as G}from"path";import{asksBeforeWriting as M,confirmWritePlan as I,printWritePlan as O,toolWritePlan as S}from"../lib/write-plan.js";import N from"inquirer";import{logger as E}from"../utils/logger.js";import{forgetInstalls as A}from"../lib/tools/tool-installs.js";import{CLI_NAME as B,brandEnv as D}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},{option:"codebuddykey",tool:"codebuddy",need:"any"},{option:"workbuddykey",tool:"workbuddy",need:"any"}];async function F(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 L(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 R(e){console.log(o.green(e))}function q(e){console.log(o.yellow(e))}function P(e){console.error(o.red(e))}let Y=null;function z(o){const e={operation:1,authentication:2,network:3};(!Y||e[o]>e[Y])&&(Y=o)}async function H(e,t){x()||console.log(o.gray(l.t("setup.validating",{label:e})));const i=await r(t);if(i.valid)return!0;const a=l.t("errors.key_placeholder"),n="--key"===e?`${B} setup --key ${a}`:`${B} setup ${e} ${a}`;let p;if("network_error"===i.error?(z("network"),p=k(l.t("setup.unreachable",{url:s.getBaseUrl(),reason:i.message||"network error"}),`${B} base auto`,"network_error")):"invalid_api_key"===i.error?(z("authentication"),p=y(l.t("setup.invalid_key",{label:e,reason:i.message||"invalid"}),n,"invalid_api_key")):(z("operation"),p=g(l.t("setup.validate_failed",{label:e,reason:i.message||i.error||"unknown"}),n,i.error)),x())throw p;return P(p.message),console.log(o.gray(l.t("errors.next_step",{command:p.hint}))),!1}async function W(t,i,r={}){const{oneMillion:p,officialLogin:c,desktopRegistry:u,force:y,takeOver:k}=r,_=n[t];try{"claude-desktop"===t&&void 0!==u&&s.setToolSetting("claude-desktop",f,u),"codex"===t&&void 0!==p&&s.setToolSetting("codex",d,p),"claude-desktop"===t&&void 0!==c&&s.setToolSetting("claude-desktop",m,!c),await a.applyPrivateConfig(t,i,s.getModelsForTool(t),{force:y,takeOver:k})}catch(o){if(x())throw g(o instanceof Error?o.message:String(o),`${B} setup --key ${l.t("errors.key_placeholder")}`,"config_write_failed");const e=(o instanceof Error?o.message:String(o)).replace(/\s+/g," ").trim();return P("× "+l.t("setup.apply_failed",{tool:_.displayName,reason:e})),!1}return a.printApplied(t),y&&console.log(o.gray(" "+l.t("config.force_done",{tool:_.displayName,name:t}))),"codex"===t&&void 0!==p&&console.log(o.gray(" "+l.t(p?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),e(t)?.isInstalled&&!a.isToolInstalled(t)&&console.log(o.yellow(" ! "+l.t("setup.gui_preconfigured",{tool:_.displayName,install:_.installCommand}))),!0}function U(o){return!e(o)?.isInstalled&&!a.isToolInstalled(o)}export async function installMissingApps(e,t){const i=K(e).filter(o=>{const e=$(o)?.appInstaller;try{return Boolean(e&&!e.blocker()&&!e.installedPath())}catch(e){return E.logError(`setup: app installed? ${o}`,e),!1}});if(0===i.length)return!1;const s=o=>$(o)?.displayName??o;let a=t;if(void 0===a&&!x())if(j())a=!C();else if(h()){const o=i.map(s).join(l.t("setup.list_separator")),e=i.reduce((o,e)=>o+($(e)?.appInstaller.sizeMb()??0),0);console.log(""),a=(await N.prompt([{type:"confirm",name:"go",message:l.t("setup.install_app_confirm",{tools:o,size:String(e)}),default:!0}])).go}if(!a&&!x())for(const e of i)console.log(o.gray(l.t("setup.install_app_hint",{tool:s(e),command:T(e)})));return Boolean(a)}function J(o){q(l.t("setup.still_missing",{tools:o.map(o=>n[o].displayName).join(l.t("setup.list_separator")),commands:o.map(o=>`${B} config ${o} --yes`).join(l.t("setup.list_separator"))}))}function Q(e,t,i=[]){const a=S(e),n=G(s.getConfigDir(),"config.yaml");if(x())b({dry_run:!0,tools:a,install_first:i,key_file:t?n:null});else{if(0===a.length&&0===i.length){const e=(w()?o.cyan:o=>o)(l.t("runtime.dry_run_label"));return void console.log(`${e} ${l.t("setup.dry_run_none")}`)}O(a,{label:l.t("runtime.dry_run_label"),keyFile:t?n:void 0,installFirst:i})}}function V(){return"darwin"===process.platform||"win32"===process.platform||a.isToolInstalled("claude-desktop")}export async function setupCommand(r){Y=null;const p=r.key?.trim(),f=DEDICATED_KEYS.map(o=>({...o,apiKey:r[o.option]?.trim()})).filter(o=>Boolean(o.apiKey)),m=void 0!==r.oneMillion,g=void 0!==r.claudeOfficial;let y;if(g&&(y=parseOnOff(r.claudeOfficial),void 0===y))return P(l.t("setup.claude_official_invalid",{value:String(r.claudeOfficial)})),void(process.exitCode=1);const k=void 0!==r.desktopRegistry;let h;if(k&&(h=parseOnOff(r.desktopRegistry),void 0===h))return P(l.t("setup.desktop_registry_invalid",{value:String(r.desktopRegistry)})),void(process.exitCode=1);const b=g||k,w=Boolean(p||f.length>0),K={oneMillion:r.oneMillion,officialLogin:y,desktopRegistry:h,force:r.force};if(!w&&(m||b)&&v())return void Q([...m?["codex"]:[],...b?["claude-desktop"]:[]],!1);if(!w&&(m||b)){if(m){const o=s.getApiKeyForTool("codex");if(o)try{const e=!0===r.oneMillion;s.setToolSetting("codex",d,e);const t=await u(o);c(e,t??void 0),R(l.t(e?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(o){P(l.t("setup.apply_failed",{tool:n.codex.displayName,reason:o instanceof Error?o.message:String(o)})),process.exitCode=1}else P(l.t("setup.codex_1m_missing_key")),process.exitCode=1}if(b){const o=s.getApiKeyForTool("claude-desktop");o?await W("claude-desktop",o,{...K,oneMillion:void 0,takeOver:!0})?await t(["claude-desktop"],{apps:{install:!1}}):process.exitCode=1:(P(l.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!w)return P(l.t("setup.usage")),void(process.exitCode=1);const T=v();T||await i(p||f[0].apiKey);const $=[],O=[];let S,z=0,X=0;const Z=new Set,oo=f.map(o=>({tool:o.tool,label:`--${o.option}`,apiKey:o.apiKey,need:o.need}));for(const o of oo){if(!await H(o.label,o.apiKey)){X+=1;continue}const e=await F(o.apiKey);!e.probed||L(e,o.need)?(e.probed||q(l.t("setup.probe_failed",{label:o.label})),$.push({tool:o.tool,apiKey:o.apiKey,dedicated:!0}),Z.add(o.tool)):(P(l.t(`setup.key_no_${o.need}`,{label:o.label,tool:n[o.tool].displayName})),X+=1)}const eo=!!p&&await H("--key",p);p&&!eo&&(S=_[Y??"operation"]);const to=p&&eo?await F(p):void 0;if(p&&to&&!to.probed&&q(l.t("setup.probe_failed",{label:"--key"})),!(p&&to&&to.probed)||to.hasClaude||to.hasGpt||to.hasGrok||to.hasGemini||(P(l.t("setup.key_no_family")),S=1),p&&to&&void 0===S){const o=to.hasClaude||to.hasGpt||to.hasGrok||to.hasGemini,e=[{tool:"claude-code",capable:to.hasClaude,skipMsg:l.t(V()?"setup.skip_no_claude_desktop":"setup.skip_no_claude")},{tool:"codex",capable:to.hasGpt,skipMsg:l.t("setup.skip_no_gpt")},{tool:"grok",capable:to.hasGrok,skipMsg:l.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:to.hasClaude&&V(),skipMsg:"",quiet:!0},{tool:"agy",capable:to.hasGemini,skipMsg:l.t("setup.skip_no_gemini")},{tool:"codebuddy",capable:o&&a.isToolInstalled("codebuddy"),skipMsg:"",quiet:!0},{tool:"workbuddy",capable:o&&a.isToolInstalled("workbuddy"),skipMsg:"",quiet:!0}];for(const o of e)Z.has(o.tool)||(o.capable?($.push({tool:o.tool,apiKey:p,dedicated:!1}),Z.add(o.tool)):o.quiet||q(o.skipMsg))}const io=Boolean(p&&eo&&void 0===S);if(T)return Q($.filter(o=>!U(o.tool)).map(o=>o.tool),$.length>0,$.filter(o=>U(o.tool)).map(o=>o.tool)),void((X>0||void 0!==S)&&(process.exitCode=S??_[Y??"operation"]));const lo=$.filter(o=>!U(o.tool)),so=io||$.some(o=>o.dedicated),ao=!r.fromInstaller&&M();if(($.length>0||so)&&!r.fromInstaller&&!await I(lo.map(o=>o.tool),{keyFile:so?G(s.getConfigDir(),"config.yaml"):void 0,installFirst:$.filter(o=>U(o.tool)).map(o=>o.tool)}))return void(process.exitCode=_.cancelled);io&&p&&s.setApiKey(p);for(const o of $)o.dedicated&&s.setToolApiKey(o.tool,o.apiKey),U(o.tool)?O.push({tool:o.tool,apiKey:o.apiKey}):await W(o.tool,o.apiKey,{...K,takeOver:o.dedicated||ao})?z+=1:(X+=1,Z.delete(o.tool));if(void 0!==S)return O.length>0&&J(O.map(o=>o.tool)),void(process.exitCode=S);let no=[];if(O.length>0){const e=await async function(e,t,i){const s=e.map(o=>o.tool);if(0===s.length)return{still:[],applied:[],failed:[]};const r=s.map(o=>n[o].displayName).join(l.t("setup.list_separator"));let p=t;if(void 0!==p||x()||(j()?p=!C():process.stdin.isTTY&&(console.log(""),p=(await N.prompt([{type:"confirm",name:"go",message:l.t("setup.install_confirm",{tools:r}),default:!0}])).go)),!p){console.log("");for(const e of s)console.log(o.yellow("! "+l.t("setup.install_hint",{tool:n[e].displayName,install:n[e].installCommand})));return x()||console.log(o.gray(l.t("setup.install_all_hint",{cli:B}))),{still:s,applied:[],failed:[]}}const d=[];for(const e of s){console.log(o.bold(`\n${n[e].displayName}`));try{await a.installTool(e)}catch(o){E.logError(`setup: install ${e}`,o)}A(),a.isToolInstalled(e)||d.push(e)}const c=s.filter(o=>!d.includes(o));c.length>0&&console.log("");const u=[],f=[];for(const{tool:o,apiKey:t}of e.filter(o=>c.includes(o.tool)))await W(o,t,i)?u.push(o):f.push(o);return{still:d,applied:u,failed:f}}(O,r.install,K);no=e.still,z+=e.applied.length,X+=e.failed.length;for(const o of[...no,...e.failed])Z.delete(o)}if(z>0){const t=[...Z].filter(o=>!e(o)?.isInstalled&&!no.includes(o)),i=t.map(o=>n[o]?.command).filter(Boolean).join(" / "),s=l.t("setup.done",{count:String(z)});R("\n"+(i?`${s}${l.t("setup.done_commands",{commands:i})}`:s)),no.length>0&&J(no);for(const o of t){const e=a.ensureNativeOnPath(o);e&&R(l.t("setup.path_added",{tool:n[o].displayName,dir:e}))}const r=t.filter(o=>!a.isOnPath(o));if(r.length>0&&!x()&&"1"!==D("PATH_HINT_BY_CALLER")){const e=r.map(o=>n[o].command).join(" / ");console.log(o.yellow(" ! "+l.t("win32"===process.platform?"setup.path_reload_windows":"setup.path_reload",{commands:e})))}}0===z&&no.length>0&&J(no),X>0&&(P(l.t("setup.failed_summary",{count:String(X)})),x()||console.error(`${B} setup --key ${l.t("errors.key_placeholder")}`)),await t([...Z],{apps:{install:await installMissingApps([...Z],r.install)}}),(X>0||0===z&&0===no.length)&&(process.exitCode=_[Y??"operation"])}
|
package/dist/components.json
CHANGED
|
@@ -116,6 +116,20 @@
|
|
|
116
116
|
"check": ["agy", "--version"],
|
|
117
117
|
"requires": []
|
|
118
118
|
},
|
|
119
|
+
{
|
|
120
|
+
"id": "codebuddy",
|
|
121
|
+
"name": "CodeBuddy Code",
|
|
122
|
+
"category": "cli",
|
|
123
|
+
"aliases": ["codebuddy-code"],
|
|
124
|
+
"platforms": ["darwin", "linux", "win32"],
|
|
125
|
+
"adapter": "codebuddy",
|
|
126
|
+
"latest": { "type": "npm", "package": "@tencent-ai/codebuddy-code" },
|
|
127
|
+
"sources": { "all": "npmmirror 的 @tencent-ai/codebuddy-code(与 npmjs 同一份)" },
|
|
128
|
+
"verify": { "checksum": "npm sha512", "signature": "—" },
|
|
129
|
+
"install": { "type": "adapter" },
|
|
130
|
+
"check": ["codebuddy", "--version"],
|
|
131
|
+
"requires": ["node"]
|
|
132
|
+
},
|
|
119
133
|
{
|
|
120
134
|
"id": "claude-desktop",
|
|
121
135
|
"name": "Claude Desktop",
|
|
@@ -10,15 +10,36 @@
|
|
|
10
10
|
* 这个模块不依赖 config.ts(config.ts → model-registry.ts → 这里),联网刷新在 client-config-sync.ts。
|
|
11
11
|
*/
|
|
12
12
|
export declare const CLIENT_CONFIG_SCHEMA = 1;
|
|
13
|
+
/**
|
|
14
|
+
* What the gateway's model metadata says a model can do (`capabilities` on a row, the same
|
|
15
|
+
* data as `/api/pricing`; filled in by the gateway when serving, never edited by hand).
|
|
16
|
+
*/
|
|
17
|
+
export interface GatewayModelCapabilities {
|
|
18
|
+
toolCall?: boolean;
|
|
19
|
+
vision?: boolean;
|
|
20
|
+
reasoning?: boolean;
|
|
21
|
+
contextWindow?: number;
|
|
22
|
+
maxOutput?: number;
|
|
23
|
+
reasoningEfforts?: string[];
|
|
24
|
+
defaultReasoningEffort?: string;
|
|
25
|
+
/** Interfaces where tool calls work (`openai`, `openai-response`, …); absent = all of them. */
|
|
26
|
+
toolCallEndpoints?: string[];
|
|
27
|
+
}
|
|
13
28
|
/** One model row of a list (`models.<list>[]`), normalized. */
|
|
14
29
|
export interface GatewayClientModel {
|
|
15
30
|
id: string;
|
|
16
31
|
name?: string;
|
|
17
32
|
description?: string;
|
|
18
33
|
contextWindow?: number;
|
|
34
|
+
maxOutputTokens?: number;
|
|
19
35
|
autoCompactTokens?: number;
|
|
36
|
+
capabilities?: GatewayModelCapabilities;
|
|
37
|
+
/** Interfaces the gateway serves this model on (`openai`, `openai-response`, `anthropic`, `gemini`). */
|
|
38
|
+
endpointTypes?: string[];
|
|
20
39
|
/** Taken off by the gateway: not listed, and keeps the built-in entry of the same id out too. */
|
|
21
40
|
hidden?: boolean;
|
|
41
|
+
/** Marked recommended in the gateway console; tools with a short menu (CodeBuddy, WorkBuddy) always list it. */
|
|
42
|
+
recommended?: boolean;
|
|
22
43
|
/** Per-tool switches (`claude-code`, `codex`, `grok`): false keeps it out, true puts it in. */
|
|
23
44
|
clients?: Record<string, boolean>;
|
|
24
45
|
/** Only vibecli at or above this version sees the row. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash as e,randomUUID as t}from"crypto";import{existsSync as n,mkdirSync as o,readFileSync as i,renameSync as r,writeFileSync as s}from"fs";import{homedir as l}from"os";import{dirname as c,join as a}from"path";import{fileURLToPath as f}from"url";import{CLIENT_SECTION as u,MIN_CLIENT_VERSION as d}from"./gateway-protocol.js";import{brand as m,brandEnv as p}from"./brand.js";export const CLIENT_CONFIG_SCHEMA=1;const h=new Set(["haiku","sonnet","opus","reasoning","fable"]),g=/^[A-Za-z0-9._:@/\-[\]]{1,200}$/,_=/^[a-z][a-z0-9-]{0,31}$/,y=/^\d+(\.\d+){0,3}$/,b=e=>!!e&&"object"==typeof e&&!Array.isArray(e),C=e=>"number"==typeof e&&Number.isFinite(e)&&e>0?Math.floor(e):void 0;function k(e){if(!b(e)||"string"!=typeof e.id||!e.id.trim())return null;const t={id:e.id.trim()};if(!0===e.hidden)return{...t,hidden:!0};"string"==typeof e.name&&e.name.trim()&&(t.name=e.name.trim()),"string"==typeof e.description&&e.description.trim()&&(t.description=e.description.trim());const n=C(e.context_window);n&&(t.contextWindow=n);const o=C(e.auto_compact_tokens);if(o&&(t.autoCompactTokens=o),b(e.clients)){const n={};for(const[t,o]of Object.entries(e.clients))_.test(t)&&"boolean"==typeof o&&(n[t]=o);Object.keys(n).length>0&&(t.clients=n)}const i=e[d];return"string"==typeof i&&y.test(i)&&(t.minClientVersion=i),"number"==typeof e.rollout_percent&&e.rollout_percent>=0&&e.rollout_percent<=100&&(t.rolloutPercent=e.rollout_percent),t}function $(e,t,n,o){if(void 0===e)return{};if(!b(e))throw new Error(`${u}.${o} must be an object`);const i={};for(const[r,s]of Object.entries(e)){if(!t.test(r)||"string"!=typeof s||!n(s))throw new Error(`${u}.${o}.${r} is invalid`);i[r]=s}return i}function v(e,t,{nonEmpty:n=!1}={}){if(void 0===e)return[];if(!Array.isArray(e)||e.some(e=>"string"!=typeof e||!g.test(e)))throw new Error(`${u}.${t} must be a list of model ids`);if(n&&0===e.length)throw new Error(`${u}.${t} must not be empty`);return[...e]}function w(e,t,n){if(void 0===e)return{};if(!b(e))throw new Error(`${u}.${t} must be an object`);const o={};for(const[i,r]of Object.entries(e)){if(!h.has(i))throw new Error(`${u}.${t}.${i} is not a tier slot`);o[i]=v(r,`${t}.${i}`,{nonEmpty:n})}return o}const j=e=>(e??[]).filter(e=>!e.hidden).length;export function parseClientConfig(e,t){if(!b(e))return{config:null,problem:"not an object"};if(1!==e.schema)return{config:null,problem:`unsupported schema ${String(e.schema)}`};if(!b(e.models))return{config:null,problem:"models is not an object"};const n={};for(const[t,o]of Object.entries(e.models)){if(!Array.isArray(o))return{config:null,problem:`models.${t} is not a list`};const e=o.map(k);if(e.some(e=>null===e))return{config:null,problem:`models.${t} has a row without an id`};n[t]=e}let o,i;try{o=function(e){if(null==e)return;if(!b(e))throw new Error(`${u} must be an object`);const t={};if(void 0!==e.min_version){if("string"!=typeof e.min_version||e.min_version&&!y.test(e.min_version))throw new Error(`${u}.min_version is invalid`);e.min_version&&(t.minVersion=e.min_version)}const n=$(e.default_models,/^(haiku|sonnet|opus|reasoning|fable)$/,e=>g.test(e),"default_models");Object.keys(n).length&&(t.defaultModels=n);const o=w(e.retired_default_models,"retired_default_models",!1);Object.keys(o).length&&(t.retiredDefaultModels=o);const i=$(e.tool_defaults,_,e=>""===e||g.test(e),"tool_defaults");Object.keys(i).length&&(t.toolDefaults=i);const r=w(e.tier_chains,"tier_chains",!0);Object.keys(r).length&&(t.tierChains=r);const s=v(e.retired_models,"retired_models");s.length&&(t.retiredModels=s);const l=$(e.tool_min_versions,_,e=>""===e||y.test(e),"tool_min_versions");Object.keys(l).length&&(t.toolMinVersions=l);const c=v(e.agy_models,"agy_models");c.length&&(t.agyModels=c);const a=v(e.one_million_fallback,"one_million_fallback");return a.length&&(t.oneMillionFallback=a),!0===e.accept_shrink&&(t.acceptShrink=!0),t}(e[u])}catch(e){i=`${u} section dropped: ${e instanceof Error?e.message:String(e)}`}const r=b(e.personal)&&Array.isArray(e.personal.lists)?e.personal.lists.filter(e=>"string"==typeof e&&Array.isArray(n[e])):[],s=e[u];if(t&&(!b(s)||!0!==s.accept_shrink))for(const[e,o]of Object.entries(t.models)){if(r.includes(e))continue;const t=j(o),i=j(n[e]);if(t>0&&0===i||t>=4&&2*i<t)return{config:null,problem:`models.${e} shrank from ${t} to ${i}`}}return{config:{schema:1,revision:"string"==typeof e.revision?e.revision:"",models:n,...o?{client:o}:{},...r.length?{personal:r}:{}},problem:i}}export function serializeClientConfig(e){const t=Object.fromEntries(Object.entries(e.models).map(([e,t])=>[e,t.map(e=>({id:e.id,...e.hidden?{hidden:!0}:{},...e.name?{name:e.name}:{},...e.description?{description:e.description}:{},...e.contextWindow?{context_window:e.contextWindow}:{},...e.autoCompactTokens?{auto_compact_tokens:e.autoCompactTokens}:{},...e.clients?{clients:e.clients}:{},...e.minClientVersion?{[d]:e.minClientVersion}:{},...void 0!==e.rolloutPercent?{rollout_percent:e.rolloutPercent}:{}}))])),n=e.client,o=n?{...n.minVersion?{min_version:n.minVersion}:{},...n.defaultModels?{default_models:n.defaultModels}:{},...n.retiredDefaultModels?{retired_default_models:n.retiredDefaultModels}:{},...n.toolDefaults?{tool_defaults:n.toolDefaults}:{},...n.tierChains?{tier_chains:n.tierChains}:{},...n.retiredModels?{retired_models:n.retiredModels}:{},...n.toolMinVersions?{tool_min_versions:n.toolMinVersions}:{},...n.agyModels?{agy_models:n.agyModels}:{},...n.oneMillionFallback?{one_million_fallback:n.oneMillionFallback}:{},...n.acceptShrink?{accept_shrink:!0}:{}}:void 0;return{schema:e.schema,revision:e.revision,models:t,...o?{[u]:o}:{},...e.personal?{personal:{lists:e.personal}}:{}}}function O(){const e=p("CONFIG_DIR")?.trim();if(e)return e;const t=p("TEST_HOME")?.trim();return a(t||l(),m().configDirName)}export const cachePath=()=>a(O(),"client-config.json");function x(e,t){o(c(e),{recursive:!0});const n=`${e}.${process.pid}.tmp`;s(n,t,"utf-8"),r(n,e)}export function readCachedClientConfig(){try{if(!n(cachePath()))return null;const e=JSON.parse(i(cachePath(),"utf-8"));if("string"!=typeof e.site||"number"!=typeof e.fetchedAt)return null;const{config:t}=parseClientConfig(e.config);return t?{site:e.site,fetchedAt:e.fetchedAt,config:t,..."string"==typeof e.keyHash?{keyHash:e.keyHash}:{},..."string"==typeof e.etag?{etag:e.etag}:{}}:null}catch{return null}}export function writeCachedClientConfig(e){x(cachePath(),JSON.stringify({site:e.site,keyHash:e.keyHash,etag:e.etag,fetchedAt:e.fetchedAt,config:serializeClientConfig(e.config)},null,2)+"\n")}let E;export function bundledClientConfig(){if("1"===p("NO_BUNDLED_CLIENT_CONFIG"))return null;if(void 0!==E)return E;E=null;const e=c(f(import.meta.url));for(const t of[a(e,"..","..","client-config.snapshot.json"),a(e,"..","client-config.snapshot.json")])try{if(!n(t))continue;E=parseClientConfig(JSON.parse(i(t,"utf-8"))).config;break}catch{}return E}let M=null;export function setClientConfigSiteResolver(e){M=e}export function currentClientConfig(){const e=readCachedClientConfig();let t=null;try{t=M?M():null}catch{t=null}if(e&&null!==t&&e.site===t)return{config:e.config,source:"cache",fetchedAt:e.fetchedAt};const n=bundledClientConfig();return n?{config:n,source:"bundled"}:null}let A=null,V=null;export function setClientIdentityForTests(e,t){A=e,V=t}export const clientVersion=()=>A??function(){try{const e=c(f(import.meta.url));for(const t of[a(e,"..","..","package.json"),a(e,"..","package.json")])if(n(t))return String(JSON.parse(i(t,"utf-8")).version??"0.0.0")}catch{}return"0.0.0"}();function S(e,t){const n=e.split(".").map(e=>parseInt(e,10)||0),o=t.split(".").map(e=>parseInt(e,10)||0);for(let e=0;e<Math.max(n.length,o.length);e++){const t=(n[e]??0)-(o[e]??0);if(t)return t}return 0}export function installId(){if(V)return V;const e=a(O(),"install-id");try{if(n(e)){const t=i(e,"utf-8").trim();if(t)return t}const o=t();return x(e,o+"\n"),o}catch{return"unknown"}}export function rolloutBucket(t){return e("sha256").update(`${installId()}:${t}`).digest().readUInt32BE(0)%100}export function isEligible(e){return!(e.minClientVersion&&S(clientVersion(),e.minClientVersion)<0||void 0!==e.rolloutPercent&&rolloutBucket(e.id)>=e.rolloutPercent)}export function eligibleLists(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,t.map(e=>e.hidden||isEligible(e)?e:{id:e.id,hidden:!0})]))}export function usableClientSection(e){const t=e?.client;if(t&&!(t.minVersion&&S(clientVersion(),t.minVersion)<0))return t}
|
|
1
|
+
import{createHash as t,randomUUID as e}from"crypto";import{existsSync as n,mkdirSync as o,readFileSync as i,renameSync as r,writeFileSync as s}from"fs";import{homedir as l}from"os";import{dirname as c,join as a}from"path";import{fileURLToPath as f}from"url";import{CLIENT_SECTION as u,MIN_CLIENT_VERSION as d}from"./gateway-protocol.js";import{brand as p,brandEnv as m}from"./brand.js";export const CLIENT_CONFIG_SCHEMA=1;const g=new Set(["haiku","sonnet","opus","reasoning","fable"]),h=/^[A-Za-z0-9._:@/\-[\]]{1,200}$/,y=/^[a-z][a-z0-9-]{0,31}$/,_=/^\d+(\.\d+){0,3}$/,b=t=>!!t&&"object"==typeof t&&!Array.isArray(t),C=t=>"number"==typeof t&&Number.isFinite(t)&&t>0?Math.floor(t):void 0,k=/^[A-Za-z0-9._-]{1,64}$/,v=t=>{if(!Array.isArray(t))return;const e=t.filter(t=>"string"==typeof t&&k.test(t));return e.length>0?e:void 0};function E(t){if(!b(t)||"string"!=typeof t.id||!t.id.trim())return null;const e={id:t.id.trim()};if(!0===t.hidden)return{...e,hidden:!0};"string"==typeof t.name&&t.name.trim()&&(e.name=t.name.trim()),"string"==typeof t.description&&t.description.trim()&&(e.description=t.description.trim()),!0===t.recommended&&(e.recommended=!0);const n=C(t.context_window);n&&(e.contextWindow=n);const o=C(t.max_output_tokens);o&&(e.maxOutputTokens=o);const i=C(t.auto_compact_tokens);i&&(e.autoCompactTokens=i);const r=function(t){if(!b(t))return;const e={};"boolean"==typeof t.functionCall&&(e.toolCall=t.functionCall),"boolean"==typeof t.vision&&(e.vision=t.vision),"boolean"==typeof t.reasoning&&(e.reasoning=t.reasoning);const n=C(t.contextWindowTokens);n&&(e.contextWindow=n);const o=C(t.maxOutput);o&&(e.maxOutput=o);const i=v(t.reasoningEfforts);i&&(e.reasoningEfforts=i),"string"==typeof t.defaultReasoningEffort&&k.test(t.defaultReasoningEffort)&&(e.defaultReasoningEffort=t.defaultReasoningEffort);const r=v(t.functionCallEndpoints);return r&&(e.toolCallEndpoints=r),Object.keys(e).length>0?e:void 0}(t.capabilities);r&&(e.capabilities=r);const s=v(t.endpoint_types);if(s&&(e.endpointTypes=s),b(t.clients)){const n={};for(const[e,o]of Object.entries(t.clients))y.test(e)&&"boolean"==typeof o&&(n[e]=o);Object.keys(n).length>0&&(e.clients=n)}const l=t[d];return"string"==typeof l&&_.test(l)&&(e.minClientVersion=l),"number"==typeof t.rollout_percent&&t.rollout_percent>=0&&t.rollout_percent<=100&&(e.rolloutPercent=t.rollout_percent),e}function x(t,e,n,o){if(void 0===t)return{};if(!b(t))throw new Error(`${u}.${o} must be an object`);const i={};for(const[r,s]of Object.entries(t)){if(!e.test(r)||"string"!=typeof s||!n(s))throw new Error(`${u}.${o}.${r} is invalid`);i[r]=s}return i}function $(t,e,{nonEmpty:n=!1}={}){if(void 0===t)return[];if(!Array.isArray(t)||t.some(t=>"string"!=typeof t||!h.test(t)))throw new Error(`${u}.${e} must be a list of model ids`);if(n&&0===t.length)throw new Error(`${u}.${e} must not be empty`);return[...t]}function w(t,e,n){if(void 0===t)return{};if(!b(t))throw new Error(`${u}.${e} must be an object`);const o={};for(const[i,r]of Object.entries(t)){if(!g.has(i))throw new Error(`${u}.${e}.${i} is not a tier slot`);o[i]=$(r,`${e}.${i}`,{nonEmpty:n})}return o}const O=t=>(t??[]).filter(t=>!t.hidden).length;export function parseClientConfig(t,e){if(!b(t))return{config:null,problem:"not an object"};if(1!==t.schema)return{config:null,problem:`unsupported schema ${String(t.schema)}`};if(!b(t.models))return{config:null,problem:"models is not an object"};const n={};for(const[e,o]of Object.entries(t.models)){if(!Array.isArray(o))return{config:null,problem:`models.${e} is not a list`};const t=o.map(E);if(t.some(t=>null===t))return{config:null,problem:`models.${e} has a row without an id`};n[e]=t}let o,i;try{o=function(t){if(null==t)return;if(!b(t))throw new Error(`${u} must be an object`);const e={};if(void 0!==t.min_version){if("string"!=typeof t.min_version||t.min_version&&!_.test(t.min_version))throw new Error(`${u}.min_version is invalid`);t.min_version&&(e.minVersion=t.min_version)}const n=x(t.default_models,/^(haiku|sonnet|opus|reasoning|fable)$/,t=>h.test(t),"default_models");Object.keys(n).length&&(e.defaultModels=n);const o=w(t.retired_default_models,"retired_default_models",!1);Object.keys(o).length&&(e.retiredDefaultModels=o);const i=x(t.tool_defaults,y,t=>""===t||h.test(t),"tool_defaults");Object.keys(i).length&&(e.toolDefaults=i);const r=w(t.tier_chains,"tier_chains",!0);Object.keys(r).length&&(e.tierChains=r);const s=$(t.retired_models,"retired_models");s.length&&(e.retiredModels=s);const l=x(t.tool_min_versions,y,t=>""===t||_.test(t),"tool_min_versions");Object.keys(l).length&&(e.toolMinVersions=l);const c=$(t.agy_models,"agy_models");c.length&&(e.agyModels=c);const a=$(t.one_million_fallback,"one_million_fallback");return a.length&&(e.oneMillionFallback=a),!0===t.accept_shrink&&(e.acceptShrink=!0),e}(t[u])}catch(t){i=`${u} section dropped: ${t instanceof Error?t.message:String(t)}`}const r=b(t.personal)&&Array.isArray(t.personal.lists)?t.personal.lists.filter(t=>"string"==typeof t&&Array.isArray(n[t])):[],s=t[u];if(e&&(!b(s)||!0!==s.accept_shrink))for(const[t,o]of Object.entries(e.models)){if(r.includes(t))continue;const e=O(o),i=O(n[t]);if(e>0&&0===i||e>=4&&2*i<e)return{config:null,problem:`models.${t} shrank from ${e} to ${i}`}}return{config:{schema:1,revision:"string"==typeof t.revision?t.revision:"",models:n,...o?{client:o}:{},...r.length?{personal:r}:{}},problem:i}}export function serializeClientConfig(t){const e=Object.fromEntries(Object.entries(t.models).map(([t,e])=>[t,e.map(t=>{return{id:t.id,...t.hidden?{hidden:!0}:{},...t.recommended?{recommended:!0}:{},...t.name?{name:t.name}:{},...t.description?{description:t.description}:{},...t.contextWindow?{context_window:t.contextWindow}:{},...t.maxOutputTokens?{max_output_tokens:t.maxOutputTokens}:{},...t.autoCompactTokens?{auto_compact_tokens:t.autoCompactTokens}:{},...t.capabilities?{capabilities:(e=t.capabilities,{...void 0!==e.toolCall?{functionCall:e.toolCall}:{},...void 0!==e.vision?{vision:e.vision}:{},...void 0!==e.reasoning?{reasoning:e.reasoning}:{},...e.contextWindow?{contextWindowTokens:e.contextWindow}:{},...e.maxOutput?{maxOutput:e.maxOutput}:{},...e.reasoningEfforts?{reasoningEfforts:e.reasoningEfforts}:{},...e.defaultReasoningEffort?{defaultReasoningEffort:e.defaultReasoningEffort}:{},...e.toolCallEndpoints?{functionCallEndpoints:e.toolCallEndpoints}:{}})}:{},...t.endpointTypes?{endpoint_types:t.endpointTypes}:{},...t.clients?{clients:t.clients}:{},...t.minClientVersion?{[d]:t.minClientVersion}:{},...void 0!==t.rolloutPercent?{rollout_percent:t.rolloutPercent}:{}};var e})])),n=t.client,o=n?{...n.minVersion?{min_version:n.minVersion}:{},...n.defaultModels?{default_models:n.defaultModels}:{},...n.retiredDefaultModels?{retired_default_models:n.retiredDefaultModels}:{},...n.toolDefaults?{tool_defaults:n.toolDefaults}:{},...n.tierChains?{tier_chains:n.tierChains}:{},...n.retiredModels?{retired_models:n.retiredModels}:{},...n.toolMinVersions?{tool_min_versions:n.toolMinVersions}:{},...n.agyModels?{agy_models:n.agyModels}:{},...n.oneMillionFallback?{one_million_fallback:n.oneMillionFallback}:{},...n.acceptShrink?{accept_shrink:!0}:{}}:void 0;return{schema:t.schema,revision:t.revision,models:e,...o?{[u]:o}:{},...t.personal?{personal:{lists:t.personal}}:{}}}function j(){const t=m("CONFIG_DIR")?.trim();if(t)return t;const e=m("TEST_HOME")?.trim();return a(e||l(),p().configDirName)}export const cachePath=()=>a(j(),"client-config.json");function A(t,e){o(c(t),{recursive:!0});const n=`${t}.${process.pid}.tmp`;s(n,e,"utf-8"),r(n,t)}export function readCachedClientConfig(){try{if(!n(cachePath()))return null;const t=JSON.parse(i(cachePath(),"utf-8"));if("string"!=typeof t.site||"number"!=typeof t.fetchedAt)return null;const{config:e}=parseClientConfig(t.config);return e?{site:t.site,fetchedAt:t.fetchedAt,config:e,..."string"==typeof t.keyHash?{keyHash:t.keyHash}:{},..."string"==typeof t.etag?{etag:t.etag}:{}}:null}catch{return null}}export function writeCachedClientConfig(t){A(cachePath(),JSON.stringify({site:t.site,keyHash:t.keyHash,etag:t.etag,fetchedAt:t.fetchedAt,config:serializeClientConfig(t.config)},null,2)+"\n")}let M;export function bundledClientConfig(){if("1"===m("NO_BUNDLED_CLIENT_CONFIG"))return null;if(void 0!==M)return M;M=null;const t=c(f(import.meta.url));for(const e of[a(t,"..","..","client-config.snapshot.json"),a(t,"..","client-config.snapshot.json")])try{if(!n(e))continue;M=parseClientConfig(JSON.parse(i(e,"utf-8"))).config;break}catch{}return M}let T=null;export function setClientConfigSiteResolver(t){T=t}export function currentClientConfig(){const t=readCachedClientConfig();let e=null;try{e=T?T():null}catch{e=null}if(t&&null!==e&&t.site===e)return{config:t.config,source:"cache",fetchedAt:t.fetchedAt};const n=bundledClientConfig();return n?{config:n,source:"bundled"}:null}let V=null,S=null;export function setClientIdentityForTests(t,e){V=t,S=e}export const clientVersion=()=>V??function(){try{const t=c(f(import.meta.url));for(const e of[a(t,"..","..","package.json"),a(t,"..","package.json")])if(n(e))return String(JSON.parse(i(e,"utf-8")).version??"0.0.0")}catch{}return"0.0.0"}();function N(t,e){const n=t.split(".").map(t=>parseInt(t,10)||0),o=e.split(".").map(t=>parseInt(t,10)||0);for(let t=0;t<Math.max(n.length,o.length);t++){const e=(n[t]??0)-(o[t]??0);if(e)return e}return 0}export function installId(){if(S)return S;const t=a(j(),"install-id");try{if(n(t)){const e=i(t,"utf-8").trim();if(e)return e}const o=e();return A(t,o+"\n"),o}catch{return"unknown"}}export function rolloutBucket(e){return t("sha256").update(`${installId()}:${e}`).digest().readUInt32BE(0)%100}export function isEligible(t){return!(t.minClientVersion&&N(clientVersion(),t.minClientVersion)<0||void 0!==t.rolloutPercent&&rolloutBucket(t.id)>=t.rolloutPercent)}export function eligibleLists(t){return Object.fromEntries(Object.entries(t).map(([t,e])=>[t,e.map(t=>t.hidden||isEligible(t)?t:{id:t.id,hidden:!0})]))}export function usableClientSection(t){const e=t?.client;if(e&&!(e.minVersion&&N(clientVersion(),e.minVersion)<0))return e}
|
|
@@ -5,7 +5,7 @@ import type { GatewayClientModel } from './client-config.js';
|
|
|
5
5
|
* model menus, and the shared context rules: each model compacts at
|
|
6
6
|
* `autoCompactRatio` (80%) of its window unless the gateway sets a point.
|
|
7
7
|
*/
|
|
8
|
-
export type GatewayModelTool = 'codex' | 'claude-code' | 'grok';
|
|
8
|
+
export type GatewayModelTool = 'codex' | 'claude-code' | 'grok' | 'codebuddy';
|
|
9
9
|
/** Auto-compaction point for a window: the explicit value (capped at the window) or the ratio. */
|
|
10
10
|
export declare function autoCompactTokens(window: number, explicit?: number): number;
|
|
11
11
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getGatewayModelRules as e}from"./model-registry.js";export function autoCompactTokens(t,o){return o&&o>0?Math.min(o,t):Math.floor(t*e().autoCompactRatio)}export function gatewayModelSpecs(o,i,d=[]){const n=e().models,
|
|
1
|
+
import{getGatewayModelRules as e}from"./model-registry.js";export function autoCompactTokens(t,o){return o&&o>0?Math.min(o,t):Math.floor(t*e().autoCompactRatio)}export function gatewayModelSpecs(o,i,d=[]){const n=e().models,c=n.filter(e=>function(e,t){return"codebuddy"===e||("codex"===e?!1!==t.codex:"grok"===e?"grok"===modelFamily(t.id):!t.id.startsWith("claude-")&&!1!==t.claudeCode)}(o,e));if(!i)return c;const r=new Set(Object.values(i).flat().filter(e=>e.hidden).map(e=>e.id)),l=Object.fromEntries(Object.entries(i).map(([e,t])=>[e,t.filter(e=>!e.hidden)])),s=new Map;for(const e of Object.values(l).flat()){const t=e.clients?.[o];void 0===t||s.has(e.id)||s.set(e.id,t)}for(const[e,t]of s)t||r.add(e);const a=new Map(("claude-code"===o?n:c).map(e=>[e.id,e])),u=(l.gemini??[]).filter(e=>s.get(e.id)??!1!==n.find(t=>t.id===e.id)?.codex),f=("codebuddy"===o?[...l.claude??[],...l.codex??[],...l.gemini??[],...l.grok??[]]:"grok"===o?l.grok??[]:"codex"===o?[...l.codex??[],...u,...(l.claude??[]).filter(e=>e.id.startsWith("claude-")&&(s.get(e.id)??a.has(e.id)))]:function(e,t){return[...(e.codex??[]).filter(e=>"gpt"===modelFamily(e.id)),...e.gemini??[],...e.grok??[],...(e.claude??[]).filter(e=>!e.id.startsWith("claude-"))].filter(e=>e.clients?.["claude-code"]??t.get(e.id)?.claudeCode??!0)}(l,a)).filter(e=>!(e=>!1===s.get(e.id))(e));if(0===f.length)return c.filter(e=>!r.has(e.id));const m=new Set,g=[];for(const e of f){if(m.has(e.id))continue;m.add(e.id);const{clients:t,minClientVersion:o,rolloutPercent:i,...d}=e,n={...a.get(e.id),...d};void 0!==t?.codex&&(n.codex=t.codex),void 0!==t?.["claude-code"]&&(n.claudeCode=t["claude-code"]),g.push(n)}return t[o].some(e=>d.includes(e))?g:function(e,t,o){const i=[...e];return t.forEach((e,d)=>{if(o.has(e.id)||i.some(t=>t.id===e.id))return;const n=modelFamily(e.id),c=new Set(t.slice(d+1).filter(e=>modelFamily(e.id)===n).map(e=>e.id));let r=i.findIndex(e=>c.has(e.id));if(r<0){r=i.length;for(let e=i.length-1;e>=0;e--)if(modelFamily(i[e].id)===n){r=e+1;break}}i.splice(r,0,e)}),i}(g,c,r)}const t={grok:["grok"],codex:["codex","gemini","claude"],"claude-code":["codex","gemini","grok","claude"],codebuddy:["claude","codex","gemini","grok"]},o={gpt:"GPT",gemini:"Gemini",glm:"GLM",deepseek:"DeepSeek",minimax:"MiniMax",qwen:"Qwen"};export function modelBlurb(e,t={}){const o=[];for(const i of(e??"").split("|")){const e=i.trim();e&&(/\d\s*万?\s*输出|output\D*\d|\d\D*output/i.test(e)||(/[\d百千]\s*万?\s*上下文|context\D*\d|\d\D*context/i.test(e)?t.millionContext&&!o.includes("百万上下文")&&o.unshift("百万上下文"):o.push(e)))}return t.millionContext&&!o.includes("百万上下文")&&o.unshift("百万上下文"),o.length>0?o.join(" | "):void 0}export function prettyModelName(e){const t=e.replace(/^([a-z]+)(\d)/i,"$1 $2").split(/[-_\s]+/).filter(Boolean),i=[];for(const e of t){const t=i[i.length-1];if(/^\d+$/.test(e)&&t&&/^\d+$/.test(t)&&e.length<=2&&!/^\d{8}$/.test(e)){i[i.length-1]=`${t}.${e}`;continue}const d=e.toLowerCase();i.push(o[d]??(/^[a-z]\d/i.test(e)?e.toUpperCase():e[0].toUpperCase()+e.slice(1)))}return i.join(" ")}export function vendorNames(e){return[...new Set(e.map(e=>prettyModelName(e).split(" ")[0]))]}export function modelFamily(e){const t=e.toLowerCase();return t.startsWith("claude-")?"claude":t.startsWith("gemini")?"gemini":t.startsWith("grok")?"grok":/^(gpt|o\d|codex)/.test(t)?"gpt":"other"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ClientSection } from './client-config.js';
|
|
1
|
+
import { type ClientSection, type GatewayModelCapabilities } from './client-config.js';
|
|
2
2
|
export interface Models {
|
|
3
3
|
haiku: string;
|
|
4
4
|
sonnet: string;
|
|
@@ -44,8 +44,16 @@ export interface GatewayModelSpec {
|
|
|
44
44
|
name?: string;
|
|
45
45
|
description?: string;
|
|
46
46
|
contextWindow?: number;
|
|
47
|
+
/** Marked recommended in the gateway console. */
|
|
48
|
+
recommended?: boolean;
|
|
49
|
+
/** Output limit from the gateway (only some rows carry it). */
|
|
50
|
+
maxOutputTokens?: number;
|
|
47
51
|
/** Explicit auto-compaction point; defaults to `autoCompactRatio` of the window. */
|
|
48
52
|
autoCompactTokens?: number;
|
|
53
|
+
/** From the gateway's model metadata; absent for built-in entries and older gateways. */
|
|
54
|
+
capabilities?: GatewayModelCapabilities;
|
|
55
|
+
/** Interfaces the gateway serves the model on (`openai`, `openai-response`, …). */
|
|
56
|
+
endpointTypes?: string[];
|
|
49
57
|
/** `false` keeps the model out of Claude Code's picker (its window differs from the rest). */
|
|
50
58
|
claudeCode?: boolean;
|
|
51
59
|
/** `false` keeps the model out of Codex's catalog (GPT comes from Codex itself). */
|
package/dist/lib/program.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Command as e,Option as o}from"commander";import{readFileSync as s}from"fs";import{join as t,dirname as n}from"path";import{fileURLToPath as a}from"url";import{i18n as i}from"./i18n.js";import{wizard as r}from"./wizard.js";import{SUPPORTED_TOOLS as c}from"./tool-manager.js";import{DEFAULT_BASE_URL as l}from"./config.js";import{attachCommandHelp as p,helpConfiguration as m}from"./cli-help.js";import{langCommand as u,authCommand as d,doctorCommand as f,configCommand as g,statusCommand as x,refreshCommand as h}from"../commands/index.js";import{logsCommand as $}from"../commands/logs.js";import{completionCommand as y}from"../commands/completion.js";import{benchCommand as b}from"../commands/bench.js";import{updateCommand as k}from"../commands/update.js";import{upgradeCommand as _}from"../commands/upgrade.js";import{installCommand as w,listCommand as v}from"../commands/components.js";import{codexSessionsCommand as j}from"../commands/codex-sessions.js";import{sessionsExportCommand as O,sessionsListCommand as S,sessionsResumeCommand as A,sessionsShowCommand as E}from"../commands/sessions.js";import{setupCommand as G,DEDICATED_KEYS as z}from"../commands/setup.js";import{baseCommand as C}from"../commands/base.js";import{usageError as R}from"./errors.js";import{requireTerminal as B}from"./confirm.js";import{brand as I,brandEnv as L,CLI_NAME as N}from"./brand.js";const P=(I().gatewayAddresses[1]??I().gatewayAddresses[0]).url,T=(I().gatewayAddresses[2]??I().gatewayAddresses[0]).url;function U(e,o){return i.t(`help.${e}`,o)}function H(e,o){return{command:e,note:U(o)}}function K(e){const o=U(e);return o===`help.${e}`?"":o}function M(e,o=[]){return{when:K(`${e}.when`),prerequisites:K(`${e}.needs`).split("\n").filter(Boolean),alternatives:o.map(([e,o])=>H(e,o))}}function q(e){return e.helpCommand("help [command]",U("help_command"))}export function buildProgram(){const I=new e;I.name(`${N}`).summary(U("root.summary")).description(U("root.description")).configureHelp(m()).allowExcessArguments(!0).optionsGroup(U("group.global_options")).helpOption("-h, --help",U("global.help")).version(function(){try{const e=n(a(import.meta.url));return JSON.parse(s(t(e,"../../package.json"),"utf-8")).version}catch{return"1.0.0"}}(),"-v, --version",U("global.version")).option("--base <url>",U("global.base")).option("--non-interactive",U("global.non_interactive")).option("--json",U("global.json")).option("-y, --yes",U("global.yes")).option("--dry-run",U("global.dry_run")).option("--no-color",U("global.no_color")),I.configureOutput({writeErr:()=>{},outputError:()=>{}}),I.showSuggestionAfterError(),I.exitOverride(e=>{throw e}),I.commandsGroup(U("group.configure"));const K=I.command("setup").summary(U("setup.summary")).description(U("setup.description")).option("--key <key>",U("setup.opt.key"));for(const e of z){const s=new o(`--${e.option} <key>`,U(`setup.opt.${e.option}`));e.hidden&&s.hideHelp(),K.addOption(s)}K.option("--1m",U("setup.opt.one_m")).option("--no-1m",U("setup.opt.no_one_m")).option("--claude-official <on|off>",U("setup.opt.claude_official")).option("--desktop-registry <on|off>",U("setup.opt.desktop_registry")).option("--force",U("setup.opt.force")).option("--install",U("setup.opt.install")).option("--no-install",U("setup.opt.no_install")).option("--all",U("setup.opt.all")).action(async e=>{e.key||z.some(o=>e[o.option])||(e.key=L("SETUP_KEY")?.trim()||void 0,e.fromInstaller=Boolean(e.key));const o=Boolean(e.key||z.some(o=>e[o.option])),s=void 0!==e["1m"]||void 0!==e.claudeOfficial||void 0!==e.desktopRegistry,t=i.t("errors.key_placeholder");if(!o&&!s)throw R(i.t("setup.usage"),`${N} setup --key ${t}`,"missing_key");if(void 0!==e.claudeOfficial&&!["on","off"].includes(String(e.claudeOfficial).toLowerCase()))throw R(i.t("setup.claude_official_invalid",{value:String(e.claudeOfficial)}),`${N} setup --claude-official on|off`,"invalid_value");if(void 0!==e.desktopRegistry&&!["on","off"].includes(String(e.desktopRegistry).toLowerCase()))throw R(i.t("setup.desktop_registry_invalid",{value:String(e.desktopRegistry)}),`${N} setup --desktop-registry on|off`,"invalid_value");await G({key:e.key,...Object.fromEntries(z.map(o=>[o.option,e[o.option]])),all:e.all,oneMillion:e["1m"],claudeOfficial:e.claudeOfficial,desktopRegistry:e.desktopRegistry,force:e.force,install:e.install,fromInstaller:e.fromInstaller})}),p(K,{...M("setup",[[`${N} init`,"setup.alt.init"],[`${N} config <tool>`,"setup.alt.config"],[`${N} auth <key>`,"setup.alt.auth"]]),sections:[{title:U("setup.autodetect_title"),rows:[["Claude",U("setup.autodetect.claude")],["GPT",U("setup.autodetect.gpt")],["Grok",U("setup.autodetect.grok")],["Gemini",U("setup.autodetect.gemini")]]}],examples:[H(`${N} setup --key sk-xxx`,"setup.ex.key"),H(`${N} setup --install --key sk-xxx`,"setup.ex.install"),H(`${N} setup --claudekey sk-a --codexkey sk-b --agykey sk-g`,"setup.ex.split"),H(`${N} setup --force --key sk-xxx`,"setup.ex.force"),H(`${N} setup --base ${P} --key sk-xxx`,"setup.ex.base")]});const D=I.command("init").summary(U("init.summary")).description(U("init.description")).action(async()=>{B(),await r.runFirstTimeSetup()});p(D,{...M("init",[[`${N} setup --key <key>`,"init.alt.setup"],[`${N}`,"init.alt.menu"]]),examples:[H(`${N} init`,"init.ex.run"),H(`${N} init --base ${P}`,"init.ex.base"),H(`${N}`,"init.ex.menu")]});const F=I.command("auth").summary(U("auth.summary")).description(U("auth.description")).argument("[token]",U("auth.arg.token")).action(async e=>{const o=[];e&&o.push(e),await d(o)});q(F);const J=F.command("revoke").description(U("auth.revoke")).action(async()=>{await d(["revoke"])});p(J,{examples:[H(`${N} auth revoke`,"auth.ex.revoke_ask"),H(`${N} auth revoke --yes`,"auth.ex.revoke")]});const Y=F.command("reload <tool>").description(U("auth.reload")).action(async e=>{await d(["reload",e])});p(Y,{examples:[H(`${N} auth reload claude-code`,"auth.ex.reload"),H(`${N} auth reload claude-code --json`,"auth.ex.reload_json")]}),p(F,{...M("auth",[[`${N} setup --key <key>`,"auth.alt.setup"]]),examples:[H(`${N} auth`,"auth.ex.prompt"),H(`${N} auth sk-xxx --non-interactive`,"auth.ex.save"),H(`${N} auth revoke --yes`,"auth.ex.revoke"),H(`${N} auth reload claude-code`,"auth.ex.reload")]});const Q=I.command("config").summary(U("config.summary")).description(U("config.description")).argument("[args...]",U("config.arg.args")).option("-f, --force",U("config.opt.force")).allowUnknownOption(!0).action(async(e=[],o={})=>{await g(o.force?[...e,"--force"]:e)});p(Q,{...M("config",[[`${N} setup --force --key <key>`,"config.alt.setup"],[`${N} status`,"config.alt.status"]]),sections:[{title:U("config.subcommands_title"),rows:[["<tool>",U("config.sub.tool")],["<tool> --force",U("config.sub.tool_force")],["<tool> --non-interactive",U("config.sub.tool_non_interactive")],["<tool> remove",U("config.sub.tool_remove")],["<tool> restore",U("config.sub.tool_restore")],["<tool> backups",U("config.sub.tool_backups")],["<tool> clear-model",U("config.sub.tool_clear_model")],["tool-model list",U("config.sub.tool_model_list")],["tool-model set <tool> [slot] <model>",U("config.sub.tool_model_set")],["tool-model clear <tool>",U("config.sub.tool_model_clear")],["profile list",U("config.sub.profile_list")],["profile create <name>",U("config.sub.profile_create")],["profile use <name>",U("config.sub.profile_use")],["profile delete <name>",U("config.sub.profile_delete")],["preset list",U("config.sub.preset_list")],["preset save <name>",U("config.sub.preset_save")],["preset use <name>",U("config.sub.preset_use")],["preset delete <name>",U("config.sub.preset_delete")],["backup list",U("config.sub.backup_list")],["backup create [label]",U("config.sub.backup_create")],["backup restore <name>",U("config.sub.backup_restore")]]},{title:U("config.tools_title"),rows:Object.values(c).filter(e=>!e.hidden).map(e=>[e.name,e.displayName])}],examples:[H(`${N} config codex`,"config.ex.menu"),H(`${N} config claude-code --force`,"config.ex.force"),H(`${N} config tool-model set codex gpt-6-astra`,"config.ex.tool_model"),H(`${N} config profile create work`,"config.ex.profile"),H(`${N} config codex remove`,"config.ex.remove")]});const V=I.command("base").summary(U("base.summary")).description(U("base.description")).argument("[target]",U("base.arg.target")).action(async e=>{await C(e)});p(V,{...M("base",[[`${N} doctor`,"base.alt.doctor"],[`${N} bench`,"base.alt.bench"]]),sections:[{title:U("base.targets_title"),rows:[[U("base.target.none_term"),U("base.target.none")],[U("base.target.index_term"),U("base.target.index")],[U("base.target.url_term"),U("base.target.url")],["auto",U("base.target.auto")],["default",U("base.target.default",{url:l})]]}],examples:[H(`${N} base`,"base.ex.list"),H(`${N} base auto`,"base.ex.auto"),H(`${N} base 2`,"base.ex.index"),H(`${N} base ${P}`,"base.ex.url"),H(`${N} base default`,"base.ex.default")]}),I.commandsGroup(U("group.diagnose"));const W=I.command("status").summary(U("status.summary")).description(U("status.description")).action(async()=>{await x()});p(W,{...M("status",[[`${N} doctor`,"status.alt.doctor"]]),examples:[H(`${N} status`,"status.ex.show"),H(`${N} status --json`,"status.ex.json")]});const X=I.command("doctor").summary(U("doctor.summary")).description(U("doctor.description")).option("--deep",U("doctor.opt.deep")).option("--report",U("doctor.opt.report")).action(async e=>{await f({deep:e.deep,report:e.report})});p(X,{...M("doctor",[[`${N} base auto`,"doctor.alt.base"],[`${N} logs tail`,"doctor.alt.logs"]]),examples:[H(`${N} doctor`,"doctor.ex.run"),H(`${N} doctor --deep`,"doctor.ex.deep"),H(`${N} doctor --report`,"doctor.ex.report")]});const Z=I.command("bench").summary(U("bench.summary")).description(U("bench.description")).option("--samples <n>",U("bench.opt.samples"),"5").option("--stream",U("bench.opt.stream")).option("--model <model>",U("bench.opt.model")).action(async e=>{const o=[];e.samples&&o.push("--samples",e.samples),e.stream&&o.push("--stream"),e.model&&o.push("--model",e.model),await b(o)});p(Z,{...M("bench",[[`${N} base`,"bench.alt.base"]]),examples:[H(`${N} bench`,"bench.ex.run"),H(`${N} bench --samples 3`,"bench.ex.samples"),H(`${N} bench --stream`,"bench.ex.stream"),H(`${N} bench --stream --model gpt-6-astra`,"bench.ex.stream_model"),H(`${N} bench --json`,"bench.ex.json")]});const ee=I.command("logs").summary(U("logs.summary")).description(U("logs.description")).argument("[action]",U("logs.arg.action")).argument("[file]",U("logs.arg.file")).action(async(e,o)=>{const s=[];e&&s.push(e),o&&s.push(o),await $(s)});p(ee,{...M("logs",[[`${N} doctor`,"logs.alt.doctor"]]),sections:[{title:U("logs.actions_title"),rows:[["list",U("logs.action.list")],["tail [file]",U("logs.action.tail")],["path",U("logs.action.path")]]}],examples:[H(`${N} logs`,"logs.ex.list"),H(`${N} logs tail`,"logs.ex.tail"),H(`${N} logs path`,"logs.ex.path")]}),I.commandsGroup(U("group.maintain"));const oe=I.command("list").summary(U("list.summary")).description(U("list.description")).option("--refresh",U("list.opt.refresh")).action(async(e={})=>{await v({refresh:e.refresh})});p(oe,{...M("list",[[`${N} doctor`,"list.alt.doctor"]]),examples:[H(`${N} list`,"list.ex.all"),H(`${N} list --refresh`,"list.ex.refresh"),H(`${N} list --json`,"list.ex.json")]});const se=I.command("install").summary(U("install.summary")).description(U("install.description")).argument("<components...>",U("install.arg.components")).option("--force",U("install.opt.force")).action(async(e,o={})=>{await w(e,{force:o.force})});p(se,{...M("install",[[`${N} upgrade`,"install.alt.upgrade"],[`${N} setup --key ${i.t("errors.key_placeholder")}`,"install.alt.setup"]]),examples:[H(`${N} install node uv`,"install.ex.runtimes"),H(`${N} install claude-code codex`,"install.ex.clis"),H(`${N} install chatgpt`,"install.ex.app"),H(`${N} install uv --force`,"install.ex.force"),H(`${N} install node uv --yes --json`,"install.ex.json")]});const te=I.command("upgrade").summary(U("upgrade.summary")).description(U("upgrade.description")).argument("[tools...]",U("upgrade.arg.tools")).option("--force",U("upgrade.opt.force")).action(async(e=[],o={})=>{await _(e,{force:o.force})});p(te,{...M("upgrade",[[`${N} update`,"upgrade.alt.update"]]),examples:[H(`${N} upgrade`,"upgrade.ex.all"),H(`${N} upgrade codex agy`,"upgrade.ex.many"),H(`${N} upgrade claude-desktop`,"upgrade.ex.desktop"),H(`${N} upgrade chatgpt --force`,"upgrade.ex.force"),H(`${N} upgrade node`,"upgrade.ex.runtime")]});const ne=I.command("refresh").summary(U("refresh.summary")).description(U("refresh.description")).action(async()=>{await h()});p(ne,{...M("refresh",[[`${N} setup --key ${i.t("errors.key_placeholder")}`,"refresh.alt.setup"]]),examples:[H(`${N} refresh`,"refresh.ex.run"),H(`${N} refresh --base ${T}`,"refresh.ex.base")]});const ae=I.command("update").summary(U("update.summary")).description(U("update.description")).action(async()=>{await k()});p(ae,{...M("update",[[`${N} upgrade`,"update.alt.upgrade"]]),examples:[H(`${N} update`,"update.ex.check"),H(`${N} update --json`,"update.ex.json")]});const ie=I.command("codex").summary(U("codex.summary")).description(U("codex.description"));q(ie);const re=ie.command("sessions").summary(U("codex_sessions.summary")).description(U("codex_sessions.description")).option("--to <provider>",U("codex_sessions.opt.to")).option("--undo <dir>",U("codex_sessions.opt.undo")).action(async e=>{await j(e)});p(ie,{...M("codex"),examples:[H(`${N} codex sessions`,"codex_sessions.ex.move"),H(`${N} codex sessions --undo <dir>`,"codex_sessions.ex.undo")]}),p(re,{...M("codex_sessions",[[`${N} codex sessions --undo <dir>`,"codex_sessions.alt.undo"]]),examples:[H(`${N} codex sessions`,"codex_sessions.ex.move"),H(`${N} codex sessions --to custom`,"codex_sessions.ex.to"),H(`${N} codex sessions --undo <dir>`,"codex_sessions.ex.undo")]});const ce=I.command("sessions").summary(U("sessions.summary")).description(U("sessions.description"));q(ce);const le=ce.command("list",{isDefault:!0}).description(U("sessions.list")).option("--tool <tool>",U("sessions.opt.tool")).option("--dir <path>",U("sessions.opt.dir")).option("--here",U("sessions.opt.here")).option("-n, --limit <count>",U("sessions.opt.limit")).option("--all",U("sessions.opt.all")).action(async e=>{await S(e)}),pe=ce.command("show <id>").description(U("sessions.show")).option("-m, --messages <count>",U("sessions.opt.messages")).action(async(e,o)=>{await E(e,o)}),me=ce.command("resume <id>").description(U("sessions.resume")).option("--run",U("sessions.opt.run")).action(async(e,o)=>{await A(e,o)}),ue=ce.command("export <ids...>").description(U("sessions.export")).option("-o, --output <dir>",U("sessions.opt.output")).option("--tools",U("sessions.opt.tools")).action(async(e,o)=>{await O(e,o)});p(le,{examples:[H(`${N} sessions list`,"sessions.ex.list"),H(`${N} sessions list --tool codex`,"sessions.ex.codex"),H(`${N} sessions list --here --all`,"sessions.ex.here"),H(`${N} sessions list --json`,"sessions.ex.json")]}),p(pe,{examples:[H(`${N} sessions show 01a0f5fe`,"sessions.ex.show"),H(`${N} sessions show 01a0f5fe -m 20`,"sessions.ex.show_more")]}),p(me,{examples:[H(`${N} sessions resume 01a0f5fe`,"sessions.ex.resume_print"),H(`${N} sessions resume 01a0f5fe --run`,"sessions.ex.resume")]}),p(ue,{examples:[H(`${N} sessions export 01a0f5fe 7c2e9d41 -o ./sessions`,"sessions.ex.export"),H(`${N} sessions export 01a0f5fe -o ./sessions --tools`,"sessions.ex.export_tools")]}),p(ce,{...M("sessions",[[`${N} codex sessions`,"sessions.alt.codex_sessions"]]),examples:[H(`${N} sessions`,"sessions.ex.list"),H(`${N} sessions --tool codex --here`,"sessions.ex.here"),H(`${N} sessions show 01a0f5fe`,"sessions.ex.show"),H(`${N} sessions resume 01a0f5fe --run`,"sessions.ex.resume"),H(`${N} sessions export 01a0f5fe 7c2e9d41 -o ./sessions`,"sessions.ex.export")]});const de=I.command("lang").summary(U("lang.summary")).description(U("lang.description"));q(de);const fe=de.command("show").description(U("lang.show")).action(async()=>{await u(["show"])}),ge=de.command("set <locale>").description(U("lang.set")).action(async e=>{await u(["set",e])}),xe=[H(`${N} lang show`,"lang.ex.show"),H(`${N} lang set en_US`,"lang.ex.set_en"),H(`${N} lang set zh_CN`,"lang.ex.set_zh")];p(de,{...M("lang",[[`${N} enter lang`,"lang.alt.enter"]]),examples:xe}),p(fe,{examples:[xe[0],H(`${N} lang show --json`,"lang.ex.show_json")]}),p(ge,{examples:xe.slice(1)});const he=I.command("completion").summary(U("completion.summary")).description(U("completion.description")).argument("<shell>",U("completion.arg.shell")).action(async e=>{await y([e])});p(he,{...M("completion"),examples:[H(`${N} completion bash > ~/.${N}-completion.bash`,"completion.ex.bash"),H(`${N} completion zsh > ~/.${N}-completion.zsh`,"completion.ex.zsh"),H(`${N} completion fish > ~/.config/fish/completions/${N}.fish`,"completion.ex.fish")]});const $e=I.command("enter").summary(U("enter.summary")).description(U("enter.description")).argument("[option]",U("enter.arg.option")).action(async e=>{if(e&&!["lang","language","apikey","api-key","models"].includes(e)||B(),e)switch(e){case"lang":case"language":await r.configLanguage();break;case"apikey":case"api-key":await r.configApiKey();break;case"models":await r.configModels();break;default:await g([e])}else await r.run()});p($e,{...M("enter",[[`${N}`,"enter.alt.menu"],[`${N} config <tool>`,"enter.alt.config"]]),sections:[{title:U("enter.options_title"),rows:[[U("enter.option.none_term"),U("enter.option.none")],["lang",U("enter.option.lang")],["apikey",U("enter.option.apikey")],["models",U("enter.option.models")],["<tool>",U("enter.option.tool")]]}],examples:[H(`${N} enter`,"enter.ex.menu"),H(`${N} enter models`,"enter.ex.models"),H(`${N} enter codex`,"enter.ex.tool")]}),q(I),I.action(async()=>{B(),await r.run()}),p(I,{examples:[H(`${N}`,"root.ex.menu"),H(`${N} setup --key sk-xxx`,"root.ex.setup"),H(`${N} doctor`,"root.ex.doctor"),H(`${N} base auto`,"root.ex.base"),H(`${N} config codex`,"root.ex.config")]});const ye=e=>{for(const o of e.commands)o.helpOption("-h, --help",U("global.help")),ye(o)};return ye(I),I}
|
|
1
|
+
import{Command as e,Option as o}from"commander";import{readFileSync as s}from"fs";import{join as t,dirname as n}from"path";import{fileURLToPath as a}from"url";import{i18n as i}from"./i18n.js";import{wizard as r}from"./wizard.js";import{SUPPORTED_TOOLS as c}from"./tool-manager.js";import{DEFAULT_BASE_URL as l}from"./config.js";import{attachCommandHelp as p,helpConfiguration as m}from"./cli-help.js";import{langCommand as u,authCommand as d,doctorCommand as f,configCommand as g,statusCommand as x,refreshCommand as h}from"../commands/index.js";import{logsCommand as y}from"../commands/logs.js";import{completionCommand as $}from"../commands/completion.js";import{benchCommand as b}from"../commands/bench.js";import{updateCommand as k}from"../commands/update.js";import{upgradeCommand as _}from"../commands/upgrade.js";import{installCommand as w,listCommand as v}from"../commands/components.js";import{codexSessionsCommand as j}from"../commands/codex-sessions.js";import{sessionsExportCommand as O,sessionsListCommand as S,sessionsResumeCommand as A,sessionsShowCommand as E}from"../commands/sessions.js";import{setupCommand as G,DEDICATED_KEYS as z}from"../commands/setup.js";import{baseCommand as C}from"../commands/base.js";import{usageError as R}from"./errors.js";import{requireTerminal as B}from"./confirm.js";import{brand as I,brandEnv as L,CLI_NAME as N}from"./brand.js";const P=(I().gatewayAddresses[1]??I().gatewayAddresses[0]).url,T=(I().gatewayAddresses[2]??I().gatewayAddresses[0]).url;function U(e,o){return i.t(`help.${e}`,o)}function H(e,o){return{command:e,note:U(o)}}function K(e){const o=U(e);return o===`help.${e}`?"":o}function M(e,o=[]){return{when:K(`${e}.when`),prerequisites:K(`${e}.needs`).split("\n").filter(Boolean),alternatives:o.map(([e,o])=>H(e,o))}}function q(e){return e.helpCommand("help [command]",U("help_command"))}export function buildProgram(){const I=new e;I.name(`${N}`).summary(U("root.summary")).description(U("root.description")).configureHelp(m()).allowExcessArguments(!0).optionsGroup(U("group.global_options")).helpOption("-h, --help",U("global.help")).version(function(){try{const e=n(a(import.meta.url));return JSON.parse(s(t(e,"../../package.json"),"utf-8")).version}catch{return"1.0.0"}}(),"-v, --version",U("global.version")).option("--base <url>",U("global.base")).option("--non-interactive",U("global.non_interactive")).option("--json",U("global.json")).option("-y, --yes",U("global.yes")).option("--dry-run",U("global.dry_run")).option("--no-color",U("global.no_color")),I.configureOutput({writeErr:()=>{},outputError:()=>{}}),I.showSuggestionAfterError(),I.exitOverride(e=>{throw e}),I.commandsGroup(U("group.configure"));const K=I.command("setup").summary(U("setup.summary")).description(U("setup.description")).option("--key <key>",U("setup.opt.key"));for(const e of z){const s=new o(`--${e.option} <key>`,U(`setup.opt.${e.option}`));e.hidden&&s.hideHelp(),K.addOption(s)}K.option("--1m",U("setup.opt.one_m")).option("--no-1m",U("setup.opt.no_one_m")).option("--claude-official <on|off>",U("setup.opt.claude_official")).option("--desktop-registry <on|off>",U("setup.opt.desktop_registry")).option("--force",U("setup.opt.force")).option("--install",U("setup.opt.install")).option("--no-install",U("setup.opt.no_install")).option("--all",U("setup.opt.all")).action(async e=>{e.key||z.some(o=>e[o.option])||(e.key=L("SETUP_KEY")?.trim()||void 0,e.fromInstaller=Boolean(e.key));const o=Boolean(e.key||z.some(o=>e[o.option])),s=void 0!==e["1m"]||void 0!==e.claudeOfficial||void 0!==e.desktopRegistry,t=i.t("errors.key_placeholder");if(!o&&!s)throw R(i.t("setup.usage"),`${N} setup --key ${t}`,"missing_key");if(void 0!==e.claudeOfficial&&!["on","off"].includes(String(e.claudeOfficial).toLowerCase()))throw R(i.t("setup.claude_official_invalid",{value:String(e.claudeOfficial)}),`${N} setup --claude-official on|off`,"invalid_value");if(void 0!==e.desktopRegistry&&!["on","off"].includes(String(e.desktopRegistry).toLowerCase()))throw R(i.t("setup.desktop_registry_invalid",{value:String(e.desktopRegistry)}),`${N} setup --desktop-registry on|off`,"invalid_value");await G({key:e.key,...Object.fromEntries(z.map(o=>[o.option,e[o.option]])),all:e.all,oneMillion:e["1m"],claudeOfficial:e.claudeOfficial,desktopRegistry:e.desktopRegistry,force:e.force,install:e.install,fromInstaller:e.fromInstaller})}),p(K,{...M("setup",[[`${N} init`,"setup.alt.init"],[`${N} config <tool>`,"setup.alt.config"],[`${N} auth <key>`,"setup.alt.auth"]]),sections:[{title:U("setup.autodetect_title"),rows:[["Claude",U("setup.autodetect.claude")],["GPT",U("setup.autodetect.gpt")],["Grok",U("setup.autodetect.grok")],["Gemini",U("setup.autodetect.gemini")],[U("setup.autodetect.any_label"),U("setup.autodetect.any")]]}],examples:[H(`${N} setup --key sk-xxx`,"setup.ex.key"),H(`${N} setup --install --key sk-xxx`,"setup.ex.install"),H(`${N} setup --claudekey sk-a --codexkey sk-b --agykey sk-g`,"setup.ex.split"),H(`${N} setup --force --key sk-xxx`,"setup.ex.force"),H(`${N} setup --base ${P} --key sk-xxx`,"setup.ex.base")]});const D=I.command("init").summary(U("init.summary")).description(U("init.description")).action(async()=>{B(),await r.runFirstTimeSetup()});p(D,{...M("init",[[`${N} setup --key <key>`,"init.alt.setup"],[`${N}`,"init.alt.menu"]]),examples:[H(`${N} init`,"init.ex.run"),H(`${N} init --base ${P}`,"init.ex.base"),H(`${N}`,"init.ex.menu")]});const F=I.command("auth").summary(U("auth.summary")).description(U("auth.description")).argument("[token]",U("auth.arg.token")).action(async e=>{const o=[];e&&o.push(e),await d(o)});q(F);const J=F.command("revoke").description(U("auth.revoke")).action(async()=>{await d(["revoke"])});p(J,{examples:[H(`${N} auth revoke`,"auth.ex.revoke_ask"),H(`${N} auth revoke --yes`,"auth.ex.revoke")]});const Y=F.command("reload <tool>").description(U("auth.reload")).action(async e=>{await d(["reload",e])});p(Y,{examples:[H(`${N} auth reload claude-code`,"auth.ex.reload"),H(`${N} auth reload claude-code --json`,"auth.ex.reload_json")]}),p(F,{...M("auth",[[`${N} setup --key <key>`,"auth.alt.setup"]]),examples:[H(`${N} auth`,"auth.ex.prompt"),H(`${N} auth sk-xxx --non-interactive`,"auth.ex.save"),H(`${N} auth revoke --yes`,"auth.ex.revoke"),H(`${N} auth reload claude-code`,"auth.ex.reload")]});const Q=I.command("config").summary(U("config.summary")).description(U("config.description")).argument("[args...]",U("config.arg.args")).option("-f, --force",U("config.opt.force")).allowUnknownOption(!0).action(async(e=[],o={})=>{await g(o.force?[...e,"--force"]:e)});p(Q,{...M("config",[[`${N} setup --force --key <key>`,"config.alt.setup"],[`${N} status`,"config.alt.status"]]),sections:[{title:U("config.subcommands_title"),rows:[["<tool>",U("config.sub.tool")],["<tool> --force",U("config.sub.tool_force")],["<tool> --non-interactive",U("config.sub.tool_non_interactive")],["<tool> remove",U("config.sub.tool_remove")],["<tool> restore",U("config.sub.tool_restore")],["<tool> backups",U("config.sub.tool_backups")],["<tool> clear-model",U("config.sub.tool_clear_model")],["tool-model list",U("config.sub.tool_model_list")],["tool-model set <tool> [slot] <model>",U("config.sub.tool_model_set")],["tool-model clear <tool>",U("config.sub.tool_model_clear")],["profile list",U("config.sub.profile_list")],["profile create <name>",U("config.sub.profile_create")],["profile use <name>",U("config.sub.profile_use")],["profile delete <name>",U("config.sub.profile_delete")],["preset list",U("config.sub.preset_list")],["preset save <name>",U("config.sub.preset_save")],["preset use <name>",U("config.sub.preset_use")],["preset delete <name>",U("config.sub.preset_delete")],["backup list",U("config.sub.backup_list")],["backup create [label]",U("config.sub.backup_create")],["backup restore <name>",U("config.sub.backup_restore")]]},{title:U("config.tools_title"),rows:Object.values(c).filter(e=>!e.hidden).map(e=>[e.name,e.displayName])}],examples:[H(`${N} config codex`,"config.ex.menu"),H(`${N} config claude-code --force`,"config.ex.force"),H(`${N} config tool-model set codex gpt-6-astra`,"config.ex.tool_model"),H(`${N} config profile create work`,"config.ex.profile"),H(`${N} config codex remove`,"config.ex.remove")]});const V=I.command("base").summary(U("base.summary")).description(U("base.description")).argument("[target]",U("base.arg.target")).action(async e=>{await C(e)});p(V,{...M("base",[[`${N} doctor`,"base.alt.doctor"],[`${N} bench`,"base.alt.bench"]]),sections:[{title:U("base.targets_title"),rows:[[U("base.target.none_term"),U("base.target.none")],[U("base.target.index_term"),U("base.target.index")],[U("base.target.url_term"),U("base.target.url")],["auto",U("base.target.auto")],["default",U("base.target.default",{url:l})]]}],examples:[H(`${N} base`,"base.ex.list"),H(`${N} base auto`,"base.ex.auto"),H(`${N} base 2`,"base.ex.index"),H(`${N} base ${P}`,"base.ex.url"),H(`${N} base default`,"base.ex.default")]}),I.commandsGroup(U("group.diagnose"));const W=I.command("status").summary(U("status.summary")).description(U("status.description")).action(async()=>{await x()});p(W,{...M("status",[[`${N} doctor`,"status.alt.doctor"]]),examples:[H(`${N} status`,"status.ex.show"),H(`${N} status --json`,"status.ex.json")]});const X=I.command("doctor").summary(U("doctor.summary")).description(U("doctor.description")).option("--deep",U("doctor.opt.deep")).option("--report",U("doctor.opt.report")).action(async e=>{await f({deep:e.deep,report:e.report})});p(X,{...M("doctor",[[`${N} base auto`,"doctor.alt.base"],[`${N} logs tail`,"doctor.alt.logs"]]),examples:[H(`${N} doctor`,"doctor.ex.run"),H(`${N} doctor --deep`,"doctor.ex.deep"),H(`${N} doctor --report`,"doctor.ex.report")]});const Z=I.command("bench").summary(U("bench.summary")).description(U("bench.description")).option("--samples <n>",U("bench.opt.samples"),"5").option("--stream",U("bench.opt.stream")).option("--model <model>",U("bench.opt.model")).action(async e=>{const o=[];e.samples&&o.push("--samples",e.samples),e.stream&&o.push("--stream"),e.model&&o.push("--model",e.model),await b(o)});p(Z,{...M("bench",[[`${N} base`,"bench.alt.base"]]),examples:[H(`${N} bench`,"bench.ex.run"),H(`${N} bench --samples 3`,"bench.ex.samples"),H(`${N} bench --stream`,"bench.ex.stream"),H(`${N} bench --stream --model gpt-6-astra`,"bench.ex.stream_model"),H(`${N} bench --json`,"bench.ex.json")]});const ee=I.command("logs").summary(U("logs.summary")).description(U("logs.description")).argument("[action]",U("logs.arg.action")).argument("[file]",U("logs.arg.file")).action(async(e,o)=>{const s=[];e&&s.push(e),o&&s.push(o),await y(s)});p(ee,{...M("logs",[[`${N} doctor`,"logs.alt.doctor"]]),sections:[{title:U("logs.actions_title"),rows:[["list",U("logs.action.list")],["tail [file]",U("logs.action.tail")],["path",U("logs.action.path")]]}],examples:[H(`${N} logs`,"logs.ex.list"),H(`${N} logs tail`,"logs.ex.tail"),H(`${N} logs path`,"logs.ex.path")]}),I.commandsGroup(U("group.maintain"));const oe=I.command("list").summary(U("list.summary")).description(U("list.description")).option("--refresh",U("list.opt.refresh")).action(async(e={})=>{await v({refresh:e.refresh})});p(oe,{...M("list",[[`${N} doctor`,"list.alt.doctor"]]),examples:[H(`${N} list`,"list.ex.all"),H(`${N} list --refresh`,"list.ex.refresh"),H(`${N} list --json`,"list.ex.json")]});const se=I.command("install").summary(U("install.summary")).description(U("install.description")).argument("<components...>",U("install.arg.components")).option("--force",U("install.opt.force")).action(async(e,o={})=>{await w(e,{force:o.force})});p(se,{...M("install",[[`${N} upgrade`,"install.alt.upgrade"],[`${N} setup --key ${i.t("errors.key_placeholder")}`,"install.alt.setup"]]),examples:[H(`${N} install node uv`,"install.ex.runtimes"),H(`${N} install claude-code codex`,"install.ex.clis"),H(`${N} install chatgpt`,"install.ex.app"),H(`${N} install uv --force`,"install.ex.force"),H(`${N} install node uv --yes --json`,"install.ex.json")]});const te=I.command("upgrade").summary(U("upgrade.summary")).description(U("upgrade.description")).argument("[tools...]",U("upgrade.arg.tools")).option("--force",U("upgrade.opt.force")).action(async(e=[],o={})=>{await _(e,{force:o.force})});p(te,{...M("upgrade",[[`${N} update`,"upgrade.alt.update"]]),examples:[H(`${N} upgrade`,"upgrade.ex.all"),H(`${N} upgrade codex agy`,"upgrade.ex.many"),H(`${N} upgrade claude-desktop`,"upgrade.ex.desktop"),H(`${N} upgrade chatgpt --force`,"upgrade.ex.force"),H(`${N} upgrade node`,"upgrade.ex.runtime")]});const ne=I.command("refresh").summary(U("refresh.summary")).description(U("refresh.description")).action(async()=>{await h()});p(ne,{...M("refresh",[[`${N} setup --key ${i.t("errors.key_placeholder")}`,"refresh.alt.setup"]]),examples:[H(`${N} refresh`,"refresh.ex.run"),H(`${N} refresh --base ${T}`,"refresh.ex.base")]});const ae=I.command("update").summary(U("update.summary")).description(U("update.description")).action(async()=>{await k()});p(ae,{...M("update",[[`${N} upgrade`,"update.alt.upgrade"]]),examples:[H(`${N} update`,"update.ex.check"),H(`${N} update --json`,"update.ex.json")]});const ie=I.command("codex").summary(U("codex.summary")).description(U("codex.description"));q(ie);const re=ie.command("sessions").summary(U("codex_sessions.summary")).description(U("codex_sessions.description")).option("--to <provider>",U("codex_sessions.opt.to")).option("--undo <dir>",U("codex_sessions.opt.undo")).action(async e=>{await j(e)});p(ie,{...M("codex"),examples:[H(`${N} codex sessions`,"codex_sessions.ex.move"),H(`${N} codex sessions --undo <dir>`,"codex_sessions.ex.undo")]}),p(re,{...M("codex_sessions",[[`${N} codex sessions --undo <dir>`,"codex_sessions.alt.undo"]]),examples:[H(`${N} codex sessions`,"codex_sessions.ex.move"),H(`${N} codex sessions --to custom`,"codex_sessions.ex.to"),H(`${N} codex sessions --undo <dir>`,"codex_sessions.ex.undo")]});const ce=I.command("sessions").summary(U("sessions.summary")).description(U("sessions.description"));q(ce);const le=ce.command("list",{isDefault:!0}).description(U("sessions.list")).option("--tool <tool>",U("sessions.opt.tool")).option("--dir <path>",U("sessions.opt.dir")).option("--here",U("sessions.opt.here")).option("-n, --limit <count>",U("sessions.opt.limit")).option("--all",U("sessions.opt.all")).action(async e=>{await S(e)}),pe=ce.command("show <id>").description(U("sessions.show")).option("-m, --messages <count>",U("sessions.opt.messages")).action(async(e,o)=>{await E(e,o)}),me=ce.command("resume <id>").description(U("sessions.resume")).option("--run",U("sessions.opt.run")).action(async(e,o)=>{await A(e,o)}),ue=ce.command("export <ids...>").description(U("sessions.export")).option("-o, --output <dir>",U("sessions.opt.output")).option("--tools",U("sessions.opt.tools")).action(async(e,o)=>{await O(e,o)});p(le,{examples:[H(`${N} sessions list`,"sessions.ex.list"),H(`${N} sessions list --tool codex`,"sessions.ex.codex"),H(`${N} sessions list --here --all`,"sessions.ex.here"),H(`${N} sessions list --json`,"sessions.ex.json")]}),p(pe,{examples:[H(`${N} sessions show 01a0f5fe`,"sessions.ex.show"),H(`${N} sessions show 01a0f5fe -m 20`,"sessions.ex.show_more")]}),p(me,{examples:[H(`${N} sessions resume 01a0f5fe`,"sessions.ex.resume_print"),H(`${N} sessions resume 01a0f5fe --run`,"sessions.ex.resume")]}),p(ue,{examples:[H(`${N} sessions export 01a0f5fe 7c2e9d41 -o ./sessions`,"sessions.ex.export"),H(`${N} sessions export 01a0f5fe -o ./sessions --tools`,"sessions.ex.export_tools")]}),p(ce,{...M("sessions",[[`${N} codex sessions`,"sessions.alt.codex_sessions"]]),examples:[H(`${N} sessions`,"sessions.ex.list"),H(`${N} sessions --tool codex --here`,"sessions.ex.here"),H(`${N} sessions show 01a0f5fe`,"sessions.ex.show"),H(`${N} sessions resume 01a0f5fe --run`,"sessions.ex.resume"),H(`${N} sessions export 01a0f5fe 7c2e9d41 -o ./sessions`,"sessions.ex.export")]});const de=I.command("lang").summary(U("lang.summary")).description(U("lang.description"));q(de);const fe=de.command("show").description(U("lang.show")).action(async()=>{await u(["show"])}),ge=de.command("set <locale>").description(U("lang.set")).action(async e=>{await u(["set",e])}),xe=[H(`${N} lang show`,"lang.ex.show"),H(`${N} lang set en_US`,"lang.ex.set_en"),H(`${N} lang set zh_CN`,"lang.ex.set_zh")];p(de,{...M("lang",[[`${N} enter lang`,"lang.alt.enter"]]),examples:xe}),p(fe,{examples:[xe[0],H(`${N} lang show --json`,"lang.ex.show_json")]}),p(ge,{examples:xe.slice(1)});const he=I.command("completion").summary(U("completion.summary")).description(U("completion.description")).argument("<shell>",U("completion.arg.shell")).action(async e=>{await $([e])});p(he,{...M("completion"),examples:[H(`${N} completion bash > ~/.${N}-completion.bash`,"completion.ex.bash"),H(`${N} completion zsh > ~/.${N}-completion.zsh`,"completion.ex.zsh"),H(`${N} completion fish > ~/.config/fish/completions/${N}.fish`,"completion.ex.fish")]});const ye=I.command("enter").summary(U("enter.summary")).description(U("enter.description")).argument("[option]",U("enter.arg.option")).action(async e=>{if(e&&!["lang","language","apikey","api-key","models"].includes(e)||B(),e)switch(e){case"lang":case"language":await r.configLanguage();break;case"apikey":case"api-key":await r.configApiKey();break;case"models":await r.configModels();break;default:await g([e])}else await r.run()});p(ye,{...M("enter",[[`${N}`,"enter.alt.menu"],[`${N} config <tool>`,"enter.alt.config"]]),sections:[{title:U("enter.options_title"),rows:[[U("enter.option.none_term"),U("enter.option.none")],["lang",U("enter.option.lang")],["apikey",U("enter.option.apikey")],["models",U("enter.option.models")],["<tool>",U("enter.option.tool")]]}],examples:[H(`${N} enter`,"enter.ex.menu"),H(`${N} enter models`,"enter.ex.models"),H(`${N} enter codex`,"enter.ex.tool")]}),q(I),I.action(async()=>{B(),await r.run()}),p(I,{examples:[H(`${N}`,"root.ex.menu"),H(`${N} setup --key sk-xxx`,"root.ex.setup"),H(`${N} doctor`,"root.ex.doctor"),H(`${N} base auto`,"root.ex.base"),H(`${N} config codex`,"root.ex.config")]});const $e=e=>{for(const o of e.commands)o.helpOption("-h, --help",U("global.help")),$e(o)};return $e(I),I}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { GatewayModelSpec } from '../model-registry.js';
|
|
2
|
+
import type { ModelCatalog } from '../model-catalog.js';
|
|
3
|
+
/**
|
|
4
|
+
* Custom models for CodeBuddy Code (`~/.codebuddy/models.json`) and WorkBuddy
|
|
5
|
+
* (`~/.workbuddy/models.json`); both run the same agent engine and read the same file format:
|
|
6
|
+
* either `{ "models": [...], "availableModels": [...] }` or a bare array (WorkBuddy's settings page
|
|
7
|
+
* writes `[]`). Each entry names its own `url` and `apiKey`; the engine speaks OpenAI Chat
|
|
8
|
+
* Completions, or the Responses API with `api: "openai-responses"` (then `url` is the base).
|
|
9
|
+
*
|
|
10
|
+
* Our entries carry `vendor: BRAND_NAME`; the user's own entries and other keys stay. We never
|
|
11
|
+
* write `availableModels`: it would hide the user's own and the built-in models.
|
|
12
|
+
*
|
|
13
|
+
* Inside the engine a custom model is `custom-local:<id>`. A bare id that is also one of the
|
|
14
|
+
* vendor's built-in models (gpt-6-astra, glm-5.3, …) resolves to the built-in one, which needs a
|
|
15
|
+
* Tencent sign-in (checked on 2.179.3); so the default model is written with the prefix.
|
|
16
|
+
*/
|
|
17
|
+
export declare const CUSTOM_MODEL_PREFIX = "custom-local:";
|
|
18
|
+
type Dict = Record<string, unknown>;
|
|
19
|
+
export declare const isOurEntry: (entry: unknown) => entry is Dict;
|
|
20
|
+
/** The file's model entries plus how to put them back (array file vs object file). */
|
|
21
|
+
interface ModelsFile {
|
|
22
|
+
entries: unknown[];
|
|
23
|
+
wrap(entries: unknown[]): unknown;
|
|
24
|
+
}
|
|
25
|
+
export declare function readModelsFile(path: string): ModelsFile;
|
|
26
|
+
export declare function writeModelsFile(path: string, file: ModelsFile, entries: unknown[]): void;
|
|
27
|
+
/** Strip Claude Code's `[1m]` window suffix: the gateway's model id has none. */
|
|
28
|
+
export declare const bareModelId: (id: string) => string;
|
|
29
|
+
/**
|
|
30
|
+
* Chat Completions unless the gateway says tool calls only work on the Responses API (GPT-6
|
|
31
|
+
* Astra / 6.1 Sol: `functionCallEndpoints: ["openai-response"]`) or the model is only served
|
|
32
|
+
* there. Without metadata (older gateway, built-in entry) GPT goes to Responses, like Codex.
|
|
33
|
+
*/
|
|
34
|
+
export declare function usesResponses(spec: GatewayModelSpec): boolean;
|
|
35
|
+
/** The engine's entry for one model, capabilities from the gateway's metadata. */
|
|
36
|
+
/**
|
|
37
|
+
* `nameIsId`: WorkBuddy shows a custom model as `name:id` unless the name equals the id, so it
|
|
38
|
+
* gets the bare id (the CLI shows the name).
|
|
39
|
+
*/
|
|
40
|
+
export declare function modelEntry(spec: GatewayModelSpec, baseUrl: string, apiKey: string, nameIsId?: boolean): Dict;
|
|
41
|
+
/**
|
|
42
|
+
* The models to write, kept short (the app lists every entry in one flat menu): the default
|
|
43
|
+
* model, the ones the gateway marks recommended, and each vendor's first model in the gateway's
|
|
44
|
+
* order (newest first) — all limited to what the key can reach (everything offline) and to
|
|
45
|
+
* models the gateway serves over an OpenAI-style interface. The default comes first, the rest
|
|
46
|
+
* keep the gateway's order; reordering or marking models in the gateway console changes the menu.
|
|
47
|
+
* When the key's owner chose models in the console (`personal`), every chosen model is written.
|
|
48
|
+
*/
|
|
49
|
+
export declare function menuSpecs(catalog: ModelCatalog | undefined, picked: string): GatewayModelSpec[];
|
|
50
|
+
/**
|
|
51
|
+
* Replace our entries with `specs`; the user's own entries keep their place. A user entry with
|
|
52
|
+
* the same id as one of ours is replaced (its id now means our model); returned as `replaced`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function mergeEntries(existing: unknown[], specs: GatewayModelSpec[], baseUrl: string, apiKey: string, nameIsId?: boolean): {
|
|
55
|
+
entries: unknown[];
|
|
56
|
+
replaced: string[];
|
|
57
|
+
};
|
|
58
|
+
/** User entries a write would replace (same id as a model we add); for the write plan. */
|
|
59
|
+
export declare function foreignIdsReplaced(existing: unknown[], specs: GatewayModelSpec[]): string[];
|
|
60
|
+
export declare function ourEntries(entries: unknown[]): Dict[];
|
|
61
|
+
export declare function ourApiKey(entries: unknown[]): string | null;
|
|
62
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as e,readFileSync as t}from"fs";import{BRAND_NAME as r}from"../brand.js";import{gatewayModelSpecs as n,modelFamily as o,prettyModelName as i,vendorNames as s}from"../gateway-models.js";import{backupBeforeWrite as a,atomicWriteFile as p}from"./backup.js";import{withV1 as d}from"./types.js";export const CUSTOM_MODEL_PREFIX="custom-local:";const u="openai",l="openai-response",c=e=>!!e&&"object"==typeof e&&!Array.isArray(e);export const isOurEntry=e=>c(e)&&e.vendor===r;export function readModelsFile(r){if(!e(r))return{entries:[],wrap:e=>({models:e})};const n=t(r,"utf-8");if(!n.trim())return{entries:[],wrap:e=>({models:e})};let o;try{o=JSON.parse(n)}catch(e){throw new Error(`Existing ${r} cannot be parsed; back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}if(Array.isArray(o))return{entries:o,wrap:e=>e};if(c(o))return{entries:Array.isArray(o.models)?o.models:[],wrap:e=>({...o,models:e})};throw new Error(`Existing ${r} must hold a JSON object or array`)}export function writeModelsFile(r,n,o){const i=`${JSON.stringify(n.wrap(o),null,2)}\n`;e(r)&&t(r,"utf-8")===i||(a(r),p(r,i,384))}export const bareModelId=e=>e.replace(/\[[^\]]*\]$/,"");export function usesResponses(e){const t=e.capabilities?.toolCallEndpoints;if(t&&t.length>0)return t.includes(l)&&!t.includes(u);const r=e.endpointTypes;if(r&&r.length>0){if(r.includes(u))return!1;if(r.includes(l))return!0}return"gpt"===o(e.id)}function f(e){const t=e.endpointTypes;return!t||0===t.length||t.includes(u)||t.includes(l)}export function modelEntry(e,t,n,s=!1){const a=e.capabilities??{},p=usesResponses(e),u=o(e.id),l={id:e.id,name:s?e.id:e.name??i(e.id),vendor:r,url:p?d(t):`${d(t)}/chat/completions`,apiKey:n};p&&(l.api="openai-responses");const c=a.contextWindow??e.contextWindow;c&&(l.maxInputTokens=c);const f=a.maxOutput??e.maxOutputTokens;return f&&(l.maxOutputTokens=f),l.supportsToolCall=a.toolCall??!0,l.supportsImages=a.vision??"other"!==u,void 0!==a.reasoning&&(l.supportsReasoning=a.reasoning),a.reasoning&&a.reasoningEfforts&&(l.reasoning={...a.defaultReasoningEffort?{defaultEffort:a.defaultReasoningEffort}:{},supportedEfforts:a.reasoningEfforts}),l}export function menuSpecs(e,t){let r=n("codebuddy",e?.clientModels,e?.clientPersonal).filter(f);if(e){const n=new Set(e.models);r=r.filter(e=>n.has(e.id)),!r.some(e=>e.id===t)&&n.has(t)&&(r=[{id:t},...r])}else r.some(e=>e.id===t)||(r=[{id:t},...r]);const o=(e?.clientPersonal??[]).length>0,i=new Set,a=r.filter(e=>{if(o)return!0;const r=s([e.id])[0],n=!i.has(r);return i.add(r),e.id===t||!0===e.recommended||n}),p=a.findIndex(e=>e.id===t);return p>0?[a[p],...a.slice(0,p),...a.slice(p+1)]:a}export function mergeEntries(e,t,r,n,o=!1){const i=new Set(t.map(e=>e.id)),s=[],a=e.filter(e=>{if(isOurEntry(e))return!1;const t=c(e)&&"string"==typeof e.id?e.id:void 0;return!t||!i.has(t)||(s.push(t),!1)});return{entries:[...t.map(e=>modelEntry(e,r,n,o)),...a],replaced:s}}export function foreignIdsReplaced(e,t){const r=new Set(t.map(e=>e.id));return e.filter(e=>!isOurEntry(e)).filter(e=>c(e)&&"string"==typeof e.id&&r.has(e.id)).map(e=>String(e.id))}export function ourEntries(e){return e.filter(isOurEntry)}export function ourApiKey(e){const t=ourEntries(e)[0]?.apiKey;return"string"==typeof t&&t.trim()?t:null}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as e,readFileSync as t}from"fs";import{join as o}from"path";import{logger as r}from"../../utils/logger.js";import{i18n as d}from"../i18n.js";import{getToolDefaultModel as n}from"../model-registry.js";import{prettyModelName as i,vendorNames as s}from"../gateway-models.js";import{backupBeforeWrite as a,atomicWriteFile as l}from"./backup.js";import{CUSTOM_MODEL_PREFIX as c,bareModelId as u,foreignIdsReplaced as m,isOurEntry as p,menuSpecs as g,mergeEntries as f,ourApiKey as y,ourEntries as b,readModelsFile as h,writeModelsFile as j}from"./codebuddy-models.js";import{pickModel as C,toolHome as v}from"./types.js";const S=()=>process.env.CODEBUDDY_CONFIG_DIR?.trim()||o(v(),".codebuddy"),w=()=>o(S(),"models.json"),E=()=>o(S(),"settings.json"),N={command:"codebuddy",npmPackage:"@tencent-ai/codebuddy-code",brew:"codebuddy-code"};function P(){if(!e(E()))return{};const o=t(E(),"utf-8");if(!o.trim())return{};let r;try{r=JSON.parse(o)}catch(e){throw new Error(`Existing ${E()} cannot be parsed; back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}if(!(d=r)||"object"!=typeof d||Array.isArray(d))throw new Error(`Existing ${E()} must hold a JSON object`);var d;return r}function $(e){a(E()),l(E(),`${JSON.stringify(e,null,2)}\n`,384)}function _(e,t){return"string"==typeof e&&e.startsWith(c)&&t.has(e.slice(c.length))}const k=e=>u(C(e.models,n("codebuddy")));function x(e,t){return e.find(e=>e.id===t)??e[0]}let A=null;function O(e,t){const o=h(w()),{entries:r,replaced:d}=f(o.entries,t,e.baseUrl,e.apiKey);return j(w(),o,r),d}export const codebuddyAdapter={name:"codebuddy",displayName:"CodeBuddy Code",command:"codebuddy",installCommand:`npm install -g ${N.npmPackage}`,installSpec:N,get configPath(){return w()},wantsModelCatalog:!0,loadPrivateConfig(e){const t=k(e),o=g(e.catalog,t),r=P(),d=O(e,o),n=x(o,t);n&&(r.model=`${c}${n.id}`,$(r));const a=e=>e.name??i(e.id);A={names:o.map(a),vendors:s(o.map(e=>e.id)),defaultName:n?a(n):"",replaced:d}},unloadPrivateConfig(){let e;try{e=h(w())}catch(e){return void r.logError("codebuddyAdapter.unloadPrivateConfig",e)}const t=new Set(b(e.entries).map(e=>String(e.id)));t.size>0&&j(w(),e,e.entries.filter(e=>!p(e)));try{const e=P();_(e.model,t)&&(delete e.model,$(e))}catch(e){r.logError("codebuddyAdapter.unloadPrivateConfig",e)}},detectCurrentConfig(){try{return{apiKey:y(h(w()).entries)}}catch{return{apiKey:null}}},listedModels(){try{const e=b(h(w()).entries);return e.length>0?e.map(e=>String(e.id)):null}catch{return null}},refreshModelMenu(e){const t=h(w()),o=new Set(b(t.entries).map(e=>String(e.id))),r=P(),d=_(r.model,o)?String(r.model).slice(c.length):void 0,n=d&&e.catalog.models.includes(d)?d:k(e),i=g(e.catalog,n);O(e,i);const s=x(i,n);if(s&&(void 0===r.model||_(r.model,o))){const e=`${c}${s.id}`;r.model!==e&&(r.model=e,$(r))}},planNotes(){try{const e=h(w()),t=m(e.entries,g(void 0,n("codebuddy")));return t.length>0?[d.t("tools.codebuddy.replaces_models",{path:w(),list:t.join(d.t("tools.codebuddy.list_separator"))})]:[]}catch{return[]}},applyNotes(){if(!A)return[];const e=[{kind:"summary",text:d.t("tools.codebuddy.menu_written",{count:String(A.names.length),list:A.vendors.join(d.t("tools.codebuddy.list_separator")),default:A.defaultName})}];return A.replaced.length>0&&e.push({kind:"detail",text:d.t("tools.codebuddy.replaced_models",{tool:"codebuddy",list:A.replaced.join(d.t("tools.codebuddy.list_separator"))})}),e},backupPaths:()=>[w(),E()],forceResetPaths:()=>[w()],getConfig(){try{return{models:h(w()).entries,settings:P()}}catch(e){return r.logError("codebuddyAdapter.getConfig",e),null}}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{claudeCodeAdapter as o}from"./claude-code.js";import{opencodeAdapter as r}from"./opencode.js";import{codexAdapter as t}from"./codex.js";import{openclawAdapter as m}from"./openclaw.js";import{hermesAdapter as e}from"./hermes.js";import{atomcodeAdapter as p}from"./atomcode.js";import{grokAdapter as s}from"./grok.js";import{claudeDesktopAdapter as i}from"./claude-desktop.js";import{antigravityAdapter as
|
|
1
|
+
import{claudeCodeAdapter as o}from"./claude-code.js";import{opencodeAdapter as r}from"./opencode.js";import{codexAdapter as t}from"./codex.js";import{openclawAdapter as m}from"./openclaw.js";import{hermesAdapter as e}from"./hermes.js";import{atomcodeAdapter as p}from"./atomcode.js";import{grokAdapter as s}from"./grok.js";import{claudeDesktopAdapter as i}from"./claude-desktop.js";import{antigravityAdapter as d}from"./antigravity.js";import{codebuddyAdapter as f}from"./codebuddy.js";import{workbuddyAdapter as c}from"./workbuddy.js";const n=[o,r,t,m,e,p,s,i,d,f,c];export const TOOL_ADAPTERS=Object.fromEntries(n.map(o=>[o.name,o]));export function getAdapter(o){return TOOL_ADAPTERS[o]}export function listAdapters(){return[...n]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as t}from"fs";import{join as r}from"path";import{logger as o}from"../../utils/logger.js";import{i18n as e}from"../i18n.js";import{getToolDefaultModel as n}from"../model-registry.js";import{prettyModelName as d,vendorNames as s}from"../gateway-models.js";import{bareModelId as i,foreignIdsReplaced as a,isOurEntry as l,menuSpecs as p,mergeEntries as u,ourApiKey as c,ourEntries as m,readModelsFile as y,writeModelsFile as g}from"./codebuddy-models.js";import{pickModel as f,toolHome as b}from"./types.js";const k=()=>process.env.WORKBUDDY_CONFIG_DIR?.trim()||process.env.CODEBUDDY_CONFIG_DIR?.trim()||r(b(),".workbuddy"),w=()=>r(k(),"models.json"),h="https://www.codebuddy.cn/work/";let C=null;function _(t,r){const o=y(w()),{entries:e,replaced:n}=u(o.entries,r,t.baseUrl,t.apiKey,!0);return g(w(),o,e),n}const j=t=>i(f(t.models,n("workbuddy")));export const workbuddyAdapter={name:"workbuddy",displayName:"WorkBuddy",command:"workbuddy",installCommand:"darwin"===process.platform?`open ${h}`:h,get configPath(){return w()},wantsModelCatalog:!0,isInstalled:function(){return!!t(k())||"darwin"===process.platform&&["/Applications/WorkBuddy.app",r(b(),"Applications","WorkBuddy.app")].some(r=>t(r))},loadPrivateConfig(t){const r=p(t.catalog,j(t)),o=_(t,r);C={names:r.map(t=>t.name??d(t.id)),vendors:s(r.map(t=>t.id)),replaced:o}},unloadPrivateConfig(){try{const t=y(w());if(0===m(t.entries).length)return;g(w(),t,t.entries.filter(t=>!l(t)))}catch(t){o.logError("workbuddyAdapter.unloadPrivateConfig",t)}},detectCurrentConfig(){try{return{apiKey:c(y(w()).entries)}}catch{return{apiKey:null}}},listedModels(){try{const t=m(y(w()).entries);return t.length>0?t.map(t=>String(t.id)):null}catch{return null}},refreshModelMenu(t){_(t,p(t.catalog,j(t)))},planNotes(){try{const t=y(w()),r=a(t.entries,p(void 0,n("workbuddy")));return r.length>0?[e.t("tools.codebuddy.replaces_models",{path:w(),list:r.join(e.t("tools.codebuddy.list_separator"))})]:[]}catch{return[]}},applyNotes(){if(!C)return[];const t=[{kind:"summary",text:e.t("tools.workbuddy.menu_written",{count:String(C.names.length),list:C.vendors.join(e.t("tools.codebuddy.list_separator"))})},{kind:"action",text:e.t("tools.workbuddy.pick_in_app")}];return C.replaced.length>0&&t.push({kind:"detail",text:e.t("tools.codebuddy.replaced_models",{tool:"workbuddy",list:C.replaced.join(e.t("tools.codebuddy.list_separator"))})}),t},backupPaths:()=>[w()],getConfig(){try{return y(w()).entries}catch(t){return o.logError("workbuddyAdapter.getConfig",t),null}}};
|
package/dist/locales/en_US.json
CHANGED
|
@@ -450,6 +450,16 @@
|
|
|
450
450
|
"gemini": "Gemini",
|
|
451
451
|
"other": "Chinese",
|
|
452
452
|
"grok": "Grok"
|
|
453
|
+
},
|
|
454
|
+
"codebuddy": {
|
|
455
|
+
"menu_written": "Wrote {{count}} models ({{list}}), default {{default}}",
|
|
456
|
+
"list_separator": ", ",
|
|
457
|
+
"replaces_models": "Models with the same id in {{path}} will be replaced: {{list}}",
|
|
458
|
+
"replaced_models": "Replaced models with the same id in models.json: {{list}} (undo with `{{cli}} config {{tool}} restore`)"
|
|
459
|
+
},
|
|
460
|
+
"workbuddy": {
|
|
461
|
+
"menu_written": "Wrote {{count}} models ({{list}})",
|
|
462
|
+
"pick_in_app": "Sign in to WorkBuddy, then pick a model from the Custom group of the chat model menu; an enterprise admin may have turned custom models off"
|
|
453
463
|
}
|
|
454
464
|
},
|
|
455
465
|
"upgrade": {
|
|
@@ -735,14 +745,18 @@
|
|
|
735
745
|
"force": "Back up, then rewrite each config with the recommended one (fixes broken configs)",
|
|
736
746
|
"all": "Configure every tool the API key can serve (the default)",
|
|
737
747
|
"install": "Install missing tools from the China mirrors without asking",
|
|
738
|
-
"no_install": "Only print install commands for missing tools"
|
|
748
|
+
"no_install": "Only print install commands for missing tools",
|
|
749
|
+
"codebuddykey": "API key just for CodeBuddy Code",
|
|
750
|
+
"workbuddykey": "API key just for WorkBuddy"
|
|
739
751
|
},
|
|
740
752
|
"autodetect_title": "Models the --key can use and the tools configured:",
|
|
741
753
|
"autodetect": {
|
|
742
754
|
"claude": "Claude Code, Claude Desktop (macOS / Windows: written ahead even when not installed; Linux: when installed)",
|
|
743
755
|
"gpt": "Codex",
|
|
744
756
|
"grok": "Grok Build",
|
|
745
|
-
"gemini": "Antigravity CLI"
|
|
757
|
+
"gemini": "Antigravity CLI",
|
|
758
|
+
"any_label": "Any",
|
|
759
|
+
"any": "CodeBuddy Code, WorkBuddy (only when installed)"
|
|
746
760
|
},
|
|
747
761
|
"ex": {
|
|
748
762
|
"key": "Configure every tool one API key can serve",
|
package/dist/locales/zh_CN.json
CHANGED
|
@@ -450,6 +450,16 @@
|
|
|
450
450
|
"gemini": "Gemini",
|
|
451
451
|
"other": "国产",
|
|
452
452
|
"grok": "Grok"
|
|
453
|
+
},
|
|
454
|
+
"codebuddy": {
|
|
455
|
+
"menu_written": "已写入 {{count}} 个模型({{list}}),默认 {{default}}",
|
|
456
|
+
"list_separator": "、",
|
|
457
|
+
"replaces_models": "{{path}} 里同名的模型会换成本站的:{{list}}",
|
|
458
|
+
"replaced_models": "已替换 models.json 里同名的模型:{{list}}(恢复运行 `{{cli}} config {{tool}} restore`)"
|
|
459
|
+
},
|
|
460
|
+
"workbuddy": {
|
|
461
|
+
"menu_written": "已写入 {{count}} 个模型({{list}})",
|
|
462
|
+
"pick_in_app": "在 WorkBuddy 登录后,到对话框的模型菜单「自定义模型」分组里选择;企业账号的管理员可能关闭了自定义模型"
|
|
453
463
|
}
|
|
454
464
|
},
|
|
455
465
|
"upgrade": {
|
|
@@ -735,14 +745,18 @@
|
|
|
735
745
|
"force": "先备份,再用推荐配置整份重写(用于修复改坏的配置)",
|
|
736
746
|
"all": "配置令牌能用的全部工具(默认行为)",
|
|
737
747
|
"install": "未安装的工具直接从国内镜像安装,不再询问",
|
|
738
|
-
"no_install": "未安装的工具只给出安装命令,不安装"
|
|
748
|
+
"no_install": "未安装的工具只给出安装命令,不安装",
|
|
749
|
+
"codebuddykey": "CodeBuddy Code 专属令牌",
|
|
750
|
+
"workbuddykey": "WorkBuddy 专属令牌"
|
|
739
751
|
},
|
|
740
752
|
"autodetect_title": "--key 能用的模型和自动配置的工具:",
|
|
741
753
|
"autodetect": {
|
|
742
754
|
"claude": "Claude Code、Claude Desktop(macOS、Windows 上未安装也会提前写好;Linux 上已安装才配置)",
|
|
743
755
|
"gpt": "Codex",
|
|
744
756
|
"grok": "Grok Build",
|
|
745
|
-
"gemini": "Antigravity CLI"
|
|
757
|
+
"gemini": "Antigravity CLI",
|
|
758
|
+
"any_label": "任意",
|
|
759
|
+
"any": "CodeBuddy Code、WorkBuddy(已安装才配置)"
|
|
746
760
|
},
|
|
747
761
|
"ex": {
|
|
748
762
|
"key": "用一个令牌配置它能用的全部工具",
|
package/dist/models.json
CHANGED
package/models.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeapi/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.159",
|
|
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",
|