@vibeapi/api-helper 0.0.128 → 0.0.130

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -46,7 +46,7 @@ npx --yes --registry https://npm.cnb.cool/vibeapi/npm/-/packages/ @vibeapi/cli@l
46
46
  vibecli setup --key sk-xxx
47
47
  ```
48
48
 
49
- `--key` 会按令牌能访问的模型分组自动配置:有 Claude 模型配 Claude Code 和 Claude Desktop(macOS / Windows 上桌面端没装也先写好,装好打开就能用;Linux 官方版装了才配)、有 GPT 模型配 Codex、有 Grok 模型配 Grok Build、有 Gemini 模型配 Antigravity CLI(`agy`)。没装的命令行工具也会先写好配置,再问要不要从国内镜像装上(`--install` 直接装)。拿到的是多个分组的令牌(如 Claude 分组 + GPT 分组 + Grok 分组),就各配各的:
49
+ `--key` 会按令牌能访问的模型分组自动配置:有 Claude 模型配 Claude Code 和 Claude Desktop(macOS / Windows 上桌面端没装也先写好,装好打开就能用;Linux 官方版装了才配)、有 GPT 模型配 Codex、有 Grok 模型配 Grok Build、有 Gemini 模型配 Antigravity CLI(`agy`)。没装的命令行工具先问要不要从国内镜像装上(`--install` 直接装),装好才写它的配置;不装就不动它的配置目录,装好后运行 `vibecli config <工具> --yes` 补上。拿到的是多个分组的令牌(如 Claude 分组 + GPT 分组 + Grok 分组),就各配各的:
50
50
 
51
51
  ```bash
52
52
  vibecli setup --claudekey sk-a --codexkey sk-b --grokkey sk-c --desktopkey sk-d
@@ -1,6 +1,15 @@
1
1
  interface BenchOptions {
2
2
  samples: number;
3
+ /** Also send one real streaming request (costs a few tokens). */
4
+ stream?: boolean;
5
+ /** Model for the streaming request; default picked from what the key can use. */
6
+ model?: string;
3
7
  fetchFn?: typeof fetch;
4
8
  }
9
+ /**
10
+ * The cheapest model a coding tool would really use with this key: the default Haiku slot, else
11
+ * Codex's default, else whatever the key lists first.
12
+ */
13
+ export declare function pickStreamModel(available: string[]): string | undefined;
5
14
  export declare function benchCommand(args: string[], injected?: BenchOptions): Promise<void>;
6
15
  export {};
@@ -1 +1 @@
1
- import e from"chalk";import{configManager as o}from"../lib/config.js";import{savedApiKey as s}from"./base.js";import{i18n as r}from"../lib/i18n.js";import{isJsonMode as n,emitJson as t,isColorEnabled as l}from"../lib/runtime-options.js";import{usageError as m}from"../lib/errors.js";import{CLI_NAME as a}from"../lib/brand.js";function i(e){return l()?e:e=>e}export async function benchCommand(l,c=function(e){let o=5;for(let s=0;s<e.length;s+=1)if("--samples"===e[s]&&e[s+1]){const r=Number.parseInt(e[s+1],10);Number.isFinite(r)&&r>0&&r<=50&&(o=r)}return{samples:o}}(l)){const h=s();if(!h)throw m(r.t("bench.missing_api_key"),r.t("errors.next_step",{command:`${a} setup --key ${r.t("errors.key_placeholder")}`}),"missing_api_key");const p=c.fetchFn||fetch,g=o.getBaseUrl(),u=`${g}/v1/models`,b={samples:c.samples,errors:0,durations:[]};n()||console.log(i(e.gray)(r.t("bench.running")));for(let e=0;e<c.samples;e+=1){const e=Date.now();try{if(!(await p(u,{method:"GET",headers:{Authorization:`Bearer ${h}`,Accept:"application/json"}})).ok){b.errors+=1;continue}b.durations.push(Date.now()-e)}catch{b.errors+=1}}const f=function(e){const o=e.durations.slice().sort((e,o)=>e-o),s=o.reduce((e,o)=>e+o,0),r=0===o.length?0:o.length%2==0?(o[o.length/2-1]+o[o.length/2])/2:o[Math.floor(o.length/2)],n=0===o.length?0:s/o.length;return{samples:e.samples,completed:o.length,errors:e.errors,median_ms:Math.round(r),average_ms:Math.round(n),min_ms:o[0]||0,max_ms:o[o.length-1]||0}}(b),d=b.errors===c.samples;n()?t({ok:!d,base_url:g,...f}):(console.log("\n"+i(e.bold)(r.t("bench.result_title"))),console.log(` ${r.t("bench.samples")}: ${f.samples}`),console.log(` ${r.t("bench.median")}: ${f.median_ms}ms`),console.log(` ${r.t("bench.average")}: ${f.average_ms}ms`),console.log(` ${r.t("bench.min")}: ${f.min_ms}ms`),console.log(` ${r.t("bench.max")}: ${f.max_ms}ms`),console.log(` ${r.t("bench.errors")}: ${f.errors}`))}
1
+ import e from"chalk";import{configManager as o}from"../lib/config.js";import{savedApiKey as t}from"./base.js";import{i18n as s}from"../lib/i18n.js";import{isJsonMode as r,emitJson as n,isColorEnabled as l}from"../lib/runtime-options.js";import{usageError as a}from"../lib/errors.js";import{CLI_NAME as i}from"../lib/brand.js";import{runStreamCheck as m}from"../lib/stream-check.js";import{getDefaultModels as c,getToolDefaultModel as h}from"../lib/model-registry.js";function p(e){return l()?e:e=>e}export function pickStreamModel(e){return[c().haiku,h("codex")].map(e=>e.replace(/\[[^\]]*\]$/,"")).filter(Boolean).find(o=>e.includes(o))??e[0]}export async function benchCommand(l,c=function(e){let o,t=5,s=!1;for(let r=0;r<e.length;r+=1)if("--stream"===e[r]&&(s=!0),"--model"===e[r]&&e[r+1]&&(o=e[r+1]),"--samples"===e[r]&&e[r+1]){const o=Number.parseInt(e[r+1],10);Number.isFinite(o)&&o>0&&o<=50&&(t=o)}return{samples:t,stream:s,model:o}}(l)){const h=t();if(!h)throw a(s.t("bench.missing_api_key"),s.t("errors.next_step",{command:`${i} setup --key ${s.t("errors.key_placeholder")}`}),"missing_api_key");const d=c.fetchFn||fetch,g=o.getBaseUrl(),f=`${g}/v1/models`,b={samples:c.samples,errors:0,durations:[]};let u=[];r()||console.log(p(e.gray)(s.t("bench.running")));for(let e=0;e<c.samples;e+=1){const e=Date.now();try{const o=await d(f,{method:"GET",headers:{Authorization:`Bearer ${h}`,Accept:"application/json"}});if(!o.ok){b.errors+=1;continue}if(b.durations.push(Date.now()-e),c.stream&&0===u.length){const e=await o.json().catch(()=>null);u=(e?.data??[]).map(e=>e.id).filter(e=>"string"==typeof e)}}catch{b.errors+=1}}const _=function(e){const o=e.durations.slice().sort((e,o)=>e-o),t=o.reduce((e,o)=>e+o,0),s=0===o.length?0:o.length%2==0?(o[o.length/2-1]+o[o.length/2])/2:o[Math.floor(o.length/2)],r=0===o.length?0:t/o.length;return{samples:e.samples,completed:o.length,errors:e.errors,median_ms:Math.round(s),average_ms:Math.round(r),min_ms:o[0]||0,max_ms:o[o.length-1]||0}}(b),$=b.errors===c.samples;let k;if(c.stream){const o=c.model??pickStreamModel(u);r()||console.log(p(e.gray)(s.t("bench.stream_running",{model:o??"-"}))),k=o?await m({baseUrl:g,apiKey:h,model:o,fetchFn:d}):{ok:!1,failure:"no_model"}}if(r())return n({ok:!$&&(k?.ok??!0),base_url:g,..._,...k?{stream:k}:{}}),void(k&&!k.ok&&(process.exitCode=1));console.log("\n"+p(e.bold)(s.t("bench.result_title"))),console.log(` ${s.t("bench.samples")}: ${_.samples}`),console.log(` ${s.t("bench.median")}: ${_.median_ms}ms`),console.log(` ${s.t("bench.average")}: ${_.average_ms}ms`),console.log(` ${s.t("bench.min")}: ${_.min_ms}ms`),console.log(` ${s.t("bench.max")}: ${_.max_ms}ms`),console.log(` ${s.t("bench.errors")}: ${_.errors}`),k?function(o){console.log("\n"+p(e.bold)(s.t("bench.stream_title"))),"model"in o&&(console.log(` ${s.t("bench.stream_model")}: ${o.model} (${"anthropic"===o.protocol?"Anthropic Messages":"Chat Completions"})`),void 0!==o.first_token_ms&&console.log(` ${s.t("bench.stream_first_token")}: ${o.first_token_ms}ms`),console.log(` ${s.t("bench.stream_total")}: ${o.total_ms}ms`));const t=o.ok?p(e.green)("√ "+s.t("bench.stream_ok")):p(e.red)("× "+s.t(`bench.stream_fail.${o.failure}`,{cli:i}));console.log(` ${t}`),!o.ok&&"detail"in o&&o.detail&&console.log(p(e.gray)(` ${o.detail}`)),o.ok||(process.exitCode=1)}(k):console.log(p(e.gray)("\n"+s.t("bench.stream_hint",{cli:i})))}
@@ -1 +1 @@
1
- import{refreshClientConfig as o}from"../lib/client-config-sync.js";import t from"chalk";import e from"ora";import{spawnSync as s}from"child_process";import{existsSync as r,readdirSync as n,readFileSync as a}from"fs";import{connect as i}from"net";import{join as c}from"path";import{configManager as l}from"../lib/config.js";import{savedApiKey as d}from"./base.js";import{toolManager as p}from"../lib/tool-manager.js";import{i18n as u}from"../lib/i18n.js";import{validateApiKey as m}from"../lib/api-validator.js";import{getAdapter as f}from"../lib/tools/registry.js";import{findInstalls as _,installLabel as g}from"../lib/tools/tool-installs.js";import{detectManagedOverrides as h}from"../lib/tools/claude-managed.js";import{codexAuthProblem as y,codexCatalogRejection as v,codexConfigPath as w,codexWorkModeOn as j}from"../lib/tools/codex.js";import{claudeAccountLoginPresent as k}from"../lib/tools/claude-code.js";import{toolHome as b}from"../lib/tools/types.js";import{gatewayAddresses as x,probeGatewayAddress as $}from"../lib/gateway-addresses.js";import{listAdapters as T}from"../lib/tools/registry.js";import{logger as A}from"../utils/logger.js";import{maskHome as P,maskSecrets as R,uploadReport as O}from"../lib/telemetry.js";import{CLI_NAME as N}from"../lib/brand.js";const C=["HTTPS_PROXY","https_proxy","HTTP_PROXY","http_proxy","ALL_PROXY","all_proxy"];function I(o,t,e=3e3){return new Promise(s=>{const r=i({host:o,port:t}),n=o=>{r.destroy(),s(o)};r.setTimeout(e,()=>n(!1)),r.once("connect",()=>n(!0)),r.once("error",()=>n(!1))})}function H(){const o=A.getLogDir();if(!r(o))return"";const t=n(o).filter(o=>/^\d{4}-\d{2}-\d{2}\.log$/.test(o)).sort().slice(-2).map(t=>`== ${t}\n`+a(c(o,t),"utf-8")).join("\n");return R(t.slice(-15e4))}function L(){const o={};for(const t of C){const e=process.env[t]?.trim();if(e)try{const s=new URL(e.includes("://")?e:`http://${e}`);o[t]=`${s.protocol}//${s.host}`}catch{o[t]="(unparsable)"}}return o}export async function doctorCommand(r={}){const n=e(u.t("doctor.checking")).start(),i=[],A=Number(process.versions.node.split(".")[0]);i.push({name:"Node.js",status:A>=20?"pass":"fail",message:`v${process.versions.node}`}),n.text=u.t("doctor.check_proxy"),i.push(await async function(){const o=u.t("doctor.proxy"),t=new Map;for(const o of C){const e=process.env[o]?.trim();e&&!t.has(e)&&t.set(e,o)}if(0===t.size)return{name:o,status:"pass",message:u.t("doctor.proxy_none")};const e=[];for(const[o,s]of t){let t;try{t=new URL(o.includes("://")?o:`http://${o}`)}catch{e.push(`${s}=${o}`);continue}const r=Number(t.port)||("https:"===t.protocol?443:t.protocol.startsWith("socks")?1080:80);await I(t.hostname,r)||e.push(`${s}=${o}`)}return 0===e.length?{name:o,status:"pass",message:[...t.keys()].join(", ")}:{name:o,status:"fail",message:u.t("doctor.proxy_dead",{proxies:e.join(", ")})}}()),n.text=u.t("doctor.check_api_key_network");const R=d(),S=u.t("doctor.api_key_network");if(R){const o=await m(R);o.valid?i.push({name:S,status:"pass"}):"invalid_api_key"===o.error?i.push({name:S,status:"fail",message:u.t("doctor.api_key_invalid")}):(i.push({name:S,status:"fail",message:`${u.t("doctor.network_error")}: ${o.message??o.error}`}),n.text=u.t("doctor.check_other_addresses"),i.push(await async function(){const o=u.t("doctor.other_addresses"),t=l.getBaseUrl(),e=x().filter(o=>o.url!==t),s=d(),r=await Promise.all(e.map(o=>$(o.url,{apiKey:s}))),n=e.filter((o,t)=>r[t].ok).map(o=>o.url);return 0===n.length?{name:o,status:"fail",message:u.t("doctor.other_addresses_none")}:{name:o,status:"warn",message:u.t("doctor.other_addresses_found",{urls:n.join(", ")})}}()))}else i.push({name:S,status:"fail",message:u.t("doctor.api_key_missing")});n.text=u.t("doctor.check_client_config");const U=await o();i.push({name:u.t("doctor.client_config"),status:"cloud"===U.source||"cache"===U.source&&!U.problem?"pass":"warn",message:[U.source?u.t(`refresh.source.${U.source}`):u.t("refresh.source.none"),U.revision?u.t("doctor.client_config_revision",{revision:U.revision}):"",U.problem??""].filter(Boolean).join(" · ")}),n.text=u.t("doctor.check_tools");const E=p.getInstalledTools();i.push({name:u.t("doctor.installed_tools"),status:E.length>0?"pass":"warn",message:E.length>0?E.map(o=>f(o)?.displayName??o).join(", "):u.t("doctor.no_tools_installed")}),i.push(...function(){const o=[];for(const t of p.getInstalledTools()){const e=f(t);if(!e?.installSpec)continue;const s=_(e.installSpec);if(0===s.length)continue;const r=[],n=p.outdatedVersion(t);n&&r.push(u.t("doctor.tool_outdated",{min:n.min})),s.length>1&&r.push(u.t("doctor.tool_duplicates",{others:s.slice(1).map(g).join("、")})),o.push({name:e.displayName,status:r.length>0?"warn":"pass",message:[g(s[0]),...r,...r.length>0?[u.t("doctor.run_upgrade",{tool:t})]:[]].join("\n ")})}return o}());const B=function(){if(!p.isToolInstalled("claude-code"))return null;const o=u.t("doctor.claude_config"),t=h();if(t.length>0){const e=t.map(o=>`${o.source}: ${o.keys.join(", ")}`).join("; ");return{name:o,status:"fail",message:u.t("doctor.claude_managed",{detail:e})}}let e={};try{e=JSON.parse(a(c(process.env.CLAUDE_CONFIG_DIR?.trim()||c(b(),".claude"),"settings.json"),"utf-8")).env??{}}catch{}const s=l.getApiKeyForTool("claude-code");return e.ANTHROPIC_AUTH_TOKEN&&e.ANTHROPIC_BASE_URL?e.ANTHROPIC_BASE_URL!==l.getBaseUrl()||s&&e.ANTHROPIC_AUTH_TOKEN!==s?{name:o,status:"warn",message:u.t("doctor.claude_config_changed")}:{name:o,status:"pass"}:{name:o,status:"warn",message:u.t("doctor.claude_not_configured")}}();B&&i.push(B),E.includes("claude-code")&&k()&&i.push({name:u.t("doctor.claude_login"),status:"pass",message:u.t("tools.claude_code.account_login_overridden")});const K=E.includes("codex")?y():null;if(E.includes("codex")&&i.push({name:u.t("doctor.codex_auth"),status:K?"fail":"pass",message:K?u.t(`doctor.codex_${K}`,{path:P(w())}):void 0}),E.includes("codex")){const o=v();i.push({name:u.t("doctor.codex_catalog"),status:o?"fail":"pass",message:o?u.t("doctor.codex_catalog_rejected",{path:o.bin,version:o.version??"?",error:o.error}):void 0})}E.includes("codex")&&j()&&i.push({name:u.t("doctor.codex_work_mode"),status:"warn",message:u.t("tools.codex.work_mode_on")}),"win32"===process.platform&&E.includes("claude-code")&&!process.env.CLAUDE_CODE_GIT_BASH_PATH&&i.push({name:"Git for Windows",status:p.isGitInstalled()?"pass":"warn",message:p.isGitInstalled()?void 0:u.t("tools.claude_code.no_git_bash")}),r.deep&&E.includes("claude-code")&&(n.text=u.t("doctor.check_claude_request"),i.push(function(){const o=u.t("doctor.claude_request"),t=_(f("claude-code").installSpec)[0];if(!t)return{name:o,status:"warn",message:u.t("doctor.claude_request_skipped")};const e={encoding:"utf-8",timeout:12e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},r=["-p","Reply with the single word OK."],n=/\.cmd$/i.test(t.path)?s(`"${t.path}" ${r.map(o=>`"${o}"`).join(" ")}`,{...e,shell:!0}):s(t.path,r,e),a=`${n.stdout??""}`.trim();if(0===n.status&&a)return{name:o,status:"pass",message:a.slice(0,80)};const i=(`${n.stderr??""}`.trim()||a||n.error?.message||`exit ${n.status}`).slice(0,300);return{name:o,status:"fail",message:u.t("doctor.claude_request_failed",{reason:i})}}())),n.stop(),console.log("\n"+t.bold(u.t("doctor.results_title"))+"\n");const G={pass:t.green("√"),warn:t.yellow("!"),fail:t.red("×")};for(const o of i)console.log(`${G[o.status]} ${o.name}`),o.message&&console.log(t.gray(` ${o.message}`));if(i.every(o=>"pass"===o.status)&&console.log("\n"+t.green.bold(u.t("doctor.all_good"))),!r.deep&&E.includes("claude-code")&&console.log(t.gray("\n"+u.t("doctor.deep_hint"))),r.report){const o=e(u.t("doctor.report_uploading")).start(),t=await O(function(o,t){const e={};for(const o of T()){if(o.hidden)continue;let t=null;try{t=p.detectCurrentConfig(o.name).apiKey?"has_key":"no_key"}catch{t="unreadable"}e[o.name]={installed:p.isToolInstalled(o.name),version:p.installedVersion(o.name),copies:o.installSpec?_(o.installSpec).map(o=>({kind:o.kind,version:o.version,path:o.path})):void 0,config:t}}const s=l.getProfile();return{checks:o,tools:e,settings:{base_url:l.getBaseUrl(),profile:l.getActiveProfileName(),profiles:l.listProfiles().length,key_fingerprint:l.getApiKeyFingerprint()||null,tool_keys:Object.keys(s.tool_api_keys??{}),models:s.models,tool_models:s.tool_models??{},tool_settings:s.tool_settings??{},lang:l.getLang()},client_config:t,env:{shell:process.env.SHELL??process.env.ComSpec??null,term:process.env.TERM_PROGRAM??null,proxies:L()},log:H()}}(i,{source:U.source??void 0,revision:U.revision,problem:U.problem}));t?o.succeed(u.t("doctor.report_done",{code:t})):o.fail(u.t("doctor.report_failed",{cli:N}))}else i.some(o=>"fail"===o.status)&&console.log(t.gray("\n"+u.t("doctor.report_hint",{cli:N})));i.some(o=>"fail"===o.status)&&(process.exitCode=1)}
1
+ import{refreshClientConfig as o}from"../lib/client-config-sync.js";import e from"chalk";import t from"ora";import{spawnSync as s}from"child_process";import{existsSync as r,readdirSync as n,readFileSync as a}from"fs";import{connect as i}from"net";import{join as c}from"path";import{configManager as l}from"../lib/config.js";import{savedApiKey as d}from"./base.js";import{toolManager as p}from"../lib/tool-manager.js";import{i18n as u}from"../lib/i18n.js";import{validateApiKey as m}from"../lib/api-validator.js";import{getAdapter as f}from"../lib/tools/registry.js";import{findInstalls as g,installLabel as _}from"../lib/tools/tool-installs.js";import{detectManagedOverrides as h}from"../lib/tools/claude-managed.js";import{codexAuthProblem as y,codexCatalogRejection as k,codexConfigPath as w,codexWorkModeOn as b}from"../lib/tools/codex.js";import{claudeAccountLoginPresent as v}from"../lib/tools/claude-code.js";import{toolHome as j}from"../lib/tools/types.js";import{gatewayAddresses as x,probeGatewayAddress as $}from"../lib/gateway-addresses.js";import{listAdapters as T}from"../lib/tools/registry.js";import{logger as A}from"../utils/logger.js";import{maskHome as P,maskSecrets as R,uploadReport as N}from"../lib/telemetry.js";import{CLI_NAME as O}from"../lib/brand.js";import{balanceLookupEnabled as C,balanceNeedsAttention as I,balanceText as H,fetchKeyBalances as L}from"../lib/key-balance.js";const S=["HTTPS_PROXY","https_proxy","HTTP_PROXY","http_proxy","ALL_PROXY","all_proxy"];function U(o,e,t=3e3){return new Promise(s=>{const r=i({host:o,port:e}),n=o=>{r.destroy(),s(o)};r.setTimeout(t,()=>n(!1)),r.once("connect",()=>n(!0)),r.once("error",()=>n(!1))})}function E(){const o=A.getLogDir();if(!r(o))return"";const e=n(o).filter(o=>/^\d{4}-\d{2}-\d{2}\.log$/.test(o)).sort().slice(-2).map(e=>`== ${e}\n`+a(c(o,e),"utf-8")).join("\n");return R(e.slice(-15e4))}function K(){const o={};for(const e of S){const t=process.env[e]?.trim();if(t)try{const s=new URL(t.includes("://")?t:`http://${t}`);o[e]=`${s.protocol}//${s.host}`}catch{o[e]="(unparsable)"}}return o}export async function doctorCommand(r={}){const n=t(u.t("doctor.checking")).start(),i=[],A=Number(process.versions.node.split(".")[0]);i.push({name:"Node.js",status:A>=20?"pass":"fail",message:`v${process.versions.node}`}),n.text=u.t("doctor.check_proxy"),i.push(await async function(){const o=u.t("doctor.proxy"),e=new Map;for(const o of S){const t=process.env[o]?.trim();t&&!e.has(t)&&e.set(t,o)}if(0===e.size)return{name:o,status:"pass",message:u.t("doctor.proxy_none")};const t=[];for(const[o,s]of e){let e;try{e=new URL(o.includes("://")?o:`http://${o}`)}catch{t.push(`${s}=${o}`);continue}const r=Number(e.port)||("https:"===e.protocol?443:e.protocol.startsWith("socks")?1080:80);await U(e.hostname,r)||t.push(`${s}=${o}`)}return 0===t.length?{name:o,status:"pass",message:[...e.keys()].join(", ")}:{name:o,status:"fail",message:u.t("doctor.proxy_dead",{proxies:t.join(", ")})}}()),n.text=u.t("doctor.check_api_key_network");const R=d(),B=u.t("doctor.api_key_network");if(R){const o=await m(R);o.valid?(i.push({name:B,status:"pass"}),n.text=u.t("doctor.check_balance"),i.push(...await async function(o){if(!C())return[];const e=l.listToolApiKeys().map(o=>({tool:o,key:l.getApiKeyForTool(o)})).filter(e=>Boolean(e.key)&&e.key!==o),t=await L([o,...e.map(o=>o.key)]),s=[{name:u.t("doctor.balance"),key:o},...e.map(o=>({name:u.t("doctor.balance_tool",{tool:f(o.tool)?.displayName??o.tool}),key:o.key}))],r=[];for(const o of s){const e=t.get(o.key);e&&r.push({name:o.name,status:I(e)?"warn":"pass",message:H(e)})}return r}(R))):"invalid_api_key"===o.error?i.push({name:B,status:"fail",message:u.t("doctor.api_key_invalid")}):(i.push({name:B,status:"fail",message:`${u.t("doctor.network_error")}: ${o.message??o.error}`}),n.text=u.t("doctor.check_other_addresses"),i.push(await async function(){const o=u.t("doctor.other_addresses"),e=l.getBaseUrl(),t=x().filter(o=>o.url!==e),s=d(),r=await Promise.all(t.map(o=>$(o.url,{apiKey:s}))),n=t.filter((o,e)=>r[e].ok).map(o=>o.url);return 0===n.length?{name:o,status:"fail",message:u.t("doctor.other_addresses_none")}:{name:o,status:"warn",message:u.t("doctor.other_addresses_found",{urls:n.join(", ")})}}()))}else i.push({name:B,status:"fail",message:u.t("doctor.api_key_missing")});n.text=u.t("doctor.check_client_config");const G=await o();i.push({name:u.t("doctor.client_config"),status:"cloud"===G.source||"cache"===G.source&&!G.problem?"pass":"warn",message:[G.source?u.t(`refresh.source.${G.source}`):u.t("refresh.source.none"),G.revision?u.t("doctor.client_config_revision",{revision:G.revision}):"",G.problem??""].filter(Boolean).join(" · ")}),n.text=u.t("doctor.check_tools");const D=p.getInstalledTools();i.push({name:u.t("doctor.installed_tools"),status:D.length>0?"pass":"warn",message:D.length>0?D.map(o=>f(o)?.displayName??o).join(", "):u.t("doctor.no_tools_installed")}),i.push(...function(){const o=[];for(const e of p.getInstalledTools()){const t=f(e);if(!t?.installSpec)continue;const s=g(t.installSpec);if(0===s.length)continue;const r=[],n=p.outdatedVersion(e);n&&r.push(u.t("doctor.tool_outdated",{min:n.min})),s.length>1&&r.push(u.t("doctor.tool_duplicates",{others:s.slice(1).map(_).join("、")})),o.push({name:t.displayName,status:r.length>0?"warn":"pass",message:[_(s[0]),...r,...r.length>0?[u.t("doctor.run_upgrade",{tool:e})]:[]].join("\n ")})}return o}());const q=function(){if(!p.isToolInstalled("claude-code"))return null;const o=u.t("doctor.claude_config"),e=h();if(e.length>0){const t=e.map(o=>`${o.source}: ${o.keys.join(", ")}`).join("; ");return{name:o,status:"fail",message:u.t("doctor.claude_managed",{detail:t})}}let t={};try{t=JSON.parse(a(c(process.env.CLAUDE_CONFIG_DIR?.trim()||c(j(),".claude"),"settings.json"),"utf-8")).env??{}}catch{}const s=l.getApiKeyForTool("claude-code");return t.ANTHROPIC_AUTH_TOKEN&&t.ANTHROPIC_BASE_URL?t.ANTHROPIC_BASE_URL!==l.getBaseUrl()||s&&t.ANTHROPIC_AUTH_TOKEN!==s?{name:o,status:"warn",message:u.t("doctor.claude_config_changed")}:{name:o,status:"pass"}:{name:o,status:"warn",message:u.t("doctor.claude_not_configured")}}();q&&i.push(q),D.includes("claude-code")&&v()&&i.push({name:u.t("doctor.claude_login"),status:"pass",message:u.t("tools.claude_code.account_login_overridden")});const F=D.includes("codex")?y():null;if(D.includes("codex")&&i.push({name:u.t("doctor.codex_auth"),status:F?"fail":"pass",message:F?u.t(`doctor.codex_${F}`,{path:P(w())}):void 0}),D.includes("codex")){const o=k();i.push({name:u.t("doctor.codex_catalog"),status:o?"fail":"pass",message:o?u.t("doctor.codex_catalog_rejected",{path:o.bin,version:o.version??"?",error:o.error}):void 0})}D.includes("codex")&&b()&&i.push({name:u.t("doctor.codex_work_mode"),status:"warn",message:u.t("tools.codex.work_mode_on")}),"win32"===process.platform&&D.includes("claude-code")&&!process.env.CLAUDE_CODE_GIT_BASH_PATH&&i.push({name:"Git for Windows",status:p.isGitInstalled()?"pass":"warn",message:p.isGitInstalled()?void 0:u.t("tools.claude_code.no_git_bash")}),r.deep&&D.includes("claude-code")&&(n.text=u.t("doctor.check_claude_request"),i.push(function(){const o=u.t("doctor.claude_request"),e=g(f("claude-code").installSpec)[0];if(!e)return{name:o,status:"warn",message:u.t("doctor.claude_request_skipped")};const t={encoding:"utf-8",timeout:12e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},r=["-p","Reply with the single word OK."],n=/\.cmd$/i.test(e.path)?s(`"${e.path}" ${r.map(o=>`"${o}"`).join(" ")}`,{...t,shell:!0}):s(e.path,r,t),a=`${n.stdout??""}`.trim();if(0===n.status&&a)return{name:o,status:"pass",message:a.slice(0,80)};const i=(`${n.stderr??""}`.trim()||a||n.error?.message||`exit ${n.status}`).slice(0,300);return{name:o,status:"fail",message:u.t("doctor.claude_request_failed",{reason:i})}}())),n.stop(),console.log("\n"+e.bold(u.t("doctor.results_title"))+"\n");const M={pass:e.green("√"),warn:e.yellow("!"),fail:e.red("×")};for(const o of i)console.log(`${M[o.status]} ${o.name}`),o.message&&console.log(e.gray(` ${o.message}`));if(i.every(o=>"pass"===o.status)&&console.log("\n"+e.green.bold(u.t("doctor.all_good"))),!r.deep&&D.includes("claude-code")&&console.log(e.gray("\n"+u.t("doctor.deep_hint"))),r.report){const o=t(u.t("doctor.report_uploading")).start(),e=await N(function(o,e){const t={};for(const o of T()){if(o.hidden)continue;let e=null;try{e=p.detectCurrentConfig(o.name).apiKey?"has_key":"no_key"}catch{e="unreadable"}t[o.name]={installed:p.isToolInstalled(o.name),version:p.installedVersion(o.name),copies:o.installSpec?g(o.installSpec).map(o=>({kind:o.kind,version:o.version,path:o.path})):void 0,config:e}}const s=l.getProfile();return{checks:o,tools:t,settings:{base_url:l.getBaseUrl(),profile:l.getActiveProfileName(),profiles:l.listProfiles().length,key_fingerprint:l.getApiKeyFingerprint()||null,tool_keys:Object.keys(s.tool_api_keys??{}),models:s.models,tool_models:s.tool_models??{},tool_settings:s.tool_settings??{},lang:l.getLang()},client_config:e,env:{shell:process.env.SHELL??process.env.ComSpec??null,term:process.env.TERM_PROGRAM??null,proxies:K()},log:E()}}(i,{source:G.source??void 0,revision:G.revision,problem:G.problem}));e?o.succeed(u.t("doctor.report_done",{code:e})):o.fail(u.t("doctor.report_failed",{cli:O}))}else i.some(o=>"fail"===o.status)&&console.log(e.gray("\n"+u.t("doctor.report_hint",{cli:O})));i.some(o=>"fail"===o.status)&&(process.exitCode=1)}
@@ -0,0 +1,18 @@
1
+ export interface SessionsListOptions {
2
+ tool?: string;
3
+ dir?: string;
4
+ here?: boolean;
5
+ limit?: string;
6
+ all?: boolean;
7
+ }
8
+ export declare function sessionsListCommand(options?: SessionsListOptions): Promise<void>;
9
+ export declare function sessionsShowCommand(id: string, options?: {
10
+ messages?: string;
11
+ }): Promise<void>;
12
+ export declare function sessionsResumeCommand(id: string, options?: {
13
+ run?: boolean;
14
+ }): Promise<void>;
15
+ export declare function sessionsExportCommand(ids: string[], options?: {
16
+ output?: string;
17
+ tools?: boolean;
18
+ }): Promise<void>;
@@ -0,0 +1 @@
1
+ import s from"chalk";import{spawnSync as o}from"child_process";import{existsSync as t,mkdirSync as e,writeFileSync as i}from"fs";import{dirname as n,join as r,resolve as l}from"path";import{i18n as c}from"../lib/i18n.js";import{emitJson as d,isColorEnabled as m,isJsonMode as a}from"../lib/runtime-options.js";import{maskHome as f}from"../lib/telemetry.js";import{operationError as u,usageError as p}from"../lib/errors.js";import{CLI_NAME as g}from"../lib/brand.js";import{clip as h}from"../lib/sessions/formats.js";import{listSessions as w,readSession as _,resolveSession as b,resumeCommand as $,resumeLine as v,roleLabel as x,sessionMarkdown as N}from"../lib/sessions/index.js";import{padString as y,stringWidth as S}from"../utils/string-width.js";function j(s){return s.replace(/[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g,"")}function A(s){return m()?s:s=>s}function C(s){const o=new Date(s);if(Number.isNaN(o.getTime()))return s;const t=s=>String(s).padStart(2,"0");return`${o.getFullYear()}-${t(o.getMonth()+1)}-${t(o.getDate())} ${t(o.getHours())}:${t(o.getMinutes())}`}function M(s,o){const t=j(s).replace(/\s+/g," ").trim();if(S(t)<=o)return t;let e="";for(const s of t){if(S(e+s)>o-1)break;e+=s}return e+"…"}function k(s){const o=$(s);return{id:s.id,tool:s.tool,title:s.title,cwd:s.cwd,started_at:s.startedAt??null,updated_at:s.updatedAt,provider:s.provider??null,file:s.file,resume:o?v(o):null}}export async function sessionsListCommand(o={}){const t=o.all?0:Number(o.limit??20);if(!o.all&&(!Number.isInteger(t)||t<=0))throw p(c.t("sessions.bad_limit",{value:String(o.limit)}),c.t("sessions.bad_limit_hint",{cli:g}));const e=o.here?process.cwd():o.dir,i=w({tool:o.tool,dir:e,limit:t});if(a())return void d(i.map(k));if(0===i.length)return void console.log(c.t("sessions.none"));const n=A(s.gray),r=A(s.cyan),l=Math.max(...i.map(s=>S(s.toolName)),4);for(const s of i){const o=`${r(s.id.slice(0,8))} ${y(s.toolName,l)} ${n(C(s.updatedAt))}`;console.log(`${o} ${M(s.title||"-",60)}`),s.cwd&&console.log(n(` ${j(f(s.cwd))}`))}console.log(n("\n"+c.t("sessions.list_footer",{cli:g,count:String(i.length)})))}export async function sessionsShowCommand(o,t={}){const e=Number(t.messages??6);if(!Number.isInteger(e)||e<0)throw p(c.t("sessions.bad_limit",{value:String(t.messages)}),c.t("sessions.bad_limit_hint",{cli:g}));const i=b(o),n=_(i);if(a())return void d({...k(i),message_count:n.length,messages:n.slice(0,e)});const r=A(s.gray),l=A(s.cyan),m=A(s.bold),u=$(i);console.log("\n"+m(j(i.title||i.id))+"\n");const w=[[c.t("sessions.field.tool"),i.toolName],[c.t("sessions.field.id"),i.id],[c.t("sessions.field.started"),i.startedAt?C(i.startedAt):void 0],[c.t("sessions.field.updated"),C(i.updatedAt)],[c.t("sessions.field.cwd"),i.cwd?f(i.cwd):void 0],[c.t("sessions.field.provider"),i.provider],[c.t("sessions.field.messages"),String(n.length)],[c.t("sessions.field.file"),f(i.file)],[c.t("sessions.field.resume"),u?v(u):c.t("sessions.no_resume")]],N=Math.max(...w.map(([s])=>S(s)));for(const[s,o]of w)o&&console.log(` ${l(y(s,N))} ${j(o)}`);for(const s of n.slice(0,e))console.log("\n"+m(`[${x(s.role)}]`)+(s.timestamp?r(` ${C(s.timestamp)}`):"")),console.log(j(h(s.text,500)));n.length>e&&console.log(r("\n"+c.t("sessions.more_messages",{more:String(n.length-e),cli:g,id:i.id.slice(0,8)})))}export async function sessionsResumeCommand(e,i={}){const n=b(e),r=$(n);if(!r)throw p(c.t("sessions.cannot_resume",{tool:n.toolName}),c.t("sessions.cannot_resume_hint",{tool:n.toolName}));const l=v(r);if(!i.run)return void(a()?d({id:n.id,tool:n.tool,command:r.command,args:r.args,cwd:r.cwd||null,line:l}):console.log(l));const m=r.cwd&&t(r.cwd)?r.cwd:void 0;r.cwd&&!m&&console.error(A(s.yellow)(c.t("sessions.cwd_missing",{dir:r.cwd})));const f=o(r.command,r.args,{cwd:m,stdio:"inherit",shell:"win32"===process.platform});if(f.error)throw u(c.t("sessions.run_failed",{command:r.command,error:f.error.message}),c.t("sessions.run_failed_hint",{line:l}));"number"==typeof f.status&&0!==f.status&&(process.exitCode=f.status)}function D(s,o,e){const i=`${o.tool}-${o.id}`.replace(/[^A-Za-z0-9_-]/g,"_");let d=r(s,`${i}.md`);for(let o=2;e.has(d)||t(d);o++)d=r(s,`${i}-${o}.md`);if(n(l(d))!==l(s))throw u(c.t("sessions.export_bad_path",{path:d}),"");return e.add(d),d}export async function sessionsExportCommand(o,t={}){if(!t.output)throw p(c.t("sessions.export_needs_output"),c.t("sessions.export_hint",{cli:g}));const n=o.map(b),r=l(t.output);e(r,{recursive:!0});const m=new Set,u=[];for(const s of n){const o=D(r,s,m);i(o,N(s,_(s,{details:t.tools})),"utf-8"),u.push({id:s.id,tool:s.tool,path:o})}if(a())d({written:u});else for(const o of u)console.log(A(s.green)("√ ")+f(o.path))}
@@ -1 +1 @@
1
- import o from"chalk";import{getAdapter as e}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{ensureReachableGatewayAddress as i}from"./base.js";import{i18n as s}from"../lib/i18n.js";import{configManager as l}from"../lib/config.js";import{toolManager as n,SUPPORTED_TOOLS as a}from"../lib/tool-manager.js";import{validateApiKey as r,fetchModels as p}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as d,setCodexOneMillionContext as c}from"../lib/tools/codex.js";import{resolveModelCatalog as u}from"../lib/model-catalog.js";import{CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING as f,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as m}from"../lib/tools/claude-desktop.js";import{operationError as g,authenticationError as y,networkError as _,EXIT_CODES as k}from"../lib/errors.js";import{emitJson as h,isColorEnabled as b,isDryRun as w,isJsonMode as v,isNonInteractive as x,shouldAutoConfirm as C}from"../lib/runtime-options.js";import{join as $}from"path";import T from"inquirer";import{logger as j}from"../utils/logger.js";import{forgetInstalls as K}from"../lib/tools/tool-installs.js";import{CLI_NAME as N,brandEnv as G}from"../lib/brand.js";export const DEDICATED_KEYS=[{option:"claudekey",tool:"claude-code",need:"claude"},{option:"codexkey",tool:"codex",need:"gpt"},{option:"grokkey",tool:"grok",need:"grok"},{option:"desktopkey",tool:"claude-desktop",need:"claude"},{option:"agykey",tool:"agy",need:"gemini"},{option:"openclawkey",tool:"openclaw",need:"any",hidden:!0},{option:"hermeskey",tool:"hermes",need:"any",hidden:!0},{option:"atomcodekey",tool:"atomcode",need:"any",hidden:!0}];async function M(o){const e=await p(o);if(!e.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,hasGemini:!0,probed:!1};const t=e.models.map(o=>o.toLowerCase());return{hasClaude:t.some(o=>o.includes("claude")),hasGpt:t.some(o=>o.startsWith("gpt")||o.includes("gpt-")||/^o\d/.test(o)),hasGrok:t.some(o=>o.includes("grok")),hasGemini:t.some(o=>o.startsWith("gemini")),probed:!0}}function S(o,e){switch(e){case"claude":return o.hasClaude;case"gpt":return o.hasGpt;case"grok":return o.hasGrok;case"gemini":return o.hasGemini;default:return!0}}export function parseOnOff(o){const e=(o??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(e)||!["off","false","hide","0","no","n"].includes(e)&&void 0}function E(e){console.log(o.green(e))}function O(e){console.log(o.yellow(e))}function A(e){console.error(o.red(e))}let I=null;function L(o){const e={operation:1,authentication:2,network:3};(!I||e[o]>e[I])&&(I=o)}async function D(e,t){v()||console.log(o.gray(s.t("setup.validating",{label:e})));const i=await r(t);if(i.valid)return!0;const n="zh_CN"===s.getLocale()?"<你的 Key>":"<your key>",a="--key"===e?`${N} setup --key ${n}`:`${N} setup ${e} ${n}`;let p;if("network_error"===i.error?(L("network"),p=_(s.t("setup.unreachable",{url:l.getBaseUrl(),reason:i.message||"network error"}),`${N} base auto`,"network_error")):"invalid_api_key"===i.error?(L("authentication"),p=y(s.t("setup.invalid_key",{label:e,reason:i.message||"invalid"}),a,"invalid_api_key")):(L("operation"),p=g(s.t("setup.validate_failed",{label:e,reason:i.message||i.error||"unknown"}),a,i.error)),v())throw p;return A(p.message),console.log(o.gray(s.t("errors.next_step",{command:p.hint}))),!1}async function P(t,i,r={}){const{oneMillion:p,officialLogin:c,desktopRegistry:u,force:y}=r,_=a[t];try{"claude-desktop"===t&&void 0!==u&&l.setToolSetting("claude-desktop",f,u),"codex"===t&&void 0!==p&&l.setToolSetting("codex",d,p),"claude-desktop"===t&&void 0!==c&&l.setToolSetting("claude-desktop",m,!c),await n.applyPrivateConfig(t,i,l.getModelsForTool(t),{force:y})}catch(o){if(v())throw g(o instanceof Error?o.message:String(o),`${N} setup --key ${"zh_CN"===s.getLocale()?"<你的 Key>":"<your key>"}`,"config_write_failed");const e=(o instanceof Error?o.message:String(o)).replace(/\s+/g," ").trim();return A("× "+s.t("setup.apply_failed",{tool:_.displayName,reason:e})),!1}return n.printApplied(t),y&&console.log(o.gray(" "+s.t("config.force_done",{tool:_.displayName,name:t}))),"codex"===t&&void 0!==p&&console.log(o.gray(" "+s.t(p?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),e(t)?.isInstalled&&!n.isToolInstalled(t)&&console.log(o.yellow(" ! "+s.t("setup.gui_preconfigured",{tool:_.displayName,install:_.installCommand}))),!0}function R(t,i){const n=t.map(o=>{const t=e(o);return{tool:o,files:t?.backupPaths?.()??(t?[t.configPath]:[])}}),r=$(l.getConfigDir(),"config.yaml");if(v())return void h({dry_run:!0,tools:n,key_file:i?r:null});const p=(b()?o.cyan:o=>o)(s.t("runtime.dry_run_label"));if(0!==n.length){for(const{tool:e,files:t}of n)console.log(`${p} ${s.t("setup.dry_run_tool",{tool:a[e]?.displayName??e})}`),t.forEach(e=>console.log(o.gray(` ${e}`)));i&&console.log(`${p} ${s.t("setup.dry_run_key",{file:r})}`)}else console.log(`${p} ${s.t("setup.dry_run_none")}`)}function B(){return"darwin"===process.platform||"win32"===process.platform||n.isToolInstalled("claude-desktop")}export async function setupCommand(r){I=null;const p=r.key?.trim(),f=DEDICATED_KEYS.map(o=>({...o,apiKey:r[o.option]?.trim()})).filter(o=>Boolean(o.apiKey)),m=void 0!==r.oneMillion,g=void 0!==r.claudeOfficial;let y;if(g&&(y=parseOnOff(r.claudeOfficial),void 0===y))return A(s.t("setup.claude_official_invalid",{value:String(r.claudeOfficial)})),void(process.exitCode=1);const _=void 0!==r.desktopRegistry;let h;if(_&&(h=parseOnOff(r.desktopRegistry),void 0===h))return A(s.t("setup.desktop_registry_invalid",{value:String(r.desktopRegistry)})),void(process.exitCode=1);const b=g||_,$=Boolean(p||f.length>0),L={oneMillion:r.oneMillion,officialLogin:y,desktopRegistry:h,force:r.force};if(!$&&(m||b)&&w())return void R([...m?["codex"]:[],...b?["claude-desktop"]:[]],!1);if(!$&&(m||b)){if(m){const o=l.getApiKeyForTool("codex");if(o)try{const e=!0===r.oneMillion;l.setToolSetting("codex",d,e);const t=await u(o);c(e,t??void 0),E(s.t(e?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(o){A(s.t("setup.apply_failed",{tool:a.codex.displayName,reason:o instanceof Error?o.message:String(o)})),process.exitCode=1}else A(s.t("setup.codex_1m_missing_key")),process.exitCode=1}if(b){const o=l.getApiKeyForTool("claude-desktop");o?await P("claude-desktop",o,{...L,oneMillion:void 0})?await t(["claude-desktop"]):process.exitCode=1:(A(s.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!$)return A(s.t("setup.usage")),void(process.exitCode=1);const F=w();F||await i(p||f[0].apiKey);const Y=[];let q=0,z=0;const H=new Set,W=f.map(o=>({tool:o.tool,label:`--${o.option}`,apiKey:o.apiKey,need:o.need}));for(const o of W){if(!await D(o.label,o.apiKey)){z+=1;continue}const e=await M(o.apiKey);!e.probed||S(e,o.need)?(e.probed||O(s.t("setup.probe_failed",{label:o.label})),F?(Y.push(o.tool),H.add(o.tool)):(l.setToolApiKey(o.tool,o.apiKey),await P(o.tool,o.apiKey,L)?(q+=1,H.add(o.tool)):z+=1)):(A(s.t(`setup.key_no_${o.need}`,{label:o.label,tool:a[o.tool].displayName})),z+=1)}if(p){if(!await D("--key",p))return void(process.exitCode=k[I??"operation"]);F||l.setApiKey(p);const o=await M(p);if(o.probed||O(s.t("setup.probe_failed",{label:"--key"})),o.probed&&!o.hasClaude&&!o.hasGpt&&!o.hasGrok&&!o.hasGemini)return A(s.t("setup.key_no_family")),void(process.exitCode=1);const e=[{tool:"claude-code",capable:o.hasClaude,skipMsg:s.t(B()?"setup.skip_no_claude_desktop":"setup.skip_no_claude")},{tool:"codex",capable:o.hasGpt,skipMsg:s.t("setup.skip_no_gpt")},{tool:"grok",capable:o.hasGrok,skipMsg:s.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:o.hasClaude&&B(),skipMsg:"",quiet:!0},{tool:"agy",capable:o.hasGemini,skipMsg:s.t("setup.skip_no_gemini")}];for(const o of e)H.has(o.tool)||(o.capable?F?(Y.push(o.tool),H.add(o.tool)):await P(o.tool,p,L)?(q+=1,H.add(o.tool)):z+=1:o.quiet||O(o.skipMsg))}if(F)return R(Y,Y.length>0),void(z>0&&(process.exitCode=k[I??"operation"]));if(q>0){const t=await async function(t,i,r){const p=t.filter(o=>!e(o)?.isInstalled&&!n.isToolInstalled(o));if(0===p.length)return[];const d=p.map(o=>a[o].displayName).join(s.t("setup.list_separator"));let c=i;if(void 0!==c||v()||(C()?c=!x():process.stdin.isTTY&&(console.log(""),c=(await T.prompt([{type:"confirm",name:"go",message:s.t("setup.install_confirm",{tools:d}),default:!0}])).go)),!c){console.log("");for(const e of p)console.log(o.yellow("! "+s.t("setup.install_hint",{tool:a[e].displayName,install:a[e].installCommand})));return v()||console.log(o.gray(s.t("setup.install_all_hint",{cli:N}))),p}const u=[];for(const e of p){console.log(o.bold(`\n${a[e].displayName}`));try{await n.installTool(e)}catch(o){j.logError(`setup: install ${e}`,o)}K(),n.isToolInstalled(e)||u.push(e)}const f=p.filter(o=>!u.includes(o));f.length>0&&console.log("");for(const o of f){const e=l.getApiKeyForTool(o);e&&await P(o,e,{...r,oneMillion:void 0,force:void 0})}return u}([...H],r.install,L),i=[...H].filter(o=>!e(o)?.isInstalled&&!t.includes(o)),p=i.map(o=>a[o]?.command).filter(Boolean).join(" / "),d=s.t("setup.done",{count:String(q)});E("\n"+(p?`${d}${s.t("setup.done_commands",{commands:p})}`:d)),t.length>0&&O(s.t("setup.still_missing",{tools:t.map(o=>a[o].displayName).join(s.t("setup.list_separator"))}));for(const o of i){const e=n.ensureNativeOnPath(o);e&&E(s.t("setup.path_added",{tool:a[o].displayName,dir:e}))}const c=i.filter(o=>!n.isOnPath(o));if(c.length>0&&!v()&&"1"!==G("PATH_HINT_BY_CALLER")){const e=c.map(o=>a[o].command).join(" / ");console.log(o.yellow(" ! "+s.t("win32"===process.platform?"setup.path_reload_windows":"setup.path_reload",{commands:e})))}}z>0&&(A(s.t("setup.failed_summary",{count:String(z)})),v()||console.error(`${N} setup --key ${"zh_CN"===s.getLocale()?"<你的 Key>":"<your key>"}`)),await t([...H]),(z>0||0===q)&&(process.exitCode=k[I??"operation"])}
1
+ import o from"chalk";import{getAdapter as e}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{ensureReachableGatewayAddress as i}from"./base.js";import{i18n as l}from"../lib/i18n.js";import{configManager as s}from"../lib/config.js";import{toolManager as a,SUPPORTED_TOOLS as n}from"../lib/tool-manager.js";import{validateApiKey as r,fetchModels as d}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as p,setCodexOneMillionContext as c}from"../lib/tools/codex.js";import{resolveModelCatalog as u}from"../lib/model-catalog.js";import{CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING as f,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as m}from"../lib/tools/claude-desktop.js";import{operationError as g,authenticationError as y,networkError as _,EXIT_CODES as k}from"../lib/errors.js";import{emitJson as h,isColorEnabled as b,isDryRun as w,isJsonMode as v,isNonInteractive as x,shouldAutoConfirm as C}from"../lib/runtime-options.js";import{join as K}from"path";import{confirmWritePlan as j,printWritePlan as $,toolWritePlan as T}from"../lib/write-plan.js";import G from"inquirer";import{logger as N}from"../utils/logger.js";import{forgetInstalls as S}from"../lib/tools/tool-installs.js";import{CLI_NAME as M,brandEnv as E}from"../lib/brand.js";export const DEDICATED_KEYS=[{option:"claudekey",tool:"claude-code",need:"claude"},{option:"codexkey",tool:"codex",need:"gpt"},{option:"grokkey",tool:"grok",need:"grok"},{option:"desktopkey",tool:"claude-desktop",need:"claude"},{option:"agykey",tool:"agy",need:"gemini"},{option:"openclawkey",tool:"openclaw",need:"any",hidden:!0},{option:"hermeskey",tool:"hermes",need:"any",hidden:!0},{option:"atomcodekey",tool:"atomcode",need:"any",hidden:!0}];async function O(o){const e=await d(o);if(!e.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,hasGemini:!0,probed:!1};const t=e.models.map(o=>o.toLowerCase());return{hasClaude:t.some(o=>o.includes("claude")),hasGpt:t.some(o=>o.startsWith("gpt")||o.includes("gpt-")||/^o\d/.test(o)),hasGrok:t.some(o=>o.includes("grok")),hasGemini:t.some(o=>o.startsWith("gemini")),probed:!0}}function I(o,e){switch(e){case"claude":return o.hasClaude;case"gpt":return o.hasGpt;case"grok":return o.hasGrok;case"gemini":return o.hasGemini;default:return!0}}export function parseOnOff(o){const e=(o??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(e)||!["off","false","hide","0","no","n"].includes(e)&&void 0}function A(e){console.log(o.green(e))}function L(e){console.log(o.yellow(e))}function D(e){console.error(o.red(e))}let F=null;function B(o){const e={operation:1,authentication:2,network:3};(!F||e[o]>e[F])&&(F=o)}async function R(e,t){v()||console.log(o.gray(l.t("setup.validating",{label:e})));const i=await r(t);if(i.valid)return!0;const a="zh_CN"===l.getLocale()?"<你的 Key>":"<your key>",n="--key"===e?`${M} setup --key ${a}`:`${M} setup ${e} ${a}`;let d;if("network_error"===i.error?(B("network"),d=_(l.t("setup.unreachable",{url:s.getBaseUrl(),reason:i.message||"network error"}),`${M} base auto`,"network_error")):"invalid_api_key"===i.error?(B("authentication"),d=y(l.t("setup.invalid_key",{label:e,reason:i.message||"invalid"}),n,"invalid_api_key")):(B("operation"),d=g(l.t("setup.validate_failed",{label:e,reason:i.message||i.error||"unknown"}),n,i.error)),v())throw d;return D(d.message),console.log(o.gray(l.t("errors.next_step",{command:d.hint}))),!1}async function P(t,i,r={}){const{oneMillion:d,officialLogin:c,desktopRegistry:u,force:y}=r,_=n[t];try{"claude-desktop"===t&&void 0!==u&&s.setToolSetting("claude-desktop",f,u),"codex"===t&&void 0!==d&&s.setToolSetting("codex",p,d),"claude-desktop"===t&&void 0!==c&&s.setToolSetting("claude-desktop",m,!c),await a.applyPrivateConfig(t,i,s.getModelsForTool(t),{force:y})}catch(o){if(v())throw g(o instanceof Error?o.message:String(o),`${M} setup --key ${"zh_CN"===l.getLocale()?"<你的 Key>":"<your key>"}`,"config_write_failed");const e=(o instanceof Error?o.message:String(o)).replace(/\s+/g," ").trim();return D("× "+l.t("setup.apply_failed",{tool:_.displayName,reason:e})),!1}return a.printApplied(t),y&&console.log(o.gray(" "+l.t("config.force_done",{tool:_.displayName,name:t}))),"codex"===t&&void 0!==d&&console.log(o.gray(" "+l.t(d?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),e(t)?.isInstalled&&!a.isToolInstalled(t)&&console.log(o.yellow(" ! "+l.t("setup.gui_preconfigured",{tool:_.displayName,install:_.installCommand}))),!0}function Y(o){return!e(o)?.isInstalled&&!a.isToolInstalled(o)}function q(o){L(l.t("setup.still_missing",{tools:o.map(o=>n[o].displayName).join(l.t("setup.list_separator")),commands:o.map(o=>`${M} config ${o} --yes`).join(l.t("setup.list_separator"))}))}function z(e,t,i=[]){const a=T(e),n=K(s.getConfigDir(),"config.yaml");if(v())h({dry_run:!0,tools:a,install_first:i,key_file:t?n:null});else{if(0===a.length&&0===i.length){const e=(b()?o.cyan:o=>o)(l.t("runtime.dry_run_label"));return void console.log(`${e} ${l.t("setup.dry_run_none")}`)}$(a,{label:l.t("runtime.dry_run_label"),keyFile:t?n:void 0,installFirst:i})}}function H(){return"darwin"===process.platform||"win32"===process.platform||a.isToolInstalled("claude-desktop")}export async function setupCommand(r){F=null;const d=r.key?.trim(),f=DEDICATED_KEYS.map(o=>({...o,apiKey:r[o.option]?.trim()})).filter(o=>Boolean(o.apiKey)),m=void 0!==r.oneMillion,g=void 0!==r.claudeOfficial;let y;if(g&&(y=parseOnOff(r.claudeOfficial),void 0===y))return D(l.t("setup.claude_official_invalid",{value:String(r.claudeOfficial)})),void(process.exitCode=1);const _=void 0!==r.desktopRegistry;let h;if(_&&(h=parseOnOff(r.desktopRegistry),void 0===h))return D(l.t("setup.desktop_registry_invalid",{value:String(r.desktopRegistry)})),void(process.exitCode=1);const b=g||_,$=Boolean(d||f.length>0),T={oneMillion:r.oneMillion,officialLogin:y,desktopRegistry:h,force:r.force};if(!$&&(m||b)&&w())return void z([...m?["codex"]:[],...b?["claude-desktop"]:[]],!1);if(!$&&(m||b)){if(m){const o=s.getApiKeyForTool("codex");if(o)try{const e=!0===r.oneMillion;s.setToolSetting("codex",p,e);const t=await u(o);c(e,t??void 0),A(l.t(e?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(o){D(l.t("setup.apply_failed",{tool:n.codex.displayName,reason:o instanceof Error?o.message:String(o)})),process.exitCode=1}else D(l.t("setup.codex_1m_missing_key")),process.exitCode=1}if(b){const o=s.getApiKeyForTool("claude-desktop");o?await P("claude-desktop",o,{...T,oneMillion:void 0})?await t(["claude-desktop"]):process.exitCode=1:(D(l.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!$)return D(l.t("setup.usage")),void(process.exitCode=1);const B=w();B||await i(d||f[0].apiKey);const W=[],U=[];let J,Q=0,V=0;const X=new Set,Z=f.map(o=>({tool:o.tool,label:`--${o.option}`,apiKey:o.apiKey,need:o.need}));for(const o of Z){if(!await R(o.label,o.apiKey)){V+=1;continue}const e=await O(o.apiKey);!e.probed||I(e,o.need)?(e.probed||L(l.t("setup.probe_failed",{label:o.label})),W.push({tool:o.tool,apiKey:o.apiKey,dedicated:!0}),X.add(o.tool)):(D(l.t(`setup.key_no_${o.need}`,{label:o.label,tool:n[o.tool].displayName})),V+=1)}const oo=!!d&&await R("--key",d);d&&!oo&&(J=k[F??"operation"]);const eo=d&&oo?await O(d):void 0;if(d&&eo&&!eo.probed&&L(l.t("setup.probe_failed",{label:"--key"})),!(d&&eo&&eo.probed)||eo.hasClaude||eo.hasGpt||eo.hasGrok||eo.hasGemini||(D(l.t("setup.key_no_family")),J=1),d&&eo&&void 0===J){const o=[{tool:"claude-code",capable:eo.hasClaude,skipMsg:l.t(H()?"setup.skip_no_claude_desktop":"setup.skip_no_claude")},{tool:"codex",capable:eo.hasGpt,skipMsg:l.t("setup.skip_no_gpt")},{tool:"grok",capable:eo.hasGrok,skipMsg:l.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:eo.hasClaude&&H(),skipMsg:"",quiet:!0},{tool:"agy",capable:eo.hasGemini,skipMsg:l.t("setup.skip_no_gemini")}];for(const e of o)X.has(e.tool)||(e.capable?(W.push({tool:e.tool,apiKey:d,dedicated:!1}),X.add(e.tool)):e.quiet||L(e.skipMsg))}const to=Boolean(d&&oo&&void 0===J);if(B)return z(W.filter(o=>!Y(o.tool)).map(o=>o.tool),W.length>0,W.filter(o=>Y(o.tool)).map(o=>o.tool)),void((V>0||void 0!==J)&&(process.exitCode=J??k[F??"operation"]));const io=W.filter(o=>!Y(o.tool)),lo=to||W.some(o=>o.dedicated);if((W.length>0||lo)&&!await j(io.map(o=>o.tool),{keyFile:lo?K(s.getConfigDir(),"config.yaml"):void 0,installFirst:W.filter(o=>Y(o.tool)).map(o=>o.tool)}))return void(process.exitCode=k.cancelled);to&&d&&s.setApiKey(d);for(const o of W)o.dedicated&&s.setToolApiKey(o.tool,o.apiKey),Y(o.tool)?U.push({tool:o.tool,apiKey:o.apiKey}):await P(o.tool,o.apiKey,T)?Q+=1:(V+=1,X.delete(o.tool));if(void 0!==J)return U.length>0&&q(U.map(o=>o.tool)),void(process.exitCode=J);let so=[];if(U.length>0){const e=await async function(e,t,i){const s=e.map(o=>o.tool);if(0===s.length)return{still:[],applied:[],failed:[]};const r=s.map(o=>n[o].displayName).join(l.t("setup.list_separator"));let d=t;if(void 0!==d||v()||(C()?d=!x():process.stdin.isTTY&&(console.log(""),d=(await G.prompt([{type:"confirm",name:"go",message:l.t("setup.install_confirm",{tools:r}),default:!0}])).go)),!d){console.log("");for(const e of s)console.log(o.yellow("! "+l.t("setup.install_hint",{tool:n[e].displayName,install:n[e].installCommand})));return v()||console.log(o.gray(l.t("setup.install_all_hint",{cli:M}))),{still:s,applied:[],failed:[]}}const p=[];for(const e of s){console.log(o.bold(`\n${n[e].displayName}`));try{await a.installTool(e)}catch(o){N.logError(`setup: install ${e}`,o)}S(),a.isToolInstalled(e)||p.push(e)}const c=s.filter(o=>!p.includes(o));c.length>0&&console.log("");const u=[],f=[];for(const{tool:o,apiKey:t}of e.filter(o=>c.includes(o.tool)))await P(o,t,i)?u.push(o):f.push(o);return{still:p,applied:u,failed:f}}(U,r.install,T);so=e.still,Q+=e.applied.length,V+=e.failed.length;for(const o of[...so,...e.failed])X.delete(o)}if(Q>0){const t=[...X].filter(o=>!e(o)?.isInstalled&&!so.includes(o)),i=t.map(o=>n[o]?.command).filter(Boolean).join(" / "),s=l.t("setup.done",{count:String(Q)});A("\n"+(i?`${s}${l.t("setup.done_commands",{commands:i})}`:s)),so.length>0&&q(so);for(const o of t){const e=a.ensureNativeOnPath(o);e&&A(l.t("setup.path_added",{tool:n[o].displayName,dir:e}))}const r=t.filter(o=>!a.isOnPath(o));if(r.length>0&&!v()&&"1"!==E("PATH_HINT_BY_CALLER")){const e=r.map(o=>n[o].command).join(" / ");console.log(o.yellow(" ! "+l.t("win32"===process.platform?"setup.path_reload_windows":"setup.path_reload",{commands:e})))}}0===Q&&so.length>0&&q(so),V>0&&(D(l.t("setup.failed_summary",{count:String(V)})),v()||console.error(`${M} setup --key ${"zh_CN"===l.getLocale()?"<你的 Key>":"<your key>"}`)),await t([...X]),(V>0||0===Q&&0===so.length)&&(process.exitCode=k[F??"operation"])}
@@ -1 +1 @@
1
- import o from"chalk";import{configManager as e,DEFAULT_BASE_URL as t}from"../lib/config.js";import{toolManager as l,SUPPORTED_TOOLS as s}from"../lib/tool-manager.js";import{claudeCodeManager as n}from"../lib/claude-code-manager.js";import{i18n as i}from"../lib/i18n.js";import{isJsonMode as a,emitJson as r,isColorEnabled as g}from"../lib/runtime-options.js";function c(o){return g()?o:o=>o}export async function statusCommand(){const g=e.getApiKey(),p=e.getBaseUrl(),u=e.getModels(),m=i.getLocale(),d=l.getSupportedTools().map(o=>{const e=l.isToolInstalled(o.name);let t=null;return e&&"claude-code"===o.name&&(t=Boolean(n.detectCurrentConfig().apiKey)),{name:o.name,display_name:o.displayName,installed:e,config_loaded:t}}),f=e.getActiveProfileName(),$=e.listProfiles(),_=Object.keys(e.getCustomPresets()),y=e.listToolApiKeys();if(a())return void r({api_key_set:Boolean(g),api_key_fingerprint:e.getApiKeyFingerprint()||null,tool_key_fingerprints:Object.fromEntries(y.map(o=>[o,e.getToolApiKeyFingerprint(o)||null])),base_url:p,base_url_is_default:p===t,language:m,models:u,tools:d,active_profile:f,profiles:$,custom_presets:_});const b=c(o.cyan),k=c(o.green),j=c(o.yellow),A=c(o.gray),K=c(o.red);console.log("\n"+c(o.bold)(i.t("status.title"))+"\n");const C=e.getApiKeyFingerprint(),T=g?C?`sk-fp-${C}`:"sk-****":j(i.t("wizard.not_set"));console.log(` ${b(i.t("status.api_key"))}: ${g?k(T):T}`);for(const o of y){const t=e.getToolApiKeyFingerprint(o);if(!t)continue;const l=s[o]?.displayName||o;console.log(` ${b(i.t("status.tool_key_label",{tool:l}))}: ${k(`sk-fp-${t}`)}`)}const F=p===t;console.log(` ${b(i.t("status.base_url"))}: ${p}${F?A(" (default)"):""}`),console.log(` ${b(i.t("status.language"))}: ${m}`),console.log(` ${b("Profile")}: ${f} ${A("("+$.join(", ")+")")}`),console.log(` ${b(i.t("status.models"))}:`),console.log(` Haiku: ${u.haiku}`),console.log(` Sonnet: ${u.sonnet}`),console.log(` Opus: ${u.opus}`),console.log(` Reasoning: ${u.reasoning}`),_.length>0&&console.log(` ${b("Custom presets")}: ${_.join(", ")}`),console.log(` ${b(i.t("status.tools"))}:`);for(const o of d){const e=o.installed?k("✓"):K("✗");let t="";!0===o.config_loaded?t=k(" ("+i.t("status.config_loaded")+")"):!1===o.config_loaded&&(t=A(" ("+i.t("status.config_not_loaded")+")")),console.log(` ${e} ${o.display_name}${t}`)}console.log("")}
1
+ import o from"chalk";import{configManager as e,DEFAULT_BASE_URL as t}from"../lib/config.js";import{toolManager as n,SUPPORTED_TOOLS as l}from"../lib/tool-manager.js";import{claudeCodeManager as s}from"../lib/claude-code-manager.js";import{i18n as i}from"../lib/i18n.js";import{isJsonMode as a,emitJson as r,isColorEnabled as c}from"../lib/runtime-options.js";import{balanceLookupEnabled as g,balanceNeedsAttention as u,balanceText as p,fetchKeyBalances as m}from"../lib/key-balance.js";function f(o){return c()?o:o=>o}function d(o){return o?{remaining:o.remaining,unit:o.unit,symbol:o.symbol,wallet:o.wallet??null,token_remaining:o.tokenRemaining??null,account_insufficient:o.accountInsufficient??!1}:null}export async function statusCommand(){const c=e.getApiKey(),$=e.getBaseUrl(),_=e.getModels(),y=i.getLocale(),b=n.getSupportedTools().map(o=>{const e=n.isToolInstalled(o.name);let t=null;return e&&"claude-code"===o.name&&(t=Boolean(s.detectCurrentConfig().apiKey)),{name:o.name,display_name:o.displayName,installed:e,config_loaded:t}}),k=e.getActiveProfileName(),j=e.listProfiles(),A=Object.keys(e.getCustomPresets()),K=e.listToolApiKeys(),T=g()?[c,...K.map(o=>e.getApiKeyForTool(o))].filter(o=>Boolean(o)):[],F=await m(T),w=o=>o?F.get(o):void 0;if(a())return void r({api_key_set:Boolean(c),api_key_fingerprint:e.getApiKeyFingerprint()||null,tool_key_fingerprints:Object.fromEntries(K.map(o=>[o,e.getToolApiKeyFingerprint(o)||null])),balance:d(w(c)),tool_key_balances:Object.fromEntries(K.map(o=>[o,d(w(e.getApiKeyForTool(o)))])),base_url:$,base_url_is_default:$===t,language:y,models:_,tools:b,active_profile:k,profiles:j,custom_presets:A});const C=f(o.cyan),v=f(o.green),B=f(o.yellow),O=f(o.gray),P=f(o.red);console.log("\n"+f(o.bold)(i.t("status.title"))+"\n");const h=e.getApiKeyFingerprint(),N=c?h?`sk-fp-${h}`:"sk-****":B(i.t("wizard.not_set"));console.log(` ${C(i.t("status.api_key"))}: ${c?v(N):N}`);const E=w(c);if(E){const o=p(E);console.log(` ${C(i.t("status.balance"))}: ${u(E)?B(o):v(o)}`)}for(const o of K){const t=e.getToolApiKeyFingerprint(o);if(!t)continue;const n=l[o]?.displayName||o,s=w(e.getApiKeyForTool(o)),a=s?O(` · ${i.t("status.balance")} ${p(s)}`):"";console.log(` ${C(i.t("status.tool_key_label",{tool:n}))}: ${v(`sk-fp-${t}`)}${a}`)}const I=$===t;console.log(` ${C(i.t("status.base_url"))}: ${$}${I?O(" (default)"):""}`),console.log(` ${C(i.t("status.language"))}: ${y}`),console.log(` ${C("Profile")}: ${k} ${O("("+j.join(", ")+")")}`),console.log(` ${C(i.t("status.models"))}:`),console.log(` Haiku: ${_.haiku}`),console.log(` Sonnet: ${_.sonnet}`),console.log(` Opus: ${_.opus}`),console.log(` Reasoning: ${_.reasoning}`),A.length>0&&console.log(` ${C("Custom presets")}: ${A.join(", ")}`),console.log(` ${C(i.t("status.tools"))}:`);for(const o of b){const e=o.installed?v("✓"):P("✗");let t="";!0===o.config_loaded?t=v(" ("+i.t("status.config_loaded")+")"):!1===o.config_loaded&&(t=O(" ("+i.t("status.config_not_loaded")+")")),console.log(` ${e} ${o.display_name}${t}`)}console.log("")}
@@ -1 +1 @@
1
- import{spawnSync as e}from"child_process";import{closeSync as t,copyFileSync as r,createReadStream as o,createWriteStream as n,existsSync as s,mkdirSync as i,openSync as c,readFileSync as a,readSync as f,readdirSync as l,realpathSync as u,renameSync as p,statSync as d,utimesSync as m,writeFileSync as h}from"fs";import{join as g,resolve as y}from"path";import{pipeline as v}from"stream/promises";import*as S from"@iarna/toml";import{codexHome as b,toolHome as _}from"./tools/types.js";import{CLI_NAME as x}from"./brand.js";export{b as codexHome};export function currentCodexProvider(){try{const e=S.parse(a(g(b(),"config.toml"),"utf-8"));return"string"==typeof e.model_provider&&e.model_provider.trim()?e.model_provider.trim():"openai"}catch{return"openai"}}let E=()=>{if("win32"===process.platform)return`${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);const t=process.getuid?.(),r=`${e("pgrep",["-x","-i",...void 0===t?[]:["-u",String(t)],"codex"],{encoding:"utf-8"}).stdout??""}`.split(/\s+/).filter(Boolean).map(Number);if("linux"!==process.platform)return r;const o=O(b());return r.filter(e=>{let t;try{t=a(`/proc/${e}/environ`,"utf-8")}catch{return!0}const r=new Map(t.split("\0").map(e=>[e.slice(0,e.indexOf("=")),e.slice(e.indexOf("=")+1)])),n=r.get("CODEX_HOME")?.trim()||(r.get("HOME")?g(r.get("HOME"),".codex"):null);return null===n||O(n)===o})};function O(e){try{return u(e)}catch{return e}}export function setCodexProcessCheckForTests(e){E=e}export function runningCodexPids(){try{return E()}catch{return[]}}function w(e){const r=c(e,"r");try{const e=[],t=Buffer.alloc(65536);for(;;){const o=f(r,t,0,t.length,null);if(o<=0)break;const n=t.subarray(0,o).indexOf(10);if(n>=0){e.push(Buffer.from(t.subarray(0,n)));break}e.push(Buffer.from(t.subarray(0,o)))}return Buffer.concat(e).toString("utf-8")}finally{t(r)}}async function N(e,t,r){const{atime:s,mtime:i}=d(e),c=`${e}.${x}-tmp`,a=n(c);a.write(t),await v(o(e,{start:r}),a),p(c,e),m(e,s,i)}export function codexSqliteHome(){const e=b();try{const t=S.parse(a(g(e,"config.toml"),"utf-8")),r="string"==typeof t.sqlite_home?t.sqlite_home.trim():"";if(r)return"~"===r||r.startsWith("~/")?g(_(),r.slice(1)):y(e,r)}catch{}const t=process.env.CODEX_SQLITE_HOME?.trim();return t?y(t):e}async function T(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 const NO_STATE_DB="no state DB";export async function moveSessionsToProvider(e,t={}){const o=function(){const e=[],t=r=>{if(s(r))for(const o of l(r,{withFileTypes:!0})){const n=g(r,o.name);o.isDirectory()?t(n):o.isFile()&&o.name.endsWith(".jsonl")&&e.push(n)}};return t(g(b(),"sessions")),t(g(b(),"archived_sessions")),e}(),n=[];for(const t of o){let r,o;try{r=w(t)}catch{continue}try{o=JSON.parse(r)}catch{continue}const s=o.payload?.model_provider;"session_meta"===o.type&&"string"==typeof s&&s!==e&&(o.payload.model_provider=e,n.push({file:t,from:s,line:JSON.stringify(o),length:Buffer.byteLength(r,"utf-8")}))}const c=function(){const e=codexSqliteHome();if(!s(e))return null;const t=l(e).map(e=>/^state_(\d+)\.sqlite$/.exec(e)).filter(e=>!!e).sort((e,t)=>Number(t[1])-Number(e[1]));return t.length>0?g(e,t[0][0]):null}();let a=c?null:NO_STATE_DB,f=[],u=null;if(c){const t=await T(c);"string"==typeof t?a=t:(u=t,f=u.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 p={target:e,scanned:o.length,moved:n.map(({file:e,from:t})=>({file:e,from:t})),dbRows:f.length,dbSkipped:a,backupDir:null};if(t.dryRun||0===n.length&&0===f.length)return u?.close(),p;const d=g(b(),"backups",`${x}-sessions-${(new Date).toISOString().replace(/[:.]/g,"-")}`);if(i(d,{recursive:!0}),c)for(const e of["","-wal","-shm"])s(c+e)&&r(c+e,g(d,`state.sqlite${e}`));const m={target:e,moved:p.moved,threads:f,db:c};h(g(d,"manifest.json"),JSON.stringify(m,null,2)+"\n");for(const e of n)await N(e.file,e.line,e.length);return u&&(u.prepare("UPDATE threads SET model_provider = ? WHERE model_provider <> ?").run(e,e),u.close()),p.backupDir=d,p}export async function undoSessionMove(e){const t=JSON.parse(a(g(e,"manifest.json"),"utf-8"));let r=0;for(const{file:e,from:o}of t.moved){if(!s(e))continue;const t=w(e),n=JSON.parse(t);n.payload&&(n.payload.model_provider=o,await N(e,JSON.stringify(n),Buffer.byteLength(t,"utf-8")),r+=1)}let o=0;if(t.db&&s(t.db)&&t.threads.length>0){const e=await T(t.db);if("string"!=typeof e){const r=e.prepare("UPDATE threads SET model_provider = ? WHERE id = ?");for(const{id:e,from:n}of t.threads)o+=Number(r.run(n,e).changes);e.close()}}return{files:r,dbRows:o}}
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 f,readdirSync as l,realpathSync as d,renameSync as u,statSync as p,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 E}from"./tools/types.js";import{CLI_NAME as w}from"./brand.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 x=()=>{if("win32"===process.platform)return`${t("powershell.exe",["-NoProfile","-NonInteractive","-Command","(Get-Process -Name codex -ErrorAction SilentlyContinue).Id"],{encoding:"utf-8",windowsHide:!0}).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=N(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||N(n)===r})};function N(t){try{return d(t)}catch{return t}}export function setCodexProcessCheckForTests(t){x=t}export function runningCodexPids(){try{return x()}catch{return[]}}function O(t){const o=a(t,"r");try{const t=[],e=Buffer.alloc(65536);for(;;){const r=f(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 $(t,e,o){const{atime:s,mtime:i}=p(t),a=`${t}.${w}-tmp`,c=n(a);c.write(e),await S(r(t,{start:o}),c),u(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(E(),o.slice(1)):y(t,o)}catch{}const e=process.env.CODEX_SQLITE_HOME?.trim();return e?y(e):t}function D(){const t=codexSqliteHome();if(!s(t))return null;const e=l(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 T={threads:"id",local_thread_catalog:"thread_id"};function A(){const t=b(codexSqliteHome(),"sqlite");return s(t)?l(t).filter(t=>/\.(db|sqlite3?)$/.test(t)).map(e=>b(t,e)).sort():[]}function B(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=T[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 C(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 l(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=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=[D(),...A()].filter(t=>!!t);let c=a.length>0?null:NO_STATE_DB;const f=[];for(const e of a){const o=await C(e);if("string"==typeof o){c=o;break}const r=[];try{for(const n of Object.keys(T)){const s=B(o,n,t);s&&s.length>0&&r.push({db:e,table:n,rows:s})}}catch{}f.push({path:e,db:o,tables:r})}const d=f.flatMap(t=>t.tables),u=new Set(d.flatMap(t=>t.rows.map(t=>t.id))),p={target:t,scanned:r.length,moved:n.map(({file:t,from:e})=>({file:t,from:e})),dbRows:u.size,dbSkipped:c,backupDir:null},m=()=>f.forEach(t=>t.db.close());if(e.dryRun||0===n.length&&0===d.length)return m(),p;const y=b(v(),"backups",`${w}-sessions-${(new Date).toISOString().replace(/[:.]/g,"-")}`);i(y,{recursive:!0}),f.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:p.moved,tables:d};h(b(y,"manifest.json"),JSON.stringify(S,null,2)+"\n");for(const t of n)await $(t.file,t.line,t.length);for(const{db:e,tables:o}of f)for(const{table:r,rows:n}of o){const o=e.prepare(`UPDATE ${r} SET model_provider = ? WHERE ${T[r]} = ? AND model_provider = ?`);for(const{id:e,from:r}of n)o.run(t,e,r)}return m(),p.backupDir=y,p}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=O(t),n=JSON.parse(e);n.payload&&(n.payload.model_provider=r,await $(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||!T[o])continue;const r=await C(t);if("string"==typeof r)continue;const a=r.prepare(`UPDATE ${o} SET model_provider = ? WHERE ${T[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}}
@@ -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;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"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}}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 一把 Key 还能花多少,金额已是网关控制台的展示单位(USD / CNY / 自定义货币 / tokens)。
3
+ * 只用于展示:status / doctor 读它,查不到时返回 null,调用方不显示这一行,绝不报错。
4
+ */
5
+ export interface KeyBalance {
6
+ /** 令牌不限额时是账户可用余额;限额令牌是令牌剩余(网关不拿账户余额去比,账户付不起时标 accountInsufficient)。 */
7
+ remaining: number;
8
+ /** USD / CNY / CUSTOM / TOKENS;老网关回退的兼容接口里没有单位,按 USD 处理。 */
9
+ unit: string;
10
+ symbol: string;
11
+ /** 账户可用余额;网关只对不限额令牌给(限额令牌不透露账户余额),老网关查不到时也省略。 */
12
+ wallet?: number;
13
+ /** 令牌自己的剩余额度;令牌不限额时省略。 */
14
+ tokenRemaining?: number;
15
+ /** 限额令牌:账户可用余额比令牌剩余额度少,令牌额度花不完。 */
16
+ accountInsufficient?: boolean;
17
+ }
18
+ /** 状态类命令不能被余额拖慢:一次请求最多等这么久,查多把 Key 时并发。 */
19
+ export declare const BALANCE_TIMEOUT_MS = 3000;
20
+ type FetchFn = typeof fetch;
21
+ export declare function fetchKeyBalance(apiKey: string, options?: {
22
+ baseUrl?: string;
23
+ timeoutMs?: number;
24
+ fetchFn?: FetchFn;
25
+ }): Promise<KeyBalance | null>;
26
+ /** status / doctor 是否查余额;`<前缀>_SKIP_BALANCE=1`(测试默认)时不联网。 */
27
+ export declare function balanceLookupEnabled(): boolean;
28
+ /** 按 Key 去重后并发查询,返回 Key → 余额(查不到为 null)。 */
29
+ export declare function fetchKeyBalances(apiKeys: string[], options?: {
30
+ baseUrl?: string;
31
+ timeoutMs?: number;
32
+ fetchFn?: FetchFn;
33
+ }): Promise<Map<string, KeyBalance | null>>;
34
+ /** `$12.34`、`¥3.50`、`120000 tokens`。 */
35
+ export declare function formatAmount(amount: number, balance: Pick<KeyBalance, 'unit' | 'symbol'>): string;
36
+ /** 令牌设了额度上限:展示时注明「令牌额度」,充值账户不一定能解决,要去控制台调高令牌额度。 */
37
+ export declare function limitedByToken(balance: KeyBalance): boolean;
38
+ /** `$12.34`;令牌设了额度时注明,余额为 0 时提示去充值 / 调额度。 */
39
+ export declare function balanceText(balance: KeyBalance): string;
40
+ /** 用不了或快用不了:余额为 0,或限额令牌的账户付不起。doctor 记警告,status 标黄。 */
41
+ export declare function balanceNeedsAttention(balance: KeyBalance): boolean;
42
+ export {};
@@ -0,0 +1 @@
1
+ import{configManager as n}from"./config.js";import{KEY_INFO_PATH as t}from"./gateway-protocol.js";import{logger as e}from"../utils/logger.js";import{brandEnv as o}from"./brand.js";import{i18n as i}from"./i18n.js";export const BALANCE_TIMEOUT_MS=3e3;function a(n){return"number"==typeof n&&Number.isFinite(n)?n:void 0}export async function fetchKeyBalance(o,i={}){const{timeoutMs:r=BALANCE_TIMEOUT_MS,fetchFn:u=fetch}=i,c=(i.baseUrl??n.getBaseUrl()).replace(/\/+$/,""),l=new AbortController,s=setTimeout(()=>l.abort(),r),m=n=>async function(n,t,e,o){if(o.aborted)return null;const i=await e(n,{method:"GET",headers:{Authorization:`Bearer ${t}`},signal:o});return i.ok?i.json():null}(`${c}${n}`,o,u,l.signal).catch(()=>null);try{const n=function(n){const t=n?.data?.balance,e=a(t?.remaining);if(!t||void 0===e)return null;const o="string"==typeof t.unit&&t.unit?t.unit:"USD",i={remaining:e,unit:o,symbol:"string"==typeof t.symbol?t.symbol:"USD"===o?"$":""},r=a(t.wallet);void 0!==r&&(i.wallet=r);const u=a(t.token_remaining);return void 0!==u&&(i.tokenRemaining=u),!0===t.account_insufficient&&(i.accountInsufficient=!0),i}(await m(t));if(n)return n;const[e,o]=await Promise.all([m("/v1/dashboard/billing/subscription"),m("/v1/dashboard/billing/usage")]);return function(n,t){const e=a(n?.hard_limit_usd),o=a(t?.total_usage);if(void 0===e||void 0===o||e>=1e8)return null;const i=Math.max(0,Math.round(1e4*(e-o/100))/1e4);return{remaining:i,unit:"USD",symbol:"$",tokenRemaining:i}}(e,o)}catch(n){return e.logError("fetchKeyBalance",n),null}finally{clearTimeout(s)}}export function balanceLookupEnabled(){return"1"!==o("SKIP_BALANCE")}export async function fetchKeyBalances(n,t={}){const e=[...new Set(n.filter(Boolean))],o=await Promise.all(e.map(n=>fetchKeyBalance(n,t)));return new Map(e.map((n,t)=>[n,o[t]]))}export function formatAmount(n,t){return"TOKENS"===t.unit?`${Math.round(n)} tokens`:`${t.symbol}${n.toFixed(2)}`}export function limitedByToken(n){return void 0!==n.tokenRemaining}export function balanceText(n){const t=formatAmount(n.remaining,n);return n.remaining<=0?i.t(limitedByToken(n)?"status.balance_token_empty":"status.balance_empty",{amount:t}):n.accountInsufficient?i.t("status.balance_account_low",{amount:t}):limitedByToken(n)?i.t("status.balance_token_limited",{amount:t}):t}export function balanceNeedsAttention(n){return n.remaining<=0||Boolean(n.accountInsufficient)}
@@ -22,8 +22,8 @@ export interface OpenCodeMCPServerConfig {
22
22
  }
23
23
  export declare class OpenCodeManager {
24
24
  private static instance;
25
- private configPath;
26
- private constructor();
25
+ /** ~/.config/opencode/opencode.json, under toolHome() so tests and sandboxes redirect it. */
26
+ private get configPath();
27
27
  static getInstance(): OpenCodeManager;
28
28
  /**
29
29
  * 读取配置
@@ -1 +1 @@
1
- import{existsSync as e,readFileSync as o}from"fs";import{join as n}from"path";import{homedir as t}from"os";import{logger as i}from"../utils/logger.js";import{configManager as r,DEFAULT_MODELS as a}from"./config.js";import{atomicWriteFile as p}from"./tools/backup.js";export class OpenCodeManager{static instance;configPath;constructor(){this.configPath=n(t(),".config","opencode","opencode.json")}static getInstance(){return OpenCodeManager.instance||(OpenCodeManager.instance=new OpenCodeManager),OpenCodeManager.instance}getConfig(){try{if(e(this.configPath)){const e=o(this.configPath,"utf-8");return JSON.parse(e)}}catch(e){i.warn("Failed to read OpenCode config:",e),i.logError("OpenCodeManager.getConfig",e)}return{}}saveConfig(e){try{p(this.configPath,JSON.stringify(e,null,4))}catch(e){throw new Error(`Failed to save OpenCode config: ${e}`)}}loadPrivateConfig(e,o){const n=this.getConfig(),{provider:t,...i}=n,p={};if(t)for(const[e,o]of Object.entries(t))"private-newapi"!==e&&(p[e]=o);p["private-newapi"]={options:{apiKey:e,baseURL:r.getBaseUrl()}};const s={$schema:"https://opencode.ai/config.json",...i,provider:p,model:`private-newapi/${o.opus||a.opus}`,small_model:`private-newapi/${o.haiku||a.haiku}`};this.saveConfig(s)}unloadPrivateConfig(){const e=this.getConfig();e.provider&&(delete e.provider["private-newapi"],0===Object.keys(e.provider).length&&delete e.provider),e.model?.includes("private-newapi")&&delete e.model,e.small_model?.includes("private-newapi")&&delete e.small_model,this.saveConfig(e)}detectCurrentConfig(){try{const e=this.getConfig();if(!e.provider)return{apiKey:null};let o=null;return e.provider["private-newapi"]&&(o=e.provider["private-newapi"].options?.apiKey||null),{apiKey:o}}catch{return{apiKey:null}}}}export const openCodeManager=OpenCodeManager.getInstance();
1
+ import{existsSync as e,readFileSync as o}from"fs";import{join as t}from"path";import{logger as n}from"../utils/logger.js";import{configManager as i,DEFAULT_MODELS as r}from"./config.js";import{atomicWriteFile as a}from"./tools/backup.js";import{toolHome as p}from"./tools/types.js";export class OpenCodeManager{static instance;get configPath(){return t(p(),".config","opencode","opencode.json")}static getInstance(){return OpenCodeManager.instance||(OpenCodeManager.instance=new OpenCodeManager),OpenCodeManager.instance}getConfig(){try{if(e(this.configPath)){const e=o(this.configPath,"utf-8");return JSON.parse(e)}}catch(e){n.warn("Failed to read OpenCode config:",e),n.logError("OpenCodeManager.getConfig",e)}return{}}saveConfig(e){try{a(this.configPath,JSON.stringify(e,null,4))}catch(e){throw new Error(`Failed to save OpenCode config: ${e}`)}}loadPrivateConfig(e,o){const t=this.getConfig(),{provider:n,...a}=t,p={};if(n)for(const[e,o]of Object.entries(n))"private-newapi"!==e&&(p[e]=o);p["private-newapi"]={options:{apiKey:e,baseURL:i.getBaseUrl()}};const s={$schema:"https://opencode.ai/config.json",...a,provider:p,model:`private-newapi/${o.opus||r.opus}`,small_model:`private-newapi/${o.haiku||r.haiku}`};this.saveConfig(s)}unloadPrivateConfig(){const e=this.getConfig();e.provider&&(delete e.provider["private-newapi"],0===Object.keys(e.provider).length&&delete e.provider),e.model?.includes("private-newapi")&&delete e.model,e.small_model?.includes("private-newapi")&&delete e.small_model,this.saveConfig(e)}detectCurrentConfig(){try{const e=this.getConfig();if(!e.provider)return{apiKey:null};let o=null;return e.provider["private-newapi"]&&(o=e.provider["private-newapi"].options?.apiKey||null),{apiKey:o}}catch{return{apiKey:null}}}}export const openCodeManager=OpenCodeManager.getInstance();
@@ -1 +1 @@
1
- import{Command as e,Option as o}from"commander";import{readFileSync as t}from"fs";import{join as s,dirname as a}from"path";import{fileURLToPath as n}from"url";import{i18n as i}from"./i18n.js";import{wizard as r}from"./wizard.js";import{SUPPORTED_TOOLS as c}from"./tool-manager.js";import{DEFAULT_BASE_URL as l}from"./config.js";import{attachCommandHelp as p,helpConfiguration as m}from"./cli-help.js";import{langCommand as u,authCommand as d,doctorCommand as g,configCommand as f,statusCommand as x,refreshCommand as y}from"../commands/index.js";import{logsCommand as h}from"../commands/logs.js";import{completionCommand as b}from"../commands/completion.js";import{benchCommand as $}from"../commands/bench.js";import{updateCommand as k}from"../commands/update.js";import{upgradeCommand as _}from"../commands/upgrade.js";import{codexSessionsCommand as w}from"../commands/codex-sessions.js";import{setupCommand as v,DEDICATED_KEYS as j}from"../commands/setup.js";import{baseCommand as O}from"../commands/base.js";import{usageError as S}from"./errors.js";import{brand as A,brandEnv as E,CLI_NAME as G}from"./brand.js";const z=(A().gatewayAddresses[1]??A().gatewayAddresses[0]).url,C=(A().gatewayAddresses[2]??A().gatewayAddresses[0]).url;function R(e,o){return i.t(`help.${e}`,o)}function L(e,o){return{command:e,note:R(o)}}function N(e){const o=R(e);return o===`help.${e}`?"":o}function P(e,o=[]){return{when:N(`${e}.when`),prerequisites:N(`${e}.needs`).split("\n").filter(Boolean),alternatives:o.map(([e,o])=>L(e,o))}}function T(e){return e.helpCommand("help [command]",R("help_command"))}export function buildProgram(){const A=new e;A.name(`${G}`).summary(R("root.summary")).description(R("root.description")).configureHelp(m()).allowExcessArguments(!0).optionsGroup(R("group.global_options")).helpOption("-h, --help",R("global.help")).version(function(){try{const e=a(n(import.meta.url));return JSON.parse(t(s(e,"../../package.json"),"utf-8")).version}catch{return"1.0.0"}}(),"-v, --version",R("global.version")).option("--base <url>",R("global.base")).option("--non-interactive",R("global.non_interactive")).option("--json",R("global.json")).option("-y, --yes",R("global.yes")).option("--dry-run",R("global.dry_run")).option("--no-color",R("global.no_color")),A.configureOutput({writeErr:()=>{},outputError:()=>{}}),A.showSuggestionAfterError(),A.exitOverride(e=>{throw e}),A.commandsGroup(R("group.configure"));const N=A.command("setup").summary(R("setup.summary")).description(R("setup.description")).option("--key <key>",R("setup.opt.key"));for(const e of j){const t=new o(`--${e.option} <key>`,R(`setup.opt.${e.option}`));e.hidden&&t.hideHelp(),N.addOption(t)}N.option("--1m",R("setup.opt.one_m")).option("--no-1m",R("setup.opt.no_one_m")).option("--claude-official <on|off>",R("setup.opt.claude_official")).option("--desktop-registry <on|off>",R("setup.opt.desktop_registry")).option("--force",R("setup.opt.force")).option("--install",R("setup.opt.install")).option("--no-install",R("setup.opt.no_install")).option("--all",R("setup.opt.all")).action(async e=>{e.key||j.some(o=>e[o.option])||(e.key=E("SETUP_KEY")?.trim()||void 0);const o=Boolean(e.key||j.some(o=>e[o.option])),t=void 0!==e["1m"]||void 0!==e.claudeOfficial||void 0!==e.desktopRegistry,s=i.t("errors.key_placeholder");if(!o&&!t)throw S(i.t("setup.usage"),`${G} setup --key ${s}`,"missing_key");if(void 0!==e.claudeOfficial&&!["on","off"].includes(String(e.claudeOfficial).toLowerCase()))throw S(i.t("setup.claude_official_invalid",{value:String(e.claudeOfficial)}),`${G} setup --claude-official on|off`,"invalid_value");if(void 0!==e.desktopRegistry&&!["on","off"].includes(String(e.desktopRegistry).toLowerCase()))throw S(i.t("setup.desktop_registry_invalid",{value:String(e.desktopRegistry)}),`${G} setup --desktop-registry on|off`,"invalid_value");await v({key:e.key,...Object.fromEntries(j.map(o=>[o.option,e[o.option]])),all:e.all,oneMillion:e["1m"],claudeOfficial:e.claudeOfficial,desktopRegistry:e.desktopRegistry,force:e.force,install:e.install})}),p(N,{...P("setup",[[`${G} init`,"setup.alt.init"],[`${G} config <tool>`,"setup.alt.config"],[`${G} auth <key>`,"setup.alt.auth"]]),sections:[{title:R("setup.autodetect_title"),rows:[["Claude",R("setup.autodetect.claude")],["GPT",R("setup.autodetect.gpt")],["Grok",R("setup.autodetect.grok")],["Gemini",R("setup.autodetect.gemini")]]}],examples:[L(`${G} setup --key sk-xxx`,"setup.ex.key"),L(`${G} setup --install --key sk-xxx`,"setup.ex.install"),L(`${G} setup --claudekey sk-a --codexkey sk-b --agykey sk-g`,"setup.ex.split"),L(`${G} setup --force --key sk-xxx`,"setup.ex.force"),L(`${G} setup --base ${z} --key sk-xxx`,"setup.ex.base")]});const U=A.command("init").summary(R("init.summary")).description(R("init.description")).action(async()=>{await r.runFirstTimeSetup()});p(U,{...P("init",[[`${G} setup --key <key>`,"init.alt.setup"],[`${G}`,"init.alt.menu"]]),examples:[L(`${G} init`,"init.ex.run"),L(`${G} init --base ${z}`,"init.ex.base"),L(`${G}`,"init.ex.menu")]});const B=A.command("auth").summary(R("auth.summary")).description(R("auth.description")).argument("[token]",R("auth.arg.token")).action(async e=>{const o=[];e&&o.push(e),await d(o)});T(B);const H=B.command("revoke").description(R("auth.revoke")).action(async()=>{await d(["revoke"])});p(H,{examples:[L(`${G} auth revoke`,"auth.ex.revoke_ask"),L(`${G} auth revoke --yes`,"auth.ex.revoke")]});const K=B.command("reload <tool>").description(R("auth.reload")).action(async e=>{await d(["reload",e])});p(K,{examples:[L(`${G} auth reload claude-code`,"auth.ex.reload"),L(`${G} auth reload claude-code --json`,"auth.ex.reload_json")]}),p(B,{...P("auth",[[`${G} setup --key <key>`,"auth.alt.setup"]]),examples:[L(`${G} auth`,"auth.ex.prompt"),L(`${G} auth sk-xxx --non-interactive`,"auth.ex.save"),L(`${G} auth revoke --yes`,"auth.ex.revoke"),L(`${G} auth reload claude-code`,"auth.ex.reload")]});const M=A.command("config").summary(R("config.summary")).description(R("config.description")).argument("[args...]",R("config.arg.args")).option("-f, --force",R("config.opt.force")).allowUnknownOption(!0).action(async(e=[],o={})=>{await f(o.force?[...e,"--force"]:e)});p(M,{...P("config",[[`${G} setup --force --key <key>`,"config.alt.setup"],[`${G} status`,"config.alt.status"]]),sections:[{title:R("config.subcommands_title"),rows:[["<tool>",R("config.sub.tool")],["<tool> --force",R("config.sub.tool_force")],["<tool> --non-interactive",R("config.sub.tool_non_interactive")],["<tool> remove",R("config.sub.tool_remove")],["<tool> restore",R("config.sub.tool_restore")],["<tool> backups",R("config.sub.tool_backups")],["<tool> clear-model",R("config.sub.tool_clear_model")],["tool-model list",R("config.sub.tool_model_list")],["tool-model set <tool> [slot] <model>",R("config.sub.tool_model_set")],["tool-model clear <tool>",R("config.sub.tool_model_clear")],["profile list",R("config.sub.profile_list")],["profile create <name>",R("config.sub.profile_create")],["profile use <name>",R("config.sub.profile_use")],["profile delete <name>",R("config.sub.profile_delete")],["preset list",R("config.sub.preset_list")],["preset save <name>",R("config.sub.preset_save")],["preset use <name>",R("config.sub.preset_use")],["preset delete <name>",R("config.sub.preset_delete")],["backup list",R("config.sub.backup_list")],["backup create [label]",R("config.sub.backup_create")],["backup restore <name>",R("config.sub.backup_restore")]]},{title:R("config.tools_title"),rows:Object.values(c).filter(e=>!e.hidden).map(e=>[e.name,e.displayName])}],examples:[L(`${G} config codex`,"config.ex.menu"),L(`${G} config claude-code --force`,"config.ex.force"),L(`${G} config tool-model set codex gpt-6-astra`,"config.ex.tool_model"),L(`${G} config profile create work`,"config.ex.profile"),L(`${G} config codex remove`,"config.ex.remove")]});const q=A.command("base").summary(R("base.summary")).description(R("base.description")).argument("[target]",R("base.arg.target")).action(async e=>{await O(e)});p(q,{...P("base",[[`${G} doctor`,"base.alt.doctor"],[`${G} bench`,"base.alt.bench"]]),sections:[{title:R("base.targets_title"),rows:[[R("base.target.none_term"),R("base.target.none")],[R("base.target.index_term"),R("base.target.index")],[R("base.target.url_term"),R("base.target.url")],["auto",R("base.target.auto")],["default",R("base.target.default",{url:l})]]}],examples:[L(`${G} base`,"base.ex.list"),L(`${G} base auto`,"base.ex.auto"),L(`${G} base 2`,"base.ex.index"),L(`${G} base ${z}`,"base.ex.url"),L(`${G} base default`,"base.ex.default")]}),A.commandsGroup(R("group.diagnose"));const F=A.command("status").summary(R("status.summary")).description(R("status.description")).action(async()=>{await x()});p(F,{...P("status",[[`${G} doctor`,"status.alt.doctor"]]),examples:[L(`${G} status`,"status.ex.show"),L(`${G} status --json`,"status.ex.json")]});const J=A.command("doctor").summary(R("doctor.summary")).description(R("doctor.description")).option("--deep",R("doctor.opt.deep")).option("--report",R("doctor.opt.report")).action(async e=>{await g({deep:e.deep,report:e.report})});p(J,{...P("doctor",[[`${G} base auto`,"doctor.alt.base"],[`${G} logs tail`,"doctor.alt.logs"]]),examples:[L(`${G} doctor`,"doctor.ex.run"),L(`${G} doctor --deep`,"doctor.ex.deep"),L(`${G} doctor --report`,"doctor.ex.report")]});const Y=A.command("bench").summary(R("bench.summary")).description(R("bench.description")).option("--samples <n>",R("bench.opt.samples"),"5").action(async e=>{const o=[];e.samples&&o.push("--samples",e.samples),await $(o)});p(Y,{...P("bench",[[`${G} base`,"bench.alt.base"]]),examples:[L(`${G} bench`,"bench.ex.run"),L(`${G} bench --samples 3`,"bench.ex.samples"),L(`${G} bench --json`,"bench.ex.json")]});const D=A.command("logs").summary(R("logs.summary")).description(R("logs.description")).argument("[action]",R("logs.arg.action")).argument("[file]",R("logs.arg.file")).action(async(e,o)=>{const t=[];e&&t.push(e),o&&t.push(o),await h(t)});p(D,{...P("logs",[[`${G} doctor`,"logs.alt.doctor"]]),sections:[{title:R("logs.actions_title"),rows:[["list",R("logs.action.list")],["tail [file]",R("logs.action.tail")],["path",R("logs.action.path")]]}],examples:[L(`${G} logs`,"logs.ex.list"),L(`${G} logs tail`,"logs.ex.tail"),L(`${G} logs path`,"logs.ex.path")]}),A.commandsGroup(R("group.maintain"));const I=A.command("upgrade").summary(R("upgrade.summary")).description(R("upgrade.description")).argument("[tools...]",R("upgrade.arg.tools")).action(async(e=[])=>{await _(e)});p(I,{...P("upgrade",[[`${G} update`,"upgrade.alt.update"]]),examples:[L(`${G} upgrade`,"upgrade.ex.all"),L(`${G} upgrade claude-code`,"upgrade.ex.one"),L(`${G} upgrade codex agy`,"upgrade.ex.many")]});const Q=A.command("refresh").summary(R("refresh.summary")).description(R("refresh.description")).action(async()=>{await y()});p(Q,{...P("refresh",[[`${G} setup --key ${i.t("errors.key_placeholder")}`,"refresh.alt.setup"]]),examples:[L(`${G} refresh`,"refresh.ex.run"),L(`${G} refresh --base ${C}`,"refresh.ex.base")]});const V=A.command("update").summary(R("update.summary")).description(R("update.description")).action(async()=>{await k()});p(V,{...P("update",[[`${G} upgrade`,"update.alt.upgrade"]]),examples:[L(`${G} update`,"update.ex.check"),L(`${G} update --json`,"update.ex.json")]});const W=A.command("codex").summary(R("codex.summary")).description(R("codex.description"));T(W);const X=W.command("sessions").summary(R("codex_sessions.summary")).description(R("codex_sessions.description")).option("--to <provider>",R("codex_sessions.opt.to")).option("--undo <dir>",R("codex_sessions.opt.undo")).action(async e=>{await w(e)});p(W,{...P("codex"),examples:[L(`${G} codex sessions`,"codex_sessions.ex.move"),L(`${G} codex sessions --undo <dir>`,"codex_sessions.ex.undo")]}),p(X,{...P("codex_sessions",[[`${G} codex sessions --undo <dir>`,"codex_sessions.alt.undo"]]),examples:[L(`${G} codex sessions`,"codex_sessions.ex.move"),L(`${G} codex sessions --to custom`,"codex_sessions.ex.to"),L(`${G} codex sessions --undo <dir>`,"codex_sessions.ex.undo")]});const Z=A.command("lang").summary(R("lang.summary")).description(R("lang.description"));T(Z);const ee=Z.command("show").description(R("lang.show")).action(async()=>{await u(["show"])}),oe=Z.command("set <locale>").description(R("lang.set")).action(async e=>{await u(["set",e])}),te=[L(`${G} lang show`,"lang.ex.show"),L(`${G} lang set en_US`,"lang.ex.set_en"),L(`${G} lang set zh_CN`,"lang.ex.set_zh")];p(Z,{...P("lang",[[`${G} enter lang`,"lang.alt.enter"]]),examples:te}),p(ee,{examples:[te[0],L(`${G} lang show --json`,"lang.ex.show_json")]}),p(oe,{examples:te.slice(1)});const se=A.command("completion").summary(R("completion.summary")).description(R("completion.description")).argument("<shell>",R("completion.arg.shell")).action(async e=>{await b([e])});p(se,{...P("completion"),examples:[L(`${G} completion bash > ~/.${G}-completion.bash`,"completion.ex.bash"),L(`${G} completion zsh > ~/.${G}-completion.zsh`,"completion.ex.zsh"),L(`${G} completion fish > ~/.config/fish/completions/${G}.fish`,"completion.ex.fish")]});const ae=A.command("enter").summary(R("enter.summary")).description(R("enter.description")).argument("[option]",R("enter.arg.option")).action(async e=>{if(e)switch(e){case"lang":case"language":await r.configLanguage();break;case"apikey":case"api-key":await r.configApiKey();break;case"models":await r.configModels();break;default:await f([e])}else await r.run()});p(ae,{...P("enter",[[`${G}`,"enter.alt.menu"],[`${G} config <tool>`,"enter.alt.config"]]),sections:[{title:R("enter.options_title"),rows:[[R("enter.option.none_term"),R("enter.option.none")],["lang",R("enter.option.lang")],["apikey",R("enter.option.apikey")],["models",R("enter.option.models")],["<tool>",R("enter.option.tool")]]}],examples:[L(`${G} enter`,"enter.ex.menu"),L(`${G} enter models`,"enter.ex.models"),L(`${G} enter codex`,"enter.ex.tool")]}),T(A),A.action(async()=>{await r.run()}),p(A,{examples:[L(`${G}`,"root.ex.menu"),L(`${G} setup --key sk-xxx`,"root.ex.setup"),L(`${G} doctor`,"root.ex.doctor"),L(`${G} base auto`,"root.ex.base"),L(`${G} config codex`,"root.ex.config")]});const ne=e=>{for(const o of e.commands)o.helpOption("-h, --help",R("global.help")),ne(o)};return ne(A),A}
1
+ import{Command as e,Option as o}from"commander";import{readFileSync as s}from"fs";import{join as t,dirname as n}from"path";import{fileURLToPath as a}from"url";import{i18n as i}from"./i18n.js";import{wizard as r}from"./wizard.js";import{SUPPORTED_TOOLS as c}from"./tool-manager.js";import{DEFAULT_BASE_URL as l}from"./config.js";import{attachCommandHelp as p,helpConfiguration as m}from"./cli-help.js";import{langCommand as u,authCommand as d,doctorCommand as f,configCommand as g,statusCommand as x,refreshCommand as h}from"../commands/index.js";import{logsCommand as y}from"../commands/logs.js";import{completionCommand as $}from"../commands/completion.js";import{benchCommand as b}from"../commands/bench.js";import{updateCommand as k}from"../commands/update.js";import{upgradeCommand as _}from"../commands/upgrade.js";import{codexSessionsCommand as w}from"../commands/codex-sessions.js";import{sessionsExportCommand as v,sessionsListCommand as j,sessionsResumeCommand as O,sessionsShowCommand as S}from"../commands/sessions.js";import{setupCommand as A,DEDICATED_KEYS as E}from"../commands/setup.js";import{baseCommand as G}from"../commands/base.js";import{usageError as z}from"./errors.js";import{brand as C,brandEnv as R,CLI_NAME as L}from"./brand.js";const N=(C().gatewayAddresses[1]??C().gatewayAddresses[0]).url,P=(C().gatewayAddresses[2]??C().gatewayAddresses[0]).url;function T(e,o){return i.t(`help.${e}`,o)}function U(e,o){return{command:e,note:T(o)}}function B(e){const o=T(e);return o===`help.${e}`?"":o}function H(e,o=[]){return{when:B(`${e}.when`),prerequisites:B(`${e}.needs`).split("\n").filter(Boolean),alternatives:o.map(([e,o])=>U(e,o))}}function K(e){return e.helpCommand("help [command]",T("help_command"))}export function buildProgram(){const C=new e;C.name(`${L}`).summary(T("root.summary")).description(T("root.description")).configureHelp(m()).allowExcessArguments(!0).optionsGroup(T("group.global_options")).helpOption("-h, --help",T("global.help")).version(function(){try{const e=n(a(import.meta.url));return JSON.parse(s(t(e,"../../package.json"),"utf-8")).version}catch{return"1.0.0"}}(),"-v, --version",T("global.version")).option("--base <url>",T("global.base")).option("--non-interactive",T("global.non_interactive")).option("--json",T("global.json")).option("-y, --yes",T("global.yes")).option("--dry-run",T("global.dry_run")).option("--no-color",T("global.no_color")),C.configureOutput({writeErr:()=>{},outputError:()=>{}}),C.showSuggestionAfterError(),C.exitOverride(e=>{throw e}),C.commandsGroup(T("group.configure"));const B=C.command("setup").summary(T("setup.summary")).description(T("setup.description")).option("--key <key>",T("setup.opt.key"));for(const e of E){const s=new o(`--${e.option} <key>`,T(`setup.opt.${e.option}`));e.hidden&&s.hideHelp(),B.addOption(s)}B.option("--1m",T("setup.opt.one_m")).option("--no-1m",T("setup.opt.no_one_m")).option("--claude-official <on|off>",T("setup.opt.claude_official")).option("--desktop-registry <on|off>",T("setup.opt.desktop_registry")).option("--force",T("setup.opt.force")).option("--install",T("setup.opt.install")).option("--no-install",T("setup.opt.no_install")).option("--all",T("setup.opt.all")).action(async e=>{e.key||E.some(o=>e[o.option])||(e.key=R("SETUP_KEY")?.trim()||void 0);const o=Boolean(e.key||E.some(o=>e[o.option])),s=void 0!==e["1m"]||void 0!==e.claudeOfficial||void 0!==e.desktopRegistry,t=i.t("errors.key_placeholder");if(!o&&!s)throw z(i.t("setup.usage"),`${L} setup --key ${t}`,"missing_key");if(void 0!==e.claudeOfficial&&!["on","off"].includes(String(e.claudeOfficial).toLowerCase()))throw z(i.t("setup.claude_official_invalid",{value:String(e.claudeOfficial)}),`${L} setup --claude-official on|off`,"invalid_value");if(void 0!==e.desktopRegistry&&!["on","off"].includes(String(e.desktopRegistry).toLowerCase()))throw z(i.t("setup.desktop_registry_invalid",{value:String(e.desktopRegistry)}),`${L} setup --desktop-registry on|off`,"invalid_value");await A({key:e.key,...Object.fromEntries(E.map(o=>[o.option,e[o.option]])),all:e.all,oneMillion:e["1m"],claudeOfficial:e.claudeOfficial,desktopRegistry:e.desktopRegistry,force:e.force,install:e.install})}),p(B,{...H("setup",[[`${L} init`,"setup.alt.init"],[`${L} config <tool>`,"setup.alt.config"],[`${L} auth <key>`,"setup.alt.auth"]]),sections:[{title:T("setup.autodetect_title"),rows:[["Claude",T("setup.autodetect.claude")],["GPT",T("setup.autodetect.gpt")],["Grok",T("setup.autodetect.grok")],["Gemini",T("setup.autodetect.gemini")]]}],examples:[U(`${L} setup --key sk-xxx`,"setup.ex.key"),U(`${L} setup --install --key sk-xxx`,"setup.ex.install"),U(`${L} setup --claudekey sk-a --codexkey sk-b --agykey sk-g`,"setup.ex.split"),U(`${L} setup --force --key sk-xxx`,"setup.ex.force"),U(`${L} setup --base ${N} --key sk-xxx`,"setup.ex.base")]});const M=C.command("init").summary(T("init.summary")).description(T("init.description")).action(async()=>{await r.runFirstTimeSetup()});p(M,{...H("init",[[`${L} setup --key <key>`,"init.alt.setup"],[`${L}`,"init.alt.menu"]]),examples:[U(`${L} init`,"init.ex.run"),U(`${L} init --base ${N}`,"init.ex.base"),U(`${L}`,"init.ex.menu")]});const q=C.command("auth").summary(T("auth.summary")).description(T("auth.description")).argument("[token]",T("auth.arg.token")).action(async e=>{const o=[];e&&o.push(e),await d(o)});K(q);const D=q.command("revoke").description(T("auth.revoke")).action(async()=>{await d(["revoke"])});p(D,{examples:[U(`${L} auth revoke`,"auth.ex.revoke_ask"),U(`${L} auth revoke --yes`,"auth.ex.revoke")]});const F=q.command("reload <tool>").description(T("auth.reload")).action(async e=>{await d(["reload",e])});p(F,{examples:[U(`${L} auth reload claude-code`,"auth.ex.reload"),U(`${L} auth reload claude-code --json`,"auth.ex.reload_json")]}),p(q,{...H("auth",[[`${L} setup --key <key>`,"auth.alt.setup"]]),examples:[U(`${L} auth`,"auth.ex.prompt"),U(`${L} auth sk-xxx --non-interactive`,"auth.ex.save"),U(`${L} auth revoke --yes`,"auth.ex.revoke"),U(`${L} auth reload claude-code`,"auth.ex.reload")]});const J=C.command("config").summary(T("config.summary")).description(T("config.description")).argument("[args...]",T("config.arg.args")).option("-f, --force",T("config.opt.force")).allowUnknownOption(!0).action(async(e=[],o={})=>{await g(o.force?[...e,"--force"]:e)});p(J,{...H("config",[[`${L} setup --force --key <key>`,"config.alt.setup"],[`${L} status`,"config.alt.status"]]),sections:[{title:T("config.subcommands_title"),rows:[["<tool>",T("config.sub.tool")],["<tool> --force",T("config.sub.tool_force")],["<tool> --non-interactive",T("config.sub.tool_non_interactive")],["<tool> remove",T("config.sub.tool_remove")],["<tool> restore",T("config.sub.tool_restore")],["<tool> backups",T("config.sub.tool_backups")],["<tool> clear-model",T("config.sub.tool_clear_model")],["tool-model list",T("config.sub.tool_model_list")],["tool-model set <tool> [slot] <model>",T("config.sub.tool_model_set")],["tool-model clear <tool>",T("config.sub.tool_model_clear")],["profile list",T("config.sub.profile_list")],["profile create <name>",T("config.sub.profile_create")],["profile use <name>",T("config.sub.profile_use")],["profile delete <name>",T("config.sub.profile_delete")],["preset list",T("config.sub.preset_list")],["preset save <name>",T("config.sub.preset_save")],["preset use <name>",T("config.sub.preset_use")],["preset delete <name>",T("config.sub.preset_delete")],["backup list",T("config.sub.backup_list")],["backup create [label]",T("config.sub.backup_create")],["backup restore <name>",T("config.sub.backup_restore")]]},{title:T("config.tools_title"),rows:Object.values(c).filter(e=>!e.hidden).map(e=>[e.name,e.displayName])}],examples:[U(`${L} config codex`,"config.ex.menu"),U(`${L} config claude-code --force`,"config.ex.force"),U(`${L} config tool-model set codex gpt-6-astra`,"config.ex.tool_model"),U(`${L} config profile create work`,"config.ex.profile"),U(`${L} config codex remove`,"config.ex.remove")]});const Y=C.command("base").summary(T("base.summary")).description(T("base.description")).argument("[target]",T("base.arg.target")).action(async e=>{await G(e)});p(Y,{...H("base",[[`${L} doctor`,"base.alt.doctor"],[`${L} bench`,"base.alt.bench"]]),sections:[{title:T("base.targets_title"),rows:[[T("base.target.none_term"),T("base.target.none")],[T("base.target.index_term"),T("base.target.index")],[T("base.target.url_term"),T("base.target.url")],["auto",T("base.target.auto")],["default",T("base.target.default",{url:l})]]}],examples:[U(`${L} base`,"base.ex.list"),U(`${L} base auto`,"base.ex.auto"),U(`${L} base 2`,"base.ex.index"),U(`${L} base ${N}`,"base.ex.url"),U(`${L} base default`,"base.ex.default")]}),C.commandsGroup(T("group.diagnose"));const I=C.command("status").summary(T("status.summary")).description(T("status.description")).action(async()=>{await x()});p(I,{...H("status",[[`${L} doctor`,"status.alt.doctor"]]),examples:[U(`${L} status`,"status.ex.show"),U(`${L} status --json`,"status.ex.json")]});const Q=C.command("doctor").summary(T("doctor.summary")).description(T("doctor.description")).option("--deep",T("doctor.opt.deep")).option("--report",T("doctor.opt.report")).action(async e=>{await f({deep:e.deep,report:e.report})});p(Q,{...H("doctor",[[`${L} base auto`,"doctor.alt.base"],[`${L} logs tail`,"doctor.alt.logs"]]),examples:[U(`${L} doctor`,"doctor.ex.run"),U(`${L} doctor --deep`,"doctor.ex.deep"),U(`${L} doctor --report`,"doctor.ex.report")]});const V=C.command("bench").summary(T("bench.summary")).description(T("bench.description")).option("--samples <n>",T("bench.opt.samples"),"5").option("--stream",T("bench.opt.stream")).option("--model <model>",T("bench.opt.model")).action(async e=>{const o=[];e.samples&&o.push("--samples",e.samples),e.stream&&o.push("--stream"),e.model&&o.push("--model",e.model),await b(o)});p(V,{...H("bench",[[`${L} base`,"bench.alt.base"]]),examples:[U(`${L} bench`,"bench.ex.run"),U(`${L} bench --samples 3`,"bench.ex.samples"),U(`${L} bench --stream`,"bench.ex.stream"),U(`${L} bench --stream --model gpt-6-astra`,"bench.ex.stream_model"),U(`${L} bench --json`,"bench.ex.json")]});const W=C.command("logs").summary(T("logs.summary")).description(T("logs.description")).argument("[action]",T("logs.arg.action")).argument("[file]",T("logs.arg.file")).action(async(e,o)=>{const s=[];e&&s.push(e),o&&s.push(o),await y(s)});p(W,{...H("logs",[[`${L} doctor`,"logs.alt.doctor"]]),sections:[{title:T("logs.actions_title"),rows:[["list",T("logs.action.list")],["tail [file]",T("logs.action.tail")],["path",T("logs.action.path")]]}],examples:[U(`${L} logs`,"logs.ex.list"),U(`${L} logs tail`,"logs.ex.tail"),U(`${L} logs path`,"logs.ex.path")]}),C.commandsGroup(T("group.maintain"));const X=C.command("upgrade").summary(T("upgrade.summary")).description(T("upgrade.description")).argument("[tools...]",T("upgrade.arg.tools")).action(async(e=[])=>{await _(e)});p(X,{...H("upgrade",[[`${L} update`,"upgrade.alt.update"]]),examples:[U(`${L} upgrade`,"upgrade.ex.all"),U(`${L} upgrade claude-code`,"upgrade.ex.one"),U(`${L} upgrade codex agy`,"upgrade.ex.many")]});const Z=C.command("refresh").summary(T("refresh.summary")).description(T("refresh.description")).action(async()=>{await h()});p(Z,{...H("refresh",[[`${L} setup --key ${i.t("errors.key_placeholder")}`,"refresh.alt.setup"]]),examples:[U(`${L} refresh`,"refresh.ex.run"),U(`${L} refresh --base ${P}`,"refresh.ex.base")]});const ee=C.command("update").summary(T("update.summary")).description(T("update.description")).action(async()=>{await k()});p(ee,{...H("update",[[`${L} upgrade`,"update.alt.upgrade"]]),examples:[U(`${L} update`,"update.ex.check"),U(`${L} update --json`,"update.ex.json")]});const oe=C.command("codex").summary(T("codex.summary")).description(T("codex.description"));K(oe);const se=oe.command("sessions").summary(T("codex_sessions.summary")).description(T("codex_sessions.description")).option("--to <provider>",T("codex_sessions.opt.to")).option("--undo <dir>",T("codex_sessions.opt.undo")).action(async e=>{await w(e)});p(oe,{...H("codex"),examples:[U(`${L} codex sessions`,"codex_sessions.ex.move"),U(`${L} codex sessions --undo <dir>`,"codex_sessions.ex.undo")]}),p(se,{...H("codex_sessions",[[`${L} codex sessions --undo <dir>`,"codex_sessions.alt.undo"]]),examples:[U(`${L} codex sessions`,"codex_sessions.ex.move"),U(`${L} codex sessions --to custom`,"codex_sessions.ex.to"),U(`${L} codex sessions --undo <dir>`,"codex_sessions.ex.undo")]});const te=C.command("sessions").summary(T("sessions.summary")).description(T("sessions.description"));K(te);const ne=te.command("list",{isDefault:!0}).description(T("sessions.list")).option("--tool <tool>",T("sessions.opt.tool")).option("--dir <path>",T("sessions.opt.dir")).option("--here",T("sessions.opt.here")).option("-n, --limit <count>",T("sessions.opt.limit")).option("--all",T("sessions.opt.all")).action(async e=>{await j(e)}),ae=te.command("show <id>").description(T("sessions.show")).option("-m, --messages <count>",T("sessions.opt.messages")).action(async(e,o)=>{await S(e,o)}),ie=te.command("resume <id>").description(T("sessions.resume")).option("--run",T("sessions.opt.run")).action(async(e,o)=>{await O(e,o)}),re=te.command("export <ids...>").description(T("sessions.export")).option("-o, --output <dir>",T("sessions.opt.output")).option("--tools",T("sessions.opt.tools")).action(async(e,o)=>{await v(e,o)});p(ne,{examples:[U(`${L} sessions list`,"sessions.ex.list"),U(`${L} sessions list --tool codex`,"sessions.ex.codex"),U(`${L} sessions list --here --all`,"sessions.ex.here"),U(`${L} sessions list --json`,"sessions.ex.json")]}),p(ae,{examples:[U(`${L} sessions show 01a0f5fe`,"sessions.ex.show"),U(`${L} sessions show 01a0f5fe -m 20`,"sessions.ex.show_more")]}),p(ie,{examples:[U(`${L} sessions resume 01a0f5fe`,"sessions.ex.resume_print"),U(`${L} sessions resume 01a0f5fe --run`,"sessions.ex.resume")]}),p(re,{examples:[U(`${L} sessions export 01a0f5fe 7c2e9d41 -o ./sessions`,"sessions.ex.export"),U(`${L} sessions export 01a0f5fe -o ./sessions --tools`,"sessions.ex.export_tools")]}),p(te,{...H("sessions",[[`${L} codex sessions`,"sessions.alt.codex_sessions"]]),examples:[U(`${L} sessions`,"sessions.ex.list"),U(`${L} sessions --tool codex --here`,"sessions.ex.here"),U(`${L} sessions show 01a0f5fe`,"sessions.ex.show"),U(`${L} sessions resume 01a0f5fe --run`,"sessions.ex.resume"),U(`${L} sessions export 01a0f5fe 7c2e9d41 -o ./sessions`,"sessions.ex.export")]});const ce=C.command("lang").summary(T("lang.summary")).description(T("lang.description"));K(ce);const le=ce.command("show").description(T("lang.show")).action(async()=>{await u(["show"])}),pe=ce.command("set <locale>").description(T("lang.set")).action(async e=>{await u(["set",e])}),me=[U(`${L} lang show`,"lang.ex.show"),U(`${L} lang set en_US`,"lang.ex.set_en"),U(`${L} lang set zh_CN`,"lang.ex.set_zh")];p(ce,{...H("lang",[[`${L} enter lang`,"lang.alt.enter"]]),examples:me}),p(le,{examples:[me[0],U(`${L} lang show --json`,"lang.ex.show_json")]}),p(pe,{examples:me.slice(1)});const ue=C.command("completion").summary(T("completion.summary")).description(T("completion.description")).argument("<shell>",T("completion.arg.shell")).action(async e=>{await $([e])});p(ue,{...H("completion"),examples:[U(`${L} completion bash > ~/.${L}-completion.bash`,"completion.ex.bash"),U(`${L} completion zsh > ~/.${L}-completion.zsh`,"completion.ex.zsh"),U(`${L} completion fish > ~/.config/fish/completions/${L}.fish`,"completion.ex.fish")]});const de=C.command("enter").summary(T("enter.summary")).description(T("enter.description")).argument("[option]",T("enter.arg.option")).action(async e=>{if(e)switch(e){case"lang":case"language":await r.configLanguage();break;case"apikey":case"api-key":await r.configApiKey();break;case"models":await r.configModels();break;default:await g([e])}else await r.run()});p(de,{...H("enter",[[`${L}`,"enter.alt.menu"],[`${L} config <tool>`,"enter.alt.config"]]),sections:[{title:T("enter.options_title"),rows:[[T("enter.option.none_term"),T("enter.option.none")],["lang",T("enter.option.lang")],["apikey",T("enter.option.apikey")],["models",T("enter.option.models")],["<tool>",T("enter.option.tool")]]}],examples:[U(`${L} enter`,"enter.ex.menu"),U(`${L} enter models`,"enter.ex.models"),U(`${L} enter codex`,"enter.ex.tool")]}),K(C),C.action(async()=>{await r.run()}),p(C,{examples:[U(`${L}`,"root.ex.menu"),U(`${L} setup --key sk-xxx`,"root.ex.setup"),U(`${L} doctor`,"root.ex.doctor"),U(`${L} base auto`,"root.ex.base"),U(`${L} config codex`,"root.ex.config")]});const fe=e=>{for(const o of e.commands)o.helpOption("-h, --help",T("global.help")),fe(o)};return fe(C),C}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Read-only parsers for the two session formats coding tools write on disk. Nothing here opens a
3
+ * file for writing: `vibecli sessions` only lists, shows and exports.
4
+ *
5
+ * - Codex: `rollout-<time>-<uuid>.jsonl` under `$CODEX_HOME/sessions/YYYY/MM/DD/` and
6
+ * `archived_sessions/`; line 1 is `session_meta`, messages are `response_item` records.
7
+ * - Claude Code: `<projects dir>/<project>/<session uuid>.jsonl`; Claude Desktop's Cowork / Code
8
+ * sessions are the same format under `local-agent-mode-sessions/<...>/.claude/projects/`
9
+ * (the `audit.jsonl` next to them is an audit copy of the same conversation, skipped).
10
+ *
11
+ * Same rules as the developer-docs `agent-history/scripts/to-markdown.py`: context the tool injects
12
+ * into user turns (Codex AGENTS.md / environment context, Claude Code system reminders, command
13
+ * wrappers, meta and sidechain records) is not a message.
14
+ */
15
+ export type SessionRole = 'user' | 'assistant' | 'tool';
16
+ export interface SessionMessage {
17
+ role: SessionRole;
18
+ /** Plain text; tool calls are `[tool: name]` lines unless details were asked for. */
19
+ text: string;
20
+ timestamp?: string;
21
+ }
22
+ export interface SessionMeta {
23
+ id: string;
24
+ cwd: string;
25
+ title: string;
26
+ startedAt?: string;
27
+ /** Codex only: the provider the session was recorded under. */
28
+ provider?: string;
29
+ }
30
+ export interface SessionFormat {
31
+ /** Session id from the file name alone (no parsing), so lookups by id stay cheap. */
32
+ idFromFile(file: string): string;
33
+ /** Metadata from the first part of the file; null when it holds no conversation. */
34
+ summarize(file: string): SessionMeta | null;
35
+ /** Every message, in order. `details` adds tool arguments and outputs. */
36
+ read(file: string, options?: {
37
+ details?: boolean;
38
+ }): SessionMessage[];
39
+ }
40
+ /** Tool arguments / outputs are clipped to this many characters in details. */
41
+ export declare const DETAIL_LIMIT = 2000;
42
+ export declare function clip(text: string, limit?: number): string;
43
+ export declare const codexFormat: SessionFormat;
44
+ export declare const claudeFormat: SessionFormat;
45
+ /** `<projects>/<project>/<session>.jsonl`, one level deep (subagent transcripts live in deeper folders). */
46
+ export declare function claudeProjectFiles(projectsDir: string): string[];
47
+ /** Every `rollout-*.jsonl` below a Codex sessions directory (any depth). */
48
+ export declare function codexRolloutFiles(dir: string, depth?: number): string[];
49
+ /**
50
+ * Claude Desktop keeps each Cowork / Code session's Claude Code data in its own folder:
51
+ * find every `.claude/projects` below `root` and list their sessions.
52
+ */
53
+ export declare function nestedClaudeProjectFiles(root: string, depth?: number): string[];
@@ -0,0 +1 @@
1
+ import{closeSync as t,existsSync as o,openSync as e,readdirSync as n,readFileSync as r,readSync as s,statSync as i}from"fs";import{basename as c,join as u}from"path";const l=262144;export const DETAIL_LIMIT=2e3;const a=["# AGENTS.md instructions","<environment_context>","<user_instructions>","<permissions","<INSTRUCTIONS>"],f=["<system-reminder>","<command-","<local-command-","Caveat: "];function p(t){return t&&"object"==typeof t&&!Array.isArray(t)?t:{}}function m(t){return"string"==typeof t?t:""}function d(t,o){const e=t.split("\n");o&&e.pop();const n=[];for(const t of e){const o=t.trim();if(o)try{n.push(p(JSON.parse(o)))}catch{}}return n}function y(o,n){const r=e(o,"r");try{const t=Buffer.alloc(l);let o=Buffer.alloc(0);for(let e=0;e<16777216;){const i=s(r,t,0,l,e);if(i<=0)break;e+=i;const c=Buffer.concat([o,t.subarray(0,i)]),u=c.lastIndexOf(10);if(u<0)o=c;else{o=Buffer.from(c.subarray(u+1));for(const t of d(c.subarray(0,u).toString("utf-8"),!1))if(n(t))return}}for(const t of d(o.toString("utf-8"),!1))if(n(t))return}finally{t(r)}}function h(t){return d(r(t,"utf-8"),!1)}export function clip(t,o=2e3){return t.length<=o?t:`${t.slice(0,o)}\n… (${t.length})`}function x(t,o){return`[${t}]\n${clip((e=o,"string"==typeof e?e:JSON.stringify(e,null,2)??""))}`;var e}function _(t){return(t.split("\n").find(t=>t.trim())??"").trim().slice(0,200)}const F=/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;function j(t,o){const e=[];for(const n of t){if("response_item"!==n.type)continue;const t=p(n.payload),r=m(n.timestamp)||void 0,s=t.type;if("message"!==s||"user"!==t.role&&"assistant"!==t.role){if(["function_call","custom_tool_call","local_shell_call","web_search_call"].includes(m(s))){const n=m(t.name)||m(s);e.push({role:"tool",text:o?x(`tool: ${n}`,t.arguments??t.input??t.action??""):`[tool: ${n}]`,timestamp:r})}else if(o&&("function_call_output"===s||"custom_tool_call_output"===s)){const o=t.output&&"object"==typeof t.output?p(t.output).content??t.output:t.output;e.push({role:"tool",text:x("tool output",o??""),timestamp:r})}}else{const o=(Array.isArray(t.content)?t.content:[]).map(t=>m(p(t).text)).join("\n\n").trim();if(!o||"user"===t.role&&a.some(t=>o.startsWith(t)))continue;e.push({role:t.role,text:o,timestamp:r})}}return e}export const codexFormat={idFromFile(t){const o=c(t,".jsonl");return F.exec(o)?.[1]??o},summarize(t){let o,e,n=0;if(y(t,t=>(o||"session_meta"!==t.type||(o=t),e??=j([t],!1).find(t=>"user"===t.role),Boolean(e)||++n>2e3&&Boolean(o)||!o&&n>20)),!o)return null;const r=p(o.payload);return{id:m(r.id)||this.idFromFile(t),cwd:m(r.cwd),title:e?_(e.text):"",startedAt:m(r.timestamp)||m(o.timestamp)||void 0,provider:m(r.model_provider)||void 0}},read:(t,o={})=>j(h(t),Boolean(o.details))};function g(t,o){if("user"!==t.type&&"assistant"!==t.type||t.isMeta||t.isSidechain)return null;const e=p(t.message),n="string"==typeof e.content?[{type:"text",text:e.content}]:Array.isArray(e.content)?e.content:[],r=[];let s=!0;for(const t of n){const e=p(t);if("text"===e.type){const t=m(e.text).trim();if(!t||f.some(o=>t.startsWith(o)))continue;r.push(t),s=!1}else if("tool_use"===e.type)r.push(o?x(`tool: ${m(e.name)}`,e.input??""):`[tool: ${m(e.name)}]`);else if("tool_result"===e.type&&o){const t=Array.isArray(e.content)?e.content.map(t=>m(p(t).text)).join("\n"):e.content;r.push(x("tool output",t??""))}}return 0===r.length?null:{role:"assistant"===e.role?s?"tool":"assistant":s?"tool":"user",text:r.join("\n\n"),timestamp:m(t.timestamp)||void 0}}export const claudeFormat={idFromFile:t=>c(t,".jsonl"),summarize(t){let o,e="",n="",r="",s="";return y(t,t=>{if("ai-title"===t.type&&m(t.aiTitle)&&(r=m(t.aiTitle)),"summary"===t.type&&m(t.summary)&&!r&&(r=m(t.summary)),"user"!==t.type&&"assistant"!==t.type||t.isSidechain||(e||=m(t.cwd),n||=m(t.sessionId),o||=m(t.timestamp)||void 0),!s){const o=g(t,!1);"user"===o?.role&&(s=o.text)}return Boolean(s&&e)}),s||r?{id:n||this.idFromFile(t),cwd:e,title:r||_(s),startedAt:o}:null},read(t,o={}){const e=[];for(const n of h(t)){const t=g(n,Boolean(o.details));t&&e.push(t)}return e}};function A(t){try{return n(t)}catch{return[]}}function v(t){try{return i(t).isDirectory()}catch{return!1}}export function claudeProjectFiles(t){const o=[];for(const e of A(t)){const n=u(t,e);if(v(n))for(const t of A(n))t.endsWith(".jsonl")&&"audit.jsonl"!==t&&o.push(u(n,t))}return o}export function codexRolloutFiles(t,o=0){if(o>4)return[];const e=[];for(const n of A(t)){const r=u(t,n);n.startsWith("rollout-")&&n.endsWith(".jsonl")?e.push(r):v(r)&&e.push(...codexRolloutFiles(r,o+1))}return e}export function nestedClaudeProjectFiles(t,e=0){if(e>6||!o(t))return[];const n=[];for(const o of A(t)){const r=u(t,o);v(r)&&(".claude"===o?n.push(...claudeProjectFiles(u(r,"projects"))):"node_modules"!==o&&n.push(...nestedClaudeProjectFiles(r,e+1)))}return n}
@@ -0,0 +1,43 @@
1
+ import type { SessionMessage } from './formats.js';
2
+ /** One local session of any tool, as `vibecli sessions` lists it. */
3
+ export interface SessionEntry {
4
+ id: string;
5
+ tool: string;
6
+ toolName: string;
7
+ file: string;
8
+ cwd: string;
9
+ title: string;
10
+ startedAt?: string;
11
+ /** Last write to the session file. */
12
+ updatedAt: string;
13
+ provider?: string;
14
+ }
15
+ /** Tools that keep sessions vibecli can read, for `--tool` validation and help. */
16
+ export declare function sessionTools(): string[];
17
+ export declare function assertSessionTool(tool: string | undefined): void;
18
+ /** Newest first. Files are parsed only until `limit` matches are found. */
19
+ export declare function listSessions(options?: {
20
+ tool?: string;
21
+ dir?: string;
22
+ limit?: number;
23
+ }): SessionEntry[];
24
+ /** The one session whose id is `id` or starts with it (at least 4 characters). */
25
+ export declare function resolveSession(id: string): SessionEntry;
26
+ export declare function readSession(entry: SessionEntry, options?: {
27
+ details?: boolean;
28
+ }): SessionMessage[];
29
+ /** How to continue the session in its tool, or null when the tool has no such command. */
30
+ export declare function resumeCommand(entry: SessionEntry): {
31
+ command: string;
32
+ args: string[];
33
+ cwd: string;
34
+ } | null;
35
+ /** POSIX-shell / PowerShell line a user can paste: `cd '<dir>' && claude --resume <id>`. */
36
+ export declare function resumeLine(cmd: {
37
+ command: string;
38
+ args: string[];
39
+ cwd: string;
40
+ }): string;
41
+ export declare function roleLabel(role: SessionMessage['role']): string;
42
+ /** Markdown export: a metadata list, then one `##` section per message. */
43
+ export declare function sessionMarkdown(entry: SessionEntry, messages: SessionMessage[]): string;
@@ -0,0 +1 @@
1
+ import{statSync as t}from"fs";import{resolve as s,sep as o}from"path";import{listAdapters as e}from"../tools/registry.js";import{i18n as n}from"../i18n.js";import{usageError as i}from"../errors.js";import{CLI_NAME as r}from"../brand.js";function l(t){return e().filter(s=>Boolean(s.sessions)&&(!t||s.name===t))}export function sessionTools(){return l().map(t=>t.name)}function a(s){const o=[];for(const e of l(s)){let s=[];try{s=e.sessions.files()}catch{continue}for(const n of s)try{o.push({adapter:e,file:n,mtimeMs:t(n).mtimeMs})}catch{}}return o.sort((t,s)=>s.mtimeMs-t.mtimeMs)}const d=/^[A-Za-z0-9_-]{1,128}$/;function c(t,s,o){if(d.test(t))return t;const e=o.sessions.format.idFromFile(s);return d.test(e)?e:e.replace(/[^A-Za-z0-9_-]/g,"_").slice(0,128)}function f(t){let s;try{s=t.adapter.sessions.format.summarize(t.file)}catch{return null}return s?{id:c(s.id,t.file,t.adapter),tool:t.adapter.name,toolName:t.adapter.displayName,file:t.file,cwd:s.cwd,title:s.title,...s.startedAt?{startedAt:s.startedAt}:{},updatedAt:new Date(t.mtimeMs).toISOString(),...s.provider?{provider:s.provider}:{}}:null}function u(t){const o=s(t).replace(/[\\/]+$/,"");return"win32"===process.platform?o.toLowerCase():o}function m(t,s){if(!t.cwd)return!1;const e=u(t.cwd);return e===s||e.startsWith(s+o)}export function assertSessionTool(t){if(t&&!sessionTools().includes(t))throw i(n.t("sessions.unknown_tool",{tool:t,tools:sessionTools().join(", ")}),n.t("sessions.unknown_tool_hint",{cli:r}))}export function listSessions(t={}){assertSessionTool(t.tool);const s=t.dir?u(t.dir):void 0,o=t.limit&&t.limit>0?t.limit:1/0,e=[];for(const n of a(t.tool)){const t=f(n);if(t&&(!s||m(t,s))&&(e.push(t),e.length>=o))break}return e}export function resolveSession(t){const s=t.trim().toLowerCase();if(s.length<4)throw i(n.t("sessions.id_too_short",{id:t}),n.t("sessions.list_hint",{cli:r}));const o=new Set,e=[];for(const t of a()){if(!t.adapter.sessions.format.idFromFile(t.file).toLowerCase().startsWith(s))continue;const n=f(t);n&&!o.has(`${n.tool}:${n.id}`)&&(o.add(`${n.tool}:${n.id}`),e.push(n))}if(0===e.length)throw i(n.t("sessions.not_found",{id:t}),n.t("sessions.list_hint",{cli:r}));if(e.length>1)throw i(n.t("sessions.ambiguous",{id:t,ids:e.map(t=>`${t.id} (${t.toolName})`).join(", ")}),n.t("sessions.ambiguous_hint"));return e[0]}export function readSession(t,s={}){const o=l(t.tool)[0]?.sessions;return o?o.format.read(t.file,s):[]}export function resumeCommand(t){const s=l(t.tool)[0]?.sessions.resumeCommand;return s?{...s(t.id),cwd:t.cwd}:null}export function resumeLine(t){const s=t=>/^[\w@%+=:,./-]+$/.test(t)?t:`'${t.replace(/'/g,"'\\''")}'`,o=[t.command,...t.args].map(s).join(" ");return t.cwd?"win32"===process.platform?`cd ${s(t.cwd)}; ${o}`:`cd ${s(t.cwd)} && ${o}`:o}const p={user:"sessions.role.user",assistant:"sessions.role.assistant",tool:"sessions.role.tool"};export function roleLabel(t){return n.t(p[t])}export function sessionMarkdown(t,s){const o=[`- ${n.t("sessions.field.tool")}: ${t.toolName}`,`- ${n.t("sessions.field.id")}: ${t.id}`,t.startedAt?`- ${n.t("sessions.field.started")}: ${t.startedAt}`:"",`- ${n.t("sessions.field.updated")}: ${t.updatedAt}`,t.cwd?`- ${n.t("sessions.field.cwd")}: \`${t.cwd}\``:"",t.provider?`- ${n.t("sessions.field.provider")}: ${t.provider}`:""].filter(Boolean),e=s.map(t=>{const s="tool"===t.role&&t.text.startsWith("[")&&t.text.includes("\n")?"```\n"+t.text+"\n```":t.text;return`## ${roleLabel(t.role)}\n\n${s}`});return[`# ${t.title||t.id}`,o.join("\n"),...e].join("\n\n")+"\n"}