@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.
- package/components.json +157 -0
- package/dist/brand.json +2 -1
- package/dist/commands/components.d.ts +26 -0
- package/dist/commands/components.js +1 -0
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/setup.d.ts +4 -3
- package/dist/commands/setup.js +1 -1
- package/dist/commands/upgrade.d.ts +7 -3
- package/dist/commands/upgrade.js +1 -1
- package/dist/components.json +157 -0
- package/dist/lib/app-update.d.ts +46 -6
- package/dist/lib/app-update.js +1 -1
- package/dist/lib/brand.d.ts +2 -0
- package/dist/lib/brand.js +1 -1
- package/dist/lib/codex-sessions.js +1 -1
- package/dist/lib/components.d.ts +204 -0
- package/dist/lib/components.js +1 -0
- package/dist/lib/dry-run.js +1 -1
- package/dist/lib/i18n.js +1 -1
- package/dist/lib/post-apply.js +1 -1
- package/dist/lib/powershell-env.d.ts +12 -0
- package/dist/lib/powershell-env.js +1 -0
- package/dist/lib/program.js +1 -1
- package/dist/lib/runtime-options.d.ts +5 -0
- package/dist/lib/runtime-options.js +1 -1
- package/dist/lib/tool-upgrade.d.ts +2 -0
- package/dist/lib/tool-upgrade.js +1 -1
- package/dist/lib/tools/chatgpt-desktop.d.ts +45 -0
- package/dist/lib/tools/chatgpt-desktop.js +1 -0
- package/dist/lib/tools/claude-desktop-app.d.ts +17 -58
- package/dist/lib/tools/claude-desktop-app.js +1 -1
- package/dist/lib/tools/claude-desktop-cli.js +1 -1
- package/dist/lib/tools/claude-desktop.js +1 -1
- package/dist/lib/tools/codex.js +1 -1
- package/dist/lib/tools/desktop-app-installer.d.ts +102 -0
- package/dist/lib/tools/desktop-app-installer.js +1 -0
- package/dist/lib/tools/desktop-process.d.ts +4 -1
- package/dist/lib/tools/desktop-process.js +1 -1
- package/dist/lib/tools/elevated-reg.js +1 -1
- package/dist/lib/tools/tool-installs.d.ts +8 -0
- package/dist/lib/tools/tool-installs.js +1 -1
- package/dist/lib/tools/types.d.ts +32 -4
- package/dist/lib/windows-env.js +1 -1
- package/dist/lib/wizard.js +1 -1
- package/dist/locales/en_US.json +152 -12
- package/dist/locales/zh_CN.json +152 -12
- package/package.json +2 -1
package/dist/lib/app-update.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { AppInstaller, CompanionApp } from './tools/types.js';
|
|
1
2
|
/**
|
|
2
|
-
* Installing and upgrading GUI apps from the brand's download mirror
|
|
3
|
-
* Desktop). The app's own updater stays on; vibecli only offers the mirror's build when the installed copy is
|
|
3
|
+
* Installing and upgrading GUI apps from the brand's download mirror: adapters with an `appInstaller` (Claude
|
|
4
|
+
* Desktop) and companion apps that run on a tool's config (ChatGPT for `codex`). The app's own updater stays on; vibecli only offers the mirror's build when the installed copy is
|
|
4
5
|
* older, since the vendor's update server is often unreachable from mainland China.
|
|
5
6
|
*
|
|
6
7
|
* A running app is never closed without someone at a terminal agreeing (user, 2026-10-31): with a terminal and
|
|
@@ -21,24 +22,55 @@ export interface AppStatus {
|
|
|
21
22
|
/** The latest version couldn't be read (offline, mirror down). */
|
|
22
23
|
error?: string;
|
|
23
24
|
}
|
|
24
|
-
export type AppUpgradeOutcome = 'installed' | 'upgraded' | 'up_to_date' | 'not_installed' | 'left_running' | 'declined' | 'failed' | 'unavailable';
|
|
25
|
+
export type AppUpgradeOutcome = 'installed' | 'upgraded' | 'up_to_date' | 'not_installed' | 'left_running' | 'declined' | 'offered' | 'failed' | 'unavailable';
|
|
25
26
|
export interface AppUpgradeResult extends AppStatus {
|
|
26
27
|
result: AppUpgradeOutcome;
|
|
27
28
|
upgraded: boolean;
|
|
28
29
|
version_after: string | null;
|
|
29
30
|
reason?: string;
|
|
30
31
|
}
|
|
31
|
-
/**
|
|
32
|
+
/** An app vibecli can install / upgrade, and the tool whose config it runs on. */
|
|
33
|
+
export interface AppEntry extends Omit<CompanionApp, 'installedVersion'> {
|
|
34
|
+
appInstaller: AppInstaller;
|
|
35
|
+
installedVersion?(): string | null;
|
|
36
|
+
/** The tool it belongs to: itself for an adapter's own app, `codex` for ChatGPT. */
|
|
37
|
+
tool: string;
|
|
38
|
+
}
|
|
39
|
+
/** Apps vibecli can install / upgrade (on any platform; `blocker()` says whether here). */
|
|
32
40
|
export declare function appTools(): string[];
|
|
41
|
+
/** The app with this id, undefined for anything else. */
|
|
42
|
+
export declare function getApp(name: string): AppEntry | undefined;
|
|
43
|
+
/** Apps that go with these configured tools (Claude Desktop with itself, ChatGPT with codex). */
|
|
44
|
+
export declare function appsForTools(tools: string[]): string[];
|
|
45
|
+
/**
|
|
46
|
+
* The mirror's latest version only (cached an hour, failures ten minutes; `refresh` reads it again), no local
|
|
47
|
+
* probing: callers that check several apps fetch first, then probe (on Windows the PowerShell probes are
|
|
48
|
+
* synchronous and would hold up the event loop past the fetch timeouts).
|
|
49
|
+
*/
|
|
50
|
+
export declare function appLatest(tool: string, options?: {
|
|
51
|
+
refresh?: boolean;
|
|
52
|
+
}): Promise<{
|
|
53
|
+
version: string | null;
|
|
54
|
+
error?: string;
|
|
55
|
+
}>;
|
|
33
56
|
/** Installed / latest versions; the latest is read from the mirror at most once an hour unless `refresh`. */
|
|
34
57
|
export declare function appStatus(tool: string, options?: {
|
|
35
58
|
refresh?: boolean;
|
|
36
59
|
}): Promise<AppStatus>;
|
|
60
|
+
/** Local state with a latest version already fetched (`appLatest`). */
|
|
61
|
+
export declare function appStatusWith(tool: string, latest: {
|
|
62
|
+
version: string | null;
|
|
63
|
+
error?: string;
|
|
64
|
+
}): AppStatus;
|
|
37
65
|
/** From the cache only (menus): no network. */
|
|
38
66
|
export declare function cachedAppStatus(tool: string): AppStatus;
|
|
39
67
|
/** "current x, y available" / "x (latest)" / "not installed"; empty when nothing is known. */
|
|
40
68
|
export declare function appStatusText(status: AppStatus): string;
|
|
41
69
|
export declare function appUpgradeCommand(tool: string): string;
|
|
70
|
+
export declare function setQuitWaitForTests(wait: {
|
|
71
|
+
totalMs: number;
|
|
72
|
+
stepMs: number;
|
|
73
|
+
}): void;
|
|
42
74
|
export interface UpgradeAppOptions {
|
|
43
75
|
/** Install the app when it isn't installed (`vibecli upgrade`, setup after consent). */
|
|
44
76
|
install?: boolean;
|
|
@@ -46,9 +78,17 @@ export interface UpgradeAppOptions {
|
|
|
46
78
|
refresh?: boolean;
|
|
47
79
|
/** Say nothing when there is nothing to do (setup: only an outdated or missing app is worth a line). */
|
|
48
80
|
quiet?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* An installed copy is only upgraded after a yes at a terminal (setup, user 11-01: an app found installed is
|
|
83
|
+
* offered the upgrade, not overwritten); with `--yes` or without a terminal only the command is shown.
|
|
84
|
+
*/
|
|
85
|
+
askBeforeUpgrade?: boolean;
|
|
86
|
+
/** Reinstall even when the installed copy is already the latest (`vibecli upgrade <app> --force`). */
|
|
87
|
+
force?: boolean;
|
|
49
88
|
}
|
|
50
89
|
/**
|
|
51
|
-
* Bring the app to the mirror's latest version: install when missing (`install`), upgrade when older
|
|
52
|
-
* app is only quit after a yes at a terminal (and
|
|
90
|
+
* Bring the app to the mirror's latest version: install when missing (`install`), upgrade when older (after a yes
|
|
91
|
+
* with `askBeforeUpgrade`), reinstall with `force`. A running app is only quit after a yes at a terminal (and
|
|
92
|
+
* reopened afterwards); see the module comment.
|
|
53
93
|
*/
|
|
54
94
|
export declare function upgradeApp(tool: string, options?: UpgradeAppOptions): Promise<AppUpgradeResult>;
|
package/dist/lib/app-update.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import t from"chalk";import e from"inquirer";import{existsSync as r,mkdirSync as n,readFileSync as a,writeFileSync as o}from"fs";import{join as l}from"path";import{CLI_NAME as p}from"./brand.js";import{configManager as i}from"./config.js";import{i18n as s}from"./i18n.js";import{canPrompt as u,hasExplicitYes as d,isJsonMode as c}from"./runtime-options.js";import{track as f}from"./telemetry.js";import{compareVersions as m}from"./model-registry.js";import{
|
|
1
|
+
import t from"chalk";import e from"inquirer";import{existsSync as r,mkdirSync as n,readFileSync as a,writeFileSync as o}from"fs";import{join as l}from"path";import{CLI_NAME as p}from"./brand.js";import{configManager as i}from"./config.js";import{i18n as s}from"./i18n.js";import{canPrompt as u,hasExplicitYes as d,isJsonMode as c}from"./runtime-options.js";import{track as f}from"./telemetry.js";import{compareVersions as m}from"./model-registry.js";import{listAdapters as g}from"./tools/registry.js";import{logger as _}from"../utils/logger.js";function y(){return l(i.getConfigDir(),"app-releases.json")}function w(){try{if(!r(y()))return{};const t=JSON.parse(a(y(),"utf-8"));return t&&"object"==typeof t?t:{}}catch{return{}}}function h(t,e){try{n(i.getConfigDir(),{recursive:!0}),o(y(),JSON.stringify({...w(),[t]:e},null,2))}catch(t){_.logError("app-update.writeCache",t)}}function v(){return g().flatMap(t=>[...t.appInstaller?[{name:t.name,displayName:t.displayName,appInstaller:t.appInstaller,installedVersion:t.installedVersion,runningApp:t.runningApp,tool:t.name}]:[],...(t.companionApps??[]).map(e=>({...e,tool:t.name}))])}export function appTools(){return v().map(t=>t.name)}export function getApp(t){return v().find(e=>e.name===t)}export function appsForTools(t){return v().filter(e=>t.includes(e.tool)).map(t=>t.name)}function k(t){const e=getApp(t);if(!e)throw new Error(`no app installer for ${t}`);return e}function b(t,e,r){try{return e()}catch(e){return _.logError(`app-update.${t}`,e),r}}function q(t){const e=k(t),r=e.appInstaller,n=b("installedPath",()=>null!==r.installedPath(),!1);return{tool:t,name:e.displayName,installed:n,current:n?b("installedVersion",()=>e.installedVersion?.()??null,null):null,running:!!n&&b("isRunning",()=>e.runningApp?.isRunning()??!1,!1),blocker:b("blocker",()=>r.blocker(),"unsupported_platform")}}function x(t,e,r){const n=Boolean(t.installed&&t.current&&e&&m(t.current,e)<0);return{...t,latest:e,outdated:n,...r?{error:r}:{}}}export async function appLatest(t,e={}){const r=w()[t],n=r&&Date.now()-r.checked_at<(r.version?36e5:6e5);if(r&&n&&!e.refresh)return{version:r.version??null,...r.error?{error:r.error}:{}};try{const e=await k(t).appInstaller.latestVersion();return h(t,{version:e,checked_at:Date.now()}),{version:e}}catch(e){const n=e instanceof Error?e.message:String(e);return _.logError(`app-update.latest(${t})`,e),h(t,{error:n,checked_at:Date.now()}),{version:r?.version??null,error:n}}}export async function appStatus(t,e={}){const r=q(t);if(r.blocker&&"classic_install"!==r.blocker)return x(r,null);const{version:n,error:a}=await appLatest(t,e);return x(r,n,a)}export function appStatusWith(t,e){return x(q(t),e.version,e.error)}export function cachedAppStatus(t){const e=q(t);return x(e,e.blocker&&"classic_install"!==e.blocker?null:w()[t]?.version??null)}export function appStatusText(t){return t.installed?t.outdated?s.t("app_update.outdated",{current:t.current,latest:t.latest}):t.current&&t.latest?s.t("app_update.up_to_date",{current:t.current}):t.current??"":t.latest?s.t("app_update.not_installed",{latest:t.latest}):""}export function appUpgradeCommand(t){return`${p} upgrade ${t}`}function C(t){c()?process.stderr.write(t+"\n"):console.log(t)}async function S(t,r=!0){const{ok:n}=await e.prompt([{type:"confirm",name:"ok",message:t,default:r}]);return n}let U={totalMs:12e4,stepMs:1e3};export function setQuitWaitForTests(t){U=t}export async function upgradeApp(e,r={}){const n=Date.now(),a=await appStatus(e,{refresh:r.refresh??!0}),o=a.name,l=(t,r={})=>{const o={...a,result:t,upgraded:"upgraded"===t||"installed"===t,version_after:null,...r};return["up_to_date","unavailable","not_installed","offered"].includes(t)||f(`app-upgrade:${e}`,"failed"===t?"fail":"ok",{duration_ms:Date.now()-n,detail:{result:t,current:a.current,latest:a.latest,...r.reason?{reason:r.reason}:{}}}),o};if(a.blocker)return!r.quiet&&a.installed&&a.outdated&&C(t.yellow(" ! "+s.t("app_update.outdated",{current:a.current,latest:a.latest}))),r.quiet||C(t.yellow(" ! "+s.t(`app_update.blocked_${a.blocker}`,{tool:o,url:k(e).appInstaller.downloadPage,command:appUpgradeCommand(e)}))),l("unavailable",{reason:a.blocker});if(!a.latest)return r.quiet||C(t.yellow(" ! "+s.t("app_update.latest_unknown",{tool:o,reason:a.error??""}))),l("unavailable",{reason:a.error});if(!a.installed&&!r.install)return l("not_installed");const p=Boolean(r.force&&a.installed&&!a.outdated);if(a.installed&&!a.outdated&&!p)return r.quiet||(C(t.green(" √ "+s.t("app_update.already_latest",{tool:o,current:a.current??a.latest}))),C(t.gray(" "+s.t("app_update.force_hint",{command:appUpgradeCommand(e)})))),l("up_to_date");if(p?C(t.yellow(" ! "+s.t("app_update.reinstalling",{tool:o,latest:a.latest,current:a.current??"?"}))):!a.installed||r.askBeforeUpgrade&&!a.running||C(t.yellow(` ! ${o} `+appStatusText(a))),a.installed&&r.askBeforeUpgrade&&!a.running){if(!u()||d())return C(t.gray(" "+s.t("app_update.upgrade_hint",{tool:o,current:a.current??"?",latest:a.latest,command:appUpgradeCommand(e)}))),l("offered");if(!await S(s.t("app_update.upgrade_offer",{tool:o,current:a.current??"?",latest:a.latest})))return C(t.gray(" "+s.t("app_update.declined_hint",{command:appUpgradeCommand(e)}))),l("declined")}let i=!1;if(a.running){if(!u()||d())return C(t.yellow(" ! "+s.t("app_update.running_hint",{tool:o,command:appUpgradeCommand(e)}))),l("left_running");if(!await S(s.t("app_update.offer_quit",{tool:o,latest:a.latest})))return C(t.gray(" "+s.t("app_update.declined_hint",{command:appUpgradeCommand(e)}))),l("declined");const r=k(e).runningApp;if(r?.quit?.())i=!0;else{if(!r?.quitRefused?.()||!await async function(e,r){C(t.yellow(" ! "+s.t("app_update.quit_confirm_in_app",{tool:e,seconds:String(Math.round(U.totalMs/1e3))})));const n=Date.now()+U.totalMs;for(;Date.now()<n;)if(await new Promise(t=>setTimeout(t,U.stepMs)),!r.isRunning())return await new Promise(t=>setTimeout(t,Math.min(1e3,U.stepMs))),!0;return!1}(o,r)){const n=r?.quitRefused?.()?"app_update.quit_refused":"app_update.quit_failed";return C(t.yellow(" ! "+s.t(n,{tool:o,command:appUpgradeCommand(e)}))),l(r?.quitRefused?.()?"left_running":"failed",{reason:r?.quitRefused?.()?"quit_refused":"quit_failed"})}i=!0}}try{const{version:r}=await async function(e){const r=k(e).appInstaller,n=!c()&&Boolean(process.stdout.isTTY);let a=-1;try{return await r.install({downloading:n=>C(t.gray(" "+s.t("app_update.downloading",{tool:k(e).displayName,version:n,size:String(r.sizeMb())}))),percent:e=>{!n||e-a<5||(a=e,process.stdout.write(t.gray(`\r ${e}%`)),e>=100&&process.stdout.write("\n"))},verifying:()=>{n&&a>=0&&a<100&&process.stdout.write("\n"),a=100,C(t.gray(" "+s.t("app_update.verifying",{vendor:r.vendor})))},installing:()=>C(t.gray(" "+s.t("app_update.installing")))})}finally{n&&a>=0&&a<100&&process.stdout.write("\n")}}(e);return C(t.green(" √ "+(p?s.t("app_update.reinstalled",{tool:o,version:r}):a.installed?s.t("app_update.upgraded",{tool:o,from:a.current??"?",to:r}):s.t("app_update.installed",{tool:o,version:r})))),i&&!k(e).runningApp?.launch?.()&&C(t.yellow(" ! "+s.t("setup.reopen_hint",{tool:o}))),l(a.installed?"upgraded":"installed",{version_after:r,current:a.current})}catch(r){const n=r instanceof Error?r.message:String(r);return _.logError(`app-update.install(${e})`,r),C(t.yellow(" ! "+(a.installed?s.t("app_update.upgrade_failed",{tool:o,reason:n,current:a.current??"?",command:appUpgradeCommand(e)}):s.t("app_update.install_failed",{tool:o,reason:n,command:appUpgradeCommand(e)})))),i&&k(e).runningApp?.launch?.(),l("failed",{reason:n})}}
|
package/dist/lib/brand.d.ts
CHANGED
|
@@ -50,6 +50,8 @@ export interface Brand {
|
|
|
50
50
|
agy?: string;
|
|
51
51
|
/** Claude Desktop download page for macOS / Windows. */
|
|
52
52
|
claudeDesktop?: string;
|
|
53
|
+
/** ChatGPT desktop app (contains Codex) download page for macOS / Windows. */
|
|
54
|
+
chatgptDesktop?: string;
|
|
53
55
|
};
|
|
54
56
|
/** Claude Code plugin marketplaces tried before Anthropic's GitHub repo. */
|
|
55
57
|
pluginMarketplaces: BrandPluginMarketplace[];
|
package/dist/lib/brand.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as e,readdirSync as r,readFileSync as t}from"fs";import{dirname as n,join as o}from"path";import{fileURLToPath as a}from"url";const i=["id","displayName","productName","cliName","envPrefix","configDirName","providerKey","apiKeyEnv","desktopEntryName","packageName"];export const NEUTRAL_CLI_NAME="codekey";export function normalizeBrand(e){const r=e.cliName??e.shortName??"codekey";return{...e,cliName:r,envPrefix:e.envPrefix??r.toUpperCase().replace(/-/g,"_"),configDirName:e.configDirName??`.${r}`}}export function validateBrand(e,r="brand"){if(!e||"object"!=typeof e)throw new Error(`${r}: not an object`);const t=normalizeBrand(e);for(const e of i)if("string"!=typeof t[e]||!t[e].trim())throw new Error(`${r}: ${e} is required`);if(!/^[a-z][a-z0-9-]*$/.test(t.cliName))throw new Error(`${r}: cliName must be a lowercase command name`);if(!/^[A-Z][A-Z0-9_]*$/.test(t.envPrefix))throw new Error(`${r}: envPrefix must be UPPER_SNAKE`);if(!/^[a-z][a-z0-9-]*$/.test(t.providerKey))throw new Error(`${r}: providerKey must be lowercase`);const n=t.gatewayAddresses;if(!Array.isArray(n)||0===n.length||n.some(e=>!e||"string"!=typeof e.url||!/^https:\/\//.test(e.url)||"string"!=typeof e.label))throw new Error(`${r}: gatewayAddresses must be a non-empty list of { url: https://…, label }`);const o=t.links;if(!o||"string"!=typeof o.tokenPage)throw new Error(`${r}: links.tokenPage is required`);if(!Array.isArray(t.pluginMarketplaces))throw new Error(`${r}: pluginMarketplaces must be a list`);if(!Array.isArray(t.updateRegistries)||0===t.updateRegistries.length)throw new Error(`${r}: updateRegistries must be a non-empty list`);return t}export function loadBrandFile(e){return validateBrand(JSON.parse(t(e,"utf-8")),e)}let s=function(){const i=n(a(import.meta.url)),s=o(i,"..","brand.json");if(e(s))return loadBrandFile(s);const
|
|
1
|
+
import{existsSync as e,readdirSync as r,readFileSync as t}from"fs";import{dirname as n,join as o}from"path";import{fileURLToPath as a}from"url";const i=["id","displayName","productName","cliName","envPrefix","configDirName","providerKey","apiKeyEnv","desktopEntryName","packageName"];export const NEUTRAL_CLI_NAME="codekey";export function normalizeBrand(e){const r=e.cliName??e.shortName??"codekey";return{...e,cliName:r,envPrefix:e.envPrefix??r.toUpperCase().replace(/-/g,"_"),configDirName:e.configDirName??`.${r}`}}export function validateBrand(e,r="brand"){if(!e||"object"!=typeof e)throw new Error(`${r}: not an object`);const t=normalizeBrand(e);for(const e of i)if("string"!=typeof t[e]||!t[e].trim())throw new Error(`${r}: ${e} is required`);if(!/^[a-z][a-z0-9-]*$/.test(t.cliName))throw new Error(`${r}: cliName must be a lowercase command name`);if(!/^[A-Z][A-Z0-9_]*$/.test(t.envPrefix))throw new Error(`${r}: envPrefix must be UPPER_SNAKE`);if(!/^[a-z][a-z0-9-]*$/.test(t.providerKey))throw new Error(`${r}: providerKey must be lowercase`);const n=t.gatewayAddresses;if(!Array.isArray(n)||0===n.length||n.some(e=>!e||"string"!=typeof e.url||!/^https:\/\//.test(e.url)||"string"!=typeof e.label))throw new Error(`${r}: gatewayAddresses must be a non-empty list of { url: https://…, label }`);const o=t.links;if(!o||"string"!=typeof o.tokenPage)throw new Error(`${r}: links.tokenPage is required`);if(!Array.isArray(t.pluginMarketplaces))throw new Error(`${r}: pluginMarketplaces must be a list`);if(!Array.isArray(t.updateRegistries)||0===t.updateRegistries.length)throw new Error(`${r}: updateRegistries must be a non-empty list`);return t}export function loadBrandFile(e){return validateBrand(JSON.parse(t(e,"utf-8")),e)}let s=function(){const i=n(a(import.meta.url)),s=o(i,"..","brand.json");if(e(s))return loadBrandFile(s);const c=o(i,"..","..","brands");for(const n of e(c)?r(c).filter(e=>e.endsWith(".json")).sort():[]){const e=JSON.parse(t(o(c,n),"utf-8"));if(!0===e.default)return validateBrand(e,o(c,n))}throw new Error(`brand.json not found next to ${i}`)}();export function brand(){return s}export function setBrandForTests(e){const r=s;return s=e,()=>{s=r}}export function brandEnv(e){return process.env[brandEnvName(e)]}export function brandEnvName(e){return`${s.envPrefix}_${e}`}function c(e,r){return"zh_CN"===r?e.join("、"):e.length>1?`${e.slice(0,-1).join(", ")} and ${e[e.length-1]}`:e.join("")}export function brandTokens(e){const r=new URL(s.gatewayAddresses[0].url),t=s.gatewayAddresses[1]?.url??s.gatewayAddresses[0].url;return{brand:s.displayName,product:s.productName,cli:s.cliName,package:s.packageName,configDir:s.configDirName,envPrefix:s.envPrefix,siteHost:r.host,altSiteUrl:t,updateSources:c(s.updateRegistries.map(e=>e.label),e)}}export const BRAND_NAME=s.displayName;export const PROVIDER_KEY=s.providerKey;export const API_KEY_ENV=s.apiKeyEnv;export const CLI_NAME=s.cliName;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{spawnSync as t}from"child_process";import{closeSync as e,copyFileSync as o,createReadStream as r,createWriteStream as n,existsSync as s,mkdirSync as i,openSync as a,readFileSync as c,readSync as
|
|
1
|
+
import{spawnSync as t}from"child_process";import{closeSync as e,copyFileSync as o,createReadStream as r,createWriteStream as n,existsSync as s,mkdirSync as i,openSync as a,readFileSync as c,readSync as l,readdirSync as f,realpathSync as d,renameSync as p,statSync as u,utimesSync as m,writeFileSync as h}from"fs";import{basename as g,join as b,resolve as y}from"path";import{pipeline as S}from"stream/promises";import*as _ from"@iarna/toml";import{codexHome as v,toolHome as w}from"./tools/types.js";import{CLI_NAME as E}from"./brand.js";import{powerShellEnv as x}from"./powershell-env.js";export{v as codexHome};export function currentCodexProvider(){try{const t=_.parse(c(b(v(),"config.toml"),"utf-8"));return"string"==typeof t.model_provider&&t.model_provider.trim()?t.model_provider.trim():"openai"}catch{return"openai"}}let N=()=>{if("win32"===process.platform)return`${t("powershell.exe",["-NoProfile","-NonInteractive","-Command","(Get-Process -Name codex -ErrorAction SilentlyContinue).Id"],{encoding:"utf-8",windowsHide:!0,env:x()}).stdout??""}`.split(/\s+/).filter(Boolean).map(Number);const e=process.getuid?.(),o=`${t("pgrep",["-x","-i",...void 0===e?[]:["-u",String(e)],"codex"],{encoding:"utf-8"}).stdout??""}`.split(/\s+/).filter(Boolean).map(Number);if("linux"!==process.platform)return o;const r=O(v());return o.filter(t=>{let e;try{e=c(`/proc/${t}/environ`,"utf-8")}catch{return!0}const o=new Map(e.split("\0").map(t=>[t.slice(0,t.indexOf("=")),t.slice(t.indexOf("=")+1)])),n=o.get("CODEX_HOME")?.trim()||(o.get("HOME")?b(o.get("HOME"),".codex"):null);return null===n||O(n)===r})};function O(t){try{return d(t)}catch{return t}}export function setCodexProcessCheckForTests(t){N=t}export function runningCodexPids(){try{return N()}catch{return[]}}function $(t){const o=a(t,"r");try{const t=[],e=Buffer.alloc(65536);for(;;){const r=l(o,e,0,e.length,null);if(r<=0)break;const n=e.subarray(0,r).indexOf(10);if(n>=0){t.push(Buffer.from(e.subarray(0,n)));break}t.push(Buffer.from(e.subarray(0,r)))}return Buffer.concat(t).toString("utf-8")}finally{e(o)}}async function D(t,e,o){const{atime:s,mtime:i}=u(t),a=`${t}.${E}-tmp`,c=n(a);c.write(e),await S(r(t,{start:o}),c),p(a,t),m(t,s,i)}export function codexSqliteHome(){const t=v();try{const e=_.parse(c(b(t,"config.toml"),"utf-8")),o="string"==typeof e.sqlite_home?e.sqlite_home.trim():"";if(o)return"~"===o||o.startsWith("~/")?b(w(),o.slice(1)):y(t,o)}catch{}const e=process.env.CODEX_SQLITE_HOME?.trim();return e?y(e):t}function T(){const t=codexSqliteHome();if(!s(t))return null;const e=f(t).map(t=>/^state_(\d+)\.sqlite$/.exec(t)).filter(t=>!!t).sort((t,e)=>Number(e[1])-Number(t[1]));return e.length>0?b(t,e[0][0]):null}const A={threads:"id",local_thread_catalog:"thread_id"};function B(){const t=b(codexSqliteHome(),"sqlite");return s(t)?f(t).filter(t=>/\.(db|sqlite3?)$/.test(t)).map(e=>b(t,e)).sort():[]}function C(t,e,o){const r=function(t,e){return new Set(t.prepare(`PRAGMA table_info(${e})`).all().map(t=>String(t.name)))}(t,e),n=A[e];if(!r.has(n)||!r.has("model_provider"))return null;const s=r.has("host_id")?" AND host_id = 'local'":"";return t.prepare(`SELECT ${n} AS id, model_provider AS "from" FROM ${e} WHERE COALESCE(model_provider, '') NOT IN ('', ?)${s}`).all(o).map(t=>({id:String(t.id),from:String(t.from)}))}async function H(t){try{return new((await import("node:sqlite")).DatabaseSync)(t)}catch(t){return`node:sqlite unavailable (Node ${process.versions.node}; needs 22.13+): ${t instanceof Error?t.message:String(t)}`}}export const NO_STATE_DB="no state DB";export async function moveSessionsToProvider(t,e={}){const r=function(){const t=[],e=o=>{if(s(o))for(const r of f(o,{withFileTypes:!0})){const n=b(o,r.name);r.isDirectory()?e(n):r.isFile()&&r.name.endsWith(".jsonl")&&t.push(n)}};return e(b(v(),"sessions")),e(b(v(),"archived_sessions")),t}(),n=[];for(const e of r){let o,r;try{o=$(e)}catch{continue}try{r=JSON.parse(o)}catch{continue}const s=r.payload?.model_provider;"session_meta"===r.type&&"string"==typeof s&&s!==t&&(r.payload.model_provider=t,n.push({file:e,from:s,line:JSON.stringify(r),length:Buffer.byteLength(o,"utf-8")}))}const a=[T(),...B()].filter(t=>!!t);let c=a.length>0?null:NO_STATE_DB;const l=[];for(const e of a){const o=await H(e);if("string"==typeof o){c=o;break}const r=[];try{for(const n of Object.keys(A)){const s=C(o,n,t);s&&s.length>0&&r.push({db:e,table:n,rows:s})}}catch{}l.push({path:e,db:o,tables:r})}const d=l.flatMap(t=>t.tables),p=new Set(d.flatMap(t=>t.rows.map(t=>t.id))),u={target:t,scanned:r.length,moved:n.map(({file:t,from:e})=>({file:t,from:e})),dbRows:p.size,dbSkipped:c,backupDir:null},m=()=>l.forEach(t=>t.db.close());if(e.dryRun||0===n.length&&0===d.length)return m(),u;const y=b(v(),"backups",`${E}-sessions-${(new Date).toISOString().replace(/[:.]/g,"-")}`);i(y,{recursive:!0}),l.forEach(({path:t,tables:e},r)=>{if(0!==e.length)for(const e of["","-wal","-shm"])s(t+e)&&o(t+e,b(y,`${r}-${g(t)}${e}`))});const S={target:t,moved:u.moved,tables:d};h(b(y,"manifest.json"),JSON.stringify(S,null,2)+"\n");for(const t of n)await D(t.file,t.line,t.length);for(const{db:e,tables:o}of l)for(const{table:r,rows:n}of o){const o=e.prepare(`UPDATE ${r} SET model_provider = ? WHERE ${A[r]} = ? AND model_provider = ?`);for(const{id:e,from:r}of n)o.run(t,e,r)}return m(),u.backupDir=y,u}export async function undoSessionMove(t){const e=JSON.parse(c(b(t,"manifest.json"),"utf-8"));let o=0;for(const{file:t,from:r}of e.moved){if(!s(t))continue;const e=$(t),n=JSON.parse(e);n.payload&&(n.payload.model_provider=r,await D(t,JSON.stringify(n),Buffer.byteLength(e,"utf-8")),o+=1)}const r=e.tables??(e.db&&e.threads?[{db:e.db,table:"threads",rows:e.threads}]:[]),n=new Set;for(const{db:t,table:o,rows:i}of r){if(!s(t)||0===i.length||!A[o])continue;const r=await H(t);if("string"==typeof r)continue;const a=r.prepare(`UPDATE ${o} SET model_provider = ? WHERE ${A[o]} = ? AND model_provider = ?`);for(const{id:t,from:o}of i)Number(a.run(o,t,e.target).changes)>0&&n.add(t);r.close()}return{files:o,dbRows:n.size}}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The components vibecli installs and upgrades (`vibecli list` / `install` / `upgrade`): runtimes (Node, Git, uv),
|
|
3
|
+
* coding CLIs (Claude Code, Codex, Grok Build, agy) and desktop apps (Claude Desktop, ChatGPT). What each one is,
|
|
4
|
+
* where it comes from and how it is checked is declared once in `components.json` (repo root, shipped with the
|
|
5
|
+
* package); the docs and the install scripts' README are generated from the same file
|
|
6
|
+
* (`scripts/gen-components-doc.mjs`).
|
|
7
|
+
*
|
|
8
|
+
* - CLIs and apps are driven by their tool adapter (`installSpec` / `appInstaller`), as before.
|
|
9
|
+
* - Runtimes are installed by the brand's install scripts (`node.sh` / `node.ps1` …), which already find an
|
|
10
|
+
* existing copy, pick a mirror and check sha256. vibecli only upgrades a copy that one of those scripts (or the
|
|
11
|
+
* vendor's own standalone installer at the same place) manages: fnm's Node, uv in ~/.local/bin, the per-user
|
|
12
|
+
* Git for Windows. A copy from Homebrew, nvm, the system … is reported with the command that upgrades it; `--force`
|
|
13
|
+
* installs our own copy anyway.
|
|
14
|
+
* - Already installed + `install`: only the state and the upgrade command, never overwritten (user, 11-01); `--force`
|
|
15
|
+
* reinstalls.
|
|
16
|
+
*/
|
|
17
|
+
export type ComponentCategory = 'runtime' | 'cli' | 'app';
|
|
18
|
+
export interface ComponentSpec {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
category: ComponentCategory;
|
|
22
|
+
aliases?: string[];
|
|
23
|
+
platforms: NodeJS.Platform[];
|
|
24
|
+
/** Runtimes: the command and how to read its version out of `<command> --version`. */
|
|
25
|
+
detect?: {
|
|
26
|
+
command: string;
|
|
27
|
+
pattern: string;
|
|
28
|
+
};
|
|
29
|
+
latest: {
|
|
30
|
+
type: 'node-lts';
|
|
31
|
+
url: string;
|
|
32
|
+
} | {
|
|
33
|
+
type: 'devtools';
|
|
34
|
+
key: string;
|
|
35
|
+
platforms?: NodeJS.Platform[];
|
|
36
|
+
} | {
|
|
37
|
+
type: 'npm';
|
|
38
|
+
package: string;
|
|
39
|
+
staleTag?: boolean;
|
|
40
|
+
} | {
|
|
41
|
+
type: 'version-file';
|
|
42
|
+
url: string;
|
|
43
|
+
} | {
|
|
44
|
+
type: 'app';
|
|
45
|
+
};
|
|
46
|
+
/** Where it is downloaded from, per platform (`all` for every one); `{scripts}`, `{agy}`, `{devtools}` expand. */
|
|
47
|
+
sources: Partial<Record<NodeJS.Platform | 'all', string>>;
|
|
48
|
+
verify: {
|
|
49
|
+
checksum: string;
|
|
50
|
+
signature: string;
|
|
51
|
+
};
|
|
52
|
+
install: {
|
|
53
|
+
type: 'script';
|
|
54
|
+
script: string;
|
|
55
|
+
forceEnv?: Record<string, string>;
|
|
56
|
+
} | {
|
|
57
|
+
type: 'adapter';
|
|
58
|
+
} | {
|
|
59
|
+
type: 'app';
|
|
60
|
+
};
|
|
61
|
+
upgrade?: {
|
|
62
|
+
managedBy: string;
|
|
63
|
+
migrateGlobalPackages?: boolean;
|
|
64
|
+
};
|
|
65
|
+
/** Tool adapter for CLIs, app id for desktop apps. */
|
|
66
|
+
adapter?: string;
|
|
67
|
+
app?: string;
|
|
68
|
+
/** Command that shows it works after installing. */
|
|
69
|
+
check?: string[];
|
|
70
|
+
/** Components installed first when missing. */
|
|
71
|
+
requires: string[];
|
|
72
|
+
}
|
|
73
|
+
interface Manifest {
|
|
74
|
+
schema: number;
|
|
75
|
+
devtools: string;
|
|
76
|
+
components: ComponentSpec[];
|
|
77
|
+
}
|
|
78
|
+
/** Validates the shape the code relies on; a broken manifest is a build error, caught by the unit tests. */
|
|
79
|
+
export declare function parseManifest(text: string): Manifest;
|
|
80
|
+
/** Tests swap in their own manifest (null = the shipped one). */
|
|
81
|
+
export declare function setComponentManifestForTests(text: string | null): void;
|
|
82
|
+
export declare function listComponents(): ComponentSpec[];
|
|
83
|
+
/** By id or alias, case-insensitive. */
|
|
84
|
+
export declare function resolveComponent(name: string): ComponentSpec | undefined;
|
|
85
|
+
export declare function componentPlatform(): NodeJS.Platform;
|
|
86
|
+
/** `{scripts}` / `{agy}` / `{devtools}` → this brand's mirrors; null when the brand has no such mirror. */
|
|
87
|
+
export declare function expandUrl(text: string): string | null;
|
|
88
|
+
export declare function componentSource(spec: ComponentSpec, platform?: NodeJS.Platform): string;
|
|
89
|
+
/**
|
|
90
|
+
* Why components can't be installed for this account, null when they can. Everything goes into the user's own
|
|
91
|
+
* home directory: under sudo it would land in root's (and belong to root), as SYSTEM in the system profile.
|
|
92
|
+
* Plain root (a container, a server) is its own user and is fine.
|
|
93
|
+
*/
|
|
94
|
+
export declare function installBlocker(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): 'sudo' | 'system' | null;
|
|
95
|
+
export interface Probe {
|
|
96
|
+
path: string;
|
|
97
|
+
version: string | null;
|
|
98
|
+
}
|
|
99
|
+
/** Where our scripts (or the vendor's standalone installer) put the runtime, checked when PATH doesn't have it. */
|
|
100
|
+
export declare function knownRuntimePaths(id: string, platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): string[];
|
|
101
|
+
/** Every working copy: PATH order first (the first one is what a command runs), then the known places. */
|
|
102
|
+
export declare function probeRuntime(spec: ComponentSpec, platform?: NodeJS.Platform): Probe[];
|
|
103
|
+
/** Where the install script puts the runtime (fnm's default alias, ~/.local/bin, the per-user Git for Windows). */
|
|
104
|
+
export declare function scriptTarget(id: string, platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): string | null;
|
|
105
|
+
/**
|
|
106
|
+
* Who looks after this copy, and whether vibecli may upgrade it in place: `auto` = one of our install scripts
|
|
107
|
+
* (or the vendor's standalone installer at the same place) manages it; otherwise a hint names the right command.
|
|
108
|
+
*/
|
|
109
|
+
export interface RuntimeManager {
|
|
110
|
+
by: string;
|
|
111
|
+
auto: boolean;
|
|
112
|
+
/** The command that upgrades it, for copies vibecli leaves alone. */
|
|
113
|
+
hint?: string;
|
|
114
|
+
}
|
|
115
|
+
export declare function runtimeManager(id: string, path: string, platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): RuntimeManager;
|
|
116
|
+
/** The newest LTS in Node's dist index (newest first; `lts` is false or the line's codename). */
|
|
117
|
+
export declare function latestNodeLts(indexJson: string): string;
|
|
118
|
+
/** `key=value` lines of the devtools mirror's versions.txt; versions come back as x.y.z (`v2.56.0.windows.4` → 2.56.0). */
|
|
119
|
+
export declare function devtoolsVersion(text: string, key: string): string;
|
|
120
|
+
/** The newest version (cached an hour, failures ten minutes; `refresh` reads it again). Null when there is none to compare with. */
|
|
121
|
+
export declare function latestVersion(spec: ComponentSpec, options?: {
|
|
122
|
+
refresh?: boolean;
|
|
123
|
+
}): Promise<{
|
|
124
|
+
version: string | null;
|
|
125
|
+
error?: string;
|
|
126
|
+
}>;
|
|
127
|
+
export interface ComponentStatus {
|
|
128
|
+
id: string;
|
|
129
|
+
name: string;
|
|
130
|
+
category: ComponentCategory;
|
|
131
|
+
/** This platform has it at all (Claude Desktop / ChatGPT: macOS and Windows). */
|
|
132
|
+
supported: boolean;
|
|
133
|
+
installed: boolean;
|
|
134
|
+
current: string | null;
|
|
135
|
+
latest: string | null;
|
|
136
|
+
outdated: boolean;
|
|
137
|
+
path: string | null;
|
|
138
|
+
/** fnm / brew / native / npm …; null when not installed. */
|
|
139
|
+
managed_by: string | null;
|
|
140
|
+
/** vibecli upgrades it in place (`vibecli upgrade <id>`); false = `hint` names how. */
|
|
141
|
+
auto_upgrade: boolean;
|
|
142
|
+
hint?: string;
|
|
143
|
+
source: string;
|
|
144
|
+
/** Why vibecli can't install it here (sudo, SYSTEM, a desktop app's blocker), null when it can. */
|
|
145
|
+
blocker: string | null;
|
|
146
|
+
/** The latest version doesn't run on this machine; this is the newest that does (found by the last upgrade). */
|
|
147
|
+
capped_at?: string;
|
|
148
|
+
error?: string;
|
|
149
|
+
}
|
|
150
|
+
export type LatestInfo = {
|
|
151
|
+
version: string | null;
|
|
152
|
+
error?: string;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Latest versions of several components at once, before any local probing: `list` checks them all, and on
|
|
156
|
+
* Windows the probes (PowerShell for app versions and processes) are synchronous, so fetches left running
|
|
157
|
+
* across them hit their timeouts. Pass the result to `componentStatus({ latest })`.
|
|
158
|
+
*/
|
|
159
|
+
export declare function prefetchLatest(specs: ComponentSpec[], options?: {
|
|
160
|
+
refresh?: boolean;
|
|
161
|
+
}): Promise<Map<string, LatestInfo>>;
|
|
162
|
+
export declare function componentStatus(spec: ComponentSpec, options?: {
|
|
163
|
+
refresh?: boolean;
|
|
164
|
+
offline?: boolean;
|
|
165
|
+
latest?: LatestInfo;
|
|
166
|
+
}): Promise<ComponentStatus>;
|
|
167
|
+
/** Globally installed npm packages of the Node at `nodePath` (fnm keeps them per Node version). */
|
|
168
|
+
export declare function globalPackages(nodePath: string, platform?: NodeJS.Platform): Array<{
|
|
169
|
+
name: string;
|
|
170
|
+
version: string;
|
|
171
|
+
}>;
|
|
172
|
+
export type ComponentOutcome = 'installed' | 'upgraded' | 'reinstalled' | 'up_to_date' | 'already_installed' | 'manual' | 'unavailable' | 'failed';
|
|
173
|
+
export interface ComponentResult {
|
|
174
|
+
tool: string;
|
|
175
|
+
category: ComponentCategory;
|
|
176
|
+
current: string | null;
|
|
177
|
+
latest: string | null;
|
|
178
|
+
result: ComponentOutcome;
|
|
179
|
+
version_after: string | null;
|
|
180
|
+
ok: boolean;
|
|
181
|
+
reason?: string;
|
|
182
|
+
hint?: string;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Install (`mode: 'install'`) or upgrade a runtime. Installing one that is there only reports it (`--force`
|
|
186
|
+
* reinstalls); upgrading one another manager owns names that manager's command (`--force` installs ours).
|
|
187
|
+
*/
|
|
188
|
+
export declare function runRuntime(spec: ComponentSpec, mode: 'install' | 'upgrade', options?: {
|
|
189
|
+
force?: boolean;
|
|
190
|
+
}): Promise<ComponentResult>;
|
|
191
|
+
/** "x a → b: run …" for an outdated copy. */
|
|
192
|
+
export declare function upgradeAdvice(status: ComponentStatus): string;
|
|
193
|
+
export declare function setComponentDepsForTests(deps: {
|
|
194
|
+
platform?: NodeJS.Platform | null;
|
|
195
|
+
uid?: number | null;
|
|
196
|
+
systemPaths?: boolean;
|
|
197
|
+
registryPath?: () => string[];
|
|
198
|
+
versionRunner?: (path: string) => string;
|
|
199
|
+
macDeveloperTools?: () => boolean;
|
|
200
|
+
fetchText?: (url: string) => Promise<string>;
|
|
201
|
+
scriptRunner?: (url: string, env: Record<string, string>) => Promise<boolean>;
|
|
202
|
+
commandRunner?: (command: string, args: string[]) => Promise<boolean>;
|
|
203
|
+
}): void;
|
|
204
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{spawnSync as t}from"child_process";import{existsSync as e,mkdirSync as n,readFileSync as o,readdirSync as r,realpathSync as s,statSync as a,writeFileSync as i}from"fs";import{delimiter as l,dirname as c,isAbsolute as u,join as p,sep as d}from"path";import{fileURLToPath as m}from"url";import f from"chalk";import{brand as g,CLI_NAME as h}from"./brand.js";import{configManager as w}from"./config.js";import{i18n as v}from"./i18n.js";import{appLatest as y,appStatus as b,appStatusWith as $,cachedAppStatus as _,getApp as P}from"./app-update.js";import{compareVersions as x}from"./model-registry.js";import{isJsonMode as A}from"./runtime-options.js";import{track as k}from"./telemetry.js";import{runWatched as S}from"./tool-upgrade.js";import{getAdapter as D}from"./tools/registry.js";import{findInstallsIncludingNative as L,forgetInstalls as j,NPM_MIRROR as E,npmMirrorVersion as R}from"./tools/tool-installs.js";import{toolHome as C}from"./tools/types.js";import{logger as T}from"../utils/logger.js";let M=null;export function parseManifest(t){const e=JSON.parse(t);if(1!==e.schema||!Array.isArray(e.components))throw new Error("components.json: schema must be 1 with a components list");const n=new Set;for(const t of e.components){if(!t.id||!t.name||!["runtime","cli","app"].includes(t.category))throw new Error(`components.json: bad entry ${JSON.stringify(t.id)}`);for(const e of[t.id,...t.aliases??[]]){if(n.has(e))throw new Error(`components.json: duplicate name ${e}`);n.add(e)}if("runtime"===t.category&&(!t.detect||"script"!==t.install.type))throw new Error(`components.json: runtime ${t.id} needs detect + a script`);if("cli"===t.category&&!t.adapter)throw new Error(`components.json: cli ${t.id} needs an adapter`);if("app"===t.category&&!t.app)throw new Error(`components.json: app ${t.id} needs an app id`)}for(const t of e.components)for(const e of t.requires)if(!n.has(e))throw new Error(`components.json: ${t.id} requires unknown ${e}`);return e}function N(){return M||(M=parseManifest(o(function(){const t=c(m(import.meta.url)),n=[p(t,"..","..","components.json"),p(t,"..","components.json"),p(t,"components.json")],o=n.find(t=>e(t));if(!o)throw new Error(`components.json not found, searched: ${n.join(", ")}`);return o}(),"utf-8"))),M}export function setComponentManifestForTests(t){M=null===t?null:parseManifest(t)}export function listComponents(){return N().components}export function resolveComponent(t){const e=t.trim().toLowerCase();return listComponents().find(t=>t.id===e||(t.aliases??[]).includes(e))}let O=null;export function componentPlatform(){return O??process.platform}export function expandUrl(t){const e=g().installMirror??{};let n=!1;const o=t.replace(/\{(scripts|agy|devtools)\}/g,(t,o)=>{const r="devtools"===o?N().devtools:e[o];return r||(n=!0),r??""});return n?null:o}export function componentSource(t,e=componentPlatform()){return(t.sources[e]??t.sources.all??"").replace(/\{(scripts|agy|devtools)\}/g,(t,e)=>("devtools"===e?N().devtools:g().installMirror?.[e])??t)}export function installBlocker(t=process.env,e=componentPlatform()){return"win32"===e?/\\system32\\config\\systemprofile/i.test(t.USERPROFILE??"")||t.USERNAME?.endsWith("$")?"system":null:0===(U??process.getuid?.())&&t.SUDO_USER&&"root"!==t.SUDO_USER?"sudo":null}let U=null,I=!0,B=e=>{const n=/\.(cmd|bat)$/i.test(e)?t(`"${e}" --version`,{encoding:"utf-8",timeout:1e4,windowsHide:!0,shell:!0,stdio:["ignore","pipe","pipe"]}):t(e,["--version"],{encoding:"utf-8",timeout:1e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]});return`${n.stdout??""}${n.stderr??""}`},F=()=>0===t("xcode-select",["-p"],{stdio:"ignore",timeout:1e4}).status;function V(t){try{return s(t)}catch{return t}}function H(t,e){return"win32"===e?[`${t}.exe`,`${t}.cmd`]:[t]}export function knownRuntimePaths(t,e=componentPlatform(),n=process.env){const o=C();if("node"===t){if("win32"===e){const t=n.FNM_DIR||p(n.APPDATA||p(o,"AppData","Roaming"),"fnm");return[p(t,"aliases","default","node.exe"),p(n.LOCALAPPDATA||p(o,"AppData","Local"),"Programs","nodejs","node.exe")]}return[p(W(e,n),"aliases","default","bin","node"),"/opt/homebrew/bin/node","/usr/local/bin/node","/usr/bin/node"]}if("uv"===t)return"win32"===e?[p(o,".local","bin","uv.exe"),p(o,".cargo","bin","uv.exe")]:[p(n.UV_INSTALL_DIR||p(o,".local","bin"),"uv"),p(o,".cargo","bin","uv"),"/opt/homebrew/bin/uv","/usr/local/bin/uv"];if("git"===t){if("win32"===e){const t=n.LOCALAPPDATA||p(o,"AppData","Local");return[p(t,"Programs","Git","cmd","git.exe"),p(n.ProgramFiles||"C:\\Program Files","Git","cmd","git.exe")]}return["/opt/homebrew/bin/git","/usr/local/bin/git","/usr/bin/git"]}return[]}function W(t,n){if(n.FNM_DIR)return n.FNM_DIR;const o=C();if("win32"===t)return p(n.APPDATA||p(o,"AppData","Roaming"),"fnm");const r=p(o,".local","share","fnm"),s=p(o,"Library","Application Support","fnm");return"darwin"===t&&!e(r)&&e(s)?s:r}let G=()=>{const e=e=>{const n=`${t("reg",["query",e,"/v","Path"],{encoding:"utf-8",timeout:1e4,windowsHide:!0,stdio:["ignore","pipe","ignore"]}).stdout??""}`.split(/\r?\n/).find(t=>/\sREG_(EXPAND_)?SZ\s/.test(t));return n?n.replace(/^.*?REG_(EXPAND_)?SZ\s+/,""):""};return[e("HKCU\\Environment"),e("HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment")].flatMap(t=>{return(e=t,e.replace(/%([^%]+)%/g,(t,e)=>process.env[e]??t)).split(";");var e}).map(t=>t.trim().replace(/^"|"$/g,"")).filter(Boolean)},J=null;export function probeRuntime(t,e=componentPlatform()){const n=t.detect,o=new RegExp(n.pattern),r=new Set,s=[],i=n=>{if(!function(t){try{return a(t).isFile()}catch{return!1}}(n))return;if("darwin"===e&&"git"===t.id&&"/usr/bin/git"===n&&!F())return;const i=V(n),l="win32"===e?i.toLowerCase():i;if(r.has(l))return;r.add(l);const c=o.exec(B(n));c&&s.push({path:n,version:c[1]??null})},c=(process.env.PATH??"").split("win32"===e?";":l);"win32"===e&&c.push(...J??=z(()=>G())??[]);for(const t of c)if(t&&u(t))for(const o of H(n.command,e))i(p(t,o));for(const n of knownRuntimePaths(t.id,e))(I||n.startsWith(C()))&&i(n);return s}export function scriptTarget(t,e=componentPlatform(),n=process.env){const o=C();return"node"===t?"win32"===e?p(W(e,n),"aliases","default","node.exe"):p(W(e,n),"aliases","default","bin","node"):"uv"===t?p(n.UV_INSTALL_DIR||p(o,".local","bin"),"win32"===e?"uv.exe":"uv"):"git"===t&&"win32"===e?p(n.LOCALAPPDATA||p(o,"AppData","Local"),"Programs","Git","cmd","git.exe"):null}export function runtimeManager(t,e,n=componentPlatform(),o=process.env){const r=V(e),s=t=>"win32"===n?t.replace(/\//g,"\\").toLowerCase():t,a=s(r),i=s(e),l="win32"===n?"\\":"\\"===d?"/":d,u=t=>a.includes(s(t))||i.includes(s(t)),m=t=>a.startsWith(s(t)+l)||i.startsWith(s(t)+l),f=C(),g=/[\\/](Cellar|Caskroom|homebrew)[\\/]/i.test(r)||/^\/opt\/homebrew\//.test(e)||/^\/usr\/local\/(Cellar|opt)\//.test(r);if("node"===t)return u(`${l}fnm${l}`)||m(W(n,o))?{by:"fnm",auto:!0}:g?{by:"brew",auto:!1,hint:"brew upgrade node"}:u(`${l}.nvm${l}`)?{by:"nvm",auto:!1,hint:"nvm install --lts --reinstall-packages-from=current"}:u(`${l}nvm${l}`)&&"win32"===n?{by:"nvm",auto:!1,hint:"nvm install lts"}:u(`${l}.volta${l}`)||u(`${l}volta${l}`)?{by:"volta",auto:!1,hint:"volta install node@lts"}:u(`${l}scoop${l}`)?{by:"scoop",auto:!1,hint:"scoop update nodejs-lts"}:u(`${l}.asdf${l}`)?{by:"asdf",auto:!1,hint:"asdf install nodejs latest"}:u(`${l}mise${l}`)?{by:"mise",auto:!1,hint:"mise use -g node@lts"}:{by:"system",auto:!1};if("uv"===t)return[o.UV_INSTALL_DIR,p(f,".local","bin"),p(f,".cargo","bin")].filter(Boolean).some(t=>s(c(e))===s(t)||s(c(r))===s(t))?{by:"standalone",auto:!0}:g?{by:"brew",auto:!1,hint:"brew upgrade uv"}:u("pipx")?{by:"pipx",auto:!1,hint:"pipx upgrade uv"}:u(`${l}scoop${l}`)?{by:"scoop",auto:!1,hint:"scoop update uv"}:u("winget")?{by:"winget",auto:!1,hint:"winget upgrade astral-sh.uv"}:u("site-packages")||u(`${l}python`)?{by:"pip",auto:!1,hint:"pip install -U uv"}:{by:"other",auto:!1};if("git"===t){if("win32"===n){const t=o.LOCALAPPDATA||p(f,"AppData","Local");return m(p(t,"Programs","Git"))?{by:"git-for-windows-user",auto:!0}:u(`${l}scoop${l}`)?{by:"scoop",auto:!1,hint:"scoop update git"}:{by:"git-for-windows",auto:!1,hint:"git update-git-for-windows"}}return g?{by:"brew",auto:!1,hint:"brew upgrade git"}:"darwin"===n?{by:"xcode",auto:!1,hint:"softwareupdate --list"}:{by:"system",auto:!1}}return{by:"other",auto:!1}}function q(){return p(w.getConfigDir(),"component-releases.json")}function K(){try{const t=JSON.parse(o(q(),"utf-8"));return t&&"object"==typeof t?t:{}}catch{return{}}}function X(t,e){try{n(w.getConfigDir(),{recursive:!0}),i(q(),JSON.stringify({...K(),[t]:e},null,2))}catch(t){T.logError("components.writeCache",t)}}let Z=async(t,e=15e3)=>{const n=await fetch(t,{signal:AbortSignal.timeout(e)});if(!n.ok)throw new Error(`HTTP ${n.status} ${t}`);return n.text()};const Y=/(\d+\.\d+\.\d+)/;export function latestNodeLts(t){const e=JSON.parse(t).find(t=>"string"==typeof t.lts&&t.lts&&"string"==typeof t.version);if(!e)throw new Error("no LTS release in the Node index");return e.version.replace(/^v/,"")}export function devtoolsVersion(t,e){const n=t.split(/\r?\n/).find(t=>t.startsWith(`${e}=`)),o=n?Y.exec(n.slice(e.length+1)):null;if(!o)throw new Error(`${e} is not in versions.txt`);return o[1]}export async function latestVersion(t,e={}){const n=componentPlatform(),o=`${t.id}:${n}`,r=K()[o],s=r&&Date.now()-r.checked_at<(r.version?36e5:6e5);if(r&&s&&!e.refresh)return{version:r.version??null,...r.error?{error:r.error}:{}};try{const e=await async function(t,e){const n=t.latest;switch(n.type){case"node-lts":return latestNodeLts(await Z(n.url));case"devtools":return n.platforms&&!n.platforms.includes(e)?null:devtoolsVersion(await Z(`${N().devtools}/versions.txt`),n.key);case"npm":{if(n.staleTag){const e=D(t.adapter??"")?.installSpec,n=e?await R(e):"latest";if("latest"!==n)return n}const e=JSON.parse(await Z(`${E}/${n.package}/latest`));if(!e.version)throw new Error(`no version for ${n.package}`);return e.version}case"version-file":{const t=expandUrl(n.url);if(!t)return null;const e=Y.exec(await Z(t));if(!e)throw new Error(`no version in ${t}`);return e[1]}default:return null}}(t,n);return e&&X(o,{version:e,checked_at:Date.now()}),{version:e}}catch(e){const n=e instanceof Error?e.message:String(e);return T.logError(`components.latest(${t.id})`,e),X(o,{error:n,checked_at:Date.now()}),{version:r?.version??null,error:n}}}export async function prefetchLatest(t,e={}){const n=componentPlatform(),o=await Promise.all(t.map(async t=>t.platforms.includes(n)?"app"===t.category?[t.id,P(t.app)?await y(t.app,e):{version:null}]:[t.id,await latestVersion(t,e)]:[t.id,{version:null}]));return new Map(o)}export async function componentStatus(t,e={}){const n=componentPlatform(),o={id:t.id,name:t.name,category:t.category,supported:t.platforms.includes(n),source:componentSource(t,n)},r={...o,installed:!1,current:null,latest:null,outdated:!1,path:null,managed_by:null,auto_upgrade:!1,blocker:o.supported?installBlocker():"unsupported_platform"};if(!o.supported)return r;if("app"===t.category){const n=P(t.app);if(!n)return{...r,blocker:"unsupported_platform"};const o=e.latest?$(t.app,e.latest):e.offline?_(t.app):await b(t.app,{refresh:e.refresh});return{...r,installed:o.installed,current:o.current,latest:o.latest,outdated:o.outdated,path:o.installed?z(()=>n.appInstaller.installedPath()):null,managed_by:o.installed?"app":null,auto_upgrade:o.installed&&!o.blocker,blocker:o.blocker??installBlocker(),...o.error?{error:o.error}:{}}}let s=null,a=null,i=null;if("cli"===t.category){const e=D(t.adapter)?.installSpec,n=e?L(e)[0]:void 0;n&&(s=n.version,a=n.path,i={by:n.kind,auto:!0})}else{const e=probeRuntime(t,n)[0];e&&(s=e.version,a=e.path,i=runtimeManager(t.id,e.path,n))}const{version:l,error:c}=e.latest?e.latest:e.offline?{version:K()[`${t.id}:${n}`]?.version??null,error:void 0}:await latestVersion(t,{refresh:e.refresh}),u=l?K()[`${t.id}:${n}:ceiling`]:void 0,p=Boolean(u?.version&&u.error===l&&s&&x(s,u.version)>=0);return{...r,installed:Boolean(a),current:s,latest:l,outdated:Boolean(s&&l&&x(s,l)<0&&!p),...p?{capped_at:u.version}:{},path:a,managed_by:i?.by??null,auto_upgrade:i?.auto??!1,...i?.hint?{hint:i.hint}:{},...c?{error:c}:{}}}function z(t){try{return t()}catch{return null}}const Q={idleMs:18e4,timeoutMs:36e5};let tt=async(t,e)=>{const n={...Q,env:e};return"ok"===("win32"===componentPlatform()?await S("powershell.exe",["-NoProfile","-ExecutionPolicy","Bypass","-Command",`irm ${t} -TimeoutSec 30 | iex`],n):await S("sh",["-c",'script=$(curl -fsSL --connect-timeout 15 --max-time 60 "$0") && printf \'%s\\n\' "$script" | sh',t],n))},et=async(t,e)=>"ok"===await S(t,e,Q);function nt(t){A()?process.stderr.write(t+"\n"):console.log(t)}export function globalPackages(t,e=componentPlatform()){const n=c(V(t)),s="win32"===e?p(n,"node_modules"):p(c(n),"lib","node_modules"),a=[],i=(t,e)=>{try{const n=JSON.parse(o(p(t,"package.json"),"utf-8"));n.version&&a.push({name:e,version:n.version})}catch{}};let l=[];try{l=r(s)}catch{return a}for(const t of l)if(!t.startsWith(".")&&"npm"!==t&&"corepack"!==t)if(t.startsWith("@"))try{for(const e of r(p(s,t)))e.startsWith(".")||i(p(s,t,e),`${t}/${e}`)}catch{}else i(p(s,t),t);return a}function ot(t,e,n={}){const o=["installed","upgraded","reinstalled","up_to_date","already_installed"].includes(e);return{tool:t.id,category:t.category,current:t.current,latest:t.latest,result:e,version_after:null,ok:o,...n}}function rt(t){return`${h} upgrade ${t}`}export async function runRuntime(t,e,n={}){const o=Date.now(),r=componentPlatform(),s=await componentStatus(t,{refresh:!0}),a=t.name;if(!s.supported)return nt(f.yellow(" ! "+v.t("components.unsupported_platform",{tool:a}))),ot(s,"unavailable",{reason:"unsupported_platform"});if(s.blocker)return nt(f.yellow(" ! "+function(t,e){return v.t(`components.blocked_${t}`,{tool:e})}(s.blocker,a))),ot(s,"unavailable",{reason:s.blocker});const i=function(t){if("script"!==t.install.type)return null;const e=g().installMirror?.scripts;return e?`${e}/${t.install.script}.${"win32"===componentPlatform()?"ps1":"sh"}`:null}(t);if(s.installed&&!n.force){const n=f.gray(`(${s.path})`);if(s.latest&&!s.outdated)return nt(f.green(" √ "+v.t("components.up_to_date",{tool:a,current:s.current??"?"}))+n),"upgrade"===e&&nt(f.gray(" "+v.t("components.force_hint",{command:`${rt(t.id)} --force`}))),ot(s,"install"===e?"already_installed":"up_to_date");if("install"===e)return nt(f.green(" √ "+v.t("components.already_installed",{tool:a,current:s.current??"?"}))+n),s.outdated&&nt(f.yellow(" ! "+upgradeAdvice(s))),ot(s,"already_installed",s.outdated?{hint:upgradeAdvice(s)}:{});if(!s.latest)return nt(f.yellow(" ! "+v.t("components.no_latest",{tool:a,current:s.current??"?",how:at(s)}))),ot(s,"manual",{reason:s.error??"no_latest",hint:s.hint});if(!s.auto_upgrade)return nt(f.yellow(" ! "+upgradeAdvice(s))),ot(s,"manual",{hint:s.hint})}if(!i)return nt(f.yellow(" ! "+v.t("components.no_mirror",{tool:a}))),ot(s,"unavailable",{reason:"no_mirror"});s.installed&&!s.auto_upgrade&&nt(f.yellow(" ! "+v.t("components.force_beside",{tool:a,path:s.path??"?",by:s.managed_by??"?"})));const u={};s.installed&&"script"===t.install.type&&Object.assign(u,t.install.forceEnv??{}),"uv"===t.id&&s.installed&&s.auto_upgrade&&s.path&&(u.UV_INSTALL_DIR=c(s.path));const d=t.upgrade?.migrateGlobalPackages&&s.installed&&"fnm"===s.managed_by&&s.path,m=d?globalPackages(s.path,r):[],h=d?V(s.path):null;nt(f.gray(" "+v.t(s.installed?"components.upgrading":"components.installing",{tool:a,latest:s.latest??"",source:s.source}))),k(`component:${t.id}`,"start",{detail:{mode:e,force:Boolean(n.force),current:s.current}});const w=await tt(i,u);j(),J=null;const y=probeRuntime(t,r),b=scriptTarget(t.id,r,{...process.env,...u}),$=(b?y.find(t=>{return e=t.path,n=b,"win32"===r?V(e).toLowerCase()===V(n).toLowerCase():V(e)===V(n);var e,n}):void 0)??y.find(e=>runtimeManager(t.id,e.path,r).auto)??y[0];if(!w||!$)return k(`component:${t.id}`,"fail",{duration_ms:Date.now()-o}),nt(f.red(" × "+v.t("components.script_failed",{tool:a,command:(s.installed?rt:st)(t.id)}))),ot(s,"failed",{reason:w?"not_found_after":"script_failed"});d&&m.length&&h&&V($.path)!==h&&await async function(t,e,n){const o=new Set(globalPackages(e,n).map(t=>t.name)),r=t.filter(t=>!o.has(t.name));if(!r.length)return;nt(f.gray(" "+v.t("components.migrating_globals",{packages:r.map(t=>t.name).join("、")})));const s=function(t,e){const n=c(V(t));return p(n,"win32"===e?"npm.cmd":"npm")}(e,n),a=["install","-g",...r.map(t=>`${t.name}@${t.version}`),`--registry=${E}`,"--no-fund","--no-audit","--loglevel=error"];await et(s,a)||nt(f.yellow(" ! "+v.t("components.migrate_failed",{command:[s,...a].join(" ")})))}(m,$.path,r);const _=y[0];_&&_.path!==$.path&&_.version&&$.version&&x(_.version,$.version)<0&&nt(f.yellow(" ! "+v.t("components.path_shadowed",{tool:a,active:_.path,version:$.version,path:$.path}))),s.latest&&$.version&&x($.version,s.latest)<0&&(X(`${t.id}:${r}:ceiling`,{version:$.version,error:s.latest,checked_at:Date.now()}),nt(f.yellow(" ! "+v.t("components.capped",{tool:a,latest:s.latest,version:$.version})))),k(`component:${t.id}`,"ok",{duration_ms:Date.now()-o,detail:{version:$.version}});const P=s.installed?n.force&&!s.outdated?"reinstalled":"upgraded":"installed";var A;return nt(f.green(" √ "+("installed"===P?v.t("components.installed",{tool:a,version:$.version??"?"}):"reinstalled"===P?v.t("components.reinstalled",{tool:a,version:$.version??"?"}):v.t("components.upgraded",{tool:a,from:s.current??"?",to:$.version??"?"})))+f.gray(`(${$.path})`)),A=c($.path),(process.env.PATH??"").split("win32"===componentPlatform()?";":l).some(t=>"win32"===componentPlatform()?t.toLowerCase()===A.toLowerCase():t===A)||nt(f.gray(" "+v.t("components.new_terminal"))),ot(s,P,{version_after:$.version})}function st(t){return`${h} install ${t}`}function at(t){return t.hint?t.hint:v.t(`components.how_${t.managed_by??"other"}`,{tool:t.name})}export function upgradeAdvice(t){return t.auto_upgrade?v.t("components.outdated_auto",{tool:t.name,current:t.current??"?",latest:t.latest??"?",command:rt(t.id)}):v.t("components.outdated_manual",{tool:t.name,current:t.current??"?",latest:t.latest??"?",by:t.managed_by??"?",how:at(t),command:`${rt(t.id)} --force`})}export function setComponentDepsForTests(t){void 0!==t.platform&&(O=t.platform),void 0!==t.uid&&(U=t.uid),void 0!==t.systemPaths&&(I=t.systemPaths),t.registryPath&&(G=t.registryPath,J=null),t.versionRunner&&(B=t.versionRunner),t.macDeveloperTools&&(F=t.macDeveloperTools),t.fetchText&&(Z=t.fetchText),t.scriptRunner&&(tt=t.scriptRunner),t.commandRunner&&(et=t.commandRunner)}
|
package/dist/lib/dry-run.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{firstCommandWord as e}from"./cli-help.js";export function dryRunUnsupportedCommand(s){const n=e(s);if(void 0===n)return"(wizard)";const r=s.filter(e=>!e.startsWith("-")),o=r[r.indexOf(n)+1];switch(n){case"setup":case"config":case"status":case"bench":case"logs":case"completion":case"help":return null;case"doctor":return s.includes("--report")?"doctor --report":null;case"base":return void 0===o?null:`base ${o}`;case"lang":return void 0===o||"show"===o?null:`lang ${o}`;case"codex":return s.includes("--undo")?"codex sessions --undo":null;case"sessions":return"export"===o?"sessions export":"resume"===o&&s.includes("--run")?"sessions resume --run":null;default:return n}}
|
|
1
|
+
import{firstCommandWord as e}from"./cli-help.js";export function dryRunUnsupportedCommand(s){const n=e(s);if(void 0===n)return"(wizard)";const r=s.filter(e=>!e.startsWith("-")),o=r[r.indexOf(n)+1];switch(n){case"setup":case"config":case"status":case"bench":case"logs":case"list":case"completion":case"help":return null;case"doctor":return s.includes("--report")?"doctor --report":null;case"base":return void 0===o?null:`base ${o}`;case"lang":return void 0===o||"show"===o?null:`lang ${o}`;case"codex":return s.includes("--undo")?"codex sessions --undo":null;case"sessions":return"export"===o?"sessions export":"resume"===o&&s.includes("--run")?"sessions resume --run":null;default:return n}}
|
package/dist/lib/i18n.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFileSync as t,existsSync as e,readdirSync as s}from"fs";import{join as o,dirname as r}from"path";import{fileURLToPath as a}from"url";import{logger as n}from"../utils/logger.js";import{brandTokens as l}from"./brand.js";class c{static instance;currentLocale="en_US";translations=new Map;fallbackLocale="en_US";localesDir;constructor(){const t=a(import.meta.url),e=r(t);this.localesDir=o(e,"..","locales"),this.loadTranslations(),this.loadSavedLocale()}static getInstance(){return c.instance||(c.instance=new c),c.instance}loadTranslations(){try{if(!e(this.localesDir))return void n.warn(`Locales directory not found at ${this.localesDir}`);const r=s(this.localesDir).filter(t=>t.endsWith(".json"));if(0===r.length)return void n.warn("No locale files found in locales directory");for(const e of r){const s=e.replace(".json",""),r=o(this.localesDir,e);try{const e=t(r,"utf-8"),o=JSON.parse(e);this.translations.set(s,o)}catch(t){n.warn(`Failed to load locale file ${e}:`,t)}}const a=process.env.LANG||process.env.LC_ALL||process.env.LC_MESSAGES;if(a){const t=a.split(".")[0].replace("_","-");if(this.translations.has(t))this.currentLocale=t;else{const e=t.split("-")[0],s=Array.from(this.translations.keys()).find(t=>t.startsWith(e+"_"));s?this.currentLocale=s:"zh"===e?this.currentLocale="zh_CN":"en"===e&&(this.currentLocale="en_US")}}}catch(t){n.warn("Failed to load translations:",t)}}setLocale(t){this.translations.has(t)?(this.currentLocale=t,this.saveLocale()):n.warn(`Locale '${t}' not supported, falling back to '${this.currentLocale}'`)}getLocale(){return this.currentLocale}getAvailableLocales(){return Array.from(this.translations.keys())}translate(t,e){const s=t.split(".");let o=this.translations.get(this.currentLocale);for(const e of s){if(!o||"object"!=typeof o||!(e in o)){o=this.translations.get(this.fallbackLocale);for(const e of s){if(!o||"object"!=typeof o||!(e in o))return t;o=o[e]}break}o=o[e]}if("string"!=typeof o)return t;const r=l(this.currentLocale);return o=o.replace(/\{\{(\w+)\}\}/g,(t,e)=>r[e]??t),e?o.replace(/\{\{(\w+)\}\}/g,(t,s)=>e[s]
|
|
1
|
+
import{readFileSync as t,existsSync as e,readdirSync as s}from"fs";import{join as o,dirname as r}from"path";import{fileURLToPath as a}from"url";import{logger as n}from"../utils/logger.js";import{brandTokens as l}from"./brand.js";class c{static instance;currentLocale="en_US";translations=new Map;fallbackLocale="en_US";localesDir;constructor(){const t=a(import.meta.url),e=r(t);this.localesDir=o(e,"..","locales"),this.loadTranslations(),this.loadSavedLocale()}static getInstance(){return c.instance||(c.instance=new c),c.instance}loadTranslations(){try{if(!e(this.localesDir))return void n.warn(`Locales directory not found at ${this.localesDir}`);const r=s(this.localesDir).filter(t=>t.endsWith(".json"));if(0===r.length)return void n.warn("No locale files found in locales directory");for(const e of r){const s=e.replace(".json",""),r=o(this.localesDir,e);try{const e=t(r,"utf-8"),o=JSON.parse(e);this.translations.set(s,o)}catch(t){n.warn(`Failed to load locale file ${e}:`,t)}}const a=process.env.LANG||process.env.LC_ALL||process.env.LC_MESSAGES;if(a){const t=a.split(".")[0].replace("_","-");if(this.translations.has(t))this.currentLocale=t;else{const e=t.split("-")[0],s=Array.from(this.translations.keys()).find(t=>t.startsWith(e+"_"));s?this.currentLocale=s:"zh"===e?this.currentLocale="zh_CN":"en"===e&&(this.currentLocale="en_US")}}}catch(t){n.warn("Failed to load translations:",t)}}setLocale(t){this.translations.has(t)?(this.currentLocale=t,this.saveLocale()):n.warn(`Locale '${t}' not supported, falling back to '${this.currentLocale}'`)}getLocale(){return this.currentLocale}getAvailableLocales(){return Array.from(this.translations.keys())}translate(t,e){const s=t.split(".");let o=this.translations.get(this.currentLocale);for(const e of s){if(!o||"object"!=typeof o||!(e in o)){o=this.translations.get(this.fallbackLocale);for(const e of s){if(!o||"object"!=typeof o||!(e in o))return t;o=o[e]}break}o=o[e]}if("string"!=typeof o)return t;const r=l(this.currentLocale);return o=o.replace(/\{\{(\w+)\}\}/g,(t,e)=>r[e]??t),e?o.replace(/\{\{(\w+)\}\}/g,(t,s)=>e[s]??t):o}t(t,e){return this.translate(t,e)}saveLocale(){}loadSavedLocale(){}loadFromConfig(t){this.translations.has(t)&&(this.currentLocale=t)}}export function detectSystemLang(){const t=process.env.LC_ALL||process.env.LC_MESSAGES||process.env.LANG||process.env.LANGUAGE||"";let e="";try{e=Intl.DateTimeFormat().resolvedOptions().locale||""}catch{}return`${t} ${e}`.toLowerCase().split(/[\s:;,]+/).some(t=>"zh"===t||t.startsWith("zh-")||t.startsWith("zh_"))?"zh_CN":"en_US"}export{c as I18n};export const i18n=c.getInstance();
|
package/dist/lib/post-apply.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import o from"chalk";import t from"inquirer";import{i18n as n}from"./i18n.js";import{canPrompt as e,hasExplicitYes as
|
|
1
|
+
import o from"chalk";import t from"inquirer";import{i18n as n}from"./i18n.js";import{canPrompt as e,hasExplicitYes as r,shouldAutoConfirm as i}from"./runtime-options.js";import{toolManager as s}from"./tool-manager.js";import{getAdapter as a}from"./tools/registry.js";import{upgradeTool as l}from"./tool-upgrade.js";import{appsForTools as p,upgradeApp as f}from"./app-update.js";import{logger as c}from"../utils/logger.js";async function u(o){const{ok:n}=await t.prompt([{type:"confirm",name:"ok",message:o,default:!0}]);return n}export async function runPendingElevations(t){const r=e();for(const e of t){const t=a(e)?.pendingElevation?.();if(!t)continue;if(!(i()||r&&await u(t.prompt)))continue;const s=a(e)?.displayName??e;console.log(o.gray(" "+n.t("setup.elevation_running"))),console.log(t.run()?o.green(" √ "+n.t("setup.elevation_done",{tool:s})):o.yellow(" ! "+n.t("setup.elevation_failed",{tool:s})))}}export async function postApplyPrompts(t,i={}){const m=new Set;for(const o of i.apps?p(t):[])try{const t=await f(o,{install:i.apps.install,quiet:!0,askBeforeUpgrade:!0});t.upgraded&&t.running&&m.add(o)}catch(t){c.logError(`postApplyPrompts.upgradeApp(${o})`,t)}for(const n of t){const t=await(a(n)?.prepareRuntime?.())??[];for(const n of t)console.log("action"===n.kind?o.yellow(" ! "+n.text):o.green(" √ "+n.text))}await runPendingElevations(t);const g=e();for(const n of t){let t;try{t=await(a(n)?.followUp?.())}catch(o){c.logError(`postApplyPrompts.followUp(${n})`,o);continue}if(t)if("run"in t&&(r()||g))if(r()||await u(t.prompt))for(const n of await t.run())console.log("action"===n.kind?o.yellow(" ! "+n.text):o.green(" √ "+n.text));else t.decline();else console.log(o.yellow(" ! "+t.hint))}const d=r(),y=g||d?t.filter(o=>a(o)?.installSpec&&s.outdatedVersion(o)):[];if(y.length>0){const o=y.map(o=>a(o)?.displayName??o).join("、");if(d||await u(n.t("setup.offer_upgrade",{tools:o})))for(const o of y)await l(o)}for(const e of t){const t=a(e);if(m.has(e)||!t?.runningApp?.isRunning())continue;if(d||!g){console.log(o.yellow(" ! "+n.t("setup.reopen_hint",{tool:t.displayName})));continue}if(!await u(n.t("setup.offer_restart",{tool:t.displayName})))continue;const r=t.runningApp.restart();console.log(r?o.green(" √ "+n.t("setup.restarted",{tool:t.displayName})):o.yellow(" ! "+n.t("setup.restart_failed",{tool:t.displayName})))}}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment for a child `powershell.exe` (Windows PowerShell 5.1).
|
|
3
|
+
*
|
|
4
|
+
* Started from a PowerShell 7 terminal, node inherits pwsh 7's `PSModulePath` (`Documents\PowerShell\Modules`,
|
|
5
|
+
* `Program Files\PowerShell\Modules`, `…\pwsh\…\Modules`). 5.1 then finds PS7's copies of built-in modules first
|
|
6
|
+
* and can't load them: `Get-AuthenticodeSignature` fails with CouldNotAutoloadMatchingModule while the script still
|
|
7
|
+
* exits 0 (2026-11-01, user's Windows 11: Claude Desktop upgrade reported a bad signature). pwsh fixes the variable
|
|
8
|
+
* itself when it starts powershell.exe; node doesn't. Without the variable 5.1 computes its own default.
|
|
9
|
+
*/
|
|
10
|
+
export declare function powerShellEnv(base?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
11
|
+
/** Whether `command` starts Windows PowerShell (`powershell`, `powershell.exe`, with or without a path). */
|
|
12
|
+
export declare function isWindowsPowerShell(command: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function powerShellEnv(e=process.env){const o={};for(const[t,r]of Object.entries(e))"psmodulepath"!==t.toLowerCase()&&(o[t]=r);return o}export function isWindowsPowerShell(e){return/(^|[\\/])powershell(\.exe)?$/i.test(e.trim())}
|