@marsapi/cli 0.0.156 → 0.0.157

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.
@@ -28,7 +28,7 @@
28
28
  },
29
29
  {
30
30
  "description": "轻量档 | 低延迟 | 高频短任务",
31
- "group": "grp_6eg2dq9ywgrg",
31
+ "group": "grp_irydsgijuckh",
32
32
  "group_name": "",
33
33
  "hidden": false,
34
34
  "id": "claude-haiku-4-5-20251001",
@@ -46,7 +46,7 @@
46
46
  },
47
47
  {
48
48
  "description": "100 万上下文 | 推理 | 编程 | 长上下文不加价",
49
- "group": "grp_rld6af0zorqd",
49
+ "group": "grp_6eg2dq9ywgrg",
50
50
  "group_name": "",
51
51
  "hidden": false,
52
52
  "id": "claude-opus-4-6",
@@ -55,7 +55,7 @@
55
55
  },
56
56
  {
57
57
  "description": "100 万上下文 | 推理 | 编程 | 长上下文不加价",
58
- "group": "grp_pzxnceygmqlp",
58
+ "group": "grp_irydsgijuckh",
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": "grp_6lyxfgbs440g",
67
+ "group": "grp_irydsgijuckh",
68
68
  "group_name": "",
69
69
  "hidden": false,
70
70
  "id": "claude-opus-4-8",
@@ -82,7 +82,7 @@
82
82
  },
83
83
  {
84
84
  "description": "100 万上下文 | 长时 Agent 编程 | 知识工作",
85
- "group": "grp_6eg2dq9ywgrg",
85
+ "group": "grp_6co8aqwefsoh",
86
86
  "group_name": "",
87
87
  "hidden": false,
88
88
  "id": "claude-opus-5-5",
@@ -91,7 +91,7 @@
91
91
  },
92
92
  {
93
93
  "description": "100 万上下文 | Agent 编程 | 长上下文不加价",
94
- "group": "grp_pzxnceygmqlp",
94
+ "group": "grp_rld6af0zorqd",
95
95
  "group_name": "",
96
96
  "hidden": false,
97
97
  "id": "claude-sonnet-4-6",
@@ -109,7 +109,7 @@
109
109
  },
110
110
  {
111
111
  "description": "100 万上下文 | 12.8 万输出 | Agent 编程 | 知识工作",
112
- "group": "grp_6eg2dq9ywgrg",
112
+ "group": "grp_irydsgijuckh",
113
113
  "group_name": "",
114
114
  "hidden": false,
115
115
  "id": "claude-sonnet-5-5",
@@ -129,7 +129,7 @@
129
129
  },
130
130
  {
131
131
  "description": "105 万上下文 | 12.8 万输出 | 前沿档",
132
- "group": "grp_irydsgijuckh",
132
+ "group": "grp_mb5v069lpnze",
133
133
  "group_name": "",
134
134
  "hidden": false,
135
135
  "id": "gpt-5.6-sol",
@@ -138,7 +138,7 @@
138
138
  },
139
139
  {
140
140
  "description": "105 万上下文 | 12.8 万输出 | 均衡生产档",
141
- "group": "grp_6co8aqwefsoh",
141
+ "group": "grp_squ2qzjnehps",
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": "grp_mb5v069lpnze",
150
+ "group": "grp_irydsgijuckh",
151
151
  "group_name": "",
152
152
  "hidden": false,
153
153
  "id": "gpt-6-astra",
@@ -165,7 +165,7 @@
165
165
  },
166
166
  {
167
167
  "description": "105 万上下文 | 12.8 万输出 | 复杂编程与 Agent 工作流",
168
- "group": "grp_squ2qzjnehps",
168
+ "group": "grp_irydsgijuckh",
169
169
  "group_name": "",
170
170
  "hidden": false,
171
171
  "id": "gpt-6-sol",
@@ -174,7 +174,7 @@
174
174
  },
175
175
  {
176
176
  "description": "105 万上下文 | 12.8 万输出 | 文字与图像输入 | 工具调用、联网搜索、结构化输出 | 工具调用使用 Responses API",
177
- "group": "grp_squ2qzjnehps",
177
+ "group": "grp_6co8aqwefsoh",
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": "grp_6co8aqwefsoh",
186
+ "group": "grp_irydsgijuckh",
187
187
  "group_name": "",
188
188
  "hidden": false,
189
189
  "id": "gpt-6.1-terra",
@@ -248,7 +248,7 @@
248
248
  },
249
249
  {
250
250
  "description": "约 208 token/秒 | 高吞吐 | 多语言 | 编码",
251
- "group": "grp_3pi5kyqkp51b",
251
+ "group": "grp_irydsgijuckh",
252
252
  "group_name": "",
253
253
  "hidden": false,
254
254
  "id": "gemini-3.6-flash",
@@ -257,7 +257,7 @@
257
257
  },
258
258
  {
259
259
  "description": "Agent 主力 | 软件工程 | 网页开发",
260
- "group": "grp_3pi5kyqkp51b",
260
+ "group": "grp_z5khwusxuh2j",
261
261
  "group_name": "",
262
262
  "hidden": false,
263
263
  "id": "gemini-3.7-flash",
@@ -266,7 +266,7 @@
266
266
  },
267
267
  {
268
268
  "description": "推理与编码 | HLE-Verified 54.9% | 长文档工作流",
269
- "group": "grp_3pi5kyqkp51b",
269
+ "group": "grp_z5khwusxuh2j",
270
270
  "group_name": "",
271
271
  "hidden": false,
272
272
  "id": "gemini-3.8-flash",
package/dist/brand.json CHANGED
@@ -10,7 +10,7 @@
10
10
  ],
11
11
  "id": "mars-ai",
12
12
  "installMirror": {
13
- "agy": "https://cnb.cool/lib/agy/-/releases/latest/download",
13
+ "agy": "https://cnb.cool/lib/mirrors/-/releases/download/agy",
14
14
  "scripts": "https://cnb.cool/lib/install/-/git/raw/main"
15
15
  },
16
16
  "links": {
@@ -28,7 +28,7 @@
28
28
  },
29
29
  {
30
30
  "description": "轻量档 | 低延迟 | 高频短任务",
31
- "group": "grp_6eg2dq9ywgrg",
31
+ "group": "grp_irydsgijuckh",
32
32
  "group_name": "",
33
33
  "hidden": false,
34
34
  "id": "claude-haiku-4-5-20251001",
@@ -46,7 +46,7 @@
46
46
  },
47
47
  {
48
48
  "description": "100 万上下文 | 推理 | 编程 | 长上下文不加价",
49
- "group": "grp_rld6af0zorqd",
49
+ "group": "grp_6eg2dq9ywgrg",
50
50
  "group_name": "",
51
51
  "hidden": false,
52
52
  "id": "claude-opus-4-6",
@@ -55,7 +55,7 @@
55
55
  },
56
56
  {
57
57
  "description": "100 万上下文 | 推理 | 编程 | 长上下文不加价",
58
- "group": "grp_pzxnceygmqlp",
58
+ "group": "grp_irydsgijuckh",
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": "grp_6lyxfgbs440g",
67
+ "group": "grp_irydsgijuckh",
68
68
  "group_name": "",
69
69
  "hidden": false,
70
70
  "id": "claude-opus-4-8",
@@ -82,7 +82,7 @@
82
82
  },
83
83
  {
84
84
  "description": "100 万上下文 | 长时 Agent 编程 | 知识工作",
85
- "group": "grp_6eg2dq9ywgrg",
85
+ "group": "grp_6co8aqwefsoh",
86
86
  "group_name": "",
87
87
  "hidden": false,
88
88
  "id": "claude-opus-5-5",
@@ -91,7 +91,7 @@
91
91
  },
92
92
  {
93
93
  "description": "100 万上下文 | Agent 编程 | 长上下文不加价",
94
- "group": "grp_pzxnceygmqlp",
94
+ "group": "grp_rld6af0zorqd",
95
95
  "group_name": "",
96
96
  "hidden": false,
97
97
  "id": "claude-sonnet-4-6",
@@ -109,7 +109,7 @@
109
109
  },
110
110
  {
111
111
  "description": "100 万上下文 | 12.8 万输出 | Agent 编程 | 知识工作",
112
- "group": "grp_6eg2dq9ywgrg",
112
+ "group": "grp_irydsgijuckh",
113
113
  "group_name": "",
114
114
  "hidden": false,
115
115
  "id": "claude-sonnet-5-5",
@@ -129,7 +129,7 @@
129
129
  },
130
130
  {
131
131
  "description": "105 万上下文 | 12.8 万输出 | 前沿档",
132
- "group": "grp_irydsgijuckh",
132
+ "group": "grp_mb5v069lpnze",
133
133
  "group_name": "",
134
134
  "hidden": false,
135
135
  "id": "gpt-5.6-sol",
@@ -138,7 +138,7 @@
138
138
  },
139
139
  {
140
140
  "description": "105 万上下文 | 12.8 万输出 | 均衡生产档",
141
- "group": "grp_6co8aqwefsoh",
141
+ "group": "grp_squ2qzjnehps",
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": "grp_mb5v069lpnze",
150
+ "group": "grp_irydsgijuckh",
151
151
  "group_name": "",
152
152
  "hidden": false,
153
153
  "id": "gpt-6-astra",
@@ -165,7 +165,7 @@
165
165
  },
166
166
  {
167
167
  "description": "105 万上下文 | 12.8 万输出 | 复杂编程与 Agent 工作流",
168
- "group": "grp_squ2qzjnehps",
168
+ "group": "grp_irydsgijuckh",
169
169
  "group_name": "",
170
170
  "hidden": false,
171
171
  "id": "gpt-6-sol",
@@ -174,7 +174,7 @@
174
174
  },
175
175
  {
176
176
  "description": "105 万上下文 | 12.8 万输出 | 文字与图像输入 | 工具调用、联网搜索、结构化输出 | 工具调用使用 Responses API",
177
- "group": "grp_squ2qzjnehps",
177
+ "group": "grp_6co8aqwefsoh",
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": "grp_6co8aqwefsoh",
186
+ "group": "grp_irydsgijuckh",
187
187
  "group_name": "",
188
188
  "hidden": false,
189
189
  "id": "gpt-6.1-terra",
@@ -248,7 +248,7 @@
248
248
  },
249
249
  {
250
250
  "description": "约 208 token/秒 | 高吞吐 | 多语言 | 编码",
251
- "group": "grp_3pi5kyqkp51b",
251
+ "group": "grp_irydsgijuckh",
252
252
  "group_name": "",
253
253
  "hidden": false,
254
254
  "id": "gemini-3.6-flash",
@@ -257,7 +257,7 @@
257
257
  },
258
258
  {
259
259
  "description": "Agent 主力 | 软件工程 | 网页开发",
260
- "group": "grp_3pi5kyqkp51b",
260
+ "group": "grp_z5khwusxuh2j",
261
261
  "group_name": "",
262
262
  "hidden": false,
263
263
  "id": "gemini-3.7-flash",
@@ -266,7 +266,7 @@
266
266
  },
267
267
  {
268
268
  "description": "推理与编码 | HLE-Verified 54.9% | 长文档工作流",
269
- "group": "grp_3pi5kyqkp51b",
269
+ "group": "grp_z5khwusxuh2j",
270
270
  "group_name": "",
271
271
  "hidden": false,
272
272
  "id": "gemini-3.8-flash",
@@ -1 +1 @@
1
- const e=/\/-\/releases\/latest$/;export function mirrorFileUrl(r,t,l){const s=r.replace(/\/+$/,"");if(e.test(s)){const r=s.replace(e,"");return l?`${r}/-/releases/download/${l}/${t}`:`${r}/-/releases/latest/download/${t}`}return`${s}/${t}`}export function mirrorPageUrl(e){const r=e.replace(/\/+$/,""),t=/^(.*\/-\/releases)\/download\/([^/]+)$/.exec(r);return t?`${t[1]}/tag/${t[2]}`:r.replace(/\/-\/releases\/latest\/download$/,"/-/releases/latest")}
1
+ const e=/\/-\/releases\/latest$/;export function mirrorFileUrl(t,r,o){const l=t.replace(/\/+$/,"");if(e.test(l)){const t=l.replace(e,"");return o?`${t}/-/releases/download/${o}/${r}`:`${t}/-/releases/latest/download/${r}`}return`${l}/${r}`}export function mirrorPageUrl(e){const t=e.replace(/\/+$/,""),r=/^(.*\/-\/releases)\/download\/([^/]+)$/.exec(t);return r?`${r[1]}/tag/${r[2]}`:t.replace(/\/-\/releases\/latest\/download$/,"/-/releases/latest")}const t=/^\/[^?#]+\/-\/releases\/(?:latest\/download|download\/[^/]+)\/[^/]+$/;export function downloadUrls(e,r){if(!r||!e.startsWith("https://cnb.cool/"))return[e];const o=e.slice(16);return t.test(o)?[`${r.replace(/\/+$/,"")}${o}`,e]:[e]}export async function withDownloadFallback(e,t,r){const o=downloadUrls(e,t);for(const e of o.slice(0,-1))try{return await r(e)}catch{}return r(o[o.length-1])}
@@ -1 +1 @@
1
- import{execFileSync as e}from"child_process";import{createHash as r}from"crypto";import{createReadStream as t,createWriteStream as s,existsSync as o,readdirSync as i,readFileSync as n}from"fs";import{copyFile as a,mkdir as l,readFile as c,rename as u,rm as f,writeFile as p}from"fs/promises";import{isAbsolute as d,join as m,normalize as h,sep as w}from"path";import{Readable as g,Writable as b}from"stream";import{pipeline as D}from"stream/promises";import*as v from"zlib";import{logger as y}from"../../utils/logger.js";import{brandEnv as k}from"../brand.js";import{downloadNativeBinary as $,nativeLayout as C,nativePlatformKey as x}from"./claude-native-mirror.js";import{WINDOWS_PACKAGE_FAMILIES as N}from"./desktop-process.js";import{toolHome as A}from"./types.js";import{mirrorFileUrl as P}from"../mirror-url.js";import{powerShellEnv as L}from"../powershell-env.js";export function readDesktopCliPin(e,r,t=!1){const s=e.indexOf('claude-code-releases","sdkWrapperVersion"');if(s<0)return null;const o=e.lastIndexOf("JSON.parse('",s),i=e.indexOf("')",s);if(o<0||i<0)return null;try{const s=JSON.parse(e.subarray(o+12,i).toString("utf-8")),n="string"==typeof s.version?s.version:"",a=s.manifest?.platforms?.[r],l=t?a?.bundle?.checksum:a?.checksum;return/^\d+\.\d+\.\d+$/.test(n)&&"string"==typeof l&&/^[0-9a-f]{64}$/.test(l)?{version:n,checksum:l}:null}catch{return null}}function O(){const r=m(process.env.LOCALAPPDATA||"","AnthropicClaude");if(process.env.LOCALAPPDATA&&o(r)){const e=i(r).filter(e=>/^app-\d+\.\d+\.\d+$/.test(e)).sort((e,r)=>r.localeCompare(e,void 0,{numeric:!0}));for(const t of e){const e=m(r,t,"resources","app.asar");if(o(e))return e}}try{const r=e("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${N.map(e=>`'${e}'`).join(",")}) -contains $_.PackageFamilyName } | ForEach-Object { $_.InstallLocation }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"],env:L()});for(const e of r.split(/\r?\n/).map(e=>e.trim()).filter(Boolean)){const r=m(e,"app","resources","app.asar");if(o(r))return r}}catch(e){y.logError("claude-desktop-cli.windowsAsarPath",e)}return null}function E(){if(k("TEST_HOME")?.trim())return null;for(const e of["/usr/lib/claude-desktop","/opt/Claude"]){const r=m(e,"resources","app.asar");if(o(r))return r}return null}function j(){for(const e of["/Applications/Claude.app",m(A(),"Applications","Claude.app")]){const r=m(e,"Contents","Resources","app.asar");if(o(r))return r}return null}export function installedDesktopAsarPath(){return"win32"===process.platform?O():"darwin"===process.platform?j():"linux"===process.platform?E():null}class S extends b{dest;buffer=Buffer.alloc(0);remaining=0;padding=0;file=null;longName=null;collectingLongName=null;constructor(e){super(),this.dest=e}_write(e,r,t){this.buffer=this.buffer.length?Buffer.concat([this.buffer,e]):e,this.drain().then(()=>t()).catch(t)}_final(e){this.remaining>0?e(new Error("archive ends inside an entry")):e()}target(e){const r=h(e);if(!r||d(r)||".."===r||r.startsWith(`..${w}`))throw new Error(`unsafe path in archive: ${e}`);return m(this.dest,r)}async closeFile(){const e=this.file;this.file=null,e&&await new Promise((r,t)=>e.end(e=>e?t(e):r()))}async drain(){for(;;){if(this.remaining>0){if(0===this.buffer.length)return;const e=this.buffer.subarray(0,Math.min(this.remaining,this.buffer.length));this.buffer=this.buffer.subarray(e.length),this.remaining-=e.length,this.collectingLongName?this.collectingLongName.push(e):this.file&&!this.file.write(e)&&await new Promise(e=>this.file.once("drain",()=>e())),0===this.remaining&&(this.collectingLongName&&(this.longName=Buffer.concat(this.collectingLongName).toString("utf-8").replace(/\0.*$/s,""),this.collectingLongName=null),await this.closeFile());continue}if(this.padding>0){if(this.buffer.length<this.padding)return;this.buffer=this.buffer.subarray(this.padding),this.padding=0}if(this.buffer.length<512)return;const e=this.buffer.subarray(0,512);if(this.buffer=this.buffer.subarray(512),e.every(e=>0===e))continue;const r=(r,t)=>e.subarray(r,r+t).toString("utf-8").replace(/\0.*$/s,""),t=r(345,155);let o=t?`${t}/${r(0,100)}`:r(0,100);null!==this.longName&&(o=this.longName,this.longName=null);const i=parseInt(r(124,12).trim()||"0",8),n=511&parseInt(r(100,8).trim()||"644",8),a=r(156,1)||"0";if(this.remaining=i,this.padding=(512-i%512)%512,"L"===a)this.collectingLongName=[];else if("x"===a||"g"===a);else if("5"===a)await l(this.target(o),{recursive:!0});else{if("0"!==a)throw new Error(`unexpected entry type ${a} in archive: ${o}`);{const e=this.target(o);await l(m(e,".."),{recursive:!0}),this.file=s(e,{mode:n||420}),0===i&&await this.closeFile()}}}}}export async function installDesktopCli(e){const s=readDesktopCliPin(e.asar,e.platformKey,e.bundle);if(!s)return{status:"skipped",reason:"unknown app layout"};if(e.bundle&&!e.download)return{status:"skipped",reason:"no bundle mirror"};const i=e.platformKey.startsWith("win32")?"claude.exe":"claude",n=m(e.userDataDir,"claude-code",s.version),d=m(n,s.checksum.slice(0,12)),h=e.bundle?m(d,"claude.app","Contents","MacOS","claude"):m(d,i),w=m(d,".verified");try{if(o(h)&&(await c(w,"utf-8")).trim()===s.checksum)return{status:"present",version:s.version}}catch{}await l(n,{recursive:!0});const g=m(n,`.partial-${s.checksum.slice(0,12)}`),y=`${g}.download`;try{await f(w,{force:!0}),await f(g,{recursive:!0,force:!0});let i="mirror";if(e.bundle){if(e.onDownload?.(s.version),await e.download(s.version,y),await async function(e,s,o){const i=r("sha256");if(await D(t(e),new b({write(e,r,t){i.update(e),t()}})),i.digest("hex")!==s)throw new Error("downloaded bundle does not match the app's checksum");const n=v.createZstdDecompress;if(!n)throw new Error(`Node ${process.version} cannot decompress zstd (needs 22.15 or newer)`);await D(t(e),n(),new S(o))}(y,s.checksum,g),!o(m(g,"claude.app","Contents","MacOS","claude")))throw new Error("bundle has no claude.app");await f(d,{recursive:!0,force:!0}),await u(g,d)}else{const r=e.localVersionsDir?m(e.localVersionsDir,s.version):null;if(r&&o(r))await a(r,g),i="local";else{e.onDownload?.(s.version);const r=e.download??((r,t)=>$(e.platformKey,r,t));await r(s.version,g)}await l(d,{recursive:!0}),await u(g,h)}return await p(w,s.checksum),{status:"installed",version:s.version,source:i}}finally{await f(g,{recursive:!0,force:!0}),await f(y,{force:!0}),await f(`${g}.download`,{force:!0})}}let F=(...e)=>fetch(...e);export function setDesktopCliFetchForTests(e){F=e}export async function ensureDesktopCli(e){const r=x();if(!r)return{status:"skipped",reason:"unsupported architecture"};if("win32"===process.platform){const t=O();return t?installDesktopCli({userDataDir:e.userDataDir,asar:n(t),platformKey:r,localVersionsDir:C().versionsDir,onDownload:e.onDownload}):{status:"skipped",reason:"app.asar not found"}}if("darwin"===process.platform){const t=j();if(!t)return{status:"skipped",reason:"app.asar not found"};const{mirror:o,desktopVersion:i}=e;return installDesktopCli({userDataDir:e.userDataDir,asar:n(t),platformKey:r,bundle:!0,onDownload:e.onDownload,download:o&&i?(e,t)=>async function(e,r){const t=await F(e,{signal:AbortSignal.timeout(9e5)});if(!t.ok||!t.body)throw new Error(`${e}: HTTP ${t.status}`);await D(g.fromWeb(t.body),s(r))}(P(o,`claude-code-${e}-${r}.app.tar.zst`,`v${i}`),t):void 0})}if("linux"===process.platform){const t=E();return t?installDesktopCli({userDataDir:e.userDataDir,asar:n(t),platformKey:r.replace(/-musl$/,""),localVersionsDir:r.endsWith("-musl")?void 0:C().versionsDir,onDownload:e.onDownload}):{status:"skipped",reason:"app.asar not found"}}return{status:"skipped",reason:"unsupported platform"}}
1
+ import{execFileSync as e}from"child_process";import{createHash as r}from"crypto";import{createReadStream as t,createWriteStream as s,existsSync as o,readdirSync as n,readFileSync as i}from"fs";import{copyFile as a,mkdir as l,readFile as c,rename as u,rm as f,writeFile as p}from"fs/promises";import{isAbsolute as d,join as m,normalize as h,sep as w}from"path";import{Readable as g,Writable as b}from"stream";import{pipeline as D}from"stream/promises";import*as v from"zlib";import{logger as y}from"../../utils/logger.js";import{brand as k,brandEnv as $}from"../brand.js";import{downloadNativeBinary as C,nativeLayout as x,nativePlatformKey as N}from"./claude-native-mirror.js";import{WINDOWS_PACKAGE_FAMILIES as A}from"./desktop-process.js";import{toolHome as P}from"./types.js";import{mirrorFileUrl as L,withDownloadFallback as O}from"../mirror-url.js";import{powerShellEnv as E}from"../powershell-env.js";export function readDesktopCliPin(e,r,t=!1){const s=e.indexOf('claude-code-releases","sdkWrapperVersion"');if(s<0)return null;const o=e.lastIndexOf("JSON.parse('",s),n=e.indexOf("')",s);if(o<0||n<0)return null;try{const s=JSON.parse(e.subarray(o+12,n).toString("utf-8")),i="string"==typeof s.version?s.version:"",a=s.manifest?.platforms?.[r],l=t?a?.bundle?.checksum:a?.checksum;return/^\d+\.\d+\.\d+$/.test(i)&&"string"==typeof l&&/^[0-9a-f]{64}$/.test(l)?{version:i,checksum:l}:null}catch{return null}}function j(){const r=m(process.env.LOCALAPPDATA||"","AnthropicClaude");if(process.env.LOCALAPPDATA&&o(r)){const e=n(r).filter(e=>/^app-\d+\.\d+\.\d+$/.test(e)).sort((e,r)=>r.localeCompare(e,void 0,{numeric:!0}));for(const t of e){const e=m(r,t,"resources","app.asar");if(o(e))return e}}try{const r=e("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${A.map(e=>`'${e}'`).join(",")}) -contains $_.PackageFamilyName } | ForEach-Object { $_.InstallLocation }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"],env:E()});for(const e of r.split(/\r?\n/).map(e=>e.trim()).filter(Boolean)){const r=m(e,"app","resources","app.asar");if(o(r))return r}}catch(e){y.logError("claude-desktop-cli.windowsAsarPath",e)}return null}function S(){if($("TEST_HOME")?.trim())return null;for(const e of["/usr/lib/claude-desktop","/opt/Claude"]){const r=m(e,"resources","app.asar");if(o(r))return r}return null}function F(){for(const e of["/Applications/Claude.app",m(P(),"Applications","Claude.app")]){const r=m(e,"Contents","Resources","app.asar");if(o(r))return r}return null}export function installedDesktopAsarPath(){return"win32"===process.platform?j():"darwin"===process.platform?F():"linux"===process.platform?S():null}class T extends b{dest;buffer=Buffer.alloc(0);remaining=0;padding=0;file=null;longName=null;collectingLongName=null;constructor(e){super(),this.dest=e}_write(e,r,t){this.buffer=this.buffer.length?Buffer.concat([this.buffer,e]):e,this.drain().then(()=>t()).catch(t)}_final(e){this.remaining>0?e(new Error("archive ends inside an entry")):e()}target(e){const r=h(e);if(!r||d(r)||".."===r||r.startsWith(`..${w}`))throw new Error(`unsafe path in archive: ${e}`);return m(this.dest,r)}async closeFile(){const e=this.file;this.file=null,e&&await new Promise((r,t)=>e.end(e=>e?t(e):r()))}async drain(){for(;;){if(this.remaining>0){if(0===this.buffer.length)return;const e=this.buffer.subarray(0,Math.min(this.remaining,this.buffer.length));this.buffer=this.buffer.subarray(e.length),this.remaining-=e.length,this.collectingLongName?this.collectingLongName.push(e):this.file&&!this.file.write(e)&&await new Promise(e=>this.file.once("drain",()=>e())),0===this.remaining&&(this.collectingLongName&&(this.longName=Buffer.concat(this.collectingLongName).toString("utf-8").replace(/\0.*$/s,""),this.collectingLongName=null),await this.closeFile());continue}if(this.padding>0){if(this.buffer.length<this.padding)return;this.buffer=this.buffer.subarray(this.padding),this.padding=0}if(this.buffer.length<512)return;const e=this.buffer.subarray(0,512);if(this.buffer=this.buffer.subarray(512),e.every(e=>0===e))continue;const r=(r,t)=>e.subarray(r,r+t).toString("utf-8").replace(/\0.*$/s,""),t=r(345,155);let o=t?`${t}/${r(0,100)}`:r(0,100);null!==this.longName&&(o=this.longName,this.longName=null);const n=parseInt(r(124,12).trim()||"0",8),i=511&parseInt(r(100,8).trim()||"644",8),a=r(156,1)||"0";if(this.remaining=n,this.padding=(512-n%512)%512,"L"===a)this.collectingLongName=[];else if("x"===a||"g"===a);else if("5"===a)await l(this.target(o),{recursive:!0});else{if("0"!==a)throw new Error(`unexpected entry type ${a} in archive: ${o}`);{const e=this.target(o);await l(m(e,".."),{recursive:!0}),this.file=s(e,{mode:i||420}),0===n&&await this.closeFile()}}}}}export async function installDesktopCli(e){const s=readDesktopCliPin(e.asar,e.platformKey,e.bundle);if(!s)return{status:"skipped",reason:"unknown app layout"};if(e.bundle&&!e.download)return{status:"skipped",reason:"no bundle mirror"};const n=e.platformKey.startsWith("win32")?"claude.exe":"claude",i=m(e.userDataDir,"claude-code",s.version),d=m(i,s.checksum.slice(0,12)),h=e.bundle?m(d,"claude.app","Contents","MacOS","claude"):m(d,n),w=m(d,".verified");try{if(o(h)&&(await c(w,"utf-8")).trim()===s.checksum)return{status:"present",version:s.version}}catch{}await l(i,{recursive:!0});const g=m(i,`.partial-${s.checksum.slice(0,12)}`),y=`${g}.download`;try{await f(w,{force:!0}),await f(g,{recursive:!0,force:!0});let n="mirror";if(e.bundle){if(e.onDownload?.(s.version),await e.download(s.version,y),await async function(e,s,o){const n=r("sha256");if(await D(t(e),new b({write(e,r,t){n.update(e),t()}})),n.digest("hex")!==s)throw new Error("downloaded bundle does not match the app's checksum");const i=v.createZstdDecompress;if(!i)throw new Error(`Node ${process.version} cannot decompress zstd (needs 22.15 or newer)`);await D(t(e),i(),new T(o))}(y,s.checksum,g),!o(m(g,"claude.app","Contents","MacOS","claude")))throw new Error("bundle has no claude.app");await f(d,{recursive:!0,force:!0}),await u(g,d)}else{const r=e.localVersionsDir?m(e.localVersionsDir,s.version):null;if(r&&o(r))await a(r,g),n="local";else{e.onDownload?.(s.version);const r=e.download??((r,t)=>C(e.platformKey,r,t));await r(s.version,g)}await l(d,{recursive:!0}),await u(g,h)}return await p(w,s.checksum),{status:"installed",version:s.version,source:n}}finally{await f(g,{recursive:!0,force:!0}),await f(y,{force:!0}),await f(`${g}.download`,{force:!0})}}let K=(...e)=>fetch(...e);export function setDesktopCliFetchForTests(e){K=e}export async function ensureDesktopCli(e){const r=N();if(!r)return{status:"skipped",reason:"unsupported architecture"};if("win32"===process.platform){const t=j();return t?installDesktopCli({userDataDir:e.userDataDir,asar:i(t),platformKey:r,localVersionsDir:x().versionsDir,onDownload:e.onDownload}):{status:"skipped",reason:"app.asar not found"}}if("darwin"===process.platform){const t=F();if(!t)return{status:"skipped",reason:"app.asar not found"};const{mirror:o,desktopVersion:n}=e;return installDesktopCli({userDataDir:e.userDataDir,asar:i(t),platformKey:r,bundle:!0,onDownload:e.onDownload,download:o&&n?(e,t)=>O(L(o,`claude-code-${e}-${r}.app.tar.zst`,`v${n}`),k().installMirror?.downloadCounter,e=>async function(e,r){const t=await K(e,{signal:AbortSignal.timeout(9e5)});if(!t.ok||!t.body)throw new Error(`${e}: HTTP ${t.status}`);await D(g.fromWeb(t.body),s(r))}(e,t)):void 0})}if("linux"===process.platform){const t=S();return t?installDesktopCli({userDataDir:e.userDataDir,asar:i(t),platformKey:r.replace(/-musl$/,""),localVersionsDir:r.endsWith("-musl")?void 0:x().versionsDir,onDownload:e.onDownload}):{status:"skipped",reason:"app.asar not found"}}return{status:"skipped",reason:"unsupported platform"}}
@@ -1 +1 @@
1
- import{spawnSync as t}from"child_process";import{createHash as e}from"crypto";import{accessSync as r,constants as o,copyFileSync as n,createReadStream as s,createWriteStream as i,existsSync as a,mkdirSync as c,mkdtempSync as l,readFileSync as p,renameSync as u,rmSync as d}from"fs";import{cpus as f,tmpdir as m}from"os";import{basename as g,dirname as h,join as w}from"path";import{Readable as S,Transform as A}from"stream";import{pipeline as x}from"stream/promises";import{logger as y}from"../../utils/logger.js";import{i18n as E}from"../i18n.js";import{powerShellEnv as $}from"../powershell-env.js";import{toolHome as v}from"./types.js";import{configManager as k}from"../config.js";import{mirrorFileUrl as _}from"../mirror-url.js";const P=(e,r,o={})=>{const n=t(e,r,{encoding:"utf-8",timeout:o.timeout??12e4,windowsHide:!0,input:o.input,stdio:[void 0===o.input?"ignore":"pipe","pipe","pipe"],maxBuffer:16777216,env:$()});return n.error&&y.logError(`desktop-app: ${e}`,n.error),{status:n.status,stdout:`${n.stdout??""}`,stderr:`${n.stderr??""}`}};let I=P,b=(...t)=>fetch(...t),C=null,T=null,M=null,F=null;export function setDesktopAppDepsForTests(t){void 0!==t.run&&(I=t.run??P),void 0!==t.fetch&&(b=t.fetch??((...t)=>fetch(...t))),void 0!==t.platform&&(C=t.platform),void 0!==t.arm64&&(T=t.arm64),void 0!==t.privileged&&(M=t.privileged),void 0!==t.remote&&(F=t.remote)}export function appPlatform(){return C??process.platform}export function isArm64Machine(){return null!==T?T:"arm64"===process.arch||("win32"===appPlatform()?"ARM64"===process.env.PROCESSOR_ARCHITECTURE||"ARM64"===process.env.PROCESSOR_ARCHITEW6432:"darwin"===appPlatform()&&/\bApple\b/.test(f()[0]?.model??""))}export class DesktopInstallError extends Error{key;constructor(t,e){super(t),this.name="DesktopInstallError",this.key=e}}export const fail=(t,e={})=>{const r={};for(const[t,o]of Object.entries(e))r[t]=o.trim()||E.t("app_update.reason_unknown");throw new DesktopInstallError(E.t(`app_update.error_${t}`,r),t)};export function parseSha256Sums(t){const e=new Map;for(const r of t.split(/\r?\n/)){const t=/^([0-9a-f]{64})\s+\*?(\S.*)$/i.exec(r.trim());t&&e.set(t[2].trim(),t[1].toLowerCase())}return e}async function R(t){const r=e("sha256");for await(const e of s(t))r.update(e);return r.digest("hex")}async function j(t,e){const r=await b(t,{signal:AbortSignal.timeout(e)});if(!r.ok)throw new Error(`${t}: HTTP ${r.status}`);return(await r.text()).trim()}function O(t,e){try{const r=p(w(t,"Contents","Info.plist"),"utf-8");return new RegExp(`<key>${e}</key>\\s*<string>([^<]*)</string>`).exec(r)?.[1]??null}catch{return null}}export function macBundleId(t){return O(t,"CFBundleIdentifier")}export function macAppVersion(t){return/^\d+\.\d+\.\d+/.exec(O(t,"CFBundleShortVersionString")??"")?.[0]??null}function N(t){try{return r(t,o.W_OK),!0}catch{return!1}}const B=t=>`'${t.replace(/'/g,"''")}'`;function D(t,e=12e4){return I("powershell.exe",["-NoProfile","-NonInteractive","-ExecutionPolicy","Bypass","-Command","[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; "+t],{timeout:e})}export function powerShellError(t){return t.replace(/#< CLIXML/g,"").replace(/_x000D__x000A_/g,"\n").replace(/<\/S>/g,"\n").replace(/<[^>]+>/g,"").replace(/_x[0-9A-F]{4}_/g,"").replace(/&apos;/g,"'").replace(/&quot;/g,'"').replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&").split(/\r?\n/).map(t=>t.trim()).find(t=>t&&!/^(At line|At char|所在位置|\+|~|CategoryInfo|FullyQualifiedErrorId)/i.test(t))??""}export function createDesktopAppInstaller(t){const e=()=>t.mirror()||null,r=()=>t.asset(appPlatform(),isArm64Machine()),o=()=>{const o=appPlatform();return"darwin"!==o&&"win32"!==o?"unsupported_platform":r()?e()?"darwin"===o&&(M??0===process.getuid?.())?"root":"win32"===o&&(null!==M?M:/\\system32\\config\\systemprofile/i.test(process.env.USERPROFILE??"")||!0===process.env.USERNAME?.endsWith("$"))?"system_account":"win32"===o&&(null!==F?F:Boolean(process.env.SSH_CONNECTION||process.env.SSH_CLIENT))?"remote_session":t.extraBlocker?.(o)??null:"no_mirror":"darwin"===o?"unsupported_arch":"unsupported_platform"},s=async(r=8e3)=>{const o=e();if(!o)throw new Error("no mirror");const n=t.versionFile(appPlatform(),isArm64Machine()),s=await j(_(o,n),r),i=/^(\d+\.\d+\.\d+)(\.\d+)?$/.exec(s)?.[1];if(!i)throw new Error(`unexpected ${n}: ${s.slice(0,40)}`);return i},f=()=>{for(const e of["/Applications",w(v(),"Applications")])for(const r of t.macApp.installedNames){const o=w(e,r);if(!a(w(o,"Contents","Info.plist")))continue;const n=macBundleId(o);if(null===n||n===t.macApp.bundleId)return o}return null},$=e=>{const r=I("codesign",["--verify","--deep","--strict",e],{timeout:6e5});0!==r.status&&fail("signature",{reason:(r.stderr||r.stdout).trim().split("\n")[0]||`codesign ${r.status}`});const o=I("codesign",["-dv",e]),n=`${o.stdout}\n${o.stderr}`,s=/^TeamIdentifier=(\S+)/m.exec(n)?.[1],i=/^Identifier=(\S+)/m.exec(n)?.[1];s===t.macApp.teamId&&i===t.macApp.bundleId||fail("signature",{reason:`TeamIdentifier=${s??"?"} Identifier=${i??"?"}`});const a=I("spctl",["-a","-t","exec","-vv",e],{timeout:3e5});0!==a.status&&fail("signature",{reason:(a.stderr||a.stdout).trim().split("\n")[0]||`spctl ${a.status}`})},P=()=>{const e=f();let r=e;if(!r){const e=N("/Applications")?"/Applications":w(v(),"Applications");r=w(e,t.macApp.installedNames[0])}const o=h(r);return(a(o)&&!N(o)||e&&!N(e))&&fail("no_permission",{path:r}),{target:r,existing:e}},C=e=>{const r=D(`$s = Get-AuthenticodeSignature -LiteralPath ${B(e)}; [pscustomobject]@{ status = [string]$s.Status; subject = [string]$s.SignerCertificate.Subject } | ConvertTo-Json -Compress`);let o={};try{o=JSON.parse(r.stdout.trim()||"{}")}catch{}if("Valid"!==o.status||!t.windows.signer.test(o.subject??"")){const t=o.status?`${o.status} ${o.subject??""}`:powerShellError(r.stderr)||powerShellError(r.stdout.trim().startsWith("{")?"":r.stdout)||`exit ${r.status}`;fail("signature",{reason:t.trim()})}},T=()=>{const e=D(`Get-AppxPackage | Where-Object { ${t.windows.packageFilter} } | ForEach-Object { $_.Version.ToString() }`,3e4);return/\d+\.\d+\.\d+/.exec(e.stdout)?.[0]??null};return{assetName:r,blocker:o,latestVersion:s,installedMacApp:f,windowsPackageVersion:T,verifyMacApp:$,verifyWindowsPackage:C,install:async(f={})=>{const v=o();v&&fail("blocked",{reason:E.t(`app_update.reason_${v}`)});const M=e(),F=r();let O;try{O=await s(15e3)}catch(t){fail("download",{reason:t instanceof Error?t.message:String(t)})}const N=e=>_(M,e,t.releaseTag?.(O));let H;try{H=parseSha256Sums(await j(N("SHA256SUMS"),15e3)).get(F)}catch(e){y.logError(`${t.id}: SHA256SUMS`,e)}H||fail("no_checksum",{file:F}),"darwin"===appPlatform()&&P();const W=w(k.getConfigDir(),"downloads",t.id),V=w(W,F),L=l(w(m(),`${t.id}-`));let U=w(L,F),G=!1;try{a(V)&&await R(V)===H?(U=V,f.reusing?.(O)):(f.downloading?.(O),await async function(t,e,r){let o;try{o=await b(t,{signal:AbortSignal.timeout(18e5)})}catch(t){fail("download",{reason:t instanceof Error?t.message:String(t)})}o.ok&&o.body||fail("download",{reason:`HTTP ${o.status}`});const n=Number(o.headers.get("content-length"))||0;let s=0,a=-1;const c=new A({transform(t,e,o){s+=t.length;const i=n?Math.floor(100*s/n):-1;i>=0&&i!==a&&(a=i,r?.(i)),o(null,t)}});try{await x(S.fromWeb(o.body),c,i(e))}catch(t){d(e,{force:!0}),fail("download",{reason:t instanceof Error?t.message:String(t)})}}(N(F),U,f.percent)),f.verifying?.();const e=await R(U);e!==H&&fail("checksum",{file:F,expected:H.slice(0,12),actual:e.slice(0,12)}),f.installing?.();const r="darwin"===appPlatform()?await(async(e,r)=>{const o=w(r,"mnt");c(o,{recursive:!0});const n=I("hdiutil",["attach","-nobrowse","-readonly","-noautoopen","-mountpoint",o,e],{timeout:3e5,input:"Y\n"});0!==n.status&&fail("mount",{reason:(n.stderr||n.stdout).trim().split("\n").pop()??""});let s=null;try{const e=w(o,t.macApp.source);a(e)||fail("bad_package",{reason:t.macApp.source});const{target:r,existing:n}=P(),i=h(r),l=g(r);c(i,{recursive:!0}),s=w(i,`.${l}.${process.pid}.new`),d(s,{recursive:!0,force:!0});const p=I("ditto",[e,s],{timeout:9e5});0!==p.status&&fail("copy",{reason:(p.stderr||p.stdout).trim().split("\n")[0]??""}),$(s);const f=macAppVersion(s);f||fail("bad_package",{reason:"Info.plist"});const m=w(i,`.${l}.${process.pid}.old`);try{n&&u(n,m)}catch(t){throw["EPERM","EACCES"].includes(t.code??"")&&fail("app_management",{path:n}),t}try{u(s,r)}catch(t){throw n&&u(m,n),t}return s=null,d(m,{recursive:!0,force:!0}),{version:f,location:r}}finally{s&&d(s,{recursive:!0,force:!0}),I("hdiutil",["detach",o,"-force"],{timeout:6e4})}})(U,L):await(async(t,e)=>{C(t);const r=D(`$ErrorActionPreference = 'Stop'; Add-AppxPackage -Path ${B(t)} -ForceApplicationShutdown`,9e5);if(0!==r.status){const o=powerShellError(r.stderr)||powerShellError(r.stdout)||`Add-AppxPackage ${r.status}`;/0x80073D28/i.test(`${r.stderr}\n${r.stdout}`)||fail("install",{reason:o}),await(e.elevate?.())||fail("needs_admin");const n=(t=>{const e=w(h(t),"elevated-install.log"),r=`$ErrorActionPreference = 'Stop'; try { Add-AppxPackage -Path ${B(t)} -ForceApplicationShutdown; exit 0 } catch { [IO.File]::WriteAllText(${B(e)}, $_.Exception.Message, [Text.Encoding]::UTF8); exit 1 }`,o=D(`$ErrorActionPreference = 'Stop'; $p = Start-Process -FilePath 'powershell.exe' -ArgumentList @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-EncodedCommand', '${Buffer.from(r,"utf16le").toString("base64")}') -Verb RunAs -Wait -PassThru -WindowStyle Hidden; exit $p.ExitCode`,12e5);if(0===o.status)return null;let n="";try{n=p(e,"utf-8").trim()}catch{}return n||powerShellError(o.stderr)||powerShellError(o.stdout)||`exit ${o.status}`})(t);n&&fail("install",{reason:n}),T()||fail("other_account")}const o=T();return o||fail("install",{reason:"Get-AppxPackage"}),{version:o,location:"MSIX"}})(U,f);return G=!0,r}catch(t){const e=t instanceof DesktopInstallError?t.key:void 0;throw U!==V&&a(U)&&!["checksum","signature","bad_package","mount"].includes(e??"")&&function(t,e,r){try{d(e,{recursive:!0,force:!0}),c(e,{recursive:!0});try{u(t,r)}catch{n(t,r)}}catch(t){y.logError("desktop-app: keep package",t),d(e,{recursive:!0,force:!0})}}(U,W,V),U===V&&["signature","bad_package","mount"].includes(e??"")&&d(W,{recursive:!0,force:!0}),t}finally{G&&d(W,{recursive:!0,force:!0}),d(L,{recursive:!0,force:!0})}}}}
1
+ import{spawnSync as t}from"child_process";import{createHash as e}from"crypto";import{accessSync as r,constants as o,copyFileSync as n,createReadStream as s,createWriteStream as i,existsSync as a,mkdirSync as c,mkdtempSync as l,readFileSync as p,renameSync as u,rmSync as d}from"fs";import{cpus as f,tmpdir as m}from"os";import{basename as g,dirname as h,join as w}from"path";import{Readable as S,Transform as A}from"stream";import{pipeline as x}from"stream/promises";import{logger as y}from"../../utils/logger.js";import{i18n as E}from"../i18n.js";import{powerShellEnv as $}from"../powershell-env.js";import{toolHome as v}from"./types.js";import{configManager as k}from"../config.js";import{brand as _}from"../brand.js";import{mirrorFileUrl as P,withDownloadFallback as I}from"../mirror-url.js";const b=(e,r,o={})=>{const n=t(e,r,{encoding:"utf-8",timeout:o.timeout??12e4,windowsHide:!0,input:o.input,stdio:[void 0===o.input?"ignore":"pipe","pipe","pipe"],maxBuffer:16777216,env:$()});return n.error&&y.logError(`desktop-app: ${e}`,n.error),{status:n.status,stdout:`${n.stdout??""}`,stderr:`${n.stderr??""}`}};let C=b,T=(...t)=>fetch(...t),M=null,j=null,F=null,R=null;export function setDesktopAppDepsForTests(t){void 0!==t.run&&(C=t.run??b),void 0!==t.fetch&&(T=t.fetch??((...t)=>fetch(...t))),void 0!==t.platform&&(M=t.platform),void 0!==t.arm64&&(j=t.arm64),void 0!==t.privileged&&(F=t.privileged),void 0!==t.remote&&(R=t.remote)}export function appPlatform(){return M??process.platform}export function isArm64Machine(){return null!==j?j:"arm64"===process.arch||("win32"===appPlatform()?"ARM64"===process.env.PROCESSOR_ARCHITECTURE||"ARM64"===process.env.PROCESSOR_ARCHITEW6432:"darwin"===appPlatform()&&/\bApple\b/.test(f()[0]?.model??""))}export class DesktopInstallError extends Error{key;constructor(t,e){super(t),this.name="DesktopInstallError",this.key=e}}export const fail=(t,e={})=>{const r={};for(const[t,o]of Object.entries(e))r[t]=o.trim()||E.t("app_update.reason_unknown");throw new DesktopInstallError(E.t(`app_update.error_${t}`,r),t)};export function parseSha256Sums(t){const e=new Map;for(const r of t.split(/\r?\n/)){const t=/^([0-9a-f]{64})\s+\*?(\S.*)$/i.exec(r.trim());t&&e.set(t[2].trim(),t[1].toLowerCase())}return e}async function O(t){const r=e("sha256");for await(const e of s(t))r.update(e);return r.digest("hex")}async function N(t,e){const r=await T(t,{signal:AbortSignal.timeout(e)});if(!r.ok)throw new Error(`${t}: HTTP ${r.status}`);return(await r.text()).trim()}function B(t,e){try{const r=p(w(t,"Contents","Info.plist"),"utf-8");return new RegExp(`<key>${e}</key>\\s*<string>([^<]*)</string>`).exec(r)?.[1]??null}catch{return null}}export function macBundleId(t){return B(t,"CFBundleIdentifier")}export function macAppVersion(t){return/^\d+\.\d+\.\d+/.exec(B(t,"CFBundleShortVersionString")??"")?.[0]??null}function D(t){try{return r(t,o.W_OK),!0}catch{return!1}}const H=t=>`'${t.replace(/'/g,"''")}'`;function W(t,e=12e4){return C("powershell.exe",["-NoProfile","-NonInteractive","-ExecutionPolicy","Bypass","-Command","[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; "+t],{timeout:e})}export function powerShellError(t){return t.replace(/#< CLIXML/g,"").replace(/_x000D__x000A_/g,"\n").replace(/<\/S>/g,"\n").replace(/<[^>]+>/g,"").replace(/_x[0-9A-F]{4}_/g,"").replace(/&apos;/g,"'").replace(/&quot;/g,'"').replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&").split(/\r?\n/).map(t=>t.trim()).find(t=>t&&!/^(At line|At char|所在位置|\+|~|CategoryInfo|FullyQualifiedErrorId)/i.test(t))??""}export function createDesktopAppInstaller(t){const e=()=>t.mirror()||null,r=()=>t.asset(appPlatform(),isArm64Machine()),o=()=>{const o=appPlatform();return"darwin"!==o&&"win32"!==o?"unsupported_platform":r()?e()?"darwin"===o&&(F??0===process.getuid?.())?"root":"win32"===o&&(null!==F?F:/\\system32\\config\\systemprofile/i.test(process.env.USERPROFILE??"")||!0===process.env.USERNAME?.endsWith("$"))?"system_account":"win32"===o&&(null!==R?R:Boolean(process.env.SSH_CONNECTION||process.env.SSH_CLIENT))?"remote_session":t.extraBlocker?.(o)??null:"no_mirror":"darwin"===o?"unsupported_arch":"unsupported_platform"},s=async(r=8e3)=>{const o=e();if(!o)throw new Error("no mirror");const n=t.versionFile(appPlatform(),isArm64Machine()),s=await N(P(o,n),r),i=/^(\d+\.\d+\.\d+)(\.\d+)?$/.exec(s)?.[1];if(!i)throw new Error(`unexpected ${n}: ${s.slice(0,40)}`);return i},f=()=>{for(const e of["/Applications",w(v(),"Applications")])for(const r of t.macApp.installedNames){const o=w(e,r);if(!a(w(o,"Contents","Info.plist")))continue;const n=macBundleId(o);if(null===n||n===t.macApp.bundleId)return o}return null},$=e=>{const r=C("codesign",["--verify","--deep","--strict",e],{timeout:6e5});0!==r.status&&fail("signature",{reason:(r.stderr||r.stdout).trim().split("\n")[0]||`codesign ${r.status}`});const o=C("codesign",["-dv",e]),n=`${o.stdout}\n${o.stderr}`,s=/^TeamIdentifier=(\S+)/m.exec(n)?.[1],i=/^Identifier=(\S+)/m.exec(n)?.[1];s===t.macApp.teamId&&i===t.macApp.bundleId||fail("signature",{reason:`TeamIdentifier=${s??"?"} Identifier=${i??"?"}`});const a=C("spctl",["-a","-t","exec","-vv",e],{timeout:3e5});0!==a.status&&fail("signature",{reason:(a.stderr||a.stdout).trim().split("\n")[0]||`spctl ${a.status}`})},b=()=>{const e=f();let r=e;if(!r){const e=D("/Applications")?"/Applications":w(v(),"Applications");r=w(e,t.macApp.installedNames[0])}const o=h(r);return(a(o)&&!D(o)||e&&!D(e))&&fail("no_permission",{path:r}),{target:r,existing:e}},M=e=>{const r=W(`$s = Get-AuthenticodeSignature -LiteralPath ${H(e)}; [pscustomobject]@{ status = [string]$s.Status; subject = [string]$s.SignerCertificate.Subject } | ConvertTo-Json -Compress`);let o={};try{o=JSON.parse(r.stdout.trim()||"{}")}catch{}if("Valid"!==o.status||!t.windows.signer.test(o.subject??"")){const t=o.status?`${o.status} ${o.subject??""}`:powerShellError(r.stderr)||powerShellError(r.stdout.trim().startsWith("{")?"":r.stdout)||`exit ${r.status}`;fail("signature",{reason:t.trim()})}},j=()=>{const e=W(`Get-AppxPackage | Where-Object { ${t.windows.packageFilter} } | ForEach-Object { $_.Version.ToString() }`,3e4);return/\d+\.\d+\.\d+/.exec(e.stdout)?.[0]??null};return{assetName:r,blocker:o,latestVersion:s,installedMacApp:f,windowsPackageVersion:j,verifyMacApp:$,verifyWindowsPackage:M,install:async(f={})=>{const v=o();v&&fail("blocked",{reason:E.t(`app_update.reason_${v}`)});const F=e(),R=r();let B;try{B=await s(15e3)}catch(t){fail("download",{reason:t instanceof Error?t.message:String(t)})}const D=e=>P(F,e,t.releaseTag?.(B)),V=_().installMirror?.downloadCounter;let L;try{L=parseSha256Sums(await I(D("SHA256SUMS"),V,t=>N(t,15e3))).get(R)}catch(e){y.logError(`${t.id}: SHA256SUMS`,e)}L||fail("no_checksum",{file:R}),"darwin"===appPlatform()&&b();const U=w(k.getConfigDir(),"downloads",t.id),G=w(U,R),J=l(w(m(),`${t.id}-`));let X=w(J,R),q=!1;try{a(G)&&await O(G)===L?(X=G,f.reusing?.(B)):(f.downloading?.(B),await I(D(R),V,t=>async function(t,e,r){let o;try{o=await T(t,{signal:AbortSignal.timeout(18e5)})}catch(t){fail("download",{reason:t instanceof Error?t.message:String(t)})}o.ok&&o.body||fail("download",{reason:`HTTP ${o.status}`});const n=Number(o.headers.get("content-length"))||0;let s=0,a=-1;const c=new A({transform(t,e,o){s+=t.length;const i=n?Math.floor(100*s/n):-1;i>=0&&i!==a&&(a=i,r?.(i)),o(null,t)}});try{await x(S.fromWeb(o.body),c,i(e))}catch(t){d(e,{force:!0}),fail("download",{reason:t instanceof Error?t.message:String(t)})}}(t,X,f.percent))),f.verifying?.();const e=await O(X);e!==L&&fail("checksum",{file:R,expected:L.slice(0,12),actual:e.slice(0,12)}),f.installing?.();const r="darwin"===appPlatform()?await(async(e,r)=>{const o=w(r,"mnt");c(o,{recursive:!0});const n=C("hdiutil",["attach","-nobrowse","-readonly","-noautoopen","-mountpoint",o,e],{timeout:3e5,input:"Y\n"});0!==n.status&&fail("mount",{reason:(n.stderr||n.stdout).trim().split("\n").pop()??""});let s=null;try{const e=w(o,t.macApp.source);a(e)||fail("bad_package",{reason:t.macApp.source});const{target:r,existing:n}=b(),i=h(r),l=g(r);c(i,{recursive:!0}),s=w(i,`.${l}.${process.pid}.new`),d(s,{recursive:!0,force:!0});const p=C("ditto",[e,s],{timeout:9e5});0!==p.status&&fail("copy",{reason:(p.stderr||p.stdout).trim().split("\n")[0]??""}),$(s);const f=macAppVersion(s);f||fail("bad_package",{reason:"Info.plist"});const m=w(i,`.${l}.${process.pid}.old`);try{n&&u(n,m)}catch(t){throw["EPERM","EACCES"].includes(t.code??"")&&fail("app_management",{path:n}),t}try{u(s,r)}catch(t){throw n&&u(m,n),t}return s=null,d(m,{recursive:!0,force:!0}),{version:f,location:r}}finally{s&&d(s,{recursive:!0,force:!0}),C("hdiutil",["detach",o,"-force"],{timeout:6e4})}})(X,J):await(async(t,e)=>{M(t);const r=W(`$ErrorActionPreference = 'Stop'; Add-AppxPackage -Path ${H(t)} -ForceApplicationShutdown`,9e5);if(0!==r.status){const o=powerShellError(r.stderr)||powerShellError(r.stdout)||`Add-AppxPackage ${r.status}`;/0x80073D28/i.test(`${r.stderr}\n${r.stdout}`)||fail("install",{reason:o}),await(e.elevate?.())||fail("needs_admin");const n=(t=>{const e=w(h(t),"elevated-install.log"),r=`$ErrorActionPreference = 'Stop'; try { Add-AppxPackage -Path ${H(t)} -ForceApplicationShutdown; exit 0 } catch { [IO.File]::WriteAllText(${H(e)}, $_.Exception.Message, [Text.Encoding]::UTF8); exit 1 }`,o=W(`$ErrorActionPreference = 'Stop'; $p = Start-Process -FilePath 'powershell.exe' -ArgumentList @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-EncodedCommand', '${Buffer.from(r,"utf16le").toString("base64")}') -Verb RunAs -Wait -PassThru -WindowStyle Hidden; exit $p.ExitCode`,12e5);if(0===o.status)return null;let n="";try{n=p(e,"utf-8").trim()}catch{}return n||powerShellError(o.stderr)||powerShellError(o.stdout)||`exit ${o.status}`})(t);n&&fail("install",{reason:n}),j()||fail("other_account")}const o=j();return o||fail("install",{reason:"Get-AppxPackage"}),{version:o,location:"MSIX"}})(X,f);return q=!0,r}catch(t){const e=t instanceof DesktopInstallError?t.key:void 0;throw X!==G&&a(X)&&!["checksum","signature","bad_package","mount"].includes(e??"")&&function(t,e,r){try{d(e,{recursive:!0,force:!0}),c(e,{recursive:!0});try{u(t,r)}catch{n(t,r)}}catch(t){y.logError("desktop-app: keep package",t),d(e,{recursive:!0,force:!0})}}(X,U,G),X===G&&["signature","bad_package","mount"].includes(e??"")&&d(U,{recursive:!0,force:!0}),t}finally{q&&d(U,{recursive:!0,force:!0}),d(J,{recursive:!0,force:!0})}}}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marsapi/cli",
3
- "version": "0.0.156",
3
+ "version": "0.0.157",
4
4
  "description": "Configure Claude Code, Codex, Grok Build and other coding tools for Mars AI with one command",
5
5
  "main": "dist/index.js",
6
6
  "bin": {