@vibeapi/cli 0.0.61 → 0.0.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/codex-sessions.d.ts +8 -0
- package/dist/commands/codex-sessions.js +1 -0
- package/dist/commands/completion.js +1 -1
- package/dist/commands/setup.d.ts +2 -0
- package/dist/commands/setup.js +1 -1
- package/dist/lib/codex-sessions.d.ts +39 -0
- package/dist/lib/codex-sessions.js +1 -0
- package/dist/lib/command.js +1 -1
- package/dist/lib/tools/claude-desktop.d.ts +2 -0
- package/dist/lib/tools/claude-desktop.js +1 -1
- package/dist/lib/tools/codex.js +1 -1
- package/dist/locales/en_US.json +14 -2
- package/dist/locales/zh_CN.json +14 -2
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `vibecli codex sessions [--to <provider>] [--undo <backup dir>]`: show every local
|
|
3
|
+
* Codex session again by moving them all under the provider Codex uses now.
|
|
4
|
+
*/
|
|
5
|
+
export declare function codexSessionsCommand(options: {
|
|
6
|
+
to?: string;
|
|
7
|
+
undo?: string;
|
|
8
|
+
}): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import o from"chalk";import{i18n as s}from"../lib/i18n.js";import{isDryRun as e}from"../lib/runtime-options.js";import{currentCodexProvider as n,moveSessionsToProvider as i,runningCodexPids as t,undoSessionMove as r}from"../lib/codex-sessions.js";export async function codexSessionsCommand(d){const c=t();if(c.length>0)return console.error(o.yellow(s.t("codex_sessions.codex_running",{pids:c.join(", ")}))),void(process.exitCode=1);if(d.undo){const{files:e,dbRows:n}=await r(d.undo);return void console.log(o.green("√ "+s.t("codex_sessions.undone",{files:String(e),rows:String(n)})))}const l=d.to?.trim()||n(),g=await i(l,{dryRun:e()}),m=Math.max(g.moved.length,g.dbRows);if(0===m)return void console.log(s.t("codex_sessions.nothing",{target:l,scanned:String(g.scanned)}));const a=[...new Set(g.moved.map(o=>o.from))].join("、")||"-";e()?console.log(s.t("codex_sessions.dry_run",{count:String(m),from:a,target:l})):(console.log(o.green("√ "+s.t("codex_sessions.moved",{count:String(m),from:a,target:l}))),g.dbSkipped&&console.log(o.yellow(" ! "+s.t("codex_sessions.db_skipped",{reason:g.dbSkipped}))),console.log(o.gray(" "+s.t("codex_sessions.backup",{dir:g.backupDir??""}))))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{i18n as n}from"../lib/i18n.js";import{isJsonMode as e,emitJson as o}from"../lib/runtime-options.js";const i=["init","setup","lang","auth","doctor","status","logs","completion","update","upgrade","bench","config","enter"],c=["profile","preset","backup","claude-code","codex"],s=["list","create","use","delete"],l=["list","save","use","delete"],t=["list","create","restore"],r=["revoke","reload"],m=["show","set"],a=["path","list","tail"],u=["bash","zsh","fish"],p=["--base","--non-interactive","--json","--yes","--dry-run","--no-color","--help","--version"];export async function completionCommand(_){const b=(_[0]||"").toLowerCase();if(!u.includes(b))return e()?void o({ok:!1,error:"unsupported_shell",shell:b}):void console.log(n.t("completion.unsupported_shell",{shell:b}));const $="bash"===b?`# vibecli bash completion\n_vibecli_completions() {\n local cur prev\n COMPREPLY=()\n cur="\${COMP_WORDS[COMP_CWORD]}"\n prev="\${COMP_WORDS[COMP_CWORD-1]}"\n\n case "\${prev}" in\n vibecli)\n COMPREPLY=( $(compgen -W "${i.join(" ")} ${p.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n config)\n COMPREPLY=( $(compgen -W "${c.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n profile)\n COMPREPLY=( $(compgen -W "${s.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n preset)\n COMPREPLY=( $(compgen -W "${l.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n backup)\n COMPREPLY=( $(compgen -W "${t.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n auth)\n COMPREPLY=( $(compgen -W "${r.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n lang)\n COMPREPLY=( $(compgen -W "${m.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n logs)\n COMPREPLY=( $(compgen -W "${a.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n completion)\n COMPREPLY=( $(compgen -W "${u.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n esac\n\n if [[ "\${cur}" == --* ]]; then\n COMPREPLY=( $(compgen -W "${p.join(" ")}" -- "\${cur}") )\n return 0\n fi\n}\ncomplete -F _vibecli_completions vibecli\n`:"zsh"===b?`#compdef vibecli\n_vibecli() {\n local -a commands subcommands\n local context state line\n\n _arguments -C \\\n '(-h --help)'{-h,--help}'[Show help]' \\\n '(-v --version)'{-v,--version}'[Show version]' \\\n '--base[Custom API base URL]:url:' \\\n '--non-interactive[Disable interactive prompts]' \\\n '--json[Emit JSON output]' \\\n '(-y --yes)'{-y,--yes}'[Auto-confirm prompts]' \\\n '--dry-run[Show planned changes without writing]' \\\n '--no-color[Disable colored output]' \\\n '1:command:->command' \\\n '*::arg:->args'\n\n case $state in\n command)\n commands=(\n${i.map(n=>` '${n}:vibecli ${n}'`).join("\n")}\n )\n _describe 'command' commands\n ;;\n args)\n case $line[1] in\n config)\n subcommands=(${c.map(n=>`'${n}'`).join(" ")})\n _describe 'config sub' subcommands\n ;;\n auth) _values 'auth sub' ${r.join(" ")} ;;\n lang) _values 'lang sub' ${m.join(" ")} ;;\n logs) _values 'logs action' ${a.join(" ")} ;;\n completion) _values 'shell' ${u.join(" ")} ;;\n esac\n ;;\n esac\n}\ncompdef _vibecli vibecli\n`:`# vibecli fish completion\ncomplete -c vibecli -n "__fish_use_subcommand" -a "${i.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from config" -a "${c.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from profile" -a "${s.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from preset" -a "${l.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from backup" -a "${t.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from auth" -a "${r.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from lang" -a "${m.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from logs" -a "${a.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from completion" -a "${u.join(" ")}"\ncomplete -c vibecli -l base -d 'Custom API base URL'\ncomplete -c vibecli -l non-interactive -d 'Disable interactive prompts'\ncomplete -c vibecli -l json -d 'Emit JSON output'\ncomplete -c vibecli -l yes -s y -d 'Auto-confirm prompts'\ncomplete -c vibecli -l dry-run -d 'Show planned changes without writing'\ncomplete -c vibecli -l no-color -d 'Disable colored output'\n`;e()?o({shell:b,script:$}):(console.log($),"bash"===b?console.log("# "+n.t("completion.instructions_bash")):"zsh"===b?console.log("# "+n.t("completion.instructions_zsh")):console.log("# "+n.t("completion.instructions_fish")))}
|
|
1
|
+
import{i18n as n}from"../lib/i18n.js";import{isJsonMode as e,emitJson as o}from"../lib/runtime-options.js";const i=["init","setup","lang","auth","doctor","status","logs","completion","update","upgrade","codex","bench","config","enter"],c=["profile","preset","backup","claude-code","codex"],s=["list","create","use","delete"],l=["list","save","use","delete"],t=["list","create","restore"],r=["revoke","reload"],m=["show","set"],a=["path","list","tail"],u=["bash","zsh","fish"],p=["--base","--non-interactive","--json","--yes","--dry-run","--no-color","--help","--version"];export async function completionCommand(_){const b=(_[0]||"").toLowerCase();if(!u.includes(b))return e()?void o({ok:!1,error:"unsupported_shell",shell:b}):void console.log(n.t("completion.unsupported_shell",{shell:b}));const $="bash"===b?`# vibecli bash completion\n_vibecli_completions() {\n local cur prev\n COMPREPLY=()\n cur="\${COMP_WORDS[COMP_CWORD]}"\n prev="\${COMP_WORDS[COMP_CWORD-1]}"\n\n case "\${prev}" in\n vibecli)\n COMPREPLY=( $(compgen -W "${i.join(" ")} ${p.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n config)\n COMPREPLY=( $(compgen -W "${c.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n profile)\n COMPREPLY=( $(compgen -W "${s.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n preset)\n COMPREPLY=( $(compgen -W "${l.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n backup)\n COMPREPLY=( $(compgen -W "${t.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n auth)\n COMPREPLY=( $(compgen -W "${r.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n lang)\n COMPREPLY=( $(compgen -W "${m.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n logs)\n COMPREPLY=( $(compgen -W "${a.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n completion)\n COMPREPLY=( $(compgen -W "${u.join(" ")}" -- "\${cur}") )\n return 0\n ;;\n esac\n\n if [[ "\${cur}" == --* ]]; then\n COMPREPLY=( $(compgen -W "${p.join(" ")}" -- "\${cur}") )\n return 0\n fi\n}\ncomplete -F _vibecli_completions vibecli\n`:"zsh"===b?`#compdef vibecli\n_vibecli() {\n local -a commands subcommands\n local context state line\n\n _arguments -C \\\n '(-h --help)'{-h,--help}'[Show help]' \\\n '(-v --version)'{-v,--version}'[Show version]' \\\n '--base[Custom API base URL]:url:' \\\n '--non-interactive[Disable interactive prompts]' \\\n '--json[Emit JSON output]' \\\n '(-y --yes)'{-y,--yes}'[Auto-confirm prompts]' \\\n '--dry-run[Show planned changes without writing]' \\\n '--no-color[Disable colored output]' \\\n '1:command:->command' \\\n '*::arg:->args'\n\n case $state in\n command)\n commands=(\n${i.map(n=>` '${n}:vibecli ${n}'`).join("\n")}\n )\n _describe 'command' commands\n ;;\n args)\n case $line[1] in\n config)\n subcommands=(${c.map(n=>`'${n}'`).join(" ")})\n _describe 'config sub' subcommands\n ;;\n auth) _values 'auth sub' ${r.join(" ")} ;;\n lang) _values 'lang sub' ${m.join(" ")} ;;\n logs) _values 'logs action' ${a.join(" ")} ;;\n completion) _values 'shell' ${u.join(" ")} ;;\n esac\n ;;\n esac\n}\ncompdef _vibecli vibecli\n`:`# vibecli fish completion\ncomplete -c vibecli -n "__fish_use_subcommand" -a "${i.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from config" -a "${c.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from profile" -a "${s.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from preset" -a "${l.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from backup" -a "${t.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from auth" -a "${r.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from lang" -a "${m.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from logs" -a "${a.join(" ")}"\ncomplete -c vibecli -n "__fish_seen_subcommand_from completion" -a "${u.join(" ")}"\ncomplete -c vibecli -l base -d 'Custom API base URL'\ncomplete -c vibecli -l non-interactive -d 'Disable interactive prompts'\ncomplete -c vibecli -l json -d 'Emit JSON output'\ncomplete -c vibecli -l yes -s y -d 'Auto-confirm prompts'\ncomplete -c vibecli -l dry-run -d 'Show planned changes without writing'\ncomplete -c vibecli -l no-color -d 'Disable colored output'\n`;e()?o({shell:b,script:$}):(console.log($),"bash"===b?console.log("# "+n.t("completion.instructions_bash")):"zsh"===b?console.log("# "+n.t("completion.instructions_zsh")):console.log("# "+n.t("completion.instructions_fish")))}
|
package/dist/commands/setup.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export interface SetupCommandOptions {
|
|
|
40
40
|
claudeOfficial?: string;
|
|
41
41
|
/** Replace each tool's config files wholesale (snapshotted first) instead of merging. */
|
|
42
42
|
force?: boolean;
|
|
43
|
+
/** Windows: `on` = always put Claude Desktop's config in the registry policy (for when the local file is ignored); `off` = back to automatic. */
|
|
44
|
+
desktopRegistry?: string;
|
|
43
45
|
}
|
|
44
46
|
/** `--claude-official on|off` (also true/false, show/hide, 1/0, yes/no); undefined when unrecognized. */
|
|
45
47
|
export declare function parseOnOff(raw: string | undefined): boolean | undefined;
|
package/dist/commands/setup.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"chalk";import{getAdapter as o}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{i18n as s}from"../lib/i18n.js";import{configManager as
|
|
1
|
+
import e from"chalk";import{getAdapter as o}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{i18n as s}from"../lib/i18n.js";import{configManager as i}from"../lib/config.js";import{toolManager as l,SUPPORTED_TOOLS as a}from"../lib/tool-manager.js";import{validateApiKey as d,fetchModels as n}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as r,setCodexOneMillionContext as p}from"../lib/tools/codex.js";import{resolveModelCatalog as c}from"../lib/model-catalog.js";import{CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING as u,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as f}from"../lib/tools/claude-desktop.js";async function g(e){const o=await n(e);if(!o.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,probed:!1};const t=o.models.map(e=>e.toLowerCase());return{hasClaude:t.some(e=>e.includes("claude")),hasGpt:t.some(e=>e.startsWith("gpt")||e.includes("gpt-")||/^o\d/.test(e)),hasGrok:t.some(e=>e.includes("grok")),probed:!0}}function m(e,o){return"claude"===o?e.hasClaude:"gpt"===o?e.hasGpt:e.hasGrok}export function parseOnOff(e){const o=(e??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(o)||!["off","false","hide","0","no","n"].includes(o)&&void 0}function k(o){console.log(e.green(o))}function y(o){console.log(e.yellow(o))}function _(o){console.error(e.red(o))}async function b(o,t){console.log(e.gray(s.t("setup.validating",{label:o})));const i=await d(t);return!!i.valid||(_(s.t("setup.invalid_key",{label:o,reason:i.message||i.error||"invalid"})),!1)}async function h(o,t,d={}){const{oneMillion:n,officialLogin:p,desktopRegistry:c,force:g}=d,m=a[o];try{"claude-desktop"===o&&void 0!==c&&i.setToolSetting("claude-desktop",u,c),"codex"===o&&void 0!==n&&i.setToolSetting("codex",r,n),"claude-desktop"===o&&void 0!==p&&i.setToolSetting("claude-desktop",f,!p),await l.applyPrivateConfig(o,t,i.getModelsForTool(o),{force:g})}catch(e){const o=(e instanceof Error?e.message:String(e)).replace(/\s+/g," ").trim();return _("× "+s.t("setup.apply_failed",{tool:m.displayName,reason:o})),!1}return l.printApplied(o),g&&console.log(e.gray(" "+s.t("config.force_done",{tool:m.displayName}))),"codex"===o&&void 0!==n&&console.log(e.gray(" "+s.t(n?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),l.isToolInstalled(o)||console.log(e.yellow(" ! "+s.t("setup.install_hint",{tool:m.displayName,install:m.installCommand}))),!0}export async function setupCommand(e){const d=e.key?.trim(),n=e.claudekey?.trim(),u=e.codexkey?.trim(),f=e.grokkey?.trim(),x=e.desktopkey?.trim(),v=void 0!==e.oneMillion,C=void 0!==e.claudeOfficial;let w;if(C&&(w=parseOnOff(e.claudeOfficial),void 0===w))return _(s.t("setup.claude_official_invalid",{value:String(e.claudeOfficial)})),void(process.exitCode=1);const K=void 0!==e.desktopRegistry;let M;if(K&&(M=parseOnOff(e.desktopRegistry),void 0===M))return _(s.t("setup.desktop_registry_invalid",{value:String(e.desktopRegistry)})),void(process.exitCode=1);const S=C||K,j=Boolean(d||n||u||f||x),G={oneMillion:e.oneMillion,officialLogin:w,desktopRegistry:M,force:e.force};if(!j&&(v||S)){if(v){const o=i.getApiKeyForTool("codex");if(o)try{const t=!0===e.oneMillion;i.setToolSetting("codex",r,t);const l=await c(o);p(t,l??void 0),k(s.t(t?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(e){_(s.t("setup.apply_failed",{tool:a.codex.displayName,reason:e instanceof Error?e.message:String(e)})),process.exitCode=1}else _(s.t("setup.codex_1m_missing_key")),process.exitCode=1}if(S){const e=i.getApiKeyForTool("claude-desktop");e?await h("claude-desktop",e,{...G,oneMillion:void 0})?await t(["claude-desktop"]):process.exitCode=1:(_(s.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!j)return _(s.t("setup.usage")),void(process.exitCode=1);let T=0,O=0;const A=new Set,N=[];n&&N.push({tool:"claude-code",label:"--claudekey",apiKey:n,need:"claude"}),u&&N.push({tool:"codex",label:"--codexkey",apiKey:u,need:"gpt"}),f&&N.push({tool:"grok",label:"--grokkey",apiKey:f,need:"grok"}),x&&N.push({tool:"claude-desktop",label:"--desktopkey",apiKey:x,need:"claude"});for(const e of N){if(!await b(e.label,e.apiKey)){O+=1;continue}const o=await g(e.apiKey);!o.probed||m(o,e.need)?(o.probed||y(s.t("setup.probe_failed",{label:e.label})),i.setToolApiKey(e.tool,e.apiKey),await h(e.tool,e.apiKey,G)?(T+=1,A.add(e.tool)):O+=1):(_(s.t(`setup.key_no_${e.need}`,{label:e.label,tool:a[e.tool].displayName})),O+=1)}if(d){if(!await b("--key",d))return void(process.exitCode=1);i.setApiKey(d);const e=await g(d);if(e.probed||y(s.t("setup.probe_failed",{label:"--key"})),e.probed&&!e.hasClaude&&!e.hasGpt&&!e.hasGrok)return _(s.t("setup.key_no_family")),void(process.exitCode=1);const o=[{tool:"claude-code",capable:e.hasClaude,skipMsg:s.t("setup.skip_no_claude")},{tool:"codex",capable:e.hasGpt,skipMsg:s.t("setup.skip_no_gpt")},{tool:"grok",capable:e.hasGrok,skipMsg:s.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:e.hasClaude&&l.isToolInstalled("claude-desktop"),skipMsg:s.t("setup.skip_desktop_not_installed"),quiet:!e.hasClaude}];for(const e of o)A.has(e.tool)||(e.capable?await h(e.tool,d,G)?(T+=1,A.add(e.tool)):O+=1:e.quiet||y(e.skipMsg))}if(T>0){const e=[...A].filter(e=>!o(e)?.isInstalled).map(e=>a[e]?.command).filter(Boolean).join(" / "),t=s.t("setup.done",{count:String(T)});k("\n"+(e?`${t}${s.t("setup.done_commands",{commands:e})}`:t))}O>0&&_(s.t("setup.failed_summary",{count:String(O)})),await t([...A]),(O>0||0===T)&&(process.exitCode=1)}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex lists only the threads whose `model_provider` matches the provider it is
|
|
3
|
+
* using now (`threads.model_provider IN (…)` in its state DB, source:
|
|
4
|
+
* codex-rs/state/src/runtime/threads.rs). Switching between the official login
|
|
5
|
+
* (`openai`) and VibeAPI (`custom`) therefore hides every earlier session. This
|
|
6
|
+
* moves all local sessions under one provider: the first line of each rollout
|
|
7
|
+
* (`session_meta.payload.model_provider`, which Codex re-syncs the DB from) and
|
|
8
|
+
* the `threads` table. Before anything changes, the DB files are copied and every
|
|
9
|
+
* moved session's previous provider is recorded so `--undo` can put it back.
|
|
10
|
+
*/
|
|
11
|
+
export interface MovedSession {
|
|
12
|
+
file: string;
|
|
13
|
+
from: string;
|
|
14
|
+
}
|
|
15
|
+
export interface SessionMoveResult {
|
|
16
|
+
target: string;
|
|
17
|
+
scanned: number;
|
|
18
|
+
moved: MovedSession[];
|
|
19
|
+
dbRows: number;
|
|
20
|
+
/** Why the state DB was left alone (no DB, no node:sqlite); null when updated. */
|
|
21
|
+
dbSkipped: string | null;
|
|
22
|
+
backupDir: string | null;
|
|
23
|
+
}
|
|
24
|
+
export declare function codexHome(): string;
|
|
25
|
+
/** The provider Codex uses now: `model_provider` in config.toml, else the built-in `openai`. */
|
|
26
|
+
export declare function currentCodexProvider(): string;
|
|
27
|
+
/** Tests replace the process probe. */
|
|
28
|
+
export declare function setCodexProcessCheckForTests(fake: () => number[]): void;
|
|
29
|
+
/** PIDs of running Codex processes (CLI, desktop app, background app-server); they would overwrite the edits. */
|
|
30
|
+
export declare function runningCodexPids(): number[];
|
|
31
|
+
/** Move every local session under `target`. `dryRun` only counts. */
|
|
32
|
+
export declare function moveSessionsToProvider(target: string, options?: {
|
|
33
|
+
dryRun?: boolean;
|
|
34
|
+
}): Promise<SessionMoveResult>;
|
|
35
|
+
/** Put every session recorded in a backup back under the provider it had. */
|
|
36
|
+
export declare function undoSessionMove(backupDir: string): Promise<{
|
|
37
|
+
files: number;
|
|
38
|
+
dbRows: number;
|
|
39
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{spawnSync as e}from"child_process";import{closeSync as o,copyFileSync as t,createReadStream as r,createWriteStream as n,existsSync as s,mkdirSync as i,openSync as a,readFileSync as c,readSync as f,readdirSync as l,renameSync as d,statSync as m,utimesSync as p,writeFileSync as u}from"fs";import{join as h}from"path";import{pipeline as y}from"stream/promises";import*as g from"@iarna/toml";import{toolHome as v}from"./tools/types.js";export function codexHome(){return process.env.CODEX_HOME?.trim()||h(v(),".codex")}export function currentCodexProvider(){try{const e=g.parse(c(h(codexHome(),"config.toml"),"utf-8"));return"string"==typeof e.model_provider&&e.model_provider.trim()?e.model_provider.trim():"openai"}catch{return"openai"}}let b=()=>"win32"===process.platform?`${e("powershell.exe",["-NoProfile","-NonInteractive","-Command","(Get-Process -Name codex -ErrorAction SilentlyContinue).Id"],{encoding:"utf-8",windowsHide:!0}).stdout??""}`.split(/\s+/).filter(Boolean).map(Number):`${e("pgrep",["-x","-i","codex"],{encoding:"utf-8"}).stdout??""}`.split(/\s+/).filter(Boolean).map(Number);export function setCodexProcessCheckForTests(e){b=e}export function runningCodexPids(){try{return b()}catch{return[]}}function x(e){const t=a(e,"r");try{const e=[],o=Buffer.alloc(65536);for(;;){const r=f(t,o,0,o.length,null);if(r<=0)break;const n=o.subarray(0,r).indexOf(10);if(n>=0){e.push(Buffer.from(o.subarray(0,n)));break}e.push(Buffer.from(o.subarray(0,r)))}return Buffer.concat(e).toString("utf-8")}finally{o(t)}}async function S(e,o,t){const{atime:s,mtime:i}=m(e),a=`${e}.vibecli-tmp`,c=n(a);c.write(o),await y(r(e,{start:t}),c),d(a,e),p(e,s,i)}async function w(e){try{return new((await import("node:sqlite")).DatabaseSync)(e)}catch(e){return`node:sqlite unavailable (Node ${process.versions.node}; needs 22.13+): ${e instanceof Error?e.message:String(e)}`}}export async function moveSessionsToProvider(e,o={}){const r=function(){const e=[],o=t=>{if(s(t))for(const r of l(t,{withFileTypes:!0})){const n=h(t,r.name);r.isDirectory()?o(n):r.isFile()&&r.name.endsWith(".jsonl")&&e.push(n)}};return o(h(codexHome(),"sessions")),o(h(codexHome(),"archived_sessions")),e}(),n=[];for(const o of r){let t,r;try{t=x(o)}catch{continue}try{r=JSON.parse(t)}catch{continue}const s=r.payload?.model_provider;"session_meta"===r.type&&"string"==typeof s&&s!==e&&(r.payload.model_provider=e,n.push({file:o,from:s,line:JSON.stringify(r),length:Buffer.byteLength(t,"utf-8")}))}const a=function(){const e=codexHome();if(!s(e))return null;const o=l(e).map(e=>/^state_(\d+)\.sqlite$/.exec(e)).filter(e=>!!e).sort((e,o)=>Number(o[1])-Number(e[1]));return o.length>0?h(e,o[0][0]):null}();let c=a?null:"no state DB",f=[],d=null;if(a){const o=await w(a);"string"==typeof o?c=o:(d=o,f=d.prepare('SELECT id, model_provider AS "from" FROM threads WHERE model_provider <> ?').all(e).map(e=>({id:String(e.id),from:String(e.from)})))}const m={target:e,scanned:r.length,moved:n.map(({file:e,from:o})=>({file:e,from:o})),dbRows:f.length,dbSkipped:c,backupDir:null};if(o.dryRun||0===n.length&&0===f.length)return d?.close(),m;const p=h(codexHome(),"backups",`vibecli-sessions-${(new Date).toISOString().replace(/[:.]/g,"-")}`);if(i(p,{recursive:!0}),a)for(const e of["","-wal","-shm"])s(a+e)&&t(a+e,h(p,`state.sqlite${e}`));const y={target:e,moved:m.moved,threads:f,db:a};u(h(p,"manifest.json"),JSON.stringify(y,null,2)+"\n");for(const e of n)await S(e.file,e.line,e.length);return d&&(d.prepare("UPDATE threads SET model_provider = ? WHERE model_provider <> ?").run(e,e),d.close()),m.backupDir=p,m}export async function undoSessionMove(e){const o=JSON.parse(c(h(e,"manifest.json"),"utf-8"));let t=0;for(const{file:e,from:r}of o.moved){if(!s(e))continue;const o=x(e),n=JSON.parse(o);n.payload&&(n.payload.model_provider=r,await S(e,JSON.stringify(n),Buffer.byteLength(o,"utf-8")),t+=1)}let r=0;if(o.db&&s(o.db)&&o.threads.length>0){const e=await w(o.db);if("string"!=typeof e){const t=e.prepare("UPDATE threads SET model_provider = ? WHERE id = ?");for(const{id:e,from:n}of o.threads)r+=Number(t.run(n,e).changes);e.close()}}return{files:t,dbRows:r}}
|
package/dist/lib/command.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Command as e}from"commander";import{i18n as o,detectSystemLang as a}from"./i18n.js";import{configManager as t}from"./config.js";import{wizard as i}from"./wizard.js";import{langCommand as n,authCommand as s,doctorCommand as r,configCommand as c,statusCommand as m}from"../commands/index.js";import{logsCommand as
|
|
1
|
+
import{Command as e}from"commander";import{i18n as o,detectSystemLang as a}from"./i18n.js";import{configManager as t}from"./config.js";import{wizard as i}from"./wizard.js";import{langCommand as n,authCommand as s,doctorCommand as r,configCommand as c,statusCommand as m}from"../commands/index.js";import{logsCommand as d}from"../commands/logs.js";import{completionCommand as p}from"../commands/completion.js";import{benchCommand as l}from"../commands/bench.js";import{updateCommand as g}from"../commands/update.js";import{runModelRefresh as u}from"./model-refresh.js";import{upgradeCommand as f}from"../commands/upgrade.js";import{codexSessionsCommand as h}from"../commands/codex-sessions.js";import{setupCommand as y}from"../commands/setup.js";import k from"chalk";import{readFileSync as b}from"fs";import{join as v,dirname as w}from"path";import{fileURLToPath as $}from"url";import{setRuntimeOptions as x,detectColorPreferenceFromEnv as C,isColorEnabled as j,isJsonMode as A}from"./runtime-options.js";import{cleanupAnthropicEnvVars as I,machineEnvVarsLeft as P}from"./env-cleanup.js";import{runStartupUpdate as D}from"./auto-update.js";export class Command{program;constructor(){const i=t.isLangChosen()?t.getLang():a();o.loadFromConfig(i),this.program=new e,this.setupProgram()}getVersion(){try{const e=$(import.meta.url),o=w(e),a=v(o,"../../package.json");return JSON.parse(b(a,"utf-8")).version}catch{return"1.0.0"}}setupProgram(){this.program.name("vibecli").description(o.t("cli.title")).version(this.getVersion(),"-v, --version",o.t("commands.version")).helpOption("-h, --help",o.t("commands.help")).option("--base <url>","Custom API base URL").option("--non-interactive","Disable interactive prompts (CI mode)").option("--json","Emit machine-readable JSON output where applicable").option("--yes, -y","Auto-confirm prompts that have a default action").option("--dry-run","Show planned changes without writing anywhere").option("--no-color","Disable colored output"),this.program.command("setup").description(o.t("commands.setup")).option("--key <key>","API key for all capable tools (capability auto-detected)").option("--claudekey <key>","Dedicated API key for Claude Code").option("--codexkey <key>","Dedicated API key for Codex").option("--grokkey <key>","Dedicated API key for Grok Build").option("--desktopkey <key>","Dedicated API key for Claude Desktop (3p mode)").option("--1m","Enable the 1M context window for Codex").option("--no-1m","Disable the 1M context window for Codex").option("--claude-official <on|off>","Claude Desktop: show (on) or hide (off, default) the official Claude.ai sign-in entry").option("--desktop-registry <on|off>","Windows Claude Desktop: always write the config to the registry policy (on, asks for admin once if needed) or decide automatically (off)").option("--force","Replace each tool's config files wholesale (snapshotted first) instead of merging — repairs hand-broken configs").option("--all","Configure every tool the key can serve (default behavior)").action(async e=>{await y({key:e.key,claudekey:e.claudekey,codexkey:e.codexkey,grokkey:e.grokkey,desktopkey:e.desktopkey,all:e.all,oneMillion:e["1m"],claudeOfficial:e.claudeOfficial,desktopRegistry:e.desktopRegistry,force:e.force})}),this.program.command("init").description(o.t("commands.init")).action(async()=>{await this.handleInitCommand()});const e=this.program.command("lang").description(o.t("commands.lang"));e.command("show").description(o.t("lang.show_usage")).action(async()=>{await n(["show"])}),e.command("set <locale>").description(o.t("lang.set_usage")).action(async e=>{await n(["set",e])});const a=this.program.command("auth").description(o.t("commands.auth"));a.argument("[token]","API token").action(async e=>{const o=[];e&&o.push(e),await s(o)}),a.command("revoke").description("Revoke saved API key").action(async()=>{await s(["revoke"])}),a.command("reload <tool>").description("Reload plan configuration to the specified tool (e.g., claude)").action(async e=>{await s(["reload",e])}),this.program.command("doctor").description(o.t("commands.doctor")).option("--deep","Also send one real Claude Code request through the written config").action(async e=>{await r({deep:e.deep})}),this.program.command("status").description(o.t("commands.status")).action(async()=>{await m()}),this.program.command("logs").description("Inspect vibecli log files").argument("[action]","list|tail|path").argument("[file]","specific log file when using tail").action(async(e,o)=>{const a=[];e&&a.push(e),o&&a.push(o),await d(a)}),this.program.command("completion <shell>").description("Print shell completion script (bash|zsh|fish)").action(async e=>{await p([e])}),this.program.command("update").description("Check for a newer version across CNB and npm mirrors").action(async()=>{await g()}),this.program.command("upgrade [tools...]").description(o.t("commands.upgrade")).action(async(e=[])=>{await f(e)}),this.program.command("codex").description(o.t("commands.codex")).command("sessions").description(o.t("commands.codex_sessions")).option("--to <provider>","Provider to move the sessions under (default: the one Codex uses now)").option("--undo <dir>","Put the sessions back as recorded in this backup directory").action(async e=>{await h(e)}),this.program.command("bench").description("Benchmark the configured API endpoint").option("--samples <n>","number of samples to send","5").action(async e=>{const o=[];e.samples&&o.push("--samples",e.samples),await l(o)}),this.program.command("config").description("Manage profiles, presets, backups, and per-tool config").argument("[args...]","Subcommand and arguments").allowUnknownOption(!0).action(async e=>{await c(e||[])}),this.program.command("enter [option]").description(o.t("commands.enter")).action(async e=>{if(e)switch(e){case"lang":case"language":await i.configLanguage();break;case"apikey":case"api-key":await i.configApiKey();break;case"models":await i.configModels();break;default:{const o=[e];await c(o);break}}else await i.run()}),this.program.action(async()=>{await i.run()}),this.program.configureHelp({sortSubcommands:!0,subcommandTerm:e=>e.name()+" "+e.usage()}),this.program.addHelpText("after",`\n${k.bold(o.t("cli.examples"))}:\n ${k.gray("$ vibecli # Interactive main menu")}\n ${k.gray("$ vibecli init # Run first-time setup wizard")}\n ${k.gray("$ vibecli setup --key sk-xxx # One-shot setup (auto-detect capable tools)")}\n ${k.gray("$ vibecli setup --claudekey sk-a --codexkey sk-b --grokkey sk-c")}\n ${k.gray("$ vibecli setup --desktopkey sk-d --claude-official off # Claude Desktop, hide Claude.ai login")}\n ${k.gray("$ vibecli setup --key sk-xxx --force # Replace broken tool configs with the recommended ones")}\n ${k.gray("$ vibecli config codex --force # Same, for one tool")}\n ${k.gray("$ vibecli status --json # Machine-readable status")}\n ${k.gray("$ vibecli config profile list")}\n ${k.gray("$ vibecli config profile create work")}\n ${k.gray("$ vibecli config profile use work")}\n ${k.gray("$ vibecli config preset save fast")}\n ${k.gray("$ vibecli config backup create snapshot")}\n ${k.gray("$ vibecli auth <token> --non-interactive")}\n ${k.gray("$ vibecli auth revoke --yes")}\n ${k.gray("$ vibecli logs path")}\n ${k.gray("$ vibecli completion bash")}\n ${k.gray("$ vibecli bench --samples 3")}\n ${k.gray("$ vibecli update")}\n ${k.gray("$ vibecli upgrade claude-code")}\n ${k.gray('$ vibecli --base "https://custom.api.com" init # Custom base URL')}\n`)}async handleInitCommand(){await i.runFirstTimeSetup()}cleanupLeakedEnvVars(){const e=I();if(0===e.length||A())return;const a=o.t("messages.env_vars_cleared",{vars:e.join(", ")});console.log(j()?k.yellow(a):a);const t=P();if(t.length>0){const e=o.t("messages.env_vars_machine_left",{vars:t.join(", ")});console.log(j()?k.yellow(e):e)}}preflightArgs(e){const o=o=>e.includes(o),a=!o("--no-color")&&C();let i;x({nonInteractive:o("--non-interactive"),json:o("--json"),yes:o("--yes")||o("-y"),dryRun:o("--dry-run"),color:a}),a||(k.level=0);for(let o=0;o<e.length;o+=1){const a=e[o];if("--base"===a&&e[o+1]){i=e[o+1];break}if(a.startsWith("--base=")){i=a.slice(7);break}}i&&t.setBaseUrl(i)}async execute(e){try{if(this.preflightArgs(e),this.cleanupLeakedEnvVars(),(await D(e)).handled)return;await u(e),await this.program.parseAsync(e,{from:"user"})}catch(e){if(e instanceof Error){const a=j()?k.red:e=>e;console.error(a(o.t("cli.error_general")),e.message)}process.exit(1)}}getProgram(){return this.program}}
|
|
@@ -8,6 +8,8 @@ import { type ModelCatalog } from '../model-catalog.js';
|
|
|
8
8
|
* the app is gateway-only; `false` leaves the chooser visible.
|
|
9
9
|
*/
|
|
10
10
|
export declare const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING = "hide_official_login";
|
|
11
|
+
/** Windows: always write the HKCU policy (the user found the local library ignored), never remove it. */
|
|
12
|
+
export declare const CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING = "force_registry";
|
|
11
13
|
/** One model as advertised to Claude Desktop's picker (`inferenceModels[]`). */
|
|
12
14
|
export interface InferenceModel {
|
|
13
15
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{chmodSync as e,existsSync as t,mkdirSync as o,readdirSync as n,readFileSync as r,rmSync as s}from"fs";import{dirname as i}from"path";import{join as a}from"path";import{randomUUID as l}from"crypto";import{execFileSync as c}from"child_process";import{userInfo as d}from"os";import{logger as p}from"../../utils/logger.js";import{i18n as u}from"../i18n.js";import{BRAND_NAME as f}from"../brand.js";import{backupBeforeWrite as m,atomicWriteFile as g}from"./backup.js";import{toolHome as h}from"./types.js";import{canRestartDesktop as y,isDesktopRunning as k,restartDesktop as b,WINDOWS_PACKAGE_FAMILIES as A}from"./desktop-process.js";import{setUserRegistryElevated as C}from"./elevated-reg.js";import{UserActionNeeded as _}from"./types.js";import{baseModelId as E,isClaudeModel as D}from"../model-catalog.js";const v=f;export const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING="hide_official_login";const w=/^[a-f0-9-]{36}$/;function M(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}export function claudeDesktopUserDataDir(){const e=process.env.CLAUDE_USER_DATA_DIR?.trim();if(e)return e;const o=h(),n=Boolean(process.env.VIBECLI_TEST_HOME?.trim());switch(process.platform){case"darwin":return a(o,"Library","Application Support","Claude-3p");case"win32":{const e=!n&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:a(o,"AppData","Local");return A.map(t=>a(e,"Packages",t,"LocalCache","Local","Claude-3p")).find(e=>t(e))??a(e,"Claude-3p")}default:{const e=!n&&process.env.XDG_CONFIG_HOME?process.env.XDG_CONFIG_HOME:a(o,".config");return a(e,"Claude-3p")}}}const O=()=>a(claudeDesktopUserDataDir(),"configLibrary"),P=()=>a(O(),"_meta.json"),S=e=>a(O(),`${e}.json`),x=()=>a(claudeDesktopUserDataDir(),"claude_desktop_config.json");function L(e){if(!t(e))return null;const o=r(e,"utf-8");if(!o.trim())return null;try{const e=JSON.parse(o);return M(e)?e:null}catch(t){throw new Error(`Existing ${e} cannot be parsed, back it up and fix it first: ${t instanceof Error?t.message:String(t)}`)}}function I(n,r){const s=i(n);t(s)||o(s,{recursive:!0,mode:448}),m(n),g(n,JSON.stringify(r,null,2)+"\n");try{e(n,384)}catch(e){p.logError("claude-desktop.writeJson.chmod",e)}}function j(){const e=L(P());if(!e)return null;const t=Array.isArray(e.entries)?e.entries.filter(e=>M(e)&&"string"==typeof e.id&&"string"==typeof e.name):[];return{...e,appliedId:"string"==typeof e.appliedId?e.appliedId:"",entries:t}}function T(e){return e?.entries.find(e=>e.name===v&&w.test(e.id))}const $={opus:0,fable:1,sonnet:2,haiku:3};function N(e){let t=/^claude-(opus|sonnet|haiku|fable)-(\d+(?:-\d+)*)/i.exec(e);return t?{family:t[1].toLowerCase(),version:t[2].split("-").map(Number)}:(t=/^claude-(\d+(?:-\d+)*)-(opus|sonnet|haiku)/i.exec(e),t?{family:t[2].toLowerCase(),version:t[1].split("-").map(Number)}:null)}export function humanizeModelId(e){const t=N(e);return t?`${t.family[0].toUpperCase()+t.family.slice(1)} ${t.version.filter(e=>e<1e7).slice(0,2).join(".")}`:e}function G(e){return N(e)?.family}export function buildInferenceModels(e,t){const{primary:o,bySlot:n}=function(e){const t=["opus","sonnet","haiku","reasoning"].map(t=>E(e[t]||"")).filter(Boolean);return{primary:t[0]??"",bySlot:t}}(e),r=new Set,s=t?.labels??{};let i;if(t&&t.models.some(D)){i=[...new Set(t.models.filter(D).map(E))];for(const e of t.oneMillion)r.add(e)}else{i=[];for(const t of["opus","sonnet","haiku","reasoning"]){const o=(e[t]||"").trim(),n=E(o);n&&(i.includes(n)||i.push(n),/\[1m\]/i.test(o)&&r.add(n))}}const a=e=>$[G(e)??""]??9;i.sort((e,t)=>{if(e===o)return-1;if(t===o)return 1;const n=a(e)-a(t);if(0!==n)return n;const r=N(e),s=N(t);return r&&s?function(e,t){const o=Math.max(e.length,t.length);for(let n=0;n<o;n++){const o=(t[n]??0)-(e[n]??0);if(0!==o)return o}return 0}(r.version,s.version):e.localeCompare(t)});const l=new Set,c=new Map;for(const e of n){const t=G(e);t&&i.includes(e)&&!c.has(t)&&c.set(t,e)}return i.map(e=>{const t=G(e),o={name:e,labelOverride:s[e]||humanizeModelId(e)};if(r.has(e)&&(o.supports1m=!0,o.prefer1m=!0),t){o.anthropicFamilyTier=t;const n=c.get(t);n&&n!==e||l.has(t)||(o.isFamilyDefault=!0,l.add(t))}return o})}let K=null,U=null,R=null,F=null;function H(e){return{inferenceProvider:"gateway",inferenceCredentialKind:"static",inferenceGatewayBaseUrl:(e.baseUrl||"").trim().replace(/\/+$/,""),inferenceGatewayApiKey:e.apiKey,inferenceModels:buildInferenceModels(e.models,e.catalog),disableDeploymentModeChooser:!1!==e.settings?.hide_official_login,chatTabEnabled:!0,chatAdvancedFileAnalysisEnabled:!0,autoModeEnabled:!0,coworkEgressAllowedHosts:["*"],disableEssentialTelemetry:!0,disableNonessentialTelemetry:!0,disableNonessentialServices:!1}}const B={defaultModelEffort:"medium",modelPrefer1mContext:!0,skipWebFetchPreflight:!0,toolSearchEnabled:!0,builtinBrowserEnabled:!0,isDesktopExtensionEnabled:!0,sshHostAllowlist:["*"],claudeAiImport:{enabled:!0,automatic3pImport:!0,exportEnabled:!0},coworkVmIpv6Enabled:!0,mcpToolTimeoutSec:3600,updateViaUpdatesHost:!0};function V(e){return Object.fromEntries(Object.entries(B).filter(([t])=>!e(t)))}const J="SOFTWARE\\Policies\\Claude",W=`HKCU\\${J}`,z="HKLM\\SOFTWARE\\Policies\\Claude",Z="vibecli-claude-policy.reg",X=e=>c("reg",e,{stdio:["ignore","pipe","pipe"]}).toString();let q=X;export function setRegRunnerForTests(e){q=e??X}function Q(){return"win32"===process.platform}function Y(e){let t;try{t=q(["query",e])}catch{return null}const o=new Map;for(const e of t.split(/\r?\n/)){const t=/^\s{2,}(\S+)\s+(REG_[A-Z_]+)\s*(.*)$/.exec(e);t&&o.set(t[1],t[3])}return o}function ee(){if(null===Y(W))return;const e=a(claudeDesktopUserDataDir(),Z);try{t(i(e))||o(i(e),{recursive:!0,mode:448}),m(e),q(["export",W,e,"/y"])}catch(e){p.logError("claude-desktop.snapshotPolicy",e)}}function te(e){ee();for(const[t,o]of Object.entries(e)){const[e,n]="boolean"==typeof o?["REG_DWORD",o?"1":"0"]:"number"==typeof o?["REG_DWORD",String(o)]:"string"==typeof o?["REG_SZ",o]:["REG_SZ",JSON.stringify(o)];q(["add",W,"/v",t,"/t",e,"/d",n,"/f"])}}function oe(e){const t=Y(W);if(!t)return;ee();let o=t.size;for(const n of e)t.has(n)&&(q(["delete",W,"/v",n,"/f"]),o-=1);o<=0&&q(["delete",W,"/f"])}const ne=[...Object.keys(H({apiKey:"",baseUrl:"",models:{haiku:"",sonnet:"",opus:"",reasoning:""}})),...Object.keys(B),"banner"];export function detectManagedConfig(){try{if("darwin"===process.platform){let e="";try{e=d().username}catch{}return[e?`/Library/Managed Preferences/${e}/com.anthropic.claudefordesktop.plist`:"","/Library/Managed Preferences/com.anthropic.claudefordesktop.plist"].filter(Boolean).find(e=>t(e))??null}if("win32"===process.platform)return Y(z)?z:null;const e="/etc/claude-desktop/managed-settings.json";return t(e)?e:null}catch(e){return p.logError("claude-desktop.detectManagedConfig",e),null}}const re=/\d+\.\d+\.\d+/;function se(e){const t=e=>e.split(".").map(Number);return e.sort((e,o)=>{const[n,r]=[t(e),t(o)];for(let e=0;e<3;e++)if(n[e]!==r[e])return r[e]-n[e];return 0})[0]??null}const ie="darwin"===process.platform?"open -a Claude":"win32"===process.platform?"Claude":"claude-desktop",ae="darwin"===process.platform||"win32"===process.platform?"https://cnb.cool/vibeapi/claude-desktop/-/releases/latest":"https://claude.ai/download",le="darwin"===process.platform?`open ${ae}`:"win32"===process.platform?`start ${ae}`:`xdg-open ${ae}`;export const claudeDesktopAdapter={name:"claude-desktop",displayName:"Claude Desktop",command:ie,installCommand:le,configPath:P(),isInstalled:function(){const e=h();let o;switch(process.platform){case"darwin":o=["/Applications/Claude.app",a(e,"Applications","Claude.app")];break;case"win32":{const t=process.env.LOCALAPPDATA||a(e,"AppData","Local");o=[a(t,"AnthropicClaude"),a(t,"Programs","Claude"),...A.map(e=>a(t,"Packages",e))];break}default:o=["/usr/lib/claude-desktop","/opt/Claude","/usr/bin/claude-desktop",a(e,".local","bin","claude-desktop")]}return o.push(claudeDesktopUserDataDir(),a(claudeDesktopUserDataDir(),"..","Claude")),o.some(e=>t(e))},installedVersion:function(){if("darwin"===process.platform){for(const e of["/Applications/Claude.app",a(h(),"Applications","Claude.app")]){const o=a(e,"Contents","Info.plist");if(!t(o))continue;const n=/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(r(o,"utf-8")),s=n?re.exec(n[1])?.[0]:void 0;if(s)return s}return null}if("win32"===process.platform){const e=a(process.env.LOCALAPPDATA||a(h(),"AppData","Local"),"AnthropicClaude");if(t(e)){const t=n(e).map(e=>/^app-(\d+\.\d+\.\d+)$/.exec(e)?.[1]).filter(e=>!!e);if(t.length>0)return se(t)}const o=A.map(e=>`'${e}'`).join(",");return se(c("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${o}) -contains $_.PackageFamilyName } | ForEach-Object { $_.Version.ToString() }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"]}).split(/\r?\n/).flatMap(e=>re.exec(e)?.[0]??[]))}return null},runningApp:y()?{isRunning:k,restart:b}:void 0,wantsModelCatalog:!0,loadPrivateConfig(e){const o=j()??{appliedId:"",entries:[]};let n=T(o);n||(n={id:l(),name:v},o.entries.push(n));const r=H(e);U=!0===r.disableDeploymentModeChooser,K={models:r.inferenceModels,source:e.catalog?e.catalog.oneMillionSource:"slots",groups:e.catalog?.matchedGroups??[]};const s=L(S(n.id))??{};I(S(n.id),{...V(e=>e in s),...s,...r}),o.appliedId=n.id,I(P(),o);const i=L(x())??{};if("3p"!==i.deploymentMode&&I(x(),{...i,deploymentMode:"3p"}),R=null,F=null,Q()){const e=Y(W),o=ne.filter(t=>e?.has(t)),n={...V(t=>e?.has(t)??!1),...r},s=function(){const e=!Boolean(process.env.VIBECLI_TEST_HOME?.trim())&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:a(h(),"AppData","Local");return!!t(a(e,"AnthropicClaude"))||A.some(o=>t(a(e,"Packages",o,"LocalCache","Local","Claude-3p")))}();try{s?oe(ne):te(n)}catch(t){p.logError("claude-desktop.policy",t),R=t instanceof Error?t.message.trim():String(t),o.length>0&&(F=s?{action:"remove",values:Object.fromEntries(o.map(e=>[e,null])),deleteKey:o.length===e.size}:{action:"write",values:n,deleteKey:!1})}}},pendingElevation(){const e=F;return e?{prompt:u.t(`tools.claude_desktop.elevate_${e.action}`),run:()=>{if(!C(J,e.values,e.deleteKey))return!1;const t=Y(W),o="remove"===e.action?Object.keys(e.values).every(e=>!t?.has(e)):Object.keys(e.values).every(e=>t?.has(e));return o&&(F=null,R=null),o}}:null},unloadPrivateConfig(){if(Q())try{oe(ne)}catch(e){p.logError("claude-desktop.removePolicy",e)}const e=j(),t=T(e);if(!e||!t)return;m(S(t.id)),s(S(t.id),{force:!0});const o=e.entries.filter(e=>e.id!==t.id);0===o.length?(m(P()),s(P(),{force:!0})):I(P(),{...e,entries:o,appliedId:e.appliedId===t.id?o[0].id:e.appliedId})},listedModels(){const e=j(),t=T(e);if(!t||e?.appliedId!==t.id)return null;const o=L(S(t.id))?.inferenceModels;return Array.isArray(o)?o.map(e=>String(e.name)):null},refreshModelMenu(e){const t=j(),o=T(t);if(!o||t?.appliedId!==o.id)return;const n=L(S(o.id));if(!n)return;const r=buildInferenceModels(e.models,e.catalog);if(JSON.stringify(n.inferenceModels)!==JSON.stringify(r)){if(Q()&&Y(W)?.has("inferenceModels"))try{te({inferenceModels:r})}catch(e){throw p.logError("claude-desktop.refreshModelMenu registry",e),new _(u.t("tools.claude_desktop.refresh_needs_admin"))}I(S(o.id),{...n,inferenceModels:r})}},detectCurrentConfig(){try{if(Q()){const e=Y(W)?.get("inferenceGatewayApiKey");if(e)return{apiKey:e}}const e=T(j());if(!e)return{apiKey:null};const t=L(S(e.id)),o=t?.inferenceGatewayApiKey;return{apiKey:"string"==typeof o&&o?o:null}}catch(e){return p.logError("claude-desktop.detectCurrentConfig",e),{apiKey:null}}},getConfig(){try{const e=j(),t=T(e);return{meta:e,applied:t?L(S(t.id)):null,desktop:L(x()),...Q()?{policy:Object.fromEntries(Y(W)??[])}:{}}}catch(e){return p.logError("claude-desktop.getConfig",e),null}},clearPinnedModels(){let e=!1;Q()&&Y(W)?.has("inferenceModels")&&(ee(),q(["delete",W,"/v","inferenceModels","/f"]),e=!0);const t=T(j()),o=t?L(S(t.id)):null;if(t&&o&&void 0!==o.inferenceModels){const{inferenceModels:n,...r}=o;I(S(t.id),r),e=!0}return e?["inferenceModels"]:[]},applyNotes(){const e=[];if(K&&K.models.length>0){const{models:t,source:o,groups:n}=K;e.push({kind:"summary",text:u.t("tools.claude_desktop.models_summary",{count:String(t.length),default:t[0].labelOverride??t[0].name})}),e.push({kind:"detail",text:u.t(`tools.claude_desktop.models_written_${o}`,{count:String(t.length),list:t.map(e=>`${e.labelOverride}${e.supports1m?" (1M)":""}`).join(", "),groups:n.join(" / ")})})}null!==U&&e.push({kind:"detail",text:u.t(U?"tools.claude_desktop.official_login_hidden":"tools.claude_desktop.official_login_shown")}),y()&&!k()||e.push({kind:"action",text:u.t("tools.claude_desktop.restart_hint")}),F?(e.push({kind:"action",text:u.t(`tools.claude_desktop.policy_stale_${F.action}`)}),e.push({kind:"detail",text:R??""})):R?(e.push({kind:"detail",text:u.t("tools.claude_desktop.registry_denied")}),e.push({kind:"detail",text:R})):Q()&&e.push({kind:"detail",text:u.t("tools.claude_desktop.registry_written",{key:W})});const t=detectManagedConfig();return t&&e.push({kind:"action",text:u.t("tools.claude_desktop.managed_conflict",{path:t})}),e},forceResetPaths(){const e=[P(),x()];try{const t=T(j());t&&e.push(S(t.id))}catch{}return e},backupPaths(){const e=[P(),x()];Q()&&e.push(a(claudeDesktopUserDataDir(),Z));try{const t=T(j());t&&e.push(S(t.id))}catch{}return e}};
|
|
1
|
+
import{chmodSync as e,existsSync as t,mkdirSync as o,readdirSync as n,readFileSync as r,rmSync as s}from"fs";import{dirname as i}from"path";import{join as a}from"path";import{randomUUID as l}from"crypto";import{execFileSync as c}from"child_process";import{userInfo as d}from"os";import{logger as p}from"../../utils/logger.js";import{i18n as u}from"../i18n.js";import{BRAND_NAME as f}from"../brand.js";import{backupBeforeWrite as m,atomicWriteFile as g}from"./backup.js";import{toolHome as h}from"./types.js";import{canRestartDesktop as y,isDesktopRunning as k,restartDesktop as b,WINDOWS_PACKAGE_FAMILIES as _}from"./desktop-process.js";import{setUserRegistryElevated as A}from"./elevated-reg.js";import{UserActionNeeded as C}from"./types.js";import{baseModelId as E,isClaudeModel as D}from"../model-catalog.js";const v=f;export const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING="hide_official_login";export const CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING="force_registry";const w=/^[a-f0-9-]{36}$/;function M(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}export function claudeDesktopUserDataDir(){const e=process.env.CLAUDE_USER_DATA_DIR?.trim();if(e)return e;const o=h(),n=Boolean(process.env.VIBECLI_TEST_HOME?.trim());switch(process.platform){case"darwin":return a(o,"Library","Application Support","Claude-3p");case"win32":{const e=!n&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:a(o,"AppData","Local");return _.map(t=>a(e,"Packages",t,"LocalCache","Local","Claude-3p")).find(e=>t(e))??a(e,"Claude-3p")}default:{const e=!n&&process.env.XDG_CONFIG_HOME?process.env.XDG_CONFIG_HOME:a(o,".config");return a(e,"Claude-3p")}}}const O=()=>a(claudeDesktopUserDataDir(),"configLibrary"),S=()=>a(O(),"_meta.json"),P=e=>a(O(),`${e}.json`),x=()=>a(claudeDesktopUserDataDir(),"claude_desktop_config.json");function I(e){if(!t(e))return null;const o=r(e,"utf-8");if(!o.trim())return null;try{const e=JSON.parse(o);return M(e)?e:null}catch(t){throw new Error(`Existing ${e} cannot be parsed, back it up and fix it first: ${t instanceof Error?t.message:String(t)}`)}}function L(n,r){const s=i(n);t(s)||o(s,{recursive:!0,mode:448}),m(n),g(n,JSON.stringify(r,null,2)+"\n");try{e(n,384)}catch(e){p.logError("claude-desktop.writeJson.chmod",e)}}function j(){const e=I(S());if(!e)return null;const t=Array.isArray(e.entries)?e.entries.filter(e=>M(e)&&"string"==typeof e.id&&"string"==typeof e.name):[];return{...e,appliedId:"string"==typeof e.appliedId?e.appliedId:"",entries:t}}function T(e){return e?.entries.find(e=>e.name===v&&w.test(e.id))}const $={opus:0,fable:1,sonnet:2,haiku:3};function G(e){let t=/^claude-(opus|sonnet|haiku|fable)-(\d+(?:-\d+)*)/i.exec(e);return t?{family:t[1].toLowerCase(),version:t[2].split("-").map(Number)}:(t=/^claude-(\d+(?:-\d+)*)-(opus|sonnet|haiku)/i.exec(e),t?{family:t[2].toLowerCase(),version:t[1].split("-").map(Number)}:null)}export function humanizeModelId(e){const t=G(e);return t?`${t.family[0].toUpperCase()+t.family.slice(1)} ${t.version.filter(e=>e<1e7).slice(0,2).join(".")}`:e}function N(e){return G(e)?.family}export function buildInferenceModels(e,t){const{primary:o,bySlot:n}=function(e){const t=["opus","sonnet","haiku","reasoning"].map(t=>E(e[t]||"")).filter(Boolean);return{primary:t[0]??"",bySlot:t}}(e),r=new Set,s=t?.labels??{};let i;if(t&&t.models.some(D)){i=[...new Set(t.models.filter(D).map(E))];for(const e of t.oneMillion)r.add(e)}else{i=[];for(const t of["opus","sonnet","haiku","reasoning"]){const o=(e[t]||"").trim(),n=E(o);n&&(i.includes(n)||i.push(n),/\[1m\]/i.test(o)&&r.add(n))}}const a=e=>$[N(e)??""]??9;i.sort((e,t)=>{if(e===o)return-1;if(t===o)return 1;const n=a(e)-a(t);if(0!==n)return n;const r=G(e),s=G(t);return r&&s?function(e,t){const o=Math.max(e.length,t.length);for(let n=0;n<o;n++){const o=(t[n]??0)-(e[n]??0);if(0!==o)return o}return 0}(r.version,s.version):e.localeCompare(t)});const l=new Set,c=new Map;for(const e of n){const t=N(e);t&&i.includes(e)&&!c.has(t)&&c.set(t,e)}return i.map(e=>{const t=N(e),o={name:e,labelOverride:s[e]||humanizeModelId(e)};if(r.has(e)&&(o.supports1m=!0,o.prefer1m=!0),t){o.anthropicFamilyTier=t;const n=c.get(t);n&&n!==e||l.has(t)||(o.isFamilyDefault=!0,l.add(t))}return o})}let R=null,K=null,U=null,F=null;function H(e){return{inferenceProvider:"gateway",inferenceCredentialKind:"static",inferenceGatewayBaseUrl:(e.baseUrl||"").trim().replace(/\/+$/,""),inferenceGatewayApiKey:e.apiKey,inferenceModels:buildInferenceModels(e.models,e.catalog),disableDeploymentModeChooser:!1!==e.settings?.hide_official_login,chatTabEnabled:!0,chatAdvancedFileAnalysisEnabled:!0,autoModeEnabled:!0,coworkEgressAllowedHosts:["*"],disableEssentialTelemetry:!0,disableNonessentialTelemetry:!0,disableNonessentialServices:!1}}const B={defaultModelEffort:"medium",modelPrefer1mContext:!0,skipWebFetchPreflight:!0,toolSearchEnabled:!0,builtinBrowserEnabled:!0,isDesktopExtensionEnabled:!0,sshHostAllowlist:["*"],claudeAiImport:{enabled:!0,automatic3pImport:!0,exportEnabled:!0},coworkVmIpv6Enabled:!0,mcpToolTimeoutSec:3600,updateViaUpdatesHost:!0};function V(e){return Object.fromEntries(Object.entries(B).filter(([t])=>!e(t)))}const J="SOFTWARE\\Policies\\Claude",W=`HKCU\\${J}`,z="HKLM\\SOFTWARE\\Policies\\Claude",Z="vibecli-claude-policy.reg",X=e=>c("reg",e,{stdio:["ignore","pipe","pipe"]}).toString();let q=X;export function setRegRunnerForTests(e){q=e??X}function Y(){return"win32"===process.platform}function Q(e){let t;try{t=q(["query",e])}catch{return null}const o=new Map;for(const e of t.split(/\r?\n/)){const t=/^\s{2,}(\S+)\s+(REG_[A-Z_]+)\s*(.*)$/.exec(e);t&&o.set(t[1],t[3])}return o}function ee(){if(null===Q(W))return;const e=a(claudeDesktopUserDataDir(),Z);try{t(i(e))||o(i(e),{recursive:!0,mode:448}),m(e),q(["export",W,e,"/y"])}catch(e){p.logError("claude-desktop.snapshotPolicy",e)}}function te(e){ee();for(const[t,o]of Object.entries(e)){const[e,n]="boolean"==typeof o?["REG_DWORD",o?"1":"0"]:"number"==typeof o?["REG_DWORD",String(o)]:"string"==typeof o?["REG_SZ",o]:["REG_SZ",JSON.stringify(o)];q(["add",W,"/v",t,"/t",e,"/d",n,"/f"])}}function oe(e){const t=Q(W);if(!t)return;ee();let o=t.size;for(const n of e)t.has(n)&&(q(["delete",W,"/v",n,"/f"]),o-=1);o<=0&&q(["delete",W,"/f"])}const ne=[...Object.keys(H({apiKey:"",baseUrl:"",models:{haiku:"",sonnet:"",opus:"",reasoning:""}})),...Object.keys(B),"banner"];export function detectManagedConfig(){try{if("darwin"===process.platform){let e="";try{e=d().username}catch{}return[e?`/Library/Managed Preferences/${e}/com.anthropic.claudefordesktop.plist`:"","/Library/Managed Preferences/com.anthropic.claudefordesktop.plist"].filter(Boolean).find(e=>t(e))??null}if("win32"===process.platform)return Q(z)?z:null;const e="/etc/claude-desktop/managed-settings.json";return t(e)?e:null}catch(e){return p.logError("claude-desktop.detectManagedConfig",e),null}}const re=/\d+\.\d+\.\d+/;function se(e){const t=e=>e.split(".").map(Number);return e.sort((e,o)=>{const[n,r]=[t(e),t(o)];for(let e=0;e<3;e++)if(n[e]!==r[e])return r[e]-n[e];return 0})[0]??null}const ie="darwin"===process.platform?"open -a Claude":"win32"===process.platform?"Claude":"claude-desktop",ae="darwin"===process.platform||"win32"===process.platform?"https://cnb.cool/vibeapi/claude-desktop/-/releases/latest":"https://claude.ai/download",le="darwin"===process.platform?`open ${ae}`:"win32"===process.platform?`start ${ae}`:`xdg-open ${ae}`;export const claudeDesktopAdapter={name:"claude-desktop",displayName:"Claude Desktop",command:ie,installCommand:le,configPath:S(),isInstalled:function(){const e=h();let o;switch(process.platform){case"darwin":o=["/Applications/Claude.app",a(e,"Applications","Claude.app")];break;case"win32":{const t=process.env.LOCALAPPDATA||a(e,"AppData","Local");o=[a(t,"AnthropicClaude"),a(t,"Programs","Claude"),..._.map(e=>a(t,"Packages",e))];break}default:o=["/usr/lib/claude-desktop","/opt/Claude","/usr/bin/claude-desktop",a(e,".local","bin","claude-desktop")]}return o.push(claudeDesktopUserDataDir(),a(claudeDesktopUserDataDir(),"..","Claude")),o.some(e=>t(e))},installedVersion:function(){if("darwin"===process.platform){for(const e of["/Applications/Claude.app",a(h(),"Applications","Claude.app")]){const o=a(e,"Contents","Info.plist");if(!t(o))continue;const n=/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(r(o,"utf-8")),s=n?re.exec(n[1])?.[0]:void 0;if(s)return s}return null}if("win32"===process.platform){const e=a(process.env.LOCALAPPDATA||a(h(),"AppData","Local"),"AnthropicClaude");if(t(e)){const t=n(e).map(e=>/^app-(\d+\.\d+\.\d+)$/.exec(e)?.[1]).filter(e=>!!e);if(t.length>0)return se(t)}const o=_.map(e=>`'${e}'`).join(",");return se(c("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${o}) -contains $_.PackageFamilyName } | ForEach-Object { $_.Version.ToString() }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"]}).split(/\r?\n/).flatMap(e=>re.exec(e)?.[0]??[]))}return null},runningApp:y()?{isRunning:k,restart:b}:void 0,wantsModelCatalog:!0,loadPrivateConfig(e){const o=j()??{appliedId:"",entries:[]};let n=T(o);n||(n={id:l(),name:v},o.entries.push(n));const r=H(e);K=!0===r.disableDeploymentModeChooser,R={models:r.inferenceModels,source:e.catalog?e.catalog.oneMillionSource:"slots",groups:e.catalog?.matchedGroups??[]};const s=I(P(n.id))??{};L(P(n.id),{...V(e=>e in s),...s,...r}),o.appliedId=n.id,L(S(),o);const i=I(x())??{};if("3p"!==i.deploymentMode&&L(x(),{...i,deploymentMode:"3p"}),U=null,F=null,Y()){const o=Q(W),n=ne.filter(e=>o?.has(e)),s={...V(e=>o?.has(e)??!1),...r},i=!0===e.settings?.force_registry,l=!i&&function(){const e=!Boolean(process.env.VIBECLI_TEST_HOME?.trim())&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:a(h(),"AppData","Local");return!!t(a(e,"AnthropicClaude"))||_.some(o=>t(a(e,"Packages",o,"LocalCache","Local","Claude-3p")))}();try{l?oe(ne):te(s)}catch(e){p.logError("claude-desktop.policy",e),U=e instanceof Error?e.message.trim():String(e),(n.length>0||i)&&(F=l?{action:"remove",values:Object.fromEntries(n.map(e=>[e,null])),deleteKey:n.length===o.size}:{action:"write",values:s,deleteKey:!1})}}},pendingElevation(){const e=F;return e?{prompt:u.t(`tools.claude_desktop.elevate_${e.action}`),run:()=>{if(!A(J,e.values,e.deleteKey))return!1;const t=Q(W),o="remove"===e.action?Object.keys(e.values).every(e=>!t?.has(e)):Object.keys(e.values).every(e=>t?.has(e));return o&&(F=null,U=null),o}}:null},unloadPrivateConfig(){if(Y())try{oe(ne)}catch(e){p.logError("claude-desktop.removePolicy",e)}const e=j(),t=T(e);if(!e||!t)return;m(P(t.id)),s(P(t.id),{force:!0});const o=e.entries.filter(e=>e.id!==t.id);0===o.length?(m(S()),s(S(),{force:!0})):L(S(),{...e,entries:o,appliedId:e.appliedId===t.id?o[0].id:e.appliedId})},listedModels(){const e=j(),t=T(e);if(!t||e?.appliedId!==t.id)return null;const o=I(P(t.id))?.inferenceModels;return Array.isArray(o)?o.map(e=>String(e.name)):null},refreshModelMenu(e){const t=j(),o=T(t);if(!o||t?.appliedId!==o.id)return;const n=I(P(o.id));if(!n)return;const r=buildInferenceModels(e.models,e.catalog);if(JSON.stringify(n.inferenceModels)!==JSON.stringify(r)){if(Y()&&Q(W)?.has("inferenceModels"))try{te({inferenceModels:r})}catch(e){throw p.logError("claude-desktop.refreshModelMenu registry",e),new C(u.t("tools.claude_desktop.refresh_needs_admin"))}L(P(o.id),{...n,inferenceModels:r})}},detectCurrentConfig(){try{if(Y()){const e=Q(W)?.get("inferenceGatewayApiKey");if(e)return{apiKey:e}}const e=T(j());if(!e)return{apiKey:null};const t=I(P(e.id)),o=t?.inferenceGatewayApiKey;return{apiKey:"string"==typeof o&&o?o:null}}catch(e){return p.logError("claude-desktop.detectCurrentConfig",e),{apiKey:null}}},getConfig(){try{const e=j(),t=T(e);return{meta:e,applied:t?I(P(t.id)):null,desktop:I(x()),...Y()?{policy:Object.fromEntries(Q(W)??[])}:{}}}catch(e){return p.logError("claude-desktop.getConfig",e),null}},clearPinnedModels(){let e=!1;Y()&&Q(W)?.has("inferenceModels")&&(ee(),q(["delete",W,"/v","inferenceModels","/f"]),e=!0);const t=T(j()),o=t?I(P(t.id)):null;if(t&&o&&void 0!==o.inferenceModels){const{inferenceModels:n,...r}=o;L(P(t.id),r),e=!0}return e?["inferenceModels"]:[]},applyNotes(){const e=[];if(R&&R.models.length>0){const{models:t,source:o,groups:n}=R;e.push({kind:"summary",text:u.t("tools.claude_desktop.models_summary",{count:String(t.length),default:t[0].labelOverride??t[0].name})}),e.push({kind:"detail",text:u.t(`tools.claude_desktop.models_written_${o}`,{count:String(t.length),list:t.map(e=>`${e.labelOverride}${e.supports1m?" (1M)":""}`).join(", "),groups:n.join(" / ")})})}null!==K&&e.push({kind:"detail",text:u.t(K?"tools.claude_desktop.official_login_hidden":"tools.claude_desktop.official_login_shown")}),y()&&!k()||e.push({kind:"action",text:u.t("tools.claude_desktop.restart_hint")}),F?(e.push({kind:"action",text:u.t(`tools.claude_desktop.policy_stale_${F.action}`)}),e.push({kind:"detail",text:U??""})):U?(e.push({kind:"detail",text:u.t("tools.claude_desktop.registry_denied")}),e.push({kind:"detail",text:U})):Y()&&e.push({kind:"detail",text:u.t("tools.claude_desktop.registry_written",{key:W})});const t=detectManagedConfig();return t&&e.push({kind:"action",text:u.t("tools.claude_desktop.managed_conflict",{path:t})}),e},forceResetPaths(){const e=[S(),x()];try{const t=T(j());t&&e.push(P(t.id))}catch{}return e},backupPaths(){const e=[S(),x()];Y()&&e.push(a(claudeDesktopUserDataDir(),Z));try{const t=T(j());t&&e.push(P(t.id))}catch{}return e}};
|
package/dist/lib/tools/codex.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as e,readFileSync as
|
|
1
|
+
import{existsSync as e,readFileSync as t}from"fs";import{join as o}from"path";import*as n from"@iarna/toml";import{logger as r}from"../../utils/logger.js";import{i18n as i}from"../i18n.js";import{backupBeforeWrite as l,atomicWriteFile as a}from"./backup.js";import{pickModel as s,toolHome as d,withV1 as c}from"./types.js";import{getToolDefaultModel as m}from"../model-registry.js";import{buildCodexCatalog as p,codexCatalogPath as u,loadBundledCodexModels as _,loadPreviousCodexModels as g,previousGatewayModelIds as f}from"./codex-catalog.js";import{gatewayModelSpecs as x,modelFamily as y}from"../gateway-models.js";const k=()=>o(d(),".codex"),h=()=>o(k(),"config.toml"),w=()=>o(k(),"auth.json"),C="OPENAI_API_KEY",b="custom",j=1e6,v=9e5;export const CODEX_ONE_MILLION_CONTEXT_SETTING="one_million_context";function E(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function M(e,t){return E(e[t])||(e[t]={}),e[t]}function O(){if(!e(h()))return{};const o=t(h(),"utf-8");if(!o.trim())return{};try{const e=n.parse(o);if(!E(e))throw new Error("config.toml root must be a TOML table");return e}catch(e){throw new Error(`Existing ~/.codex/config.toml cannot be parsed, back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}}function N(){if(!e(w()))return{};try{const e=JSON.parse(t(w(),"utf-8"));return E(e)?e:{}}catch{return{}}}let S=null;function A(o,n,i){const s=!1!==n.settings?.one_million_context;!function(e){e.model_context_window===j&&delete e.model_context_window,e.model_auto_compact_token_limit===v&&delete e.model_auto_compact_token_limit}(o);const d=_()??g();if(!d)return r.logError("codexAdapter.writeModelCatalog",new Error("no Codex binary found; model catalog skipped")),S="skipped",o.model_catalog_json===u()&&delete o.model_catalog_json,void(s&&(o.model_context_window=j,o.model_auto_compact_token_limit=v));const c=n.catalog,m=p({bundled:d,specs:x("codex",c?.clientModels),...c?{keyModels:c.models}:{},gatewayAvailable:c?.models??f(),oneMillion:s,selectedModel:i,..."gateway"===c?.oneMillionSource?{claudeOneMillion:c.oneMillion}:{}});S={listed:m.models.filter(e=>"list"===e.visibility).map(e=>({id:String(e.slug),name:String(e.display_name??e.slug)}))};const y=JSON.stringify(m,null,2)+"\n",k=u();e(k)&&t(k,"utf-8")===y||(l(k),a(k,y)),o.model_catalog_json=k}export function setCodexOneMillionContext(e,t){const o=O(),r=n.stringify(o),i="string"==typeof o.model?o.model:m("codex");A(o,{settings:{[CODEX_ONE_MILLION_CONTEXT_SETTING]:e},catalog:t},i);const s=n.stringify(o);s!==r&&(l(h()),a(h(),s))}export const codexAdapter={name:"codex",displayName:"Codex",command:"codex",installCommand:"npm install -g @openai/codex",upgradeCommand:"npm install -g @openai/codex@latest",installSpec:{command:"codex",npmPackage:"@openai/codex",brew:"codex"},configPath:h(),wantsModelCatalog:!0,listedModels(){if(O().model_catalog_json!==u())return null;try{return(JSON.parse(t(u(),"utf-8")).models??[]).filter(e=>"list"===e.visibility).map(e=>String(e.slug))}catch{return null}},refreshModelMenu(e){O().model_catalog_json===u()&&setCodexOneMillionContext(!1!==e.settings?.one_million_context,e.catalog)},applyNotes(){if("skipped"===S)return[{kind:"action",text:i.t("tools.codex.catalog_skipped")}];if(!S)return[];const e=new Map;for(const t of S.listed)e.set(y(t.id),(e.get(y(t.id))??0)+1);const t=["gpt","claude","other","grok"].filter(t=>e.has(t)).map(t=>`${i.t(`tools.model_family.${t}`)} ${e.get(t)}`).join(" · ");return[{kind:"summary",text:i.t("tools.codex.catalog_written",{count:String(S.listed.length),breakdown:t})},{kind:"detail",text:S.listed.map(e=>e.name).join(", ")}]},loadPrivateConfig(e){const t=m("codex"),o=s(e.models,t),r=function(e){return/(?:^|\/)claude(?:-|$)/i.test(e)}(o)?t:o,i=c(e.baseUrl),d=O();d.model=r,d.model_provider=b,d.model_reasoning_effort="high",A(d,e,r);const p=M(d,"model_providers"),u=E(p[b])?{...p[b]}:{};delete u.env_key,p[b]={...u,name:"custom",wire_api:"responses",requires_openai_auth:!0,experimental_bearer_token:e.apiKey.trim(),base_url:i};const _=M(d,"profiles"),g=E(_[r])?{..._[r]}:{};_[r]={...g,model_provider:b,model:r},M(M(d,"tui"),"model_availability_nux")[r]=4;const f=M(d,"features");f.goals=!0,f.js_repl=!1,l(h()),a(h(),n.stringify(d)),function(e){const t=e.trim();if(!t)return;const o={...N(),auth_mode:"apikey",[C]:t};l(w()),a(w(),JSON.stringify(o,null,2)+"\n")}(e.apiKey)},unloadPrivateConfig(){if(!e(h()))return;let t;try{t=O()}catch(e){return void r.logError("codexAdapter.unloadPrivateConfig",e)}const o=t.model_providers;E(o)&&(delete o[b],0===Object.keys(o).length&&delete t.model_providers),t.model_provider===b&&delete t.model_provider,t.model_catalog_json===u()&&delete t.model_catalog_json,l(h()),a(h(),n.stringify(t))},detectCurrentConfig(){try{const e=O().model_providers?.[b],t=e?.experimental_bearer_token;if("string"==typeof t&&t.trim())return{apiKey:t.trim()}}catch{}const e=N()[C];return{apiKey:"string"==typeof e&&e.trim()?e.trim():null}},getConfig(){try{return O()}catch(e){return r.logError("codexAdapter.getConfig",e),null}},backupPaths:()=>[h(),w(),u()]};
|
package/dist/locales/en_US.json
CHANGED
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
"tool": "Tool management",
|
|
19
19
|
"status": "Show current configuration status",
|
|
20
20
|
"setup": "One-shot setup (--key auto-detects capable tools / --claudekey --codexkey for per-tool keys)",
|
|
21
|
-
"upgrade": "Upgrade Claude Code, Codex and other coding tools (falls back to the npm mirror)"
|
|
21
|
+
"upgrade": "Upgrade Claude Code, Codex and other coding tools (falls back to the npm mirror)",
|
|
22
|
+
"codex": "Codex helpers",
|
|
23
|
+
"codex_sessions": "Show every local Codex session again (sessions from another login or provider are hidden)"
|
|
22
24
|
},
|
|
23
25
|
"lang": {
|
|
24
26
|
"current": "Current language",
|
|
@@ -357,7 +359,8 @@
|
|
|
357
359
|
"restart_failed": "Could not restart {{tool}}; quit it completely and open it again",
|
|
358
360
|
"elevation_running": "Click Yes in the Windows prompt…",
|
|
359
361
|
"elevation_done": "{{tool}} registry updated",
|
|
360
|
-
"elevation_failed": "Could not update {{tool}}'s registry (prompt declined, or this account is not an administrator): open PowerShell as administrator and run vibecli setup"
|
|
362
|
+
"elevation_failed": "Could not update {{tool}}'s registry (prompt declined, or this account is not an administrator): open PowerShell as administrator and run vibecli setup",
|
|
363
|
+
"desktop_registry_invalid": "--desktop-registry takes on or off, got {{value}}"
|
|
361
364
|
},
|
|
362
365
|
"tools": {
|
|
363
366
|
"version_outdated": "version {{current}} is too old (needs {{min}} or later); upgrade with {{upgrade}}",
|
|
@@ -440,5 +443,14 @@
|
|
|
440
443
|
"changed": "{{tool}} model menu synced with VibeAPI: {{changes}}",
|
|
441
444
|
"added": "added {{models}}",
|
|
442
445
|
"removed": "removed {{models}}"
|
|
446
|
+
},
|
|
447
|
+
"codex_sessions": {
|
|
448
|
+
"codex_running": "Codex is still running (PIDs {{pids}}) and would overwrite the change: quit Codex completely (desktop app and background server included) first",
|
|
449
|
+
"nothing": "Scanned {{scanned}} sessions; all are already under \"{{target}}\"",
|
|
450
|
+
"dry_run": "Would move {{count}} sessions from \"{{from}}\" to \"{{target}}\" (dry run, nothing changed)",
|
|
451
|
+
"moved": "Moved {{count}} sessions from \"{{from}}\" to \"{{target}}\"; reopen Codex to see them. Run again after switching login back",
|
|
452
|
+
"db_skipped": "Codex's database was not updated ({{reason}}); session files were. Upgrade Node.js to 22.13+ and run again",
|
|
453
|
+
"backup": "Backup and undo record in {{dir}}; undo with vibecli codex sessions --undo <that dir>",
|
|
454
|
+
"undone": "Restored {{files}} session files and {{rows}} database rows"
|
|
443
455
|
}
|
|
444
456
|
}
|
package/dist/locales/zh_CN.json
CHANGED
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
"tool": "工具管理",
|
|
19
19
|
"status": "显示当前配置状态",
|
|
20
20
|
"setup": "一条命令完成配置(--key 按能力自动选工具 / --claudekey --codexkey 双令牌分别配置)",
|
|
21
|
-
"upgrade": "升级 Claude Code、Codex 等编码工具(官方渠道连不上时改走国内镜像)"
|
|
21
|
+
"upgrade": "升级 Claude Code、Codex 等编码工具(官方渠道连不上时改走国内镜像)",
|
|
22
|
+
"codex": "Codex 辅助功能",
|
|
23
|
+
"codex_sessions": "让 Codex 本地所有会话都显示在列表里(换过登录方式或服务商后旧会话会被隐藏)"
|
|
22
24
|
},
|
|
23
25
|
"lang": {
|
|
24
26
|
"current": "当前语言",
|
|
@@ -357,7 +359,8 @@
|
|
|
357
359
|
"restart_failed": "{{tool}} 没能自动重启,请完全退出后手动打开",
|
|
358
360
|
"elevation_running": "请在弹出的系统窗口里点「是」…",
|
|
359
361
|
"elevation_done": "{{tool}} 的注册表已更新",
|
|
360
|
-
"elevation_failed": "没能更新 {{tool}} 的注册表(系统确认被取消,或这个账号不是管理员):用管理员身份打开 PowerShell 再运行 vibecli setup"
|
|
362
|
+
"elevation_failed": "没能更新 {{tool}} 的注册表(系统确认被取消,或这个账号不是管理员):用管理员身份打开 PowerShell 再运行 vibecli setup",
|
|
363
|
+
"desktop_registry_invalid": "--desktop-registry 只接受 on 或 off,收到的是 {{value}}"
|
|
361
364
|
},
|
|
362
365
|
"tools": {
|
|
363
366
|
"version_outdated": "版本 {{current}} 过旧,需要 {{min}} 及以上,运行 {{upgrade}} 升级",
|
|
@@ -440,5 +443,14 @@
|
|
|
440
443
|
"changed": "已按 VibeAPI 最新模型清单更新 {{tool}}:{{changes}}",
|
|
441
444
|
"added": "新增 {{models}}",
|
|
442
445
|
"removed": "移除 {{models}}"
|
|
446
|
+
},
|
|
447
|
+
"codex_sessions": {
|
|
448
|
+
"codex_running": "Codex 还在运行(进程 {{pids}}),它会覆盖这次修改:请先完全退出 Codex(含桌面版和后台服务)再运行",
|
|
449
|
+
"nothing": "已扫描 {{scanned}} 个会话,全都在「{{target}}」下,不用处理",
|
|
450
|
+
"dry_run": "将把 {{count}} 个会话从「{{from}}」移到「{{target}}」(试运行,未修改)",
|
|
451
|
+
"moved": "已把 {{count}} 个会话从「{{from}}」移到「{{target}}」,重开 Codex 后都能在列表里看到;以后换回另一种登录方式时再运行一次",
|
|
452
|
+
"db_skipped": "Codex 的数据库没有更新({{reason}}),会话文件已改好;升级 Node.js 到 22.13 以上后再运行一次",
|
|
453
|
+
"backup": "备份与还原记录在 {{dir}},还原用 vibecli codex sessions --undo <这个目录>",
|
|
454
|
+
"undone": "已还原 {{files}} 个会话文件、{{rows}} 条数据库记录"
|
|
443
455
|
}
|
|
444
456
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeapi/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.63",
|
|
4
4
|
"description": "CLI tool for managing AI coding assistants (Claude Code, Codex, OpenClaw, Hermes, AtomCode, Grok Build) with one unified config",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|