@xhscopy-ai/cli 0.0.140 → 0.0.142
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.
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"claude": [
|
|
11
11
|
{
|
|
12
12
|
"description": "100 万上下文 | 高强度推理 | 长时 Agent | SWE-bench Verified 95%",
|
|
13
|
-
"group": "
|
|
13
|
+
"group": "grp_6eg2dq9ywgrg",
|
|
14
14
|
"group_name": "",
|
|
15
15
|
"hidden": false,
|
|
16
16
|
"id": "claude-fable-5",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"description": "100 万上下文 | 12.8 万输出 | 自适应思考常开 | 长时 Agent 与多步研究",
|
|
22
|
-
"group": "
|
|
22
|
+
"group": "grp_6eg2dq9ywgrg",
|
|
23
23
|
"group_name": "",
|
|
24
24
|
"hidden": false,
|
|
25
25
|
"id": "claude-fable-5-1",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
"description": "100 万上下文 | 12.8 万输出 | 低延迟 | 高频轻量任务",
|
|
40
|
-
"group": "
|
|
40
|
+
"group": "grp_rld6af0zorqd",
|
|
41
41
|
"group_name": "",
|
|
42
42
|
"hidden": false,
|
|
43
43
|
"id": "claude-haiku-5-5",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
57
|
"description": "100 万上下文 | 推理 | 编程 | 长上下文不加价",
|
|
58
|
-
"group": "
|
|
58
|
+
"group": "grp_6co8aqwefsoh",
|
|
59
59
|
"group_name": "",
|
|
60
60
|
"hidden": false,
|
|
61
61
|
"id": "claude-opus-4-7",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
"description": "100 万上下文 | 推理 | 编程 | 长上下文不加价",
|
|
67
|
-
"group": "
|
|
67
|
+
"group": "grp_6eg2dq9ywgrg",
|
|
68
68
|
"group_name": "",
|
|
69
69
|
"hidden": false,
|
|
70
70
|
"id": "claude-opus-4-8",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"description": "100 万上下文 | Agent 编程 | 长上下文不加价",
|
|
94
|
-
"group": "
|
|
94
|
+
"group": "grp_6eg2dq9ywgrg",
|
|
95
95
|
"group_name": "",
|
|
96
96
|
"hidden": false,
|
|
97
97
|
"id": "claude-sonnet-4-6",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
102
|
"description": "100 万上下文 | Agent 编程 | 工具调用 | 知识工作",
|
|
103
|
-
"group": "
|
|
103
|
+
"group": "grp_6eg2dq9ywgrg",
|
|
104
104
|
"group_name": "",
|
|
105
105
|
"hidden": false,
|
|
106
106
|
"id": "claude-sonnet-5",
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
},
|
|
139
139
|
{
|
|
140
140
|
"description": "105 万上下文 | 12.8 万输出 | 均衡生产档",
|
|
141
|
-
"group": "
|
|
141
|
+
"group": "grp_irydsgijuckh",
|
|
142
142
|
"group_name": "",
|
|
143
143
|
"hidden": false,
|
|
144
144
|
"id": "gpt-5.6-terra",
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
},
|
|
148
148
|
{
|
|
149
149
|
"description": "105 万上下文 | 12.8 万输出 | 思考强度至 max | 计算机操作 / 编码 / 科学基准接近饱和",
|
|
150
|
-
"group": "
|
|
150
|
+
"group": "grp_6co8aqwefsoh",
|
|
151
151
|
"group_name": "",
|
|
152
152
|
"hidden": false,
|
|
153
153
|
"id": "gpt-6-astra",
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
},
|
|
157
157
|
{
|
|
158
158
|
"description": "转发至 gpt-6-sol | 实际由 gpt-6-sol 响应 | 105 万上下文 | 12.8 万输出",
|
|
159
|
-
"group": "
|
|
159
|
+
"group": "grp_mb5v069lpnze",
|
|
160
160
|
"group_name": "",
|
|
161
161
|
"hidden": false,
|
|
162
162
|
"id": "gpt-6-luna",
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
},
|
|
175
175
|
{
|
|
176
176
|
"description": "105 万上下文 | 12.8 万输出 | 文字与图像输入 | 工具调用、联网搜索、结构化输出 | 工具调用使用 Responses API",
|
|
177
|
-
"group": "
|
|
177
|
+
"group": "grp_irydsgijuckh",
|
|
178
178
|
"group_name": "",
|
|
179
179
|
"hidden": false,
|
|
180
180
|
"id": "gpt-6.1-sol",
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
},
|
|
184
184
|
{
|
|
185
185
|
"description": "105 万上下文 | 12.8 万输出 | 计算机操作与日常 Agent 任务 | 均衡档",
|
|
186
|
-
"group": "
|
|
186
|
+
"group": "grp_6co8aqwefsoh",
|
|
187
187
|
"group_name": "",
|
|
188
188
|
"hidden": false,
|
|
189
189
|
"id": "gpt-6.1-terra",
|
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
"gemini": [
|
|
195
195
|
{
|
|
196
196
|
"description": "高吞吐 | 低延迟 | 大批量",
|
|
197
|
-
"group": "
|
|
197
|
+
"group": "grp_z5khwusxuh2j",
|
|
198
198
|
"group_name": "",
|
|
199
199
|
"hidden": false,
|
|
200
200
|
"id": "gemini-3-flash",
|
|
@@ -239,7 +239,7 @@
|
|
|
239
239
|
},
|
|
240
240
|
{
|
|
241
241
|
"description": "高吞吐 | 低成本 | 大批量常规任务",
|
|
242
|
-
"group": "
|
|
242
|
+
"group": "grp_z5khwusxuh2j",
|
|
243
243
|
"group_name": "",
|
|
244
244
|
"hidden": false,
|
|
245
245
|
"id": "gemini-3.5-flash",
|
|
@@ -266,7 +266,7 @@
|
|
|
266
266
|
},
|
|
267
267
|
{
|
|
268
268
|
"description": "推理与编码 | HLE-Verified 54.9% | 长文档工作流",
|
|
269
|
-
"group": "
|
|
269
|
+
"group": "grp_3pi5kyqkp51b",
|
|
270
270
|
"group_name": "",
|
|
271
271
|
"hidden": false,
|
|
272
272
|
"id": "gemini-3.8-flash",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"claude": [
|
|
11
11
|
{
|
|
12
12
|
"description": "100 万上下文 | 高强度推理 | 长时 Agent | SWE-bench Verified 95%",
|
|
13
|
-
"group": "
|
|
13
|
+
"group": "grp_6eg2dq9ywgrg",
|
|
14
14
|
"group_name": "",
|
|
15
15
|
"hidden": false,
|
|
16
16
|
"id": "claude-fable-5",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"description": "100 万上下文 | 12.8 万输出 | 自适应思考常开 | 长时 Agent 与多步研究",
|
|
22
|
-
"group": "
|
|
22
|
+
"group": "grp_6eg2dq9ywgrg",
|
|
23
23
|
"group_name": "",
|
|
24
24
|
"hidden": false,
|
|
25
25
|
"id": "claude-fable-5-1",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
"description": "100 万上下文 | 12.8 万输出 | 低延迟 | 高频轻量任务",
|
|
40
|
-
"group": "
|
|
40
|
+
"group": "grp_rld6af0zorqd",
|
|
41
41
|
"group_name": "",
|
|
42
42
|
"hidden": false,
|
|
43
43
|
"id": "claude-haiku-5-5",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
57
|
"description": "100 万上下文 | 推理 | 编程 | 长上下文不加价",
|
|
58
|
-
"group": "
|
|
58
|
+
"group": "grp_6co8aqwefsoh",
|
|
59
59
|
"group_name": "",
|
|
60
60
|
"hidden": false,
|
|
61
61
|
"id": "claude-opus-4-7",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
"description": "100 万上下文 | 推理 | 编程 | 长上下文不加价",
|
|
67
|
-
"group": "
|
|
67
|
+
"group": "grp_6eg2dq9ywgrg",
|
|
68
68
|
"group_name": "",
|
|
69
69
|
"hidden": false,
|
|
70
70
|
"id": "claude-opus-4-8",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"description": "100 万上下文 | Agent 编程 | 长上下文不加价",
|
|
94
|
-
"group": "
|
|
94
|
+
"group": "grp_6eg2dq9ywgrg",
|
|
95
95
|
"group_name": "",
|
|
96
96
|
"hidden": false,
|
|
97
97
|
"id": "claude-sonnet-4-6",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
102
|
"description": "100 万上下文 | Agent 编程 | 工具调用 | 知识工作",
|
|
103
|
-
"group": "
|
|
103
|
+
"group": "grp_6eg2dq9ywgrg",
|
|
104
104
|
"group_name": "",
|
|
105
105
|
"hidden": false,
|
|
106
106
|
"id": "claude-sonnet-5",
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
},
|
|
139
139
|
{
|
|
140
140
|
"description": "105 万上下文 | 12.8 万输出 | 均衡生产档",
|
|
141
|
-
"group": "
|
|
141
|
+
"group": "grp_irydsgijuckh",
|
|
142
142
|
"group_name": "",
|
|
143
143
|
"hidden": false,
|
|
144
144
|
"id": "gpt-5.6-terra",
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
},
|
|
148
148
|
{
|
|
149
149
|
"description": "105 万上下文 | 12.8 万输出 | 思考强度至 max | 计算机操作 / 编码 / 科学基准接近饱和",
|
|
150
|
-
"group": "
|
|
150
|
+
"group": "grp_6co8aqwefsoh",
|
|
151
151
|
"group_name": "",
|
|
152
152
|
"hidden": false,
|
|
153
153
|
"id": "gpt-6-astra",
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
},
|
|
157
157
|
{
|
|
158
158
|
"description": "转发至 gpt-6-sol | 实际由 gpt-6-sol 响应 | 105 万上下文 | 12.8 万输出",
|
|
159
|
-
"group": "
|
|
159
|
+
"group": "grp_mb5v069lpnze",
|
|
160
160
|
"group_name": "",
|
|
161
161
|
"hidden": false,
|
|
162
162
|
"id": "gpt-6-luna",
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
},
|
|
175
175
|
{
|
|
176
176
|
"description": "105 万上下文 | 12.8 万输出 | 文字与图像输入 | 工具调用、联网搜索、结构化输出 | 工具调用使用 Responses API",
|
|
177
|
-
"group": "
|
|
177
|
+
"group": "grp_irydsgijuckh",
|
|
178
178
|
"group_name": "",
|
|
179
179
|
"hidden": false,
|
|
180
180
|
"id": "gpt-6.1-sol",
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
},
|
|
184
184
|
{
|
|
185
185
|
"description": "105 万上下文 | 12.8 万输出 | 计算机操作与日常 Agent 任务 | 均衡档",
|
|
186
|
-
"group": "
|
|
186
|
+
"group": "grp_6co8aqwefsoh",
|
|
187
187
|
"group_name": "",
|
|
188
188
|
"hidden": false,
|
|
189
189
|
"id": "gpt-6.1-terra",
|
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
"gemini": [
|
|
195
195
|
{
|
|
196
196
|
"description": "高吞吐 | 低延迟 | 大批量",
|
|
197
|
-
"group": "
|
|
197
|
+
"group": "grp_z5khwusxuh2j",
|
|
198
198
|
"group_name": "",
|
|
199
199
|
"hidden": false,
|
|
200
200
|
"id": "gemini-3-flash",
|
|
@@ -239,7 +239,7 @@
|
|
|
239
239
|
},
|
|
240
240
|
{
|
|
241
241
|
"description": "高吞吐 | 低成本 | 大批量常规任务",
|
|
242
|
-
"group": "
|
|
242
|
+
"group": "grp_z5khwusxuh2j",
|
|
243
243
|
"group_name": "",
|
|
244
244
|
"hidden": false,
|
|
245
245
|
"id": "gemini-3.5-flash",
|
|
@@ -266,7 +266,7 @@
|
|
|
266
266
|
},
|
|
267
267
|
{
|
|
268
268
|
"description": "推理与编码 | HLE-Verified 54.9% | 长文档工作流",
|
|
269
|
-
"group": "
|
|
269
|
+
"group": "grp_3pi5kyqkp51b",
|
|
270
270
|
"group_name": "",
|
|
271
271
|
"hidden": false,
|
|
272
272
|
"id": "gemini-3.8-flash",
|
package/dist/lib/auto-update.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{chmodSync as e,copyFileSync as t,existsSync as r,lstatSync as
|
|
1
|
+
import{chmodSync as e,copyFileSync as t,existsSync as r,lstatSync as o,mkdirSync as n,readdirSync as s,readFileSync as a,readlinkSync as i,renameSync as l,rmSync as c,symlinkSync as u,writeFileSync as p}from"fs";import{homedir as d}from"os";import{basename as m,dirname as f,join as h,sep as _}from"path";import{spawnSync as g}from"child_process";import y from"chalk";import{checkForUpdate as v,readLocalPackage as x,UPDATE_SOURCES as w}from"../commands/update.js";import{i18n as k}from"./i18n.js";import{isColorEnabled as S}from"./runtime-options.js";import{logger as b}from"../utils/logger.js";import{isHelpRequest as $}from"./cli-help.js";import{brand as E,brandEnvName as P}from"./brand.js";import{flushTelemetry as I,track as j}from"./telemetry.js";export const INSTALL_RETRY_INTERVAL_MS=36e5;export const INSTALL_TIMEOUT_MS=45e3;function A(e,t){return S()?e(t):t}export function resolveUpdateCachePath(e=process.env){const t=e[P("CONFIG_DIR")]?.trim();if(t)return h(t,"update-state.json");const r=e[P("TEST_HOME")]?.trim();return h(r||d(),E().configDirName,"update-state.json")}export function isGlobalPackageInstall(e){return e.split(_).includes("node_modules")}export function isNpxExecution(e=process.env){return"exec"===e.npm_command||"npx"===e.npm_lifecycle_event}export function isPnpmGlobalInstall(e){return e.includes(`${_}.pnpm${_}`)||e.includes(`${_}pnpm${_}global${_}`)}export function resolveNpmGlobalPrefix(e){const t=`${_}node_modules${_}`,r=e.indexOf(t);if(r<0)return null;const o=e.slice(0,r);return o.endsWith(`${_}lib`)?f(o):o}export function shouldSkipStartupUpdate(e,t=process.env){return"1"===t[P("SKIP_AUTO_UPDATE")]||"1"===t[P("DISABLE_AUTO_UPDATE")]||(!(!["--json","--non-interactive","--dry-run","--help","-h","--version","-v"].some(t=>e.includes(t))&&!$(e))||e.includes("update")||e.includes("completion"))}function N(t,r,o,s,a){try{n(f(t),{recursive:!0,mode:448});const i=`${t}.tmp-${process.pid}`,c={package_name:r,checked_at:o,latest:s.latest,source:s.source,registry:s.registry,errors:s.errors,...void 0===a?{}:{install_attempted_at:a,install_attempted_version:s.latest||void 0}};p(i,JSON.stringify(c),{encoding:"utf-8",mode:384}),l(i,t),e(t,384)}catch(e){b.warn("Failed to persist update check cache:",e)}}export function windowsShellCommand(e,t){return[e,...t.map(e=>`"${e}"`)].join(" ")}const T=(e,t)=>{const r={stdio:"inherit",timeout:45e3,killSignal:"SIGTERM"};return"win32"===process.platform?g(windowsShellCommand(e,t),{...r,shell:!0}):g(e,t,r)},U=(e,t)=>g(process.execPath,[process.argv[1],...e],{stdio:"inherit",env:t}),O="-update-";function D(e,t){for(let r=0;;r++)try{return void l(e,t)}catch(e){const t=e.code;if(r>=9||"EPERM"!==t&&"EACCES"!==t&&"EBUSY"!==t)throw e;Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,200)}}export function swapStagedPackage(e,s,l,p,d){const _=p.split("/"),g=[h(e,"node_modules",..._),h(e,"lib","node_modules",..._)].find(e=>r(h(e,"package.json")));if(!g)return!1;const y=JSON.parse(a(h(g,"package.json"),"utf-8"));if(y.version!==d)return!1;const v=h(f(l),`.${m(l)}${O}old-${process.pid}`);D(l,v);try{D(g,l)}catch(e){throw D(v,l),e}c(v,{recursive:!0,force:!0,maxRetries:3});const x="string"==typeof y.bin?[_[_.length-1]]:Object.keys(y.bin||{});for(const[r,a]of[[h(e,"bin"),h(s,"bin")],[e,s]])for(const e of x.flatMap(e=>["",".cmd",".ps1"].map(t=>e+t))){const s=h(r,e),l=h(a,e),c=o(s,{throwIfNoEntry:!1});if(!o(l,{throwIfNoEntry:!1})&&c&&!c.isDirectory())try{n(a,{recursive:!0}),c.isSymbolicLink()?u(i(s),l):t(s,l)}catch(e){b.warn("Failed to restore command shim:",e)}}return!0}export async function runStartupUpdate(e,t={}){const o=t.env||process.env,n=t.localPackage||x(),i=t.globalInstall??isGlobalPackageInstall(n.root),l=t.npx??isNpxExecution(o);if(!i||l||shouldSkipStartupUpdate(e,o))return{status:"skipped",handled:!1,source:null};const u=t.now??Date.now(),p=t.cachePath||resolveUpdateCachePath(o),d=function(e,t){try{if(!r(e))return null;const o=JSON.parse(a(e,"utf-8"));return o.package_name===t.name&&Number.isFinite(o.checked_at)?o:null}catch{return null}}(p,n);let g=function(e,t,r){if(!e||e.latest||r-e.checked_at>=6e5)return null;const o=Array.isArray(e.errors)?e.errors:[];return{current:t.version,latest:null,up_to_date:null,source:e.source,registry:e.registry,errors:o,error:o.map(e=>`${e.source}: ${e.error}`).join("; ")||"unknown"}}(d,n,u),S=null;if(g||(g=await v({localPackage:n,fetchFn:t.fetchFn}),g.latest&&d?.install_attempted_version===g.latest&&Number.isFinite(d.install_attempted_at)&&(S=d.install_attempted_at),N(p,n.name,u,g,S??void 0)),!g.latest)return{status:"unavailable",handled:!1,source:null};if(g.up_to_date)return{status:"current",handled:!1,source:g.source};if(null!==S&&u-S<36e5)return{status:"update_failed",handled:!1,source:g.source};const b=t.output||console.log,$=t.errorOutput||console.error,E=t.installRunner||T,D=isPnpmGlobalInstall(n.root),R=D?"win32"===process.platform?"pnpm.cmd":"pnpm":"win32"===process.platform?"npm.cmd":"npm",C=D?null:resolveNpmGlobalPrefix(n.root),G=n.root,F=C&&G.endsWith(_+n.name.split("/").join(_))?h(f(G),`.${m(G)}${O}${process.pid}`):null;F&&function(e,t){try{for(const r of s(e))r.startsWith(`.${t}${O}`)&&c(h(e,r),{recursive:!0,force:!0})}catch{}}(f(G),m(G)),N(p,n.name,u,g,u),b(A(y.cyan,k.t("update.auto_installing",{version:g.latest})));const L={from:n.version,to:g.latest,staged:Boolean(F)};j("self-update","start",{detail:L}),await I();const M=[...g.registry?[g.registry]:[],...w.map(e=>e.registry).filter(e=>e!==g.registry)],B=Date.now();let J=null,W="unknown",K=0;for(const e of M){if(Date.now()-B>=45e3)break;K++;const t=E(R,D?["add","--global",`${n.name}@${g.latest}`,"--registry",e]:["install","--global",...F?["--prefix",F]:C?["--prefix",C]:[],`${n.name}@${g.latest}`,"--registry",e,"--no-audit","--no-fund","--fetch-timeout=15000","--fetch-retries=1","--fetch-retry-mintimeout=1000","--fetch-retry-maxtimeout=3000"]);if(0===t.status){if(!F){J=e;break}try{if(!swapStagedPackage(F,C,G,n.name,g.latest)){W="staged install incomplete";continue}J=e;break}catch(e){W=e instanceof Error?e.message:String(e);break}finally{c(F,{recursive:!0,force:!0,maxRetries:3})}}else W=t.error?.message||`exit ${t.status??"unknown"}`,F&&c(F,{recursive:!0,force:!0,maxRetries:3})}const Y=Date.now()-B;if(j("self-update",J?"ok":Y>=45e3?"timeout":"fail",{duration_ms:Y,...J?{}:{error:W},detail:{...L,attempts:K,registry:J}}),await I(),!J)return $(A(y.yellow,k.t("update.auto_failed",{error:W}))),{status:"update_failed",handled:!1,source:g.source};b(A(y.green,k.t("update.auto_installed",{version:g.latest})));const H=(t.reexecRunner||U)(e,{...o,[P("SKIP_AUTO_UPDATE")]:"1"});return H.error?($(A(y.yellow,k.t("update.reexec_failed",{error:H.error.message}))),{status:"update_failed",handled:!1,source:g.source}):(process.exitCode=H.status??1,{status:"reexecuted",handled:!0,source:g.source})}
|
package/dist/lib/tools/codex.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash as e}from"crypto";import{existsSync as t,mkdirSync as o,readdirSync as n,readFileSync as r,rmSync as i,statSync as s,writeFileSync as l}from"fs";import{join as a}from"path";import*as c from"@iarna/toml";import{logger as d}from"../../utils/logger.js";import{i18n as u}from"../i18n.js";import{backupBeforeWrite as m,atomicWriteFile as p}from"./backup.js";import{codexHome as f,pickModel as g,toolHome as _,withV1 as x}from"./types.js";import{moveSessionsToProvider as h,NO_STATE_DB as y,runningCodexPids as k}from"../codex-sessions.js";import{codexFormat as b,codexRolloutFiles as v}from"../sessions/formats.js";import{getToolDefaultModel as j}from"../model-registry.js";import{configManager as w}from"../config.js";import{maskHome as C,track as O}from"../telemetry.js";import{buildCodexCatalog as S,catalogRejections as M,codexCatalogPath as A,fillFromOlderEntries as E,installedCodexBinaries as N,loadBundledCodexModels as P,loadPreviousCodexModels as T,previousGatewayModelIds as D}from"./codex-catalog.js";import{gatewayModelSpecs as I,modelFamily as L}from"../gateway-models.js";import{findInstalls as $,mirrorInstallCommand as J,brandInstallScripts as G}from"./tool-installs.js";const R=()=>f(),K=()=>a(R(),"config.toml"),X="sessions_move_declined",B=["browser_use","browser_use_external","computer_use"];function W(e){const t=e.features;if(!Q(t)||!B.every(e=>!1===t[e]))return!1;for(const e of B)delete t[e];return!0}export function codexWorkModeOn(){try{const e=Z();return e.model_provider===Y&&Q(e.desktop)&&"STEPS_PROSE"===e.desktop.conversationDetailMode}catch{return!1}}function q(){try{if(Q(Z().desktop))return!0}catch{}if("darwin"===process.platform)return["/Applications",a(_(),"Applications")].some(e=>["ChatGPT.app","Codex.app"].some(o=>t(a(e,o))));if("win32"===process.platform){const e=a(process.env.LOCALAPPDATA||a(_(),"AppData","Local"),"Packages");try{return n(e).some(e=>/^OpenAI\.(Codex|ChatGPT)/i.test(e))}catch{return!1}}return t("/usr/lib/chatgpt/ChatGPT")}export function codexConfigPath(){return K()}const U=()=>a(R(),"auth.json"),z="OPENAI_API_KEY",Y="custom",F=1e6,H=9e5;export const CODEX_ONE_MILLION_CONTEXT_SETTING="one_million_context";function Q(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function V(e,t){return Q(e[t])||(e[t]={}),e[t]}function Z(){if(!t(K()))return{};const e=r(K(),"utf-8");if(!e.trim())return{};try{const t=c.parse(e);if(!Q(t))throw new Error("config.toml root must be a TOML table");return t}catch(e){throw new Error(`Existing ~/.codex/config.toml cannot be parsed; back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}}function ee(){if(!t(U()))return{};try{const e=JSON.parse(r(U(),"utf-8"));return Q(e)?e:{}}catch{return{}}}let te=null;function oe(e){const t=e.profiles;if(Q(t)){for(const[e,o]of Object.entries(t))Q(o)&&2===Object.keys(o).length&&o.model_provider===Y&&o.model===e&&delete t[e];0===Object.keys(t).length&&delete e.profiles}}let ne=null;const re=()=>a(w.getConfigDir(),"codex-catalog-check.json");function ie(e){const o=A();t(o)&&r(o,"utf-8")===e||(m(o),p(o,e))}function se(t,n){if(0===n.length)return[];const i=function(t,o){const n=e("sha256").update(t);for(const e of o)try{const t=s(e);n.update(`\0${e}\0${t.size}\0${t.mtimeMs}`)}catch{n.update(`\0${e}`)}return n.digest("hex")}(t,n);if(function(e){try{return JSON.parse(r(re(),"utf-8")).signature===e}catch{return!1}}(i))return[];const a=M(A(),n);return 0===a.length&&function(e){try{o(w.getConfigDir(),{recursive:!0}),l(re(),JSON.stringify({signature:e})+"\n")}catch(e){d.logError("codexAdapter.rememberAccepted",e)}}(i),a}function le(e,t,o){const n=!1!==t.settings?.one_million_context;!function(e){e.model_context_window===F&&delete e.model_context_window,e.model_auto_compact_token_limit===H&&delete e.model_auto_compact_token_limit}(e);const r=()=>{e.model_catalog_json===A()&&delete e.model_catalog_json,n&&(e.model_context_window=F,e.model_auto_compact_token_limit=H)},s=P()??T();if(!s)return d.logError("codexAdapter.writeModelCatalog",new Error("no Codex binary found; model catalog skipped")),ne="skipped",void r();const l=t.catalog,a=e=>S({bundled:e,specs:I("codex",l?.clientModels),...l?{keyModels:l.models}:{},gatewayAvailable:l?.models??D(),oneMillion:n,selectedModel:o,..."gateway"===l?.oneMillionSource?{claudeOneMillion:l.oneMillion}:{}}),c=e=>JSON.stringify(e,null,2)+"\n";let u=a(s);ie(c(u));const m=N(),p=se(c(u),m);if(p.length>0){const e=Date.now();let t=!1;for(const e of p){const o=P(e.bin);if(o){for(const e of[{models:E(u.models,o)},{models:E(a(o).models,o)}])if(ie(c(e)),0===se(c(e),m).length){u=e,t=!0;break}if(t)break}}if(O("codex-catalog",t?"fallback":"fail",{duration_ms:Date.now()-e,error:p[0].error,detail:{rejected_by:p.map(e=>({version:e.version,path:C(e.bin)}))}}),!t)return ne={rejectedBy:p[0]},i(A(),{force:!0}),void r()}ne={listed:u.models.filter(e=>"list"===e.visibility).map(e=>({id:String(e.slug),name:String(e.display_name??e.slug)}))},e.model_catalog_json=A()}export function codexCatalogRejection(){let e;try{e=Z()}catch{return null}return e.model_catalog_json===A()&&t(A())?M(A())[0]??null:null}export function setCodexOneMillionContext(e,t){const o=Z(),n=c.stringify(o),r="string"==typeof o.model?o.model:j("codex");le(o,{settings:{[CODEX_ONE_MILLION_CONTEXT_SETTING]:e},catalog:t},r);const i=c.stringify(o);i!==n&&(m(K()),p(K(),i))}const ae={command:"codex",npmPackage:"@openai/codex",native:{binDir:"win32"===process.platform?["AppData","Local","Programs","OpenAI","Codex","bin"]:[".local","bin"],updateArgs:["update"],updateTimeoutMs:12e4,dataDirs:[[".codex","packages","standalone"]]},mirrorScript:G("codex"),brew:"codex"};export const codexAdapter={name:"codex",displayName:"Codex",command:"codex",installCommand:J(ae),installSpec:ae,configPath:K(),sessions:{format:b,files:()=>[...v(a(f(),"sessions")),...v(a(f(),"archived_sessions"))],resumeCommand:e=>({command:"codex",args:["resume",e]})},wantsModelCatalog:!0,listedModels(){if(Z().model_catalog_json!==A())return null;try{return(JSON.parse(r(A(),"utf-8")).models??[]).filter(e=>"list"===e.visibility).map(e=>String(e.slug))}catch{return null}},refreshModelMenu(e){if(Z().model_catalog_json!==A())return;setCodexOneMillionContext(!1!==e.settings?.one_million_context,e.catalog);const t=Z();W(t)&&(m(K()),p(K(),c.stringify(t)))},async followUp(){if(Z().model_provider!==Y)return null;const e=await h(Y,{dryRun:!0}),t=Math.max(e.moved.length,e.dbRows);if(0===t)return null;const o=w.getToolSettings("codex")[X];if("number"==typeof o&&t<=o)return null;const n={count:String(t)};return k().length>0?{hint:u.t("tools.codex.sessions_hidden_running",n)}:{prompt:u.t("tools.codex.sessions_offer",n),hint:u.t("tools.codex.sessions_hidden",n),async run(){const e=await h(Y),t=[...new Set(e.moved.map(e=>e.from))].join("、")||"-",o=String(Math.max(e.moved.length,e.dbRows)),n=[{kind:"summary",text:u.t("codex_sessions.moved",{count:o,from:t,target:Y})},{kind:"summary",text:u.t("codex_sessions.backup",{dir:e.backupDir??""})}];return e.dbSkipped&&e.dbSkipped!==y&&n.push({kind:"action",text:u.t("codex_sessions.db_skipped",{reason:e.dbSkipped})}),n},decline(){w.setToolSetting("codex",X,t)}}},applyNotes(){if("skipped"===ne)return 0===$(ae).length?[]:[{kind:"action",text:u.t("tools.codex.catalog_skipped")}];if(!ne)return[];if("rejectedBy"in ne){const{bin:e,version:t}=ne.rejectedBy;return[{kind:"action",text:u.t("tools.codex.catalog_rejected",{path:e,version:t??"?"})}]}const e=new Map;for(const t of ne.listed)e.set(L(t.id),(e.get(L(t.id))??0)+1);const t=["gpt","claude","gemini","other","grok"].filter(t=>e.has(t)).map(t=>`${u.t(`tools.model_family.${t}`)} ${e.get(t)}`).join(" · ");return[{kind:"summary",text:u.t("tools.codex.catalog_written",{count:String(ne.listed.length),breakdown:t})},{kind:"detail",text:ne.listed.map(e=>e.name).join(", ")},...codexWorkModeOn()||q()?[{kind:"action",text:u.t(codexWorkModeOn()?"tools.codex.work_mode_on":"tools.codex.work_mode_hint")}]:[]]},loadPrivateConfig(e){const t=j("codex"),o=g(e.models,t),n=function(e){return/(?:^|\/)claude(?:-|$)/i.test(e)}(o)?t:o,r=x(e.baseUrl),i=Z();i.model=n,i.model_provider=Y,i.model_reasoning_effort="high",le(i,e,n);const s=V(i,"model_providers"),l=Q(s[Y])?{...s[Y]}:{};delete l.env_key;const{experimental_bearer_token:a,...d}=l;s[Y]={...d,name:"custom",wire_api:"responses",requires_openai_auth:!0,base_url:r},oe(i),V(V(i,"tui"),"model_availability_nux")[n]=4;const u=V(i,"features");u.goals=!0,u.js_repl=!1,W(i),m(K()),p(K(),c.stringify(i)),function(e){const t=e.trim();if(!t)return;const o={...ee(),auth_mode:"apikey",[z]:t};m(U()),p(U(),JSON.stringify(o,null,2)+"\n",384)}(e.apiKey)},holdsOurConfig(e){const t=ee()[z];return"string"==typeof t&&e.includes(t.trim())},unloadPrivateConfig(e){if(te=function(e){const t=ee(),o="string"==typeof t[z]?t[z].trim():"";if(!o)return Q(t.tokens)?"chatgpt":null;if(!e.includes(o))return"other_key";const{[z]:n,auth_mode:r,...s}=t;return m(U()),Q(s.tokens)?(p(U(),JSON.stringify({...s,auth_mode:"chatgpt"},null,2)+"\n",384),"chatgpt"):(i(U(),{force:!0}),"signed_out")}(e?.savedKeys??[]),!t(K()))return;let o;try{o=Z()}catch(e){return void d.logError("codexAdapter.unloadPrivateConfig",e)}const n=o.model_providers;Q(n)&&(delete n[Y],0===Object.keys(n).length&&delete o.model_providers),o.model_provider===Y&&delete o.model_provider,o.model_catalog_json===A()&&delete o.model_catalog_json,W(o),oe(o),m(K()),p(K(),c.stringify(o))},unloadNotes(){switch(te){case"chatgpt":return[{kind:"action",text:u.t("tools.codex.unload_chatgpt_restored")}];case"other_key":return[{kind:"action",text:u.t("tools.codex.unload_other_key")}];default:return[{kind:"action",text:u.t("tools.codex.unload_sign_in")}]}},detectCurrentConfig(){const e=ee()[z];return{apiKey:"string"==typeof e&&e.trim()?e.trim():null}},getConfig(){try{return Z()}catch(e){return d.logError("codexAdapter.getConfig",e),null}},backupPaths:()=>[K(),U(),A()]};export function codexAuthProblem(){try{const e=Z(),t=e.model_providers?.[Y];if(e.model_provider!==Y||!t)return null;if("string"==typeof t.experimental_bearer_token&&t.experimental_bearer_token)return"stale_bearer";const o=ee();return!0===t.requires_openai_auth&&"chatgpt"===o.auth_mode?"chatgpt_login":null}catch{return null}}
|
|
1
|
+
import{createHash as e}from"crypto";import{existsSync as t,mkdirSync as o,readdirSync as n,readFileSync as r,rmSync as i,statSync as s,writeFileSync as a}from"fs";import{join as l}from"path";import*as c from"@iarna/toml";import{logger as d}from"../../utils/logger.js";import{i18n as u}from"../i18n.js";import{backupBeforeWrite as m,atomicWriteFile as p}from"./backup.js";import{codexHome as f,pickModel as _,toolHome as g,withV1 as x}from"./types.js";import{moveSessionsToProvider as h,NO_STATE_DB as y,runningCodexPids as k}from"../codex-sessions.js";import{codexFormat as b,codexRolloutFiles as v}from"../sessions/formats.js";import{getToolDefaultModel as w}from"../model-registry.js";import{configManager as j}from"../config.js";import{maskHome as C,track as O}from"../telemetry.js";import{buildCodexCatalog as S,catalogRejections as M,codexCatalogPath as A,fillFromOlderEntries as E,installedCodexBinaries as N,loadBundledCodexModels as P,loadPreviousCodexModels as T,previousGatewayModelIds as D}from"./codex-catalog.js";import{gatewayModelSpecs as I,modelFamily as L}from"../gateway-models.js";import{findInstalls as $,mirrorInstallCommand as J,brandInstallScripts as G}from"./tool-installs.js";const R=()=>f(),K=()=>l(R(),"config.toml"),X="sessions_move_declined",B=["browser_use","browser_use_external","computer_use"];function U(e){const t=e.features;if(!Q(t)||!B.every(e=>!1===t[e]))return!1;for(const e of B)delete t[e];return!0}export function codexWorkModeOn(){try{const e=Z();return e.model_provider===Y&&Q(e.desktop)&&"STEPS_PROSE"===e.desktop.conversationDetailMode}catch{return!1}}function W(){try{if(Q(Z().desktop))return!0}catch{}if("darwin"===process.platform)return["/Applications",l(g(),"Applications")].some(e=>["ChatGPT.app","Codex.app"].some(o=>t(l(e,o))));if("win32"===process.platform){const e=l(process.env.LOCALAPPDATA||l(g(),"AppData","Local"),"Packages");try{return n(e).some(e=>/^OpenAI\.(Codex|ChatGPT)/i.test(e))}catch{return!1}}return t("/usr/lib/chatgpt/ChatGPT")}export function codexConfigPath(){return K()}const q=()=>l(R(),"auth.json"),z="OPENAI_API_KEY",Y="custom",F=1e6,H=9e5;export const CODEX_ONE_MILLION_CONTEXT_SETTING="one_million_context";function Q(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function V(e,t){return Q(e[t])||(e[t]={}),e[t]}function Z(){if(!t(K()))return{};const e=r(K(),"utf-8");if(!e.trim())return{};try{const t=c.parse(e);if(!Q(t))throw new Error("config.toml root must be a TOML table");return t}catch(e){throw new Error(`Existing ~/.codex/config.toml cannot be parsed; back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}}function ee(){if(!t(q()))return{};try{const e=JSON.parse(r(q(),"utf-8"));return Q(e)?e:{}}catch{return{}}}let te=null;function oe(e){const t=e.profiles;if(Q(t)){for(const[e,o]of Object.entries(t))Q(o)&&2===Object.keys(o).length&&o.model_provider===Y&&o.model===e&&delete t[e];0===Object.keys(t).length&&delete e.profiles}}let ne=null;const re=()=>l(j.getConfigDir(),"codex-catalog-check.json");function ie(e){const o=A();t(o)&&r(o,"utf-8")===e||(m(o),p(o,e))}function se(t,n){if(0===n.length)return[];const i=function(t,o){const n=e("sha256").update(t);for(const e of o)try{const t=s(e);n.update(`\0${e}\0${t.size}\0${t.mtimeMs}`)}catch{n.update(`\0${e}`)}return n.digest("hex")}(t,n);if(function(e){try{return JSON.parse(r(re(),"utf-8")).signature===e}catch{return!1}}(i))return[];const l=M(A(),n);return 0===l.length&&function(e){try{o(j.getConfigDir(),{recursive:!0}),a(re(),JSON.stringify({signature:e})+"\n")}catch(e){d.logError("codexAdapter.rememberAccepted",e)}}(i),l}function ae(e,t,o){const n=!1!==t.settings?.one_million_context;!function(e){e.model_context_window===F&&delete e.model_context_window,e.model_auto_compact_token_limit===H&&delete e.model_auto_compact_token_limit}(e);const r=()=>{e.model_catalog_json===A()&&delete e.model_catalog_json,n&&(e.model_context_window=F,e.model_auto_compact_token_limit=H)},s=P()??T();if(!s)return d.logError("codexAdapter.writeModelCatalog",new Error("no Codex binary found; model catalog skipped")),ne="skipped",void r();const a=t.catalog,l=e=>S({bundled:e,specs:I("codex",a?.clientModels),...a?{keyModels:a.models}:{},gatewayAvailable:a?.models??D(),oneMillion:n,selectedModel:o,..."gateway"===a?.oneMillionSource?{claudeOneMillion:a.oneMillion}:{}}),c=e=>JSON.stringify(e,null,2)+"\n";let u=l(s);ie(c(u));const m=N(),p=se(c(u),m);if(p.length>0){const e=Date.now();let t=!1;for(const e of p){const o=P(e.bin);if(o){for(const e of[{models:E(u.models,o)},{models:E(l(o).models,o)}])if(ie(c(e)),0===se(c(e),m).length){u=e,t=!0;break}if(t)break}}if(O("codex-catalog",t?"fallback":"fail",{duration_ms:Date.now()-e,error:p[0].error,detail:{rejected_by:p.map(e=>({version:e.version,path:C(e.bin)}))}}),!t)return ne={rejectedBy:p[0]},i(A(),{force:!0}),void r()}ne={listed:u.models.filter(e=>"list"===e.visibility).map(e=>({id:String(e.slug),name:String(e.display_name??e.slug)}))},e.model_catalog_json=A()}export function codexCatalogRejection(){let e;try{e=Z()}catch{return null}return e.model_catalog_json===A()&&t(A())?M(A())[0]??null:null}export function setCodexOneMillionContext(e,t){const o=Z(),n=c.stringify(o),r="string"==typeof o.model?o.model:w("codex");ae(o,{settings:{[CODEX_ONE_MILLION_CONTEXT_SETTING]:e},catalog:t},r);const i=c.stringify(o);i!==n&&(m(K()),p(K(),i))}const le={command:"codex",npmPackage:"@openai/codex",native:{binDir:"win32"===process.platform?["AppData","Local","Programs","OpenAI","Codex","bin"]:[".local","bin"],updateArgs:["update"],updateTimeoutMs:12e4,dataDirs:[[".codex","packages","standalone"]]},mirrorScript:G("codex"),brew:"codex"};export const codexAdapter={name:"codex",displayName:"Codex",command:"codex",installCommand:J(le),installSpec:le,configPath:K(),sessions:{format:b,files:()=>[...v(l(f(),"sessions")),...v(l(f(),"archived_sessions"))],resumeCommand:e=>({command:"codex",args:["resume",e]})},wantsModelCatalog:!0,listedModels(){if(Z().model_catalog_json!==A())return null;try{return(JSON.parse(r(A(),"utf-8")).models??[]).filter(e=>"list"===e.visibility).map(e=>String(e.slug))}catch{return null}},refreshModelMenu(e){if(Z().model_catalog_json!==A())return;setCodexOneMillionContext(!1!==e.settings?.one_million_context,e.catalog);const t=Z(),o=function(e,t){const o=Q(e.model_providers)?e.model_providers[Y]:void 0;return!(!Q(o)||o.base_url!==t||!0===o.supports_standalone_web_search||(o.supports_standalone_web_search=!0,0))}(t,x(e.baseUrl));(U(t)||o)&&(m(K()),p(K(),c.stringify(t)))},async followUp(){if(Z().model_provider!==Y)return null;const e=await h(Y,{dryRun:!0}),t=Math.max(e.moved.length,e.dbRows);if(0===t)return null;const o=j.getToolSettings("codex")[X];if("number"==typeof o&&t<=o)return null;const n={count:String(t)};return k().length>0?{hint:u.t("tools.codex.sessions_hidden_running",n)}:{prompt:u.t("tools.codex.sessions_offer",n),hint:u.t("tools.codex.sessions_hidden",n),async run(){const e=await h(Y),t=[...new Set(e.moved.map(e=>e.from))].join("、")||"-",o=String(Math.max(e.moved.length,e.dbRows)),n=[{kind:"summary",text:u.t("codex_sessions.moved",{count:o,from:t,target:Y})},{kind:"summary",text:u.t("codex_sessions.backup",{dir:e.backupDir??""})}];return e.dbSkipped&&e.dbSkipped!==y&&n.push({kind:"action",text:u.t("codex_sessions.db_skipped",{reason:e.dbSkipped})}),n},decline(){j.setToolSetting("codex",X,t)}}},applyNotes(){if("skipped"===ne)return 0===$(le).length?[]:[{kind:"action",text:u.t("tools.codex.catalog_skipped")}];if(!ne)return[];if("rejectedBy"in ne){const{bin:e,version:t}=ne.rejectedBy;return[{kind:"action",text:u.t("tools.codex.catalog_rejected",{path:e,version:t??"?"})}]}const e=new Map;for(const t of ne.listed)e.set(L(t.id),(e.get(L(t.id))??0)+1);const t=["gpt","claude","gemini","other","grok"].filter(t=>e.has(t)).map(t=>`${u.t(`tools.model_family.${t}`)} ${e.get(t)}`).join(" · ");return[{kind:"summary",text:u.t("tools.codex.catalog_written",{count:String(ne.listed.length),breakdown:t})},{kind:"detail",text:ne.listed.map(e=>e.name).join(", ")},...codexWorkModeOn()||W()?[{kind:"action",text:u.t(codexWorkModeOn()?"tools.codex.work_mode_on":"tools.codex.work_mode_hint")}]:[]]},loadPrivateConfig(e){const t=w("codex"),o=_(e.models,t),n=function(e){return/(?:^|\/)claude(?:-|$)/i.test(e)}(o)?t:o,r=x(e.baseUrl),i=Z();i.model=n,i.model_provider=Y,i.model_reasoning_effort="high",ae(i,e,n);const s=V(i,"model_providers"),a=Q(s[Y])?{...s[Y]}:{};delete a.env_key;const{experimental_bearer_token:l,...d}=a;s[Y]={...d,name:"custom",wire_api:"responses",requires_openai_auth:!0,supports_standalone_web_search:!0,base_url:r},oe(i),V(V(i,"tui"),"model_availability_nux")[n]=4;const u=V(i,"features");u.goals=!0,u.js_repl=!1,U(i),m(K()),p(K(),c.stringify(i)),function(e){const t=e.trim();if(!t)return;const o={...ee(),auth_mode:"apikey",[z]:t};m(q()),p(q(),JSON.stringify(o,null,2)+"\n",384)}(e.apiKey)},holdsOurConfig(e){const t=ee()[z];return"string"==typeof t&&e.includes(t.trim())},unloadPrivateConfig(e){if(te=function(e){const t=ee(),o="string"==typeof t[z]?t[z].trim():"";if(!o)return Q(t.tokens)?"chatgpt":null;if(!e.includes(o))return"other_key";const{[z]:n,auth_mode:r,...s}=t;return m(q()),Q(s.tokens)?(p(q(),JSON.stringify({...s,auth_mode:"chatgpt"},null,2)+"\n",384),"chatgpt"):(i(q(),{force:!0}),"signed_out")}(e?.savedKeys??[]),!t(K()))return;let o;try{o=Z()}catch(e){return void d.logError("codexAdapter.unloadPrivateConfig",e)}const n=o.model_providers;Q(n)&&(delete n[Y],0===Object.keys(n).length&&delete o.model_providers),o.model_provider===Y&&delete o.model_provider,o.model_catalog_json===A()&&delete o.model_catalog_json,U(o),oe(o),m(K()),p(K(),c.stringify(o))},unloadNotes(){switch(te){case"chatgpt":return[{kind:"action",text:u.t("tools.codex.unload_chatgpt_restored")}];case"other_key":return[{kind:"action",text:u.t("tools.codex.unload_other_key")}];default:return[{kind:"action",text:u.t("tools.codex.unload_sign_in")}]}},detectCurrentConfig(){const e=ee()[z];return{apiKey:"string"==typeof e&&e.trim()?e.trim():null}},getConfig(){try{return Z()}catch(e){return d.logError("codexAdapter.getConfig",e),null}},backupPaths:()=>[K(),q(),A()]};export function codexAuthProblem(){try{const e=Z(),t=e.model_providers?.[Y];if(e.model_provider!==Y||!t)return null;if("string"==typeof t.experimental_bearer_token&&t.experimental_bearer_token)return"stale_bearer";const o=ee();return!0===t.requires_openai_auth&&"chatgpt"===o.auth_mode?"chatgpt_login":null}catch{return null}}
|