@qoder-ai/qoder-agent-sdk 1.0.16 → 1.0.19
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 +48 -44
- package/dist/auth.d.ts +5 -2
- package/dist/core/brand.d.ts +22 -0
- package/dist/core/constants.d.ts +16 -6
- package/dist/core/runtime-launch-options.d.ts +7 -0
- package/dist/core/runtime-selection.d.ts +24 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +26 -26
- package/dist/protocol/common.d.ts +27 -0
- package/dist/protocol/control.d.ts +5 -1
- package/dist/protocol/hooks.d.ts +2 -1
- package/dist/protocol/index.d.ts +1 -1
- package/dist/protocol/index.js +1 -1
- package/dist/protocol/messages.d.ts +6 -0
- package/dist/query/query-runner.d.ts +4 -2
- package/dist/runtime-manifest.json +10 -2
- package/dist/session/transcript-paths.d.ts +3 -3
- package/dist/types/auth.d.ts +27 -2
- package/dist/types/common.d.ts +1 -1
- package/dist/types/control.d.ts +12 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/options.d.ts +14 -1
- package/dist/types/tools.d.ts +58 -2
- package/package.json +4 -55
- package/scripts/postinstall.cjs +127 -135
package/scripts/postinstall.cjs
CHANGED
|
@@ -22,22 +22,15 @@ const https = require('https');
|
|
|
22
22
|
const os = require('os');
|
|
23
23
|
const path = require('path');
|
|
24
24
|
|
|
25
|
-
const GLOBAL_PROD_DOWNLOAD_BASE_URL =
|
|
26
|
-
'https://download.qoder.com/qodercli/releases';
|
|
25
|
+
const GLOBAL_PROD_DOWNLOAD_BASE_URL = 'https://download.qoder.com/qodercli/releases';
|
|
27
26
|
const GLOBAL_DEV_DOWNLOAD_BASE_URL =
|
|
28
27
|
'https://qs-cli-dev.oss-cn-hangzhou.aliyuncs.com/qodercli/dev/releases';
|
|
29
|
-
const CN_PROD_DOWNLOAD_BASE_URL =
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
'qoder-worker-runtime.obf.mjs',
|
|
36
|
-
'qoder-worker-runtime.mjs',
|
|
37
|
-
];
|
|
38
|
-
const REQUIRED_WORKER_RUNTIME_ASSETS = [
|
|
39
|
-
path.join('vendor', 'ripgrep', 'x64-win32', 'rg.exe'),
|
|
40
|
-
];
|
|
28
|
+
const CN_PROD_DOWNLOAD_BASE_URL = 'https://static.qoder.com.cn/qoder-cli-cn/releases';
|
|
29
|
+
const CN_DEV_DOWNLOAD_BASE_URL = 'https://static.qoder.com.cn/qoder-cli-cn/dev/releases';
|
|
30
|
+
const PACKAGE_JSON = require('../package.json');
|
|
31
|
+
const LOG_PREFIX = `[${PACKAGE_JSON.name ?? '@qoder-ai/qoder-agent-sdk'}]`;
|
|
32
|
+
const WORKER_RUNTIME_ENTRY_NAMES = ['qoder-worker-runtime.obf.mjs', 'qoder-worker-runtime.mjs'];
|
|
33
|
+
const REQUIRED_WORKER_RUNTIME_ASSETS = [path.join('vendor', 'ripgrep', 'x64-win32', 'rg.exe')];
|
|
41
34
|
|
|
42
35
|
function isTruthy(value) {
|
|
43
36
|
return value === '1' || value === 'true';
|
|
@@ -48,12 +41,9 @@ function getCliVersion() {
|
|
|
48
41
|
if (fromEnv) return fromEnv.replace(/^v/, '');
|
|
49
42
|
|
|
50
43
|
try {
|
|
51
|
-
const
|
|
52
|
-
const version = packageJson.qoderCliVersion ?? packageJson.version;
|
|
44
|
+
const version = PACKAGE_JSON.qoderCliVersion ?? PACKAGE_JSON.version;
|
|
53
45
|
if (!version) {
|
|
54
|
-
throw new Error(
|
|
55
|
-
'package.json must define "qoderCliVersion" or "version".',
|
|
56
|
-
);
|
|
46
|
+
throw new Error('package.json must define "qoderCliVersion" or "version".');
|
|
57
47
|
}
|
|
58
48
|
return String(version).replace(/^v/, '');
|
|
59
49
|
} catch (error) {
|
|
@@ -62,20 +52,21 @@ function getCliVersion() {
|
|
|
62
52
|
}
|
|
63
53
|
|
|
64
54
|
function isDevCliVersion(version) {
|
|
65
|
-
return
|
|
55
|
+
return (
|
|
56
|
+
/^\d+\.\d+\.\d+-/.test(version) ||
|
|
57
|
+
/(?:^|[.-])(alpha|beta|dev|nightly|rc|canary)(?:[.-]|$)/i.test(version)
|
|
58
|
+
);
|
|
66
59
|
}
|
|
67
60
|
|
|
68
61
|
function normalizeCliSite(value) {
|
|
69
62
|
const normalized = String(value).trim().toLowerCase();
|
|
70
63
|
if (normalized === 'global') return 'global';
|
|
71
64
|
if (normalized === 'cn') return 'cn';
|
|
72
|
-
throw new Error(
|
|
73
|
-
`Unsupported QODER_CLI_SITE "${value}". Supported: global, cn`,
|
|
74
|
-
);
|
|
65
|
+
throw new Error(`Unsupported QODER_CLI_SITE "${value}". Supported: global, cn`);
|
|
75
66
|
}
|
|
76
67
|
|
|
77
68
|
function getCliSite() {
|
|
78
|
-
return normalizeCliSite(process.env.QODER_CLI_SITE ?? 'global');
|
|
69
|
+
return normalizeCliSite(process.env.QODER_CLI_SITE ?? PACKAGE_JSON.qoderSdkBrand ?? 'global');
|
|
79
70
|
}
|
|
80
71
|
|
|
81
72
|
function getCliArtifactPrefix(site = getCliSite()) {
|
|
@@ -87,10 +78,8 @@ function getDownloadBaseUrl(version = getCliVersion()) {
|
|
|
87
78
|
return process.env.QODER_CLI_MIRROR;
|
|
88
79
|
}
|
|
89
80
|
const site = getCliSite();
|
|
90
|
-
if (site
|
|
91
|
-
|
|
92
|
-
'QODER_CLI_SITE=cn requires QODER_CLI_MIRROR for CLI downloads.',
|
|
93
|
-
);
|
|
81
|
+
if (site === 'cn') {
|
|
82
|
+
return isDevCliVersion(version) ? CN_DEV_DOWNLOAD_BASE_URL : CN_PROD_DOWNLOAD_BASE_URL;
|
|
94
83
|
}
|
|
95
84
|
if (isDevCliVersion(version)) {
|
|
96
85
|
return GLOBAL_DEV_DOWNLOAD_BASE_URL;
|
|
@@ -104,13 +93,9 @@ function getWorkerRuntimeDownloadBaseUrl(version = getCliVersion()) {
|
|
|
104
93
|
}
|
|
105
94
|
const site = getCliSite();
|
|
106
95
|
if (site === 'cn') {
|
|
107
|
-
return isDevCliVersion(version)
|
|
108
|
-
? CN_DEV_DOWNLOAD_BASE_URL
|
|
109
|
-
: CN_PROD_DOWNLOAD_BASE_URL;
|
|
96
|
+
return isDevCliVersion(version) ? CN_DEV_DOWNLOAD_BASE_URL : CN_PROD_DOWNLOAD_BASE_URL;
|
|
110
97
|
}
|
|
111
|
-
return isDevCliVersion(version)
|
|
112
|
-
? GLOBAL_DEV_DOWNLOAD_BASE_URL
|
|
113
|
-
: GLOBAL_PROD_DOWNLOAD_BASE_URL;
|
|
98
|
+
return isDevCliVersion(version) ? GLOBAL_DEV_DOWNLOAD_BASE_URL : GLOBAL_PROD_DOWNLOAD_BASE_URL;
|
|
114
99
|
}
|
|
115
100
|
|
|
116
101
|
function normalizeDownloadBaseUrl(baseUrl, version = getCliVersion()) {
|
|
@@ -158,6 +143,7 @@ function normalizePlatformOverride(value) {
|
|
|
158
143
|
'linux-x64',
|
|
159
144
|
'linux-x64-baseline',
|
|
160
145
|
'linux-x64-musl',
|
|
146
|
+
'windows-arm64',
|
|
161
147
|
'windows-x64',
|
|
162
148
|
]);
|
|
163
149
|
|
|
@@ -180,10 +166,10 @@ function getPlatformTarget() {
|
|
|
180
166
|
}
|
|
181
167
|
|
|
182
168
|
if (process.platform === 'win32') {
|
|
183
|
-
if (process.arch !== 'x64') {
|
|
169
|
+
if (process.arch !== 'x64' && process.arch !== 'arm64') {
|
|
184
170
|
throw new Error(`Unsupported Windows architecture: ${process.arch}`);
|
|
185
171
|
}
|
|
186
|
-
return
|
|
172
|
+
return `windows-${process.arch}`;
|
|
187
173
|
}
|
|
188
174
|
|
|
189
175
|
if (process.platform === 'linux') {
|
|
@@ -209,10 +195,7 @@ function getArtifactName(target = getPlatformTarget()) {
|
|
|
209
195
|
|
|
210
196
|
function getDownloadUrl() {
|
|
211
197
|
const version = getCliVersion();
|
|
212
|
-
const baseUrl = normalizeDownloadBaseUrl(
|
|
213
|
-
getDownloadBaseUrl(version),
|
|
214
|
-
version,
|
|
215
|
-
);
|
|
198
|
+
const baseUrl = normalizeDownloadBaseUrl(getDownloadBaseUrl(version), version);
|
|
216
199
|
return `${baseUrl}/${getArtifactName()}`;
|
|
217
200
|
}
|
|
218
201
|
|
|
@@ -226,23 +209,15 @@ function hasWorkerRuntimeDownloadSiteOverride() {
|
|
|
226
209
|
|
|
227
210
|
function getManifestWorkerRuntime(manifest = readRuntimeManifest()) {
|
|
228
211
|
const workerRuntime = manifest?.workerRuntime;
|
|
229
|
-
return workerRuntime && typeof workerRuntime === 'object'
|
|
230
|
-
? workerRuntime
|
|
231
|
-
: null;
|
|
212
|
+
return workerRuntime && typeof workerRuntime === 'object' ? workerRuntime : null;
|
|
232
213
|
}
|
|
233
214
|
|
|
234
215
|
function getManifestWorkerRuntimeDownloadUrl(manifest = readRuntimeManifest()) {
|
|
235
216
|
const workerRuntime = getManifestWorkerRuntime(manifest);
|
|
236
217
|
if (!workerRuntime || workerRuntime.packaged === true) return null;
|
|
237
218
|
|
|
238
|
-
const candidates = [
|
|
239
|
-
|
|
240
|
-
workerRuntime.artifact?.url,
|
|
241
|
-
workerRuntime.source?.url,
|
|
242
|
-
];
|
|
243
|
-
const url = candidates.find(
|
|
244
|
-
(candidate) => typeof candidate === 'string' && candidate.length > 0,
|
|
245
|
-
);
|
|
219
|
+
const candidates = [workerRuntime.url, workerRuntime.artifact?.url, workerRuntime.source?.url];
|
|
220
|
+
const url = candidates.find((candidate) => typeof candidate === 'string' && candidate.length > 0);
|
|
246
221
|
return url ?? null;
|
|
247
222
|
}
|
|
248
223
|
|
|
@@ -256,9 +231,7 @@ function getManifestWorkerRuntimeSha256(manifest = readRuntimeManifest()) {
|
|
|
256
231
|
workerRuntime.source?.sha256,
|
|
257
232
|
];
|
|
258
233
|
const checksum = candidates.find(
|
|
259
|
-
(candidate) =>
|
|
260
|
-
typeof candidate === 'string' &&
|
|
261
|
-
/^[a-fA-F0-9]{64}$/.test(candidate.trim()),
|
|
234
|
+
(candidate) => typeof candidate === 'string' && /^[a-fA-F0-9]{64}$/.test(candidate.trim()),
|
|
262
235
|
);
|
|
263
236
|
return checksum ? checksum.trim().toLowerCase() : null;
|
|
264
237
|
}
|
|
@@ -276,10 +249,7 @@ function getWorkerRuntimeDownloadUrl() {
|
|
|
276
249
|
}
|
|
277
250
|
|
|
278
251
|
const version = getCliVersion();
|
|
279
|
-
const baseUrl = normalizeDownloadBaseUrl(
|
|
280
|
-
getWorkerRuntimeDownloadBaseUrl(version),
|
|
281
|
-
version,
|
|
282
|
-
);
|
|
252
|
+
const baseUrl = normalizeDownloadBaseUrl(getWorkerRuntimeDownloadBaseUrl(version), version);
|
|
283
253
|
return `${baseUrl}/${getWorkerRuntimeArtifactName()}`;
|
|
284
254
|
}
|
|
285
255
|
|
|
@@ -297,8 +267,52 @@ function getBundledDir() {
|
|
|
297
267
|
}
|
|
298
268
|
|
|
299
269
|
function getBundledCliPath() {
|
|
300
|
-
const
|
|
301
|
-
|
|
270
|
+
const names = getCliSite() === 'cn' ? ['qodercn', 'qoderclicn'] : ['qoder', 'qodercli'];
|
|
271
|
+
for (const name of names) {
|
|
272
|
+
const cliName = process.platform === 'win32' ? `${name}.exe` : name;
|
|
273
|
+
const candidate = path.join(getBundledDir(), cliName);
|
|
274
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
275
|
+
}
|
|
276
|
+
const fallback = names[1];
|
|
277
|
+
return path.join(getBundledDir(), process.platform === 'win32' ? `${fallback}.exe` : fallback);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function getReleaseManifestUrl(version = getCliVersion()) {
|
|
281
|
+
const site = getCliSite();
|
|
282
|
+
let base;
|
|
283
|
+
if (site === 'cn') {
|
|
284
|
+
base = isDevCliVersion(version)
|
|
285
|
+
? 'https://static.qoder.com.cn/qoder-cli-cn/dev'
|
|
286
|
+
: 'https://static.qoder.com.cn/qoder-cli-cn';
|
|
287
|
+
} else {
|
|
288
|
+
base = isDevCliVersion(version)
|
|
289
|
+
? 'https://qs-cli-dev.oss-cn-hangzhou.aliyuncs.com/qodercli/dev'
|
|
290
|
+
: 'https://download.qoder.com/qodercli';
|
|
291
|
+
}
|
|
292
|
+
return `${base}/channels/${version}/manifest.json`;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function manifestTarget(target = getPlatformTarget()) {
|
|
296
|
+
const [osName, rawArch, variant] = target.split('-');
|
|
297
|
+
const arch = rawArch === 'x64' ? 'amd64' : rawArch;
|
|
298
|
+
return {
|
|
299
|
+
os: osName === 'windows' ? 'windows' : osName,
|
|
300
|
+
arch: variant ? `${arch}-${variant}` : arch,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function selectManifestArtifact(manifest, target = getPlatformTarget()) {
|
|
305
|
+
const expected = manifestTarget(target);
|
|
306
|
+
const candidates = (manifest?.files ?? []).filter(
|
|
307
|
+
(file) => file.os === expected.os && file.arch === expected.arch,
|
|
308
|
+
);
|
|
309
|
+
const selected = candidates.find((file) => file.variant !== 'legacy') ?? candidates[0];
|
|
310
|
+
if (!selected?.url || !selected?.sha256) {
|
|
311
|
+
throw new Error(
|
|
312
|
+
`CLI release manifest has no artifact for ${target}: ${getReleaseManifestUrl()}`,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
return selected;
|
|
302
316
|
}
|
|
303
317
|
|
|
304
318
|
function getPackagedWorkerRuntimeDir() {
|
|
@@ -323,9 +337,7 @@ function getPackagedWorkerRuntimeInfoPath() {
|
|
|
323
337
|
}
|
|
324
338
|
|
|
325
339
|
function hasPackagedWorkerRuntime() {
|
|
326
|
-
return getPackagedWorkerRuntimePaths().some((candidate) =>
|
|
327
|
-
fs.existsSync(candidate),
|
|
328
|
-
);
|
|
340
|
+
return getPackagedWorkerRuntimePaths().some((candidate) => fs.existsSync(candidate));
|
|
329
341
|
}
|
|
330
342
|
|
|
331
343
|
function readPackagedWorkerRuntimeInfo() {
|
|
@@ -350,9 +362,7 @@ function isPackagedWorkerRuntimeCompatibleWithSite(site = getCliSite()) {
|
|
|
350
362
|
|
|
351
363
|
const expectedProductName = getCliArtifactPrefix(site);
|
|
352
364
|
const buildInfo =
|
|
353
|
-
runtimeInfo.build && typeof runtimeInfo.build === 'object'
|
|
354
|
-
? runtimeInfo.build
|
|
355
|
-
: {};
|
|
365
|
+
runtimeInfo.build && typeof runtimeInfo.build === 'object' ? runtimeInfo.build : {};
|
|
356
366
|
const actualProductName = buildInfo.productName;
|
|
357
367
|
const actualSite = buildInfo.site;
|
|
358
368
|
|
|
@@ -364,11 +374,7 @@ function isPackagedWorkerRuntimeCompatibleWithSite(site = getCliSite()) {
|
|
|
364
374
|
return false;
|
|
365
375
|
}
|
|
366
376
|
|
|
367
|
-
if (
|
|
368
|
-
typeof actualSite === 'string' &&
|
|
369
|
-
actualSite.length > 0 &&
|
|
370
|
-
actualSite !== site
|
|
371
|
-
) {
|
|
377
|
+
if (typeof actualSite === 'string' && actualSite.length > 0 && actualSite !== site) {
|
|
372
378
|
return false;
|
|
373
379
|
}
|
|
374
380
|
|
|
@@ -398,10 +404,7 @@ function getDefaultRuntimeTransport() {
|
|
|
398
404
|
}
|
|
399
405
|
|
|
400
406
|
function shouldInstallWorkerRuntimeForDefaultWorker() {
|
|
401
|
-
return (
|
|
402
|
-
getDefaultRuntimeTransport() === 'worker' &&
|
|
403
|
-
!isPackagedWorkerRuntimeCompatibleWithSite()
|
|
404
|
-
);
|
|
407
|
+
return getDefaultRuntimeTransport() === 'worker' && !isPackagedWorkerRuntimeCompatibleWithSite();
|
|
405
408
|
}
|
|
406
409
|
|
|
407
410
|
function shouldSkipBundledCliDownloadForWorkerRuntime() {
|
|
@@ -429,9 +432,7 @@ function requestUrl(url, redirectCount = 0) {
|
|
|
429
432
|
reject(new Error('Redirect response missing location header'));
|
|
430
433
|
return;
|
|
431
434
|
}
|
|
432
|
-
const nextUrl = location.startsWith('http')
|
|
433
|
-
? location
|
|
434
|
-
: new URL(location, url).href;
|
|
435
|
+
const nextUrl = location.startsWith('http') ? location : new URL(location, url).href;
|
|
435
436
|
response.resume();
|
|
436
437
|
resolve(requestUrl(nextUrl, redirectCount + 1));
|
|
437
438
|
return;
|
|
@@ -456,10 +457,7 @@ async function downloadFile(url, destPath) {
|
|
|
456
457
|
}
|
|
457
458
|
|
|
458
459
|
await new Promise((resolve, reject) => {
|
|
459
|
-
const totalSize = Number.parseInt(
|
|
460
|
-
response.headers['content-length'] || '0',
|
|
461
|
-
10,
|
|
462
|
-
);
|
|
460
|
+
const totalSize = Number.parseInt(response.headers['content-length'] || '0', 10);
|
|
463
461
|
let downloadedSize = 0;
|
|
464
462
|
let lastProgress = 0;
|
|
465
463
|
const file = fs.createWriteStream(destPath);
|
|
@@ -519,9 +517,7 @@ function sha256File(filePath) {
|
|
|
519
517
|
|
|
520
518
|
async function verifyChecksum(archiveUrl, archivePath, expectedSha256) {
|
|
521
519
|
if (isTruthy(process.env.QODER_SKIP_CHECKSUM)) {
|
|
522
|
-
console.log(
|
|
523
|
-
`${LOG_PREFIX} QODER_SKIP_CHECKSUM is set, skipping checksum verification.`,
|
|
524
|
-
);
|
|
520
|
+
console.log(`${LOG_PREFIX} QODER_SKIP_CHECKSUM is set, skipping checksum verification.`);
|
|
525
521
|
return;
|
|
526
522
|
}
|
|
527
523
|
|
|
@@ -532,9 +528,7 @@ async function verifyChecksum(archiveUrl, archivePath, expectedSha256) {
|
|
|
532
528
|
}
|
|
533
529
|
const actual = sha256File(archivePath);
|
|
534
530
|
if (actual !== expected) {
|
|
535
|
-
throw new Error(
|
|
536
|
-
`Checksum verification failed. Expected ${expected}, actual ${actual}`,
|
|
537
|
-
);
|
|
531
|
+
throw new Error(`Checksum verification failed. Expected ${expected}, actual ${actual}`);
|
|
538
532
|
}
|
|
539
533
|
console.log(`${LOG_PREFIX} Checksum verified.`);
|
|
540
534
|
return;
|
|
@@ -545,9 +539,7 @@ async function verifyChecksum(archiveUrl, archivePath, expectedSha256) {
|
|
|
545
539
|
const expected = parseSha256(fs.readFileSync(checksumPath, 'utf8'));
|
|
546
540
|
const actual = sha256File(archivePath);
|
|
547
541
|
if (actual !== expected) {
|
|
548
|
-
throw new Error(
|
|
549
|
-
`Checksum verification failed. Expected ${expected}, actual ${actual}`,
|
|
550
|
-
);
|
|
542
|
+
throw new Error(`Checksum verification failed. Expected ${expected}, actual ${actual}`);
|
|
551
543
|
}
|
|
552
544
|
console.log(`${LOG_PREFIX} Checksum verified.`);
|
|
553
545
|
}
|
|
@@ -577,12 +569,7 @@ function getTarExtractInvocation(archivePath, destDir) {
|
|
|
577
569
|
const cwd = pathApi.dirname(archivePath);
|
|
578
570
|
return {
|
|
579
571
|
cwd,
|
|
580
|
-
args: [
|
|
581
|
-
'-xzf',
|
|
582
|
-
pathApi.basename(archivePath),
|
|
583
|
-
'-C',
|
|
584
|
-
pathApi.relative(cwd, destDir) || '.',
|
|
585
|
-
],
|
|
572
|
+
args: ['-xzf', pathApi.basename(archivePath), '-C', pathApi.relative(cwd, destDir) || '.'],
|
|
586
573
|
};
|
|
587
574
|
}
|
|
588
575
|
|
|
@@ -624,7 +611,7 @@ function findCliBinary(dir, cliName) {
|
|
|
624
611
|
|
|
625
612
|
function isCliBinaryName(fileName, cliName) {
|
|
626
613
|
if (fileName === cliName) return true;
|
|
627
|
-
const sourceNames = ['qodercli', 'qoderclicn'];
|
|
614
|
+
const sourceNames = ['qoder', 'qodercli', 'qodercn', 'qoderclicn'];
|
|
628
615
|
if (process.platform === 'win32') {
|
|
629
616
|
return sourceNames.some(
|
|
630
617
|
(sourceName) =>
|
|
@@ -635,8 +622,7 @@ function isCliBinaryName(fileName, cliName) {
|
|
|
635
622
|
return sourceNames.some(
|
|
636
623
|
(sourceName) =>
|
|
637
624
|
fileName === sourceName ||
|
|
638
|
-
(new RegExp(`^${sourceName}-.+$`, 'i').test(fileName) &&
|
|
639
|
-
!fileName.endsWith('.sha256')),
|
|
625
|
+
(new RegExp(`^${sourceName}-.+$`, 'i').test(fileName) && !fileName.endsWith('.sha256')),
|
|
640
626
|
);
|
|
641
627
|
}
|
|
642
628
|
|
|
@@ -658,11 +644,12 @@ function copyDirContents(srcDir, destDir) {
|
|
|
658
644
|
}
|
|
659
645
|
|
|
660
646
|
function installExtractedContents(extractDir, bundledDir) {
|
|
661
|
-
const
|
|
647
|
+
const canonicalName = getCliSite() === 'cn' ? 'qoderclicn' : 'qodercli';
|
|
648
|
+
const cliName = process.platform === 'win32' ? `${canonicalName}.exe` : canonicalName;
|
|
662
649
|
const extractedCli = findCliBinary(extractDir, cliName);
|
|
663
650
|
if (!extractedCli) {
|
|
664
651
|
throw new Error(
|
|
665
|
-
'CLI binary not found in extracted archive. Expected qodercli/qoderclicn or platform-suffixed variants.',
|
|
652
|
+
'CLI binary not found in extracted archive. Expected qoder/qodercli/qodercn/qoderclicn or platform-suffixed variants.',
|
|
666
653
|
);
|
|
667
654
|
}
|
|
668
655
|
|
|
@@ -679,17 +666,14 @@ function installExtractedContents(extractDir, bundledDir) {
|
|
|
679
666
|
}
|
|
680
667
|
|
|
681
668
|
const files = fs.readdirSync(bundledDir);
|
|
682
|
-
console.log(
|
|
683
|
-
`${LOG_PREFIX} Copied ${files.length} file(s) to _bundled: ${files.join(', ')}`,
|
|
684
|
-
);
|
|
669
|
+
console.log(`${LOG_PREFIX} Copied ${files.length} file(s) to _bundled: ${files.join(', ')}`);
|
|
685
670
|
return target;
|
|
686
671
|
}
|
|
687
672
|
|
|
688
673
|
function findWorkerRuntimeRoot(dir) {
|
|
689
674
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
690
675
|
const hasWorkerRuntime = entries.some(
|
|
691
|
-
(entry) =>
|
|
692
|
-
entry.isFile() && WORKER_RUNTIME_ENTRY_NAMES.includes(entry.name),
|
|
676
|
+
(entry) => entry.isFile() && WORKER_RUNTIME_ENTRY_NAMES.includes(entry.name),
|
|
693
677
|
);
|
|
694
678
|
if (hasWorkerRuntime) return dir;
|
|
695
679
|
|
|
@@ -712,9 +696,7 @@ function getWorkerRuntimeEntryPath(runtimeDir) {
|
|
|
712
696
|
function assertWorkerRuntimeComplete(runtimeDir, sourceDescription) {
|
|
713
697
|
const runtimePath = getWorkerRuntimeEntryPath(runtimeDir);
|
|
714
698
|
if (!fs.existsSync(runtimePath)) {
|
|
715
|
-
throw new Error(
|
|
716
|
-
`Worker runtime entry missing in ${sourceDescription}: ${runtimePath}`,
|
|
717
|
-
);
|
|
699
|
+
throw new Error(`Worker runtime entry missing in ${sourceDescription}: ${runtimePath}`);
|
|
718
700
|
}
|
|
719
701
|
|
|
720
702
|
const missingAssets = REQUIRED_WORKER_RUNTIME_ASSETS.filter(
|
|
@@ -748,18 +730,14 @@ function installExtractedWorkerRuntime(extractDir, workerDir) {
|
|
|
748
730
|
const runtimePath = assertWorkerRuntimeComplete(workerDir, workerDir);
|
|
749
731
|
|
|
750
732
|
const files = fs.readdirSync(workerDir);
|
|
751
|
-
console.log(
|
|
752
|
-
`${LOG_PREFIX} Copied ${files.length} file(s) to _worker: ${files.join(', ')}`,
|
|
753
|
-
);
|
|
733
|
+
console.log(`${LOG_PREFIX} Copied ${files.length} file(s) to _worker: ${files.join(', ')}`);
|
|
754
734
|
return runtimePath;
|
|
755
735
|
}
|
|
756
736
|
|
|
757
737
|
async function installWorkerRuntimeFromDownload() {
|
|
758
738
|
const url = getWorkerRuntimeDownloadUrl();
|
|
759
739
|
const expectedSha256 = getWorkerRuntimeExpectedSha256(url);
|
|
760
|
-
const tempDir = fs.mkdtempSync(
|
|
761
|
-
path.join(os.tmpdir(), 'qoder-worker-runtime-'),
|
|
762
|
-
);
|
|
740
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'qoder-worker-runtime-'));
|
|
763
741
|
const archivePath = path.join(tempDir, path.basename(new URL(url).pathname));
|
|
764
742
|
const extractDir = path.join(tempDir, 'extract');
|
|
765
743
|
|
|
@@ -768,10 +746,7 @@ async function installWorkerRuntimeFromDownload() {
|
|
|
768
746
|
await verifyChecksum(url, archivePath, expectedSha256);
|
|
769
747
|
fs.mkdirSync(extractDir, { recursive: true });
|
|
770
748
|
await extractArchive(archivePath, extractDir);
|
|
771
|
-
return installExtractedWorkerRuntime(
|
|
772
|
-
extractDir,
|
|
773
|
-
getPackagedWorkerRuntimeDir(),
|
|
774
|
-
);
|
|
749
|
+
return installExtractedWorkerRuntime(extractDir, getPackagedWorkerRuntimeDir());
|
|
775
750
|
} finally {
|
|
776
751
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
777
752
|
}
|
|
@@ -779,16 +754,12 @@ async function installWorkerRuntimeFromDownload() {
|
|
|
779
754
|
|
|
780
755
|
async function main() {
|
|
781
756
|
if (isTruthy(process.env.QODER_SKIP_DOWNLOAD)) {
|
|
782
|
-
console.log(
|
|
783
|
-
`${LOG_PREFIX} QODER_SKIP_DOWNLOAD is set, skipping runtime downloads.`,
|
|
784
|
-
);
|
|
757
|
+
console.log(`${LOG_PREFIX} QODER_SKIP_DOWNLOAD is set, skipping runtime downloads.`);
|
|
785
758
|
return;
|
|
786
759
|
}
|
|
787
760
|
|
|
788
761
|
if (shouldInstallWorkerRuntimeForDefaultWorker()) {
|
|
789
|
-
console.log(
|
|
790
|
-
`${LOG_PREFIX} Package default runtime is Worker; downloading Worker runtime.`,
|
|
791
|
-
);
|
|
762
|
+
console.log(`${LOG_PREFIX} Package default runtime is Worker; downloading Worker runtime.`);
|
|
792
763
|
await installWorkerRuntimeFromDownload();
|
|
793
764
|
}
|
|
794
765
|
|
|
@@ -808,20 +779,41 @@ async function main() {
|
|
|
808
779
|
const version = getCliVersion();
|
|
809
780
|
const bundleName = getCliArtifactPrefix();
|
|
810
781
|
const target = getPlatformTarget();
|
|
811
|
-
|
|
812
|
-
|
|
782
|
+
let archiveName;
|
|
783
|
+
let downloadUrl;
|
|
784
|
+
let expectedSha256;
|
|
785
|
+
if (process.env.QODER_CLI_MIRROR) {
|
|
786
|
+
archiveName = getArtifactName(target);
|
|
787
|
+
downloadUrl = getDownloadUrl();
|
|
788
|
+
} else {
|
|
789
|
+
const manifestUrl = getReleaseManifestUrl(version);
|
|
790
|
+
const manifestPath = path.join(
|
|
791
|
+
fs.mkdtempSync(path.join(os.tmpdir(), 'qoder-cli-manifest-')),
|
|
792
|
+
'manifest.json',
|
|
793
|
+
);
|
|
794
|
+
try {
|
|
795
|
+
await downloadWithRetry(manifestUrl, manifestPath);
|
|
796
|
+
const selected = selectManifestArtifact(
|
|
797
|
+
JSON.parse(fs.readFileSync(manifestPath, 'utf8')),
|
|
798
|
+
target,
|
|
799
|
+
);
|
|
800
|
+
downloadUrl = selected.url;
|
|
801
|
+
expectedSha256 = selected.sha256;
|
|
802
|
+
archiveName = path.basename(new URL(downloadUrl).pathname);
|
|
803
|
+
} finally {
|
|
804
|
+
fs.rmSync(path.dirname(manifestPath), { recursive: true, force: true });
|
|
805
|
+
}
|
|
806
|
+
}
|
|
813
807
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'qoder-cli-'));
|
|
814
808
|
const archivePath = path.join(tempDir, archiveName);
|
|
815
809
|
const extractDir = path.join(tempDir, 'extract');
|
|
816
810
|
|
|
817
|
-
console.log(
|
|
818
|
-
`${LOG_PREFIX} Installing ${bundleName} ${version} for ${target}.`,
|
|
819
|
-
);
|
|
811
|
+
console.log(`${LOG_PREFIX} Installing ${bundleName} ${version} for ${target}.`);
|
|
820
812
|
|
|
821
813
|
try {
|
|
822
814
|
fs.mkdirSync(extractDir, { recursive: true });
|
|
823
815
|
await downloadWithRetry(downloadUrl, archivePath);
|
|
824
|
-
await verifyChecksum(downloadUrl, archivePath);
|
|
816
|
+
await verifyChecksum(downloadUrl, archivePath, expectedSha256);
|
|
825
817
|
await extractArchive(archivePath, extractDir);
|
|
826
818
|
const installedPath = installExtractedContents(extractDir, getBundledDir());
|
|
827
819
|
const stats = fs.statSync(installedPath);
|
|
@@ -829,9 +821,7 @@ async function main() {
|
|
|
829
821
|
`${LOG_PREFIX} CLI binary installed: ${installedPath} (${(stats.size / 1024 / 1024).toFixed(2)} MB)`,
|
|
830
822
|
);
|
|
831
823
|
} catch (error) {
|
|
832
|
-
console.error(
|
|
833
|
-
`${LOG_PREFIX} ERROR: Failed to install bundled CLI: ${error.message}`,
|
|
834
|
-
);
|
|
824
|
+
console.error(`${LOG_PREFIX} ERROR: Failed to install bundled CLI: ${error.message}`);
|
|
835
825
|
console.error(
|
|
836
826
|
`${LOG_PREFIX} Set QODER_SKIP_DOWNLOAD=1 to skip download and use a system qodercli.`,
|
|
837
827
|
);
|
|
@@ -866,6 +856,7 @@ module.exports = {
|
|
|
866
856
|
getPackagedWorkerRuntimePaths,
|
|
867
857
|
getRuntimeManifestPath,
|
|
868
858
|
getPlatformTarget,
|
|
859
|
+
getReleaseManifestUrl,
|
|
869
860
|
getDefaultRuntimeTransport,
|
|
870
861
|
getWorkerRuntimeExpectedSha256,
|
|
871
862
|
getWorkerRuntimeArtifactName,
|
|
@@ -879,6 +870,7 @@ module.exports = {
|
|
|
879
870
|
isDevCliVersion,
|
|
880
871
|
normalizeDownloadBaseUrl,
|
|
881
872
|
normalizePlatformOverride,
|
|
873
|
+
selectManifestArtifact,
|
|
882
874
|
readPackagedWorkerRuntimeInfo,
|
|
883
875
|
readRuntimeManifest,
|
|
884
876
|
shouldInstallWorkerRuntimeForDefaultWorker,
|