@vibeapi/api-helper 0.0.147 → 0.0.149

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.
Files changed (47) hide show
  1. package/components.json +157 -0
  2. package/dist/brand.json +2 -1
  3. package/dist/commands/components.d.ts +26 -0
  4. package/dist/commands/components.js +1 -0
  5. package/dist/commands/doctor.js +1 -1
  6. package/dist/commands/setup.d.ts +4 -3
  7. package/dist/commands/setup.js +1 -1
  8. package/dist/commands/upgrade.d.ts +7 -3
  9. package/dist/commands/upgrade.js +1 -1
  10. package/dist/components.json +157 -0
  11. package/dist/lib/app-update.d.ts +46 -6
  12. package/dist/lib/app-update.js +1 -1
  13. package/dist/lib/brand.d.ts +2 -0
  14. package/dist/lib/brand.js +1 -1
  15. package/dist/lib/codex-sessions.js +1 -1
  16. package/dist/lib/components.d.ts +204 -0
  17. package/dist/lib/components.js +1 -0
  18. package/dist/lib/dry-run.js +1 -1
  19. package/dist/lib/i18n.js +1 -1
  20. package/dist/lib/post-apply.js +1 -1
  21. package/dist/lib/powershell-env.d.ts +12 -0
  22. package/dist/lib/powershell-env.js +1 -0
  23. package/dist/lib/program.js +1 -1
  24. package/dist/lib/runtime-options.d.ts +5 -0
  25. package/dist/lib/runtime-options.js +1 -1
  26. package/dist/lib/tool-upgrade.d.ts +2 -0
  27. package/dist/lib/tool-upgrade.js +1 -1
  28. package/dist/lib/tools/chatgpt-desktop.d.ts +45 -0
  29. package/dist/lib/tools/chatgpt-desktop.js +1 -0
  30. package/dist/lib/tools/claude-desktop-app.d.ts +17 -58
  31. package/dist/lib/tools/claude-desktop-app.js +1 -1
  32. package/dist/lib/tools/claude-desktop-cli.js +1 -1
  33. package/dist/lib/tools/claude-desktop.js +1 -1
  34. package/dist/lib/tools/codex.js +1 -1
  35. package/dist/lib/tools/desktop-app-installer.d.ts +102 -0
  36. package/dist/lib/tools/desktop-app-installer.js +1 -0
  37. package/dist/lib/tools/desktop-process.d.ts +4 -1
  38. package/dist/lib/tools/desktop-process.js +1 -1
  39. package/dist/lib/tools/elevated-reg.js +1 -1
  40. package/dist/lib/tools/tool-installs.d.ts +8 -0
  41. package/dist/lib/tools/tool-installs.js +1 -1
  42. package/dist/lib/tools/types.d.ts +32 -4
  43. package/dist/lib/windows-env.js +1 -1
  44. package/dist/lib/wizard.js +1 -1
  45. package/dist/locales/en_US.json +152 -12
  46. package/dist/locales/zh_CN.json +152 -12
  47. package/package.json +2 -1
@@ -0,0 +1,157 @@
1
+ {
2
+ "schema": 1,
3
+ "about": "Components VibeCLI installs and upgrades (vibecli list / install / upgrade). Read by src/lib/components.ts and by scripts/gen-components-doc.mjs (docs, the install scripts' README). {scripts} = the brand's installMirror.scripts, {agy} = installMirror.agy, {devtools} = the neutral CNB mirror of fnm / uv / Git for Windows.",
4
+ "devtools": "https://cnb.cool/lib/devtools/-/releases/latest/download",
5
+ "components": [
6
+ {
7
+ "id": "node",
8
+ "name": "Node.js",
9
+ "category": "runtime",
10
+ "aliases": ["nodejs"],
11
+ "platforms": ["darwin", "linux", "win32"],
12
+ "detect": { "command": "node", "pattern": "v(\\d+\\.\\d+\\.\\d+)" },
13
+ "latest": { "type": "node-lts", "url": "https://registry.npmmirror.com/-/binary/node/index.json" },
14
+ "sources": {
15
+ "all": "fnm({devtools})+ Node 镜像 https://npmmirror.com/mirrors/node"
16
+ },
17
+ "verify": { "checksum": "fnm:SHA256SUMS;Node:fnm 下载时核对官方 SHASUMS256.txt", "signature": "—" },
18
+ "install": { "type": "script", "script": "node", "forceEnv": { "NODE_INSTALL_FORCE": "1" } },
19
+ "upgrade": { "managedBy": "fnm", "migrateGlobalPackages": true },
20
+ "check": ["node", "--version"],
21
+ "requires": []
22
+ },
23
+ {
24
+ "id": "git",
25
+ "name": "Git",
26
+ "category": "runtime",
27
+ "platforms": ["darwin", "linux", "win32"],
28
+ "detect": { "command": "git", "pattern": "git version (\\d+\\.\\d+\\.\\d+)" },
29
+ "latest": { "type": "devtools", "key": "git", "platforms": ["win32"] },
30
+ "sources": {
31
+ "darwin": "苹果命令行工具(xcode-select)",
32
+ "linux": "系统包管理器(apt、dnf、yum、zypper、pacman、apk)",
33
+ "win32": "Git for Windows({devtools})"
34
+ },
35
+ "verify": {
36
+ "checksum": "Windows:SHA256SUMS(取自 GitHub 公布的 digest)",
37
+ "signature": "macOS / Linux:系统包管理器自己的签名"
38
+ },
39
+ "install": { "type": "script", "script": "git", "forceEnv": { "GIT_INSTALL_FORCE": "1" } },
40
+ "upgrade": { "managedBy": "git-for-windows-user" },
41
+ "check": ["git", "--version"],
42
+ "requires": []
43
+ },
44
+ {
45
+ "id": "uv",
46
+ "name": "uv",
47
+ "category": "runtime",
48
+ "aliases": ["python-uv"],
49
+ "platforms": ["darwin", "linux", "win32"],
50
+ "detect": { "command": "uv", "pattern": "uv (\\d+\\.\\d+\\.\\d+)" },
51
+ "latest": { "type": "devtools", "key": "uv" },
52
+ "sources": {
53
+ "all": "uv 官方程序({devtools});Python 从 npmmirror 的 python-build-standalone 镜像、包从阿里云 PyPI 镜像"
54
+ },
55
+ "verify": { "checksum": "SHA256SUMS", "signature": "—" },
56
+ "install": { "type": "script", "script": "uv", "forceEnv": { "UV_INSTALL_FORCE": "1" } },
57
+ "upgrade": { "managedBy": "uv-standalone" },
58
+ "check": ["uv", "--version"],
59
+ "requires": []
60
+ },
61
+ {
62
+ "id": "claude-code",
63
+ "name": "Claude Code",
64
+ "category": "cli",
65
+ "aliases": ["claude"],
66
+ "platforms": ["darwin", "linux", "win32"],
67
+ "adapter": "claude-code",
68
+ "latest": { "type": "npm", "package": "@anthropic-ai/claude-code" },
69
+ "sources": {
70
+ "all": "npmmirror 的 @anthropic-ai/claude-code-<平台>(与 downloads.claude.ai 同一文件),按官方原生布局安装({scripts}/claude-code.sh / .ps1)"
71
+ },
72
+ "verify": { "checksum": "npm sha512;连得上时再核对 Anthropic 发布清单的 sha256", "signature": "—" },
73
+ "install": { "type": "adapter" },
74
+ "check": ["claude", "--version"],
75
+ "requires": []
76
+ },
77
+ {
78
+ "id": "codex",
79
+ "name": "Codex",
80
+ "category": "cli",
81
+ "platforms": ["darwin", "linux", "win32"],
82
+ "adapter": "codex",
83
+ "latest": { "type": "npm", "package": "@openai/codex" },
84
+ "sources": {
85
+ "all": "npmmirror 的 @openai/codex(vendor 目录与官方 codex-package 逐文件相同),按官方原生布局安装({scripts}/codex.sh / .ps1)"
86
+ },
87
+ "verify": { "checksum": "npm sha512", "signature": "—" },
88
+ "install": { "type": "adapter" },
89
+ "check": ["codex", "--version"],
90
+ "requires": []
91
+ },
92
+ {
93
+ "id": "grok",
94
+ "name": "Grok Build",
95
+ "category": "cli",
96
+ "platforms": ["darwin", "linux", "win32"],
97
+ "adapter": "grok",
98
+ "latest": { "type": "npm", "package": "@xai-official/grok", "staleTag": true },
99
+ "sources": { "all": "npmmirror 的 @xai-official/grok-<平台>({scripts}/grok.sh / .ps1)" },
100
+ "verify": { "checksum": "npm sha512", "signature": "—" },
101
+ "install": { "type": "adapter" },
102
+ "check": ["grok", "--version"],
103
+ "requires": []
104
+ },
105
+ {
106
+ "id": "agy",
107
+ "name": "Antigravity CLI",
108
+ "category": "cli",
109
+ "aliases": ["antigravity"],
110
+ "platforms": ["darwin", "linux", "win32"],
111
+ "adapter": "agy",
112
+ "latest": { "type": "version-file", "url": "{agy}/version.txt" },
113
+ "sources": { "all": "高速下载站 {agy}(每小时同步官方)" },
114
+ "verify": { "checksum": "官方清单的 sha512", "signature": "—" },
115
+ "install": { "type": "adapter" },
116
+ "check": ["agy", "--version"],
117
+ "requires": []
118
+ },
119
+ {
120
+ "id": "claude-desktop",
121
+ "name": "Claude Desktop",
122
+ "category": "app",
123
+ "platforms": ["darwin", "win32"],
124
+ "app": "claude-desktop",
125
+ "latest": { "type": "app" },
126
+ "sources": {
127
+ "darwin": "高速下载站 lib/claude-desktop(官方 dmg)",
128
+ "win32": "高速下载站 lib/claude-desktop(官方 MSIX)"
129
+ },
130
+ "verify": {
131
+ "checksum": "SHA256SUMS",
132
+ "signature": "macOS:Team ID Q6L2SF6YDW + 公证;Windows:Authenticode O=Anthropic, PBC"
133
+ },
134
+ "install": { "type": "app" },
135
+ "requires": []
136
+ },
137
+ {
138
+ "id": "chatgpt",
139
+ "name": "ChatGPT",
140
+ "category": "app",
141
+ "aliases": ["chatgpt-desktop", "codex-desktop", "codex-app"],
142
+ "platforms": ["darwin", "win32"],
143
+ "app": "chatgpt",
144
+ "latest": { "type": "app" },
145
+ "sources": {
146
+ "darwin": "高速下载站 lib/chatgpt-desktop(官方 dmg,只有 Apple 芯片版)",
147
+ "win32": "高速下载站 lib/chatgpt-desktop(Microsoft Store 同一个 MSIX)"
148
+ },
149
+ "verify": {
150
+ "checksum": "SHA256SUMS",
151
+ "signature": "macOS:Team ID 2DC432GLL2 + 公证;Windows:Microsoft Store 签名(OpenAI 发布者)"
152
+ },
153
+ "install": { "type": "app" },
154
+ "requires": []
155
+ }
156
+ ]
157
+ }
package/dist/brand.json CHANGED
@@ -42,7 +42,8 @@
42
42
  "installMirror": {
43
43
  "scripts": "https://cnb.cool/vibeapi/install/-/git/raw/main",
44
44
  "agy": "https://cnb.cool/lib/agy/-/releases/latest/download",
45
- "claudeDesktop": "https://cnb.cool/lib/claude-desktop/-/releases/latest"
45
+ "claudeDesktop": "https://cnb.cool/lib/claude-desktop/-/releases/latest",
46
+ "chatgptDesktop": "https://cnb.cool/lib/chatgpt-desktop/-/releases/latest"
46
47
  },
47
48
  "pluginMarketplaces": [
48
49
  {
@@ -0,0 +1,26 @@
1
+ import { type ComponentResult, type ComponentSpec } from '../lib/components.js';
2
+ /** Names → components (ids or aliases), with the components they require put first; unknown names are reported. */
3
+ export declare function resolveTargets(names: string[]): {
4
+ specs: ComponentSpec[];
5
+ unknown: string[];
6
+ };
7
+ /**
8
+ * `vibecli list`: every component, whether it is installed, which version, the newest one and where it comes
9
+ * from. Latest versions are cached an hour (`--refresh` reads them again). `--json`: `{ components: [...] }`.
10
+ */
11
+ export declare function listCommand(options?: {
12
+ refresh?: boolean;
13
+ }): Promise<void>;
14
+ /** One component, the way `install` (missing → install, there → report) or `upgrade` treats it. */
15
+ export declare function installComponent(spec: ComponentSpec, force: boolean): Promise<ComponentResult>;
16
+ /**
17
+ * `vibecli install <component...>`: installs the missing ones from China-reachable mirrors (checksums and, for
18
+ * desktop apps, the vendor's signature checked). One that is already installed is only reported, with the
19
+ * upgrade command when it is behind (user, 11-01); `--force` reinstalls. Exit code 1 when any of them didn't
20
+ * end up installed. `--json`: `{ components: [{ tool, category, current, latest, result, version_after, ok }] }`.
21
+ */
22
+ export declare function installCommand(names: string[], options?: {
23
+ force?: boolean;
24
+ }): Promise<void>;
25
+ /** Runtimes behind their latest (cached versions only, no network): one line each after a plain `vibecli upgrade`. */
26
+ export declare function outdatedRuntimeHints(): Promise<string[]>;
@@ -0,0 +1 @@
1
+ import t from"chalk";import{appUpgradeCommand as e,upgradeApp as n}from"../lib/app-update.js";import{CLI_NAME as o}from"../lib/brand.js";import{componentStatus as r,listComponents as a,prefetchLatest as l,resolveComponent as s,runRuntime as i,upgradeAdvice as c}from"../lib/components.js";import{i18n as u}from"../lib/i18n.js";import{emitJson as d,isJsonMode as p,progressToStderr as m}from"../lib/runtime-options.js";import{mirrorInstall as f,upgradeTool as g}from"../lib/tool-upgrade.js";import{getAdapter as _}from"../lib/tools/registry.js";import{findInstallsIncludingNative as y,forgetInstalls as b}from"../lib/tools/tool-installs.js";function h(t){p()?process.stderr.write(t+"\n"):console.log(t)}function w(t){let e=0;for(const n of t)e+=/[ᄀ-ᅟ⺀-꓏가-힣豈-﫿︰-﹏＀-⦆¢-₩]/.test(n)?2:1;return e}function k(t,e){return t+" ".repeat(Math.max(0,e-w(t)))}export function resolveTargets(t){const e=[],n=[],o=(t,e)=>{if(!n.includes(t)&&!e.includes(t.id)){for(const n of t.requires){const r=s(n);r&&o(r,[...e,t.id])}n.push(t)}};for(const n of t){const t=s(n);t?o(t,[]):e.push(n)}return{specs:n,unknown:e}}function v(e){return e.supported?!e.installed&&e.blocker?t.gray(function(t){for(const e of[`components.reason_${t}`,`app_update.reason_${t}`]){const t=u.t(e);if(t!==e)return t}return t}(e.blocker)):e.installed?e.outdated?t.yellow(e.auto_upgrade?u.t("components.state.outdated_auto",{command:`${o} upgrade ${e.id}`}):u.t("components.state.outdated_manual",{how:e.hint??u.t(`components.how_${e.managed_by??"other"}`,{tool:e.name})})):e.latest?t.green(u.t("components.state.latest")):t.gray(u.t("components.state.unknown_latest")):t.gray(u.t("components.state.missing",{command:`${o} install ${e.id}`})):t.gray(u.t("components.state.unsupported"))}export async function listCommand(e={}){const n=a(),o=await l(n,{refresh:e.refresh}),s=[];for(const t of n)s.push(await r(t,{latest:o.get(t.id)}));if(p())return void d({components:s});const i=s.map(t=>({s:t,cells:[t.name,t.installed?t.current??"?":"—",t.latest??"—",t.installed?u.t(`components.by.${t.managed_by??"other"}`):"—"]})),c=[u.t("components.col.name"),u.t("components.col.current"),u.t("components.col.latest"),u.t("components.col.managed")],m=c.map((t,e)=>Math.max(w(t),...i.map(t=>w(t.cells[e])))+2);for(const e of["runtime","cli","app"]){const n=i.filter(t=>t.s.category===e);if(n.length){console.log(t.bold(`\n${u.t(`components.category.${e}`)}`)),console.log(t.gray(" "+c.map((t,e)=>k(t,m[e])).join("")+u.t("components.col.state")));for(const{s:e,cells:o}of n)console.log(" "+o.map((t,e)=>k(t,m[e])).join("")+v(e)),e.source&&e.supported&&console.log(t.gray(" "+u.t("components.source",{source:e.source})))}}const f=s.filter(t=>t.error&&!t.latest);f.length&&console.log(t.yellow("\n ! "+u.t("components.latest_unknown",{tools:f.map(t=>t.name).join("、")})))}export async function installComponent(o,a){return p()||console.log(t.bold(`\n${o.name}`)),"runtime"===o.category?i(o,"install",{force:a}):"cli"===o.category?async function(e,n){const o=_(e.adapter),a=await r(e,{refresh:!0}),l={tool:e.id,category:"cli",current:a.current,latest:a.latest,version_after:null};if(!o?.installSpec)return{...l,result:"unavailable",ok:!1,reason:"no_install_spec"};if(a.blocker)return h(t.yellow(" ! "+u.t(`components.blocked_${a.blocker}`,{tool:e.name}))),{...l,result:"unavailable",ok:!1,reason:a.blocker};if(a.installed&&!n){const n=t.gray(`(${a.path})`);return a.outdated?(h(t.green(" √ "+u.t("components.already_installed",{tool:e.name,current:a.current??"?"}))+n),h(t.yellow(" ! "+c(a))),{...l,result:"already_installed",ok:!0,hint:c(a)}):(h(t.green(" √ "+u.t(a.latest?"components.up_to_date":"components.already_installed",{tool:e.name,current:a.current??"?"}))+n),{...l,result:"already_installed",ok:!0})}let s;a.installed?(h(t.yellow(" ! "+u.t("components.reinstalling",{tool:e.name,current:a.current??"?"}))),s=await f(o.installSpec)):s=await g(o.name),b();const i=y(o.installSpec)[0];a.installed&&s&&h(t.green(" √ "+u.t("components.reinstalled",{tool:e.name,version:i?.version??"?"})));const d=s&&i?a.installed?"reinstalled":"installed":"failed";return{...l,result:d,ok:"failed"!==d,version_after:i?.version??null}}(o,a):async function(o,a){const l=await r(o,{refresh:!0});if(l.installed&&!a){const n={tool:o.id,category:"app",current:l.current,latest:l.latest,version_after:null};if(l.outdated){h(t.green(" √ "+u.t("components.already_installed",{tool:o.name,current:l.current??"?"})));const r=u.t("app_update.upgrade_hint",{tool:o.name,current:l.current??"?",latest:l.latest??"?",command:e(o.app)});return h(t.yellow(" ! "+r)),{...n,result:"already_installed",ok:!0,hint:r}}return h(t.green(" √ "+u.t(l.latest?"components.up_to_date":"components.already_installed",{tool:o.name,current:l.current??"?"}))),{...n,result:"already_installed",ok:!0}}return function(t,e){const n={installed:"installed",upgraded:e.current&&e.latest&&e.current===e.version_after?"reinstalled":"upgraded",up_to_date:"up_to_date",declined:"manual",offered:"already_installed",left_running:"manual",not_installed:"unavailable",unavailable:"unavailable",failed:"failed"}[e.result]??"failed";return{tool:t.id,category:"app",current:e.current,latest:e.latest,result:n,version_after:e.version_after,ok:["installed","upgraded","reinstalled","up_to_date","already_installed"].includes(n),...e.reason?{reason:e.reason}:{}}}(o,await n(o.app,{install:!0,force:a}))}(o,a)}export async function installCommand(e,n={}){const{specs:o,unknown:r}=resolveTargets(e);if(r.length||!o.length)return console.error(t.red(u.t("components.unknown",{names:r.join(", ")||"—"}))),console.error(u.t("components.known",{ids:a().map(t=>t.id).join(" / ")})),void(process.exitCode=1);const l=[];for(const t of o)l.push(await m(()=>installComponent(t,Boolean(n.force))));p()&&d({components:l}),l.some(t=>!t.ok)&&(process.exitCode=1)}export async function outdatedRuntimeHints(){const t=a().filter(t=>"runtime"===t.category);return(await Promise.all(t.map(t=>r(t,{offline:!0})))).filter(t=>t.installed&&t.outdated).map(t=>c(t))}
@@ -1 +1 @@
1
- import{refreshClientConfig as o}from"../lib/client-config-sync.js";import t from"chalk";import e from"ora";import{spawnSync as s}from"child_process";import{existsSync as r,readdirSync as n,readFileSync as a}from"fs";import{connect as c}from"net";import{join as i}from"path";import{configManager as l}from"../lib/config.js";import{savedApiKey as d}from"./base.js";import{toolManager as p}from"../lib/tool-manager.js";import{i18n as u}from"../lib/i18n.js";import{validateApiKey as m}from"../lib/api-validator.js";import{getAdapter as f}from"../lib/tools/registry.js";import{findInstalls as _,installLabel as g}from"../lib/tools/tool-installs.js";import{detectManagedOverrides as h}from"../lib/tools/claude-managed.js";import{codexAuthProblem as y,codexCatalogRejection as k,codexConfigPath as b,codexWorkModeOn as w}from"../lib/tools/codex.js";import{claudeAccountLoginPresent as v}from"../lib/tools/claude-code.js";import{toolHome as j}from"../lib/tools/types.js";import{gatewayAddresses as x,probeGatewayAddress as $}from"../lib/gateway-addresses.js";import{listAdapters as T}from"../lib/tools/registry.js";import{logger as A}from"../utils/logger.js";import{maskHome as P,maskSecrets as R,uploadReport as N}from"../lib/telemetry.js";import{CLI_NAME as O}from"../lib/brand.js";import{appStatus as C,appStatusText as I,appTools as H,appUpgradeCommand as L}from"../lib/app-update.js";import{balanceLookupEnabled as S,balanceNeedsAttention as U,balanceText as E,fetchKeyBalances as K}from"../lib/key-balance.js";const B=["HTTPS_PROXY","https_proxy","HTTP_PROXY","http_proxy","ALL_PROXY","all_proxy"];function G(o,t,e=3e3){return new Promise(s=>{const r=c({host:o,port:t}),n=o=>{r.destroy(),s(o)};r.setTimeout(e,()=>n(!1)),r.once("connect",()=>n(!0)),r.once("error",()=>n(!1))})}function D(){const o=A.getLogDir();if(!r(o))return"";const t=n(o).filter(o=>/^\d{4}-\d{2}-\d{2}\.log$/.test(o)).sort().slice(-2).map(t=>`== ${t}\n`+a(i(o,t),"utf-8")).join("\n");return R(t.slice(-15e4))}function q(){const o={};for(const t of B){const e=process.env[t]?.trim();if(e)try{const s=new URL(e.includes("://")?e:`http://${e}`);o[t]=`${s.protocol}//${s.host}`}catch{o[t]="(unparsable)"}}return o}export async function doctorCommand(r={}){const n=e(u.t("doctor.checking")).start(),c=[],A=Number(process.versions.node.split(".")[0]);c.push({name:"Node.js",status:A>=20?"pass":"fail",message:`v${process.versions.node}`}),n.text=u.t("doctor.check_proxy"),c.push(await async function(){const o=u.t("doctor.proxy"),t=new Map;for(const o of B){const e=process.env[o]?.trim();e&&!t.has(e)&&t.set(e,o)}if(0===t.size)return{name:o,status:"pass",message:u.t("doctor.proxy_none")};const e=[];for(const[o,s]of t){let t;try{t=new URL(o.includes("://")?o:`http://${o}`)}catch{e.push(`${s}=${o}`);continue}const r=Number(t.port)||("https:"===t.protocol?443:t.protocol.startsWith("socks")?1080:80);await G(t.hostname,r)||e.push(`${s}=${o}`)}return 0===e.length?{name:o,status:"pass",message:[...t.keys()].join(", ")}:{name:o,status:"fail",message:u.t("doctor.proxy_dead",{proxies:e.join(", ")})}}()),n.text=u.t("doctor.check_api_key_network");const R=d(),F=u.t("doctor.api_key_network");if(R){const o=await m(R);o.valid?(c.push({name:F,status:"pass"}),n.text=u.t("doctor.check_balance"),c.push(...await async function(o){if(!S())return[];const t=l.listToolApiKeys().map(o=>({tool:o,key:l.getApiKeyForTool(o)})).filter(t=>Boolean(t.key)&&t.key!==o),e=await K([o,...t.map(o=>o.key)]),s=[{name:u.t("doctor.balance"),key:o},...t.map(o=>({name:u.t("doctor.balance_tool",{tool:f(o.tool)?.displayName??o.tool}),key:o.key}))],r=[];for(const o of s){const t=e.get(o.key);t&&r.push({name:o.name,status:U(t)?"warn":"pass",message:E(t)})}return r}(R))):"invalid_api_key"===o.error?c.push({name:F,status:"fail",message:u.t("doctor.api_key_invalid")}):(c.push({name:F,status:"fail",message:`${u.t("doctor.network_error")}: ${o.message??o.error}`}),n.text=u.t("doctor.check_other_addresses"),c.push(await async function(){const o=u.t("doctor.other_addresses"),t=l.getBaseUrl(),e=x().filter(o=>o.url!==t),s=d(),r=await Promise.all(e.map(o=>$(o.url,{apiKey:s}))),n=e.filter((o,t)=>r[t].ok).map(o=>o.url);return 0===n.length?{name:o,status:"fail",message:u.t("doctor.other_addresses_none")}:{name:o,status:"warn",message:u.t("doctor.other_addresses_found",{urls:n.join(", ")})}}()))}else c.push({name:F,status:"fail",message:u.t("doctor.api_key_missing")});n.text=u.t("doctor.check_client_config");const M=await o();c.push({name:u.t("doctor.client_config"),status:"cloud"===M.source||"cache"===M.source&&!M.problem?"pass":"warn",message:[M.source?u.t(`refresh.source.${M.source}`):u.t("refresh.source.none"),M.revision?u.t("doctor.client_config_revision",{revision:M.revision}):"",M.problem??""].filter(Boolean).join(" · ")}),n.text=u.t("doctor.check_tools");const X=p.getInstalledTools();c.push({name:u.t("doctor.installed_tools"),status:X.length>0?"pass":"warn",message:X.length>0?X.map(o=>f(o)?.displayName??o).join(u.t("setup.list_separator")):u.t("doctor.no_tools_installed")}),c.push(...function(){const o=[];for(const t of p.getInstalledTools()){const e=f(t);if(!e?.installSpec)continue;const s=_(e.installSpec);if(0===s.length)continue;const r=[],n=p.outdatedVersion(t);n&&r.push(u.t("doctor.tool_outdated",{min:n.min})),s.length>1&&r.push(u.t("doctor.tool_duplicates",{others:s.slice(1).map(g).join("、")})),o.push({name:e.displayName,status:r.length>0?"warn":"pass",message:[g(s[0]),...r,...r.length>0?[u.t("doctor.run_upgrade",{tool:t})]:[]].join("\n ")})}return o}()),c.push(...await async function(){const o=[];for(const t of H()){const e=await C(t,{refresh:!0});if(!e.installed||!e.current)continue;const s=u.t("doctor.app_version",{tool:e.name});if(e.outdated){const r=e.blocker?u.t(`app_update.blocked_${e.blocker}`,{tool:e.name}):u.t("doctor.run_app_upgrade",{command:L(t)});o.push({name:s,status:"warn",message:`${I(e)}\n ${r}`})}else o.push({name:s,status:"pass",message:I(e)})}return o}());const Y=function(){if(!p.isToolInstalled("claude-code"))return null;const o=u.t("doctor.claude_config"),t=h();if(t.length>0){const e=t.map(o=>`${o.source}: ${o.keys.join(", ")}`).join("; ");return{name:o,status:"fail",message:u.t("doctor.claude_managed",{detail:e})}}let e={};try{e=JSON.parse(a(i(process.env.CLAUDE_CONFIG_DIR?.trim()||i(j(),".claude"),"settings.json"),"utf-8")).env??{}}catch{}const s=l.getApiKeyForTool("claude-code");return e.ANTHROPIC_AUTH_TOKEN&&e.ANTHROPIC_BASE_URL?e.ANTHROPIC_BASE_URL!==l.getBaseUrl()||s&&e.ANTHROPIC_AUTH_TOKEN!==s?{name:o,status:"warn",message:u.t("doctor.claude_config_changed")}:{name:o,status:"pass"}:{name:o,status:"warn",message:u.t("doctor.claude_not_configured")}}();Y&&c.push(Y),X.includes("claude-code")&&v()&&c.push({name:u.t("doctor.claude_login"),status:"pass",message:u.t("tools.claude_code.account_login_overridden")});const V=X.includes("codex")?y():null;if(X.includes("codex")&&c.push({name:u.t("doctor.codex_auth"),status:V?"fail":"pass",message:V?u.t(`doctor.codex_${V}`,{path:P(b())}):void 0}),X.includes("codex")){const o=k();c.push({name:u.t("doctor.codex_catalog"),status:o?"fail":"pass",message:o?u.t("doctor.codex_catalog_rejected",{path:o.bin,version:o.version??"?",error:o.error}):void 0})}X.includes("codex")&&w()&&c.push({name:u.t("doctor.codex_work_mode"),status:"warn",message:u.t("tools.codex.work_mode_on")}),"win32"===process.platform&&X.includes("claude-code")&&!process.env.CLAUDE_CODE_GIT_BASH_PATH&&c.push({name:"Git for Windows",status:p.isGitInstalled()?"pass":"warn",message:p.isGitInstalled()?void 0:u.t("tools.claude_code.no_git_bash")}),r.deep&&X.includes("claude-code")&&(n.text=u.t("doctor.check_claude_request"),c.push(function(){const o=u.t("doctor.claude_request"),t=_(f("claude-code").installSpec)[0];if(!t)return{name:o,status:"warn",message:u.t("doctor.claude_request_skipped")};const e={encoding:"utf-8",timeout:12e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},r=["-p","Reply with the single word OK."],n=/\.cmd$/i.test(t.path)?s(`"${t.path}" ${r.map(o=>`"${o}"`).join(" ")}`,{...e,shell:!0}):s(t.path,r,e),a=`${n.stdout??""}`.trim();if(0===n.status&&a)return{name:o,status:"pass",message:a.slice(0,80)};const c=(`${n.stderr??""}`.trim()||a||n.error?.message||`exit ${n.status}`).slice(0,300);return{name:o,status:"fail",message:u.t("doctor.claude_request_failed",{reason:c})}}())),n.stop(),console.log("\n"+t.bold(u.t("doctor.results_title"))+"\n");const W={pass:t.green("√"),warn:t.yellow("!"),fail:t.red("×")};for(const o of c)console.log(`${W[o.status]} ${o.name}`),o.message&&console.log(t.gray(` ${o.message}`));if(c.every(o=>"pass"===o.status)&&console.log("\n"+t.green.bold(u.t("doctor.all_good"))),!r.deep&&X.includes("claude-code")&&console.log(t.gray("\n"+u.t("doctor.deep_hint"))),r.report){const o=e(u.t("doctor.report_uploading")).start(),t=await N(function(o,t){const e={};for(const o of T()){if(o.hidden)continue;let t=null;try{t=p.detectCurrentConfig(o.name).apiKey?"has_key":"no_key"}catch{t="unreadable"}e[o.name]={installed:p.isToolInstalled(o.name),version:p.installedVersion(o.name),copies:o.installSpec?_(o.installSpec).map(o=>({kind:o.kind,version:o.version,path:o.path})):void 0,config:t}}const s=l.getProfile();return{checks:o,tools:e,settings:{base_url:l.getBaseUrl(),profile:l.getActiveProfileName(),profiles:l.listProfiles().length,key_fingerprint:l.getApiKeyFingerprint()||null,tool_keys:Object.keys(s.tool_api_keys??{}),models:s.models,tool_models:s.tool_models??{},tool_settings:s.tool_settings??{},lang:l.getLang()},client_config:t,env:{shell:process.env.SHELL??process.env.ComSpec??null,term:process.env.TERM_PROGRAM??null,proxies:q()},log:D()}}(c,{source:M.source??void 0,revision:M.revision,problem:M.problem}));t?o.succeed(u.t("doctor.report_done",{code:t})):o.fail(u.t("doctor.report_failed",{cli:O}))}else c.some(o=>"fail"===o.status)&&console.log(t.gray("\n"+u.t("doctor.report_hint",{cli:O})));c.some(o=>"fail"===o.status)&&(process.exitCode=1)}
1
+ import{refreshClientConfig as o}from"../lib/client-config-sync.js";import t from"chalk";import e from"ora";import{spawnSync as s}from"child_process";import{existsSync as r,readdirSync as n,readFileSync as a}from"fs";import{connect as c}from"net";import{join as i}from"path";import{configManager as l}from"../lib/config.js";import{savedApiKey as d}from"./base.js";import{toolManager as p}from"../lib/tool-manager.js";import{i18n as u}from"../lib/i18n.js";import{validateApiKey as m}from"../lib/api-validator.js";import{getAdapter as f}from"../lib/tools/registry.js";import{findInstalls as _,installLabel as g}from"../lib/tools/tool-installs.js";import{detectManagedOverrides as h}from"../lib/tools/claude-managed.js";import{codexAuthProblem as y,codexCatalogRejection as k,codexConfigPath as w,codexWorkModeOn as b}from"../lib/tools/codex.js";import{claudeAccountLoginPresent as v}from"../lib/tools/claude-code.js";import{toolHome as j}from"../lib/tools/types.js";import{gatewayAddresses as x,probeGatewayAddress as $}from"../lib/gateway-addresses.js";import{listAdapters as T}from"../lib/tools/registry.js";import{logger as A}from"../utils/logger.js";import{maskHome as P,maskSecrets as R,uploadReport as N}from"../lib/telemetry.js";import{CLI_NAME as O}from"../lib/brand.js";import{appStatus as I,appStatusText as C,appTools as H,appUpgradeCommand as L,getApp as S}from"../lib/app-update.js";import{balanceLookupEnabled as U,balanceNeedsAttention as E,balanceText as K,fetchKeyBalances as B}from"../lib/key-balance.js";const G=["HTTPS_PROXY","https_proxy","HTTP_PROXY","http_proxy","ALL_PROXY","all_proxy"];function D(o,t,e=3e3){return new Promise(s=>{const r=c({host:o,port:t}),n=o=>{r.destroy(),s(o)};r.setTimeout(e,()=>n(!1)),r.once("connect",()=>n(!0)),r.once("error",()=>n(!1))})}function q(){const o=A.getLogDir();if(!r(o))return"";const t=n(o).filter(o=>/^\d{4}-\d{2}-\d{2}\.log$/.test(o)).sort().slice(-2).map(t=>`== ${t}\n`+a(i(o,t),"utf-8")).join("\n");return R(t.slice(-15e4))}function F(){const o={};for(const t of G){const e=process.env[t]?.trim();if(e)try{const s=new URL(e.includes("://")?e:`http://${e}`);o[t]=`${s.protocol}//${s.host}`}catch{o[t]="(unparsable)"}}return o}export async function doctorCommand(r={}){const n=e(u.t("doctor.checking")).start(),c=[],A=Number(process.versions.node.split(".")[0]);c.push({name:"Node.js",status:A>=20?"pass":"fail",message:`v${process.versions.node}`}),n.text=u.t("doctor.check_proxy"),c.push(await async function(){const o=u.t("doctor.proxy"),t=new Map;for(const o of G){const e=process.env[o]?.trim();e&&!t.has(e)&&t.set(e,o)}if(0===t.size)return{name:o,status:"pass",message:u.t("doctor.proxy_none")};const e=[];for(const[o,s]of t){let t;try{t=new URL(o.includes("://")?o:`http://${o}`)}catch{e.push(`${s}=${o}`);continue}const r=Number(t.port)||("https:"===t.protocol?443:t.protocol.startsWith("socks")?1080:80);await D(t.hostname,r)||e.push(`${s}=${o}`)}return 0===e.length?{name:o,status:"pass",message:[...t.keys()].join(", ")}:{name:o,status:"fail",message:u.t("doctor.proxy_dead",{proxies:e.join(", ")})}}()),n.text=u.t("doctor.check_api_key_network");const R=d(),M=u.t("doctor.api_key_network");if(R){const o=await m(R);o.valid?(c.push({name:M,status:"pass"}),n.text=u.t("doctor.check_balance"),c.push(...await async function(o){if(!U())return[];const t=l.listToolApiKeys().map(o=>({tool:o,key:l.getApiKeyForTool(o)})).filter(t=>Boolean(t.key)&&t.key!==o),e=await B([o,...t.map(o=>o.key)]),s=[{name:u.t("doctor.balance"),key:o},...t.map(o=>({name:u.t("doctor.balance_tool",{tool:f(o.tool)?.displayName??o.tool}),key:o.key}))],r=[];for(const o of s){const t=e.get(o.key);t&&r.push({name:o.name,status:E(t)?"warn":"pass",message:K(t)})}return r}(R))):"invalid_api_key"===o.error?c.push({name:M,status:"fail",message:u.t("doctor.api_key_invalid")}):(c.push({name:M,status:"fail",message:`${u.t("doctor.network_error")}: ${o.message??o.error}`}),n.text=u.t("doctor.check_other_addresses"),c.push(await async function(){const o=u.t("doctor.other_addresses"),t=l.getBaseUrl(),e=x().filter(o=>o.url!==t),s=d(),r=await Promise.all(e.map(o=>$(o.url,{apiKey:s}))),n=e.filter((o,t)=>r[t].ok).map(o=>o.url);return 0===n.length?{name:o,status:"fail",message:u.t("doctor.other_addresses_none")}:{name:o,status:"warn",message:u.t("doctor.other_addresses_found",{urls:n.join(", ")})}}()))}else c.push({name:M,status:"fail",message:u.t("doctor.api_key_missing")});n.text=u.t("doctor.check_client_config");const X=await o();c.push({name:u.t("doctor.client_config"),status:"cloud"===X.source||"cache"===X.source&&!X.problem?"pass":"warn",message:[X.source?u.t(`refresh.source.${X.source}`):u.t("refresh.source.none"),X.revision?u.t("doctor.client_config_revision",{revision:X.revision}):"",X.problem??""].filter(Boolean).join(" · ")}),n.text=u.t("doctor.check_tools");const Y=p.getInstalledTools();c.push({name:u.t("doctor.installed_tools"),status:Y.length>0?"pass":"warn",message:Y.length>0?Y.map(o=>f(o)?.displayName??o).join(u.t("setup.list_separator")):u.t("doctor.no_tools_installed")}),c.push(...function(){const o=[];for(const t of p.getInstalledTools()){const e=f(t);if(!e?.installSpec)continue;const s=_(e.installSpec);if(0===s.length)continue;const r=[],n=p.outdatedVersion(t);n&&r.push(u.t("doctor.tool_outdated",{min:n.min})),s.length>1&&r.push(u.t("doctor.tool_duplicates",{others:s.slice(1).map(g).join("、")})),o.push({name:e.displayName,status:r.length>0?"warn":"pass",message:[g(s[0]),...r,...r.length>0?[u.t("doctor.run_upgrade",{tool:t})]:[]].join("\n ")})}return o}()),c.push(...await async function(){const o=[];for(const t of H()){const e=await I(t,{refresh:!0});if(!e.installed||!e.current)continue;const s=u.t("doctor.app_version",{tool:e.name});if(e.outdated){const r=e.blocker?u.t(`app_update.blocked_${e.blocker}`,{tool:e.name,url:S(t)?.appInstaller.downloadPage??"",command:L(t)}):u.t("doctor.run_app_upgrade",{command:L(t)});o.push({name:s,status:"warn",message:`${C(e)}\n ${r}`})}else o.push({name:s,status:"pass",message:C(e)})}return o}());const V=function(){if(!p.isToolInstalled("claude-code"))return null;const o=u.t("doctor.claude_config"),t=h();if(t.length>0){const e=t.map(o=>`${o.source}: ${o.keys.join(", ")}`).join("; ");return{name:o,status:"fail",message:u.t("doctor.claude_managed",{detail:e})}}let e={};try{e=JSON.parse(a(i(process.env.CLAUDE_CONFIG_DIR?.trim()||i(j(),".claude"),"settings.json"),"utf-8")).env??{}}catch{}const s=l.getApiKeyForTool("claude-code");return e.ANTHROPIC_AUTH_TOKEN&&e.ANTHROPIC_BASE_URL?e.ANTHROPIC_BASE_URL!==l.getBaseUrl()||s&&e.ANTHROPIC_AUTH_TOKEN!==s?{name:o,status:"warn",message:u.t("doctor.claude_config_changed")}:{name:o,status:"pass"}:{name:o,status:"warn",message:u.t("doctor.claude_not_configured")}}();V&&c.push(V),Y.includes("claude-code")&&v()&&c.push({name:u.t("doctor.claude_login"),status:"pass",message:u.t("tools.claude_code.account_login_overridden")});const W=Y.includes("codex")?y():null;if(Y.includes("codex")&&c.push({name:u.t("doctor.codex_auth"),status:W?"fail":"pass",message:W?u.t(`doctor.codex_${W}`,{path:P(w())}):void 0}),Y.includes("codex")){const o=k();c.push({name:u.t("doctor.codex_catalog"),status:o?"fail":"pass",message:o?u.t("doctor.codex_catalog_rejected",{path:o.bin,version:o.version??"?",error:o.error}):void 0})}Y.includes("codex")&&b()&&c.push({name:u.t("doctor.codex_work_mode"),status:"warn",message:u.t("tools.codex.work_mode_on")}),"win32"===process.platform&&Y.includes("claude-code")&&!process.env.CLAUDE_CODE_GIT_BASH_PATH&&c.push({name:"Git for Windows",status:p.isGitInstalled()?"pass":"warn",message:p.isGitInstalled()?void 0:u.t("tools.claude_code.no_git_bash")}),r.deep&&Y.includes("claude-code")&&(n.text=u.t("doctor.check_claude_request"),c.push(function(){const o=u.t("doctor.claude_request"),t=_(f("claude-code").installSpec)[0];if(!t)return{name:o,status:"warn",message:u.t("doctor.claude_request_skipped")};const e={encoding:"utf-8",timeout:12e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},r=["-p","Reply with the single word OK."],n=/\.cmd$/i.test(t.path)?s(`"${t.path}" ${r.map(o=>`"${o}"`).join(" ")}`,{...e,shell:!0}):s(t.path,r,e),a=`${n.stdout??""}`.trim();if(0===n.status&&a)return{name:o,status:"pass",message:a.slice(0,80)};const c=(`${n.stderr??""}`.trim()||a||n.error?.message||`exit ${n.status}`).slice(0,300);return{name:o,status:"fail",message:u.t("doctor.claude_request_failed",{reason:c})}}())),n.stop(),console.log("\n"+t.bold(u.t("doctor.results_title"))+"\n");const z={pass:t.green("√"),warn:t.yellow("!"),fail:t.red("×")};for(const o of c)console.log(`${z[o.status]} ${o.name}`),o.message&&console.log(t.gray(` ${o.message}`));if(c.every(o=>"pass"===o.status)&&console.log("\n"+t.green.bold(u.t("doctor.all_good"))),!r.deep&&Y.includes("claude-code")&&console.log(t.gray("\n"+u.t("doctor.deep_hint"))),r.report){const o=e(u.t("doctor.report_uploading")).start(),t=await N(function(o,t){const e={};for(const o of T()){if(o.hidden)continue;let t=null;try{t=p.detectCurrentConfig(o.name).apiKey?"has_key":"no_key"}catch{t="unreadable"}e[o.name]={installed:p.isToolInstalled(o.name),version:p.installedVersion(o.name),copies:o.installSpec?_(o.installSpec).map(o=>({kind:o.kind,version:o.version,path:o.path})):void 0,config:t}}const s=l.getProfile();return{checks:o,tools:e,settings:{base_url:l.getBaseUrl(),profile:l.getActiveProfileName(),profiles:l.listProfiles().length,key_fingerprint:l.getApiKeyFingerprint()||null,tool_keys:Object.keys(s.tool_api_keys??{}),models:s.models,tool_models:s.tool_models??{},tool_settings:s.tool_settings??{},lang:l.getLang()},client_config:t,env:{shell:process.env.SHELL??process.env.ComSpec??null,term:process.env.TERM_PROGRAM??null,proxies:F()},log:q()}}(c,{source:X.source??void 0,revision:X.revision,problem:X.problem}));t?o.succeed(u.t("doctor.report_done",{code:t})):o.fail(u.t("doctor.report_failed",{cli:O}))}else c.some(o=>"fail"===o.status)&&console.log(t.gray("\n"+u.t("doctor.report_hint",{cli:O})));c.some(o=>"fail"===o.status)&&(process.exitCode=1)}
@@ -92,9 +92,10 @@ export interface SetupCommandOptions extends Partial<Record<DedicatedKeyOption,
92
92
  /** `--claude-official on|off` (also true/false, show/hide, 1/0, yes/no); undefined when unrecognized. */
93
93
  export declare function parseOnOff(raw: string | undefined): boolean | undefined;
94
94
  /**
95
- * GUI apps configured ahead but not installed (Claude Desktop on macOS / Windows): install them from the download
96
- * mirror with `--install` or a yes at the prompt. The question defaults to no, so `--yes` alone doesn't download a
97
- * ~300 MB app nobody asked for (one-line installers pass `--yes`); otherwise only the command that installs it.
95
+ * Desktop apps that go with the configured tools but aren't installed (Claude Desktop; ChatGPT, which runs Codex
96
+ * on the same config): installed from the download mirror like a missing CLI tool (user, 11-01: the one-line
97
+ * installer should bring them along): `--install`, `--yes` (one-line installers pass it) or yes at the prompt
98
+ * (default yes); `--no-install`, a no, `--non-interactive` / `--json` or no terminal only print the command.
98
99
  */
99
100
  export declare function installMissingApps(tools: string[], install: boolean | undefined): Promise<boolean>;
100
101
  export declare function setupCommand(options: SetupCommandOptions): Promise<void>;
@@ -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 w,isDryRun as v,isJsonMode as x,isNonInteractive as C,shouldAutoConfirm as j}from"../lib/runtime-options.js";import{appUpgradeCommand as K}from"../lib/app-update.js";import{join as $}from"path";import{confirmWritePlan as T,printWritePlan as G,toolWritePlan as M}from"../lib/write-plan.js";import N from"inquirer";import{logger as S}from"../utils/logger.js";import{forgetInstalls as E}from"../lib/tools/tool-installs.js";import{CLI_NAME as I,brandEnv as A}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 O(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 B(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 D(e){console.log(o.green(e))}function F(e){console.log(o.yellow(e))}function L(e){console.error(o.red(e))}let R=null;function P(o){const e={operation:1,authentication:2,network:3};(!R||e[o]>e[R])&&(R=o)}async function Y(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?`${I} setup --key ${a}`:`${I} setup ${e} ${a}`;let p;if("network_error"===i.error?(P("network"),p=_(l.t("setup.unreachable",{url:s.getBaseUrl(),reason:i.message||"network error"}),`${I} base auto`,"network_error")):"invalid_api_key"===i.error?(P("authentication"),p=y(l.t("setup.invalid_key",{label:e,reason:i.message||"invalid"}),n,"invalid_api_key")):(P("operation"),p=g(l.t("setup.validate_failed",{label:e,reason:i.message||i.error||"unknown"}),n,i.error)),x())throw p;return L(p.message),console.log(o.gray(l.t("errors.next_step",{command:p.hint}))),!1}async function q(t,i,r={}){const{oneMillion:p,officialLogin:c,desktopRegistry:u,force:y}=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})}catch(o){if(x())throw g(o instanceof Error?o.message:String(o),`${I} setup --key ${l.t("errors.key_placeholder")}`,"config_write_failed");const e=(o instanceof Error?o.message:String(o)).replace(/\s+/g," ").trim();return L("× "+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 H(o){return!e(o)?.isInstalled&&!a.isToolInstalled(o)}export async function installMissingApps(t,i){const s=t.filter(o=>{const t=e(o)?.appInstaller;try{return Boolean(t&&!t.blocker()&&!t.installedPath())}catch(e){return S.logError(`setup: app installed? ${o}`,e),!1}});if(0===s.length)return!1;let a=i;if(void 0===a&&h()&&!j()){const o=s.map(o=>n[o].displayName).join(l.t("setup.list_separator"));console.log(""),a=(await N.prompt([{type:"confirm",name:"go",message:l.t("setup.install_app_confirm",{tools:o}),default:!1}])).go}if(!a&&!x())for(const e of s)console.log(o.gray(l.t("setup.install_app_hint",{tool:n[e].displayName,command:K(e)})));return Boolean(a)}function W(o){F(l.t("setup.still_missing",{tools:o.map(o=>n[o].displayName).join(l.t("setup.list_separator")),commands:o.map(o=>`${I} config ${o} --yes`).join(l.t("setup.list_separator"))}))}function U(e,t,i=[]){const a=M(e),n=$(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")}`)}G(a,{label:l.t("runtime.dry_run_label"),keyFile:t?n:void 0,installFirst:i})}}function z(){return"darwin"===process.platform||"win32"===process.platform||a.isToolInstalled("claude-desktop")}export async function setupCommand(r){R=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 L(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 L(l.t("setup.desktop_registry_invalid",{value:String(r.desktopRegistry)})),void(process.exitCode=1);const b=g||_,w=Boolean(p||f.length>0),K={oneMillion:r.oneMillion,officialLogin:y,desktopRegistry:h,force:r.force};if(!w&&(m||b)&&v())return void U([...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),D(l.t(e?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(o){L(l.t("setup.apply_failed",{tool:n.codex.displayName,reason:o instanceof Error?o.message:String(o)})),process.exitCode=1}else L(l.t("setup.codex_1m_missing_key")),process.exitCode=1}if(b){const o=s.getApiKeyForTool("claude-desktop");o?await q("claude-desktop",o,{...K,oneMillion:void 0})?await t(["claude-desktop"],{apps:{install:!1}}):process.exitCode=1:(L(l.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!w)return L(l.t("setup.usage")),void(process.exitCode=1);const G=v();G||await i(p||f[0].apiKey);const M=[],P=[];let J,Q=0,V=0;const X=new Set,Z=f.map(o=>({tool:o.tool,label:`--${o.option}`,apiKey:o.apiKey,need:o.need}));for(const o of Z){if(!await Y(o.label,o.apiKey)){V+=1;continue}const e=await O(o.apiKey);!e.probed||B(e,o.need)?(e.probed||F(l.t("setup.probe_failed",{label:o.label})),M.push({tool:o.tool,apiKey:o.apiKey,dedicated:!0}),X.add(o.tool)):(L(l.t(`setup.key_no_${o.need}`,{label:o.label,tool:n[o.tool].displayName})),V+=1)}const oo=!!p&&await Y("--key",p);p&&!oo&&(J=k[R??"operation"]);const eo=p&&oo?await O(p):void 0;if(p&&eo&&!eo.probed&&F(l.t("setup.probe_failed",{label:"--key"})),!(p&&eo&&eo.probed)||eo.hasClaude||eo.hasGpt||eo.hasGrok||eo.hasGemini||(L(l.t("setup.key_no_family")),J=1),p&&eo&&void 0===J){const o=[{tool:"claude-code",capable:eo.hasClaude,skipMsg:l.t(z()?"setup.skip_no_claude_desktop":"setup.skip_no_claude")},{tool:"codex",capable:eo.hasGpt,skipMsg:l.t("setup.skip_no_gpt")},{tool:"grok",capable:eo.hasGrok,skipMsg:l.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:eo.hasClaude&&z(),skipMsg:"",quiet:!0},{tool:"agy",capable:eo.hasGemini,skipMsg:l.t("setup.skip_no_gemini")}];for(const e of o)X.has(e.tool)||(e.capable?(M.push({tool:e.tool,apiKey:p,dedicated:!1}),X.add(e.tool)):e.quiet||F(e.skipMsg))}const to=Boolean(p&&oo&&void 0===J);if(G)return U(M.filter(o=>!H(o.tool)).map(o=>o.tool),M.length>0,M.filter(o=>H(o.tool)).map(o=>o.tool)),void((V>0||void 0!==J)&&(process.exitCode=J??k[R??"operation"]));const io=M.filter(o=>!H(o.tool)),lo=to||M.some(o=>o.dedicated);if((M.length>0||lo)&&!r.fromInstaller&&!await T(io.map(o=>o.tool),{keyFile:lo?$(s.getConfigDir(),"config.yaml"):void 0,installFirst:M.filter(o=>H(o.tool)).map(o=>o.tool)}))return void(process.exitCode=k.cancelled);to&&p&&s.setApiKey(p);for(const o of M)o.dedicated&&s.setToolApiKey(o.tool,o.apiKey),H(o.tool)?P.push({tool:o.tool,apiKey:o.apiKey}):await q(o.tool,o.apiKey,K)?Q+=1:(V+=1,X.delete(o.tool));if(void 0!==J)return P.length>0&&W(P.map(o=>o.tool)),void(process.exitCode=J);let so=[];if(P.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:I}))),{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){S.logError(`setup: install ${e}`,o)}E(),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 q(o,t,i)?u.push(o):f.push(o);return{still:d,applied:u,failed:f}}(P,r.install,K);so=e.still,Q+=e.applied.length,V+=e.failed.length;for(const o of[...so,...e.failed])X.delete(o)}if(Q>0){const t=[...X].filter(o=>!e(o)?.isInstalled&&!so.includes(o)),i=t.map(o=>n[o]?.command).filter(Boolean).join(" / "),s=l.t("setup.done",{count:String(Q)});D("\n"+(i?`${s}${l.t("setup.done_commands",{commands:i})}`:s)),so.length>0&&W(so);for(const o of t){const e=a.ensureNativeOnPath(o);e&&D(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"!==A("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===Q&&so.length>0&&W(so),V>0&&(L(l.t("setup.failed_summary",{count:String(V)})),x()||console.error(`${I} setup --key ${l.t("errors.key_placeholder")}`)),await t([...X],{apps:{install:await installMissingApps([...X],r.install)}}),(V>0||0===Q&&0===so.length)&&(process.exitCode=k[R??"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 _,EXIT_CODES as k}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 $,getApp as T}from"../lib/app-update.js";import{join as M}from"path";import{confirmWritePlan as G,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 O,brandEnv as B}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 D(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 F(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 L(e){console.log(o.green(e))}function R(e){console.log(o.yellow(e))}function P(e){console.error(o.red(e))}let Y=null;function q(o){const e={operation:1,authentication:2,network:3};(!Y||e[o]>e[Y])&&(Y=o)}async function z(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?`${O} setup --key ${a}`:`${O} setup ${e} ${a}`;let p;if("network_error"===i.error?(q("network"),p=_(l.t("setup.unreachable",{url:s.getBaseUrl(),reason:i.message||"network error"}),`${O} base auto`,"network_error")):"invalid_api_key"===i.error?(q("authentication"),p=y(l.t("setup.invalid_key",{label:e,reason:i.message||"invalid"}),n,"invalid_api_key")):(q("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 H(t,i,r={}){const{oneMillion:p,officialLogin:c,desktopRegistry:u,force:y}=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})}catch(o){if(x())throw g(o instanceof Error?o.message:String(o),`${O} 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 W(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 U(o){R(l.t("setup.still_missing",{tools:o.map(o=>n[o].displayName).join(l.t("setup.list_separator")),commands:o.map(o=>`${O} config ${o} --yes`).join(l.t("setup.list_separator"))}))}function J(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=(w()?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 Q(){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 _=void 0!==r.desktopRegistry;let h;if(_&&(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||_,w=Boolean(p||f.length>0),K={oneMillion:r.oneMillion,officialLogin:y,desktopRegistry:h,force:r.force};if(!w&&(m||b)&&v())return void J([...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),L(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 H("claude-desktop",o,{...K,oneMillion:void 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 $=v();$||await i(p||f[0].apiKey);const T=[],S=[];let I,q=0,V=0;const X=new Set,Z=f.map(o=>({tool:o.tool,label:`--${o.option}`,apiKey:o.apiKey,need:o.need}));for(const o of Z){if(!await z(o.label,o.apiKey)){V+=1;continue}const e=await D(o.apiKey);!e.probed||F(e,o.need)?(e.probed||R(l.t("setup.probe_failed",{label:o.label})),T.push({tool:o.tool,apiKey:o.apiKey,dedicated:!0}),X.add(o.tool)):(P(l.t(`setup.key_no_${o.need}`,{label:o.label,tool:n[o.tool].displayName})),V+=1)}const oo=!!p&&await z("--key",p);p&&!oo&&(I=k[Y??"operation"]);const eo=p&&oo?await D(p):void 0;if(p&&eo&&!eo.probed&&R(l.t("setup.probe_failed",{label:"--key"})),!(p&&eo&&eo.probed)||eo.hasClaude||eo.hasGpt||eo.hasGrok||eo.hasGemini||(P(l.t("setup.key_no_family")),I=1),p&&eo&&void 0===I){const o=[{tool:"claude-code",capable:eo.hasClaude,skipMsg:l.t(Q()?"setup.skip_no_claude_desktop":"setup.skip_no_claude")},{tool:"codex",capable:eo.hasGpt,skipMsg:l.t("setup.skip_no_gpt")},{tool:"grok",capable:eo.hasGrok,skipMsg:l.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:eo.hasClaude&&Q(),skipMsg:"",quiet:!0},{tool:"agy",capable:eo.hasGemini,skipMsg:l.t("setup.skip_no_gemini")}];for(const e of o)X.has(e.tool)||(e.capable?(T.push({tool:e.tool,apiKey:p,dedicated:!1}),X.add(e.tool)):e.quiet||R(e.skipMsg))}const to=Boolean(p&&oo&&void 0===I);if($)return J(T.filter(o=>!W(o.tool)).map(o=>o.tool),T.length>0,T.filter(o=>W(o.tool)).map(o=>o.tool)),void((V>0||void 0!==I)&&(process.exitCode=I??k[Y??"operation"]));const io=T.filter(o=>!W(o.tool)),lo=to||T.some(o=>o.dedicated);if((T.length>0||lo)&&!r.fromInstaller&&!await G(io.map(o=>o.tool),{keyFile:lo?M(s.getConfigDir(),"config.yaml"):void 0,installFirst:T.filter(o=>W(o.tool)).map(o=>o.tool)}))return void(process.exitCode=k.cancelled);to&&p&&s.setApiKey(p);for(const o of T)o.dedicated&&s.setToolApiKey(o.tool,o.apiKey),W(o.tool)?S.push({tool:o.tool,apiKey:o.apiKey}):await H(o.tool,o.apiKey,K)?q+=1:(V+=1,X.delete(o.tool));if(void 0!==I)return S.length>0&&U(S.map(o=>o.tool)),void(process.exitCode=I);let so=[];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:O}))),{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 H(o,t,i)?u.push(o):f.push(o);return{still:d,applied:u,failed:f}}(S,r.install,K);so=e.still,q+=e.applied.length,V+=e.failed.length;for(const o of[...so,...e.failed])X.delete(o)}if(q>0){const t=[...X].filter(o=>!e(o)?.isInstalled&&!so.includes(o)),i=t.map(o=>n[o]?.command).filter(Boolean).join(" / "),s=l.t("setup.done",{count:String(q)});L("\n"+(i?`${s}${l.t("setup.done_commands",{commands:i})}`:s)),so.length>0&&U(so);for(const o of t){const e=a.ensureNativeOnPath(o);e&&L(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"!==B("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===q&&so.length>0&&U(so),V>0&&(P(l.t("setup.failed_summary",{count:String(V)})),x()||console.error(`${O} setup --key ${l.t("errors.key_placeholder")}`)),await t([...X],{apps:{install:await installMissingApps([...X],r.install)}}),(V>0||0===q&&0===so.length)&&(process.exitCode=k[Y??"operation"])}
@@ -1,6 +1,10 @@
1
1
  /**
2
2
  * `vibecli upgrade [tool...]`: no argument = every installed tool vibecli knows how to upgrade (CLIs with an
3
- * `installSpec`, GUI apps with an `appInstaller` that this machine can serve). An app named explicitly is installed
4
- * when missing. `--json` prints `{ tools: [...] }`: per app its current / latest version and whether it was upgraded.
3
+ * `installSpec`, GUI apps with an `appInstaller` that this machine can serve), then one line per runtime that is
4
+ * behind (`vibecli upgrade node`). Named: CLIs, apps and runtimes (node, git, uv; components.json, aliases too). A
5
+ * tool or app named explicitly is installed when missing; `--force` reinstalls an app or runtime that is already
6
+ * the latest. `--json` prints `{ tools: [...] }`: per entry its current / latest version and whether it was upgraded.
5
7
  */
6
- export declare function upgradeCommand(tools: string[]): Promise<void>;
8
+ export declare function upgradeCommand(tools: string[], options?: {
9
+ force?: boolean;
10
+ }): Promise<void>;
@@ -1 +1 @@
1
- import o from"chalk";import{appTools as t,upgradeApp as e}from"../lib/app-update.js";import{i18n as l}from"../lib/i18n.js";import{emitJson as r,isJsonMode as n}from"../lib/runtime-options.js";import{toolManager as i}from"../lib/tool-manager.js";import{getAdapter as s,listAdapters as a}from"../lib/tools/registry.js";import{upgradeTool as p}from"../lib/tool-upgrade.js";export async function upgradeCommand(d){const c=t(),u=[...a().filter(o=>o.installSpec).map(o=>o.name),...c],m=d.length>0?d:u.filter(o=>c.includes(o)?(o=>{const t=s(o)?.appInstaller;return Boolean(t&&!t.blocker()&&t.installedPath())})(o):i.isToolInstalled(o)),f=m.filter(o=>!u.includes(o));if(f.length>0)return console.error(o.red(l.t("upgrade.unsupported",{tool:f.join(", ")}))),console.error(l.t("upgrade.supported",{tools:u.join(" / ")})),void(process.exitCode=1);if(0===m.length)return void(n()?r({tools:[]}):console.log(l.t("upgrade.nothing_installed",{tools:u.join(" / ")})));let g=0;const j=[];for(const t of m){if(c.includes(t)){const l=s(t)?.displayName??t;n()||console.log(o.bold(`\n${l}`));const r=await e(t,{install:!0}),i=["installed","upgraded","up_to_date","declined"].includes(r.result);i||(g+=1),j.push({...r,ok:i});continue}const l=await p(t);l||(g+=1),j.push({tool:t,ok:l})}n()&&r({tools:j}),g>0&&(process.exitCode=1)}
1
+ import o from"chalk";import{appTools as t,getApp as e,upgradeApp as n}from"../lib/app-update.js";import{i18n as l}from"../lib/i18n.js";import{emitJson as r,isJsonMode as i,progressToStderr as s}from"../lib/runtime-options.js";import{toolManager as a}from"../lib/tool-manager.js";import{listAdapters as p}from"../lib/tools/registry.js";import{upgradeTool as c}from"../lib/tool-upgrade.js";import{listComponents as d,resolveComponent as m,runRuntime as u}from"../lib/components.js";import{outdatedRuntimeHints as f}from"./components.js";export async function upgradeCommand(g,h={}){const j=t(),b=new Set;g=g.map(o=>{const t=m(o);return t?("runtime"===t.category&&b.add(t.id),t.adapter??t.app??t.id):o});const w=[...p().filter(o=>o.installSpec).map(o=>o.name),...j,...b],y=g.length>0?g:w.filter(o=>j.includes(o)?(o=>{const t=e(o)?.appInstaller;return Boolean(t&&!t.blocker()&&t.installedPath())})(o):a.isToolInstalled(o)),k=y.filter(o=>!w.includes(o));if(k.length>0){console.error(o.red(l.t("upgrade.unsupported",{tool:k.join(", ")})));const t=d().filter(o=>"runtime"===o.category).map(o=>o.id);return console.error(l.t("upgrade.supported",{tools:[...new Set([...w,...t])].join(" / ")})),void(process.exitCode=1)}if(0===y.length)return void(i()?r({tools:[]}):console.log(l.t("upgrade.nothing_installed",{tools:w.join(" / ")})));let x=0;const C=[];for(const t of y){if(b.has(t)){const e=m(t);i()||console.log(o.bold(`\n${e.name}`));const n=await s(()=>u(e,"upgrade",{force:h.force}));n.ok||(x+=1),C.push(n);continue}if(j.includes(t)){const l=e(t)?.displayName??t;i()||console.log(o.bold(`\n${l}`));const r=await s(()=>n(t,{install:!0,force:h.force})),a=["installed","upgraded","up_to_date","declined"].includes(r.result);a||(x+=1),C.push({...r,ok:a});continue}const l=await s(()=>c(t));l||(x+=1),C.push({tool:t,ok:l})}if(i())r({tools:C});else if(0===g.length){const t=await f();t.length&&console.log("\n"+t.map(t=>o.yellow(" ! "+t)).join("\n"))}x>0&&(process.exitCode=1)}
@@ -0,0 +1,157 @@
1
+ {
2
+ "schema": 1,
3
+ "about": "Components VibeCLI installs and upgrades (vibecli list / install / upgrade). Read by src/lib/components.ts and by scripts/gen-components-doc.mjs (docs, the install scripts' README). {scripts} = the brand's installMirror.scripts, {agy} = installMirror.agy, {devtools} = the neutral CNB mirror of fnm / uv / Git for Windows.",
4
+ "devtools": "https://cnb.cool/lib/devtools/-/releases/latest/download",
5
+ "components": [
6
+ {
7
+ "id": "node",
8
+ "name": "Node.js",
9
+ "category": "runtime",
10
+ "aliases": ["nodejs"],
11
+ "platforms": ["darwin", "linux", "win32"],
12
+ "detect": { "command": "node", "pattern": "v(\\d+\\.\\d+\\.\\d+)" },
13
+ "latest": { "type": "node-lts", "url": "https://registry.npmmirror.com/-/binary/node/index.json" },
14
+ "sources": {
15
+ "all": "fnm({devtools})+ Node 镜像 https://npmmirror.com/mirrors/node"
16
+ },
17
+ "verify": { "checksum": "fnm:SHA256SUMS;Node:fnm 下载时核对官方 SHASUMS256.txt", "signature": "—" },
18
+ "install": { "type": "script", "script": "node", "forceEnv": { "NODE_INSTALL_FORCE": "1" } },
19
+ "upgrade": { "managedBy": "fnm", "migrateGlobalPackages": true },
20
+ "check": ["node", "--version"],
21
+ "requires": []
22
+ },
23
+ {
24
+ "id": "git",
25
+ "name": "Git",
26
+ "category": "runtime",
27
+ "platforms": ["darwin", "linux", "win32"],
28
+ "detect": { "command": "git", "pattern": "git version (\\d+\\.\\d+\\.\\d+)" },
29
+ "latest": { "type": "devtools", "key": "git", "platforms": ["win32"] },
30
+ "sources": {
31
+ "darwin": "苹果命令行工具(xcode-select)",
32
+ "linux": "系统包管理器(apt、dnf、yum、zypper、pacman、apk)",
33
+ "win32": "Git for Windows({devtools})"
34
+ },
35
+ "verify": {
36
+ "checksum": "Windows:SHA256SUMS(取自 GitHub 公布的 digest)",
37
+ "signature": "macOS / Linux:系统包管理器自己的签名"
38
+ },
39
+ "install": { "type": "script", "script": "git", "forceEnv": { "GIT_INSTALL_FORCE": "1" } },
40
+ "upgrade": { "managedBy": "git-for-windows-user" },
41
+ "check": ["git", "--version"],
42
+ "requires": []
43
+ },
44
+ {
45
+ "id": "uv",
46
+ "name": "uv",
47
+ "category": "runtime",
48
+ "aliases": ["python-uv"],
49
+ "platforms": ["darwin", "linux", "win32"],
50
+ "detect": { "command": "uv", "pattern": "uv (\\d+\\.\\d+\\.\\d+)" },
51
+ "latest": { "type": "devtools", "key": "uv" },
52
+ "sources": {
53
+ "all": "uv 官方程序({devtools});Python 从 npmmirror 的 python-build-standalone 镜像、包从阿里云 PyPI 镜像"
54
+ },
55
+ "verify": { "checksum": "SHA256SUMS", "signature": "—" },
56
+ "install": { "type": "script", "script": "uv", "forceEnv": { "UV_INSTALL_FORCE": "1" } },
57
+ "upgrade": { "managedBy": "uv-standalone" },
58
+ "check": ["uv", "--version"],
59
+ "requires": []
60
+ },
61
+ {
62
+ "id": "claude-code",
63
+ "name": "Claude Code",
64
+ "category": "cli",
65
+ "aliases": ["claude"],
66
+ "platforms": ["darwin", "linux", "win32"],
67
+ "adapter": "claude-code",
68
+ "latest": { "type": "npm", "package": "@anthropic-ai/claude-code" },
69
+ "sources": {
70
+ "all": "npmmirror 的 @anthropic-ai/claude-code-<平台>(与 downloads.claude.ai 同一文件),按官方原生布局安装({scripts}/claude-code.sh / .ps1)"
71
+ },
72
+ "verify": { "checksum": "npm sha512;连得上时再核对 Anthropic 发布清单的 sha256", "signature": "—" },
73
+ "install": { "type": "adapter" },
74
+ "check": ["claude", "--version"],
75
+ "requires": []
76
+ },
77
+ {
78
+ "id": "codex",
79
+ "name": "Codex",
80
+ "category": "cli",
81
+ "platforms": ["darwin", "linux", "win32"],
82
+ "adapter": "codex",
83
+ "latest": { "type": "npm", "package": "@openai/codex" },
84
+ "sources": {
85
+ "all": "npmmirror 的 @openai/codex(vendor 目录与官方 codex-package 逐文件相同),按官方原生布局安装({scripts}/codex.sh / .ps1)"
86
+ },
87
+ "verify": { "checksum": "npm sha512", "signature": "—" },
88
+ "install": { "type": "adapter" },
89
+ "check": ["codex", "--version"],
90
+ "requires": []
91
+ },
92
+ {
93
+ "id": "grok",
94
+ "name": "Grok Build",
95
+ "category": "cli",
96
+ "platforms": ["darwin", "linux", "win32"],
97
+ "adapter": "grok",
98
+ "latest": { "type": "npm", "package": "@xai-official/grok", "staleTag": true },
99
+ "sources": { "all": "npmmirror 的 @xai-official/grok-<平台>({scripts}/grok.sh / .ps1)" },
100
+ "verify": { "checksum": "npm sha512", "signature": "—" },
101
+ "install": { "type": "adapter" },
102
+ "check": ["grok", "--version"],
103
+ "requires": []
104
+ },
105
+ {
106
+ "id": "agy",
107
+ "name": "Antigravity CLI",
108
+ "category": "cli",
109
+ "aliases": ["antigravity"],
110
+ "platforms": ["darwin", "linux", "win32"],
111
+ "adapter": "agy",
112
+ "latest": { "type": "version-file", "url": "{agy}/version.txt" },
113
+ "sources": { "all": "高速下载站 {agy}(每小时同步官方)" },
114
+ "verify": { "checksum": "官方清单的 sha512", "signature": "—" },
115
+ "install": { "type": "adapter" },
116
+ "check": ["agy", "--version"],
117
+ "requires": []
118
+ },
119
+ {
120
+ "id": "claude-desktop",
121
+ "name": "Claude Desktop",
122
+ "category": "app",
123
+ "platforms": ["darwin", "win32"],
124
+ "app": "claude-desktop",
125
+ "latest": { "type": "app" },
126
+ "sources": {
127
+ "darwin": "高速下载站 lib/claude-desktop(官方 dmg)",
128
+ "win32": "高速下载站 lib/claude-desktop(官方 MSIX)"
129
+ },
130
+ "verify": {
131
+ "checksum": "SHA256SUMS",
132
+ "signature": "macOS:Team ID Q6L2SF6YDW + 公证;Windows:Authenticode O=Anthropic, PBC"
133
+ },
134
+ "install": { "type": "app" },
135
+ "requires": []
136
+ },
137
+ {
138
+ "id": "chatgpt",
139
+ "name": "ChatGPT",
140
+ "category": "app",
141
+ "aliases": ["chatgpt-desktop", "codex-desktop", "codex-app"],
142
+ "platforms": ["darwin", "win32"],
143
+ "app": "chatgpt",
144
+ "latest": { "type": "app" },
145
+ "sources": {
146
+ "darwin": "高速下载站 lib/chatgpt-desktop(官方 dmg,只有 Apple 芯片版)",
147
+ "win32": "高速下载站 lib/chatgpt-desktop(Microsoft Store 同一个 MSIX)"
148
+ },
149
+ "verify": {
150
+ "checksum": "SHA256SUMS",
151
+ "signature": "macOS:Team ID 2DC432GLL2 + 公证;Windows:Microsoft Store 签名(OpenAI 发布者)"
152
+ },
153
+ "install": { "type": "app" },
154
+ "requires": []
155
+ }
156
+ ]
157
+ }