claude-code-arcane 2.9.2 → 2.9.3
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/CHANGELOG.md +7 -0
- package/dist/cli.js +46 -25
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [2.9.3](https://github.com/SebastianLuser/claude-code-arcane/compare/v2.9.2...v2.9.3) (2026-09-07)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **update:** resolve the content version once per run, never fabricate it ([ef78ecf](https://github.com/SebastianLuser/claude-code-arcane/commit/ef78ecf6c5ab17f1a51ea6ae27ef9fa161594798))
|
|
7
|
+
|
|
1
8
|
## [2.9.2](https://github.com/SebastianLuser/claude-code-arcane/compare/v2.9.1...v2.9.2) (2026-09-07)
|
|
2
9
|
|
|
3
10
|
|
package/dist/cli.js
CHANGED
|
@@ -1439,22 +1439,18 @@ var GitHubContentSource = class {
|
|
|
1439
1439
|
fs9.rmSync(tmpDir, { recursive: true, force: true });
|
|
1440
1440
|
}
|
|
1441
1441
|
}
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
return false;
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
async getVersion() {
|
|
1442
|
+
/**
|
|
1443
|
+
* The head commit of the branch, or null when GitHub cannot answer.
|
|
1444
|
+
*
|
|
1445
|
+
* One request, memoized, shared by isAvailable() and getVersion(). It used to be
|
|
1446
|
+
* two - a HEAD to answer "is it reachable?" and a GET to read the sha - against an
|
|
1447
|
+
* endpoint that allows 60 requests an hour unauthenticated. That doubled the cost of
|
|
1448
|
+
* every resolution and, worse, opened a window between the two calls: the HEAD spent
|
|
1449
|
+
* the last request of the hour, the GET came back 403, and the caller had already
|
|
1450
|
+
* committed to the github source. That window is where the fabricated versions came
|
|
1451
|
+
* from.
|
|
1452
|
+
*/
|
|
1453
|
+
async resolveVersion() {
|
|
1458
1454
|
if (this.resolvedVersion) return this.resolvedVersion;
|
|
1459
1455
|
try {
|
|
1460
1456
|
const response = await fetch(
|
|
@@ -1467,17 +1463,36 @@ var GitHubContentSource = class {
|
|
|
1467
1463
|
signal: AbortSignal.timeout(1e4)
|
|
1468
1464
|
}
|
|
1469
1465
|
);
|
|
1470
|
-
if (!response.ok)
|
|
1471
|
-
throw new Error(`GitHub API returned ${response.status}`);
|
|
1472
|
-
}
|
|
1466
|
+
if (!response.ok) return null;
|
|
1473
1467
|
const data = await response.json();
|
|
1474
1468
|
this.resolvedVersion = data.sha.substring(0, 12);
|
|
1475
1469
|
return this.resolvedVersion;
|
|
1476
1470
|
} catch {
|
|
1477
|
-
|
|
1478
|
-
return this.resolvedVersion;
|
|
1471
|
+
return null;
|
|
1479
1472
|
}
|
|
1480
1473
|
}
|
|
1474
|
+
async isAvailable() {
|
|
1475
|
+
return await this.resolveVersion() !== null;
|
|
1476
|
+
}
|
|
1477
|
+
/**
|
|
1478
|
+
* Throws when the version cannot be read, rather than inventing one.
|
|
1479
|
+
*
|
|
1480
|
+
* It used to answer `github-${Date.now()}` on any failure, and that string went on to
|
|
1481
|
+
* be an identity: it stamped `source_version` in the manifest, named a cache directory,
|
|
1482
|
+
* and made the install permanently un-diffable against any real version - it never
|
|
1483
|
+
* matched again, so every later run reported an update and no run ever settled. A
|
|
1484
|
+
* transient 403 became durable state on disk. Callers that cannot proceed without a
|
|
1485
|
+
* version now fall back to the cache, which knows a real one.
|
|
1486
|
+
*/
|
|
1487
|
+
async getVersion() {
|
|
1488
|
+
const version = await this.resolveVersion();
|
|
1489
|
+
if (!version) {
|
|
1490
|
+
throw new Error(
|
|
1491
|
+
"Could not read the content version from GitHub (offline, or the unauthenticated API rate limit is exhausted - it resets hourly)."
|
|
1492
|
+
);
|
|
1493
|
+
}
|
|
1494
|
+
return version;
|
|
1495
|
+
}
|
|
1481
1496
|
async downloadAndExtract(destDir) {
|
|
1482
1497
|
const tarballUrl = `https://api.github.com/repos/${this.owner}/${this.repo}/tarball/${this.branch}`;
|
|
1483
1498
|
const response = await fetch(tarballUrl, {
|
|
@@ -1548,7 +1563,9 @@ async function resolveContentSource(opts = {}) {
|
|
|
1548
1563
|
return github;
|
|
1549
1564
|
}
|
|
1550
1565
|
if (preference === "github") {
|
|
1551
|
-
throw new Error(
|
|
1566
|
+
throw new Error(
|
|
1567
|
+
"GitHub source requested but not available. Check your internet connection, or wait for the unauthenticated API rate limit to reset (hourly)."
|
|
1568
|
+
);
|
|
1552
1569
|
}
|
|
1553
1570
|
const cached = findLatestCache();
|
|
1554
1571
|
if (cached) {
|
|
@@ -2357,6 +2374,10 @@ async function updateCommand(opts) {
|
|
|
2357
2374
|
Updating ${targets.length} installation${targets.length === 1 ? "" : "s"}...`)
|
|
2358
2375
|
);
|
|
2359
2376
|
}
|
|
2377
|
+
const sharedSource = await resolveContentSource({
|
|
2378
|
+
source: opts.source ?? "auto",
|
|
2379
|
+
quiet: opts.quiet
|
|
2380
|
+
});
|
|
2360
2381
|
const results = [];
|
|
2361
2382
|
for (const target of targets) {
|
|
2362
2383
|
if (!opts.quiet) {
|
|
@@ -2364,7 +2385,7 @@ Updating ${targets.length} installation${targets.length === 1 ? "" : "s"}...`)
|
|
|
2364
2385
|
\u2022 ${target}`));
|
|
2365
2386
|
}
|
|
2366
2387
|
try {
|
|
2367
|
-
results.push(await updateTarget(target, opts));
|
|
2388
|
+
results.push(await updateTarget(target, opts, sharedSource));
|
|
2368
2389
|
} catch (err) {
|
|
2369
2390
|
if (!opts.quiet) {
|
|
2370
2391
|
console.log(chalk7.red(` Update failed: ${err.message}`));
|
|
@@ -2382,7 +2403,7 @@ Updating ${targets.length} installation${targets.length === 1 ? "" : "s"}...`)
|
|
|
2382
2403
|
printGeneralSummary(results, opts.dryRun ?? false);
|
|
2383
2404
|
}
|
|
2384
2405
|
}
|
|
2385
|
-
async function updateTarget(target, opts) {
|
|
2406
|
+
async function updateTarget(target, opts, sharedSource) {
|
|
2386
2407
|
const manifest = readManifest(target);
|
|
2387
2408
|
if (!manifest) {
|
|
2388
2409
|
if (!opts.quiet) {
|
|
@@ -2390,7 +2411,7 @@ async function updateTarget(target, opts) {
|
|
|
2390
2411
|
}
|
|
2391
2412
|
return { target, status: "no-manifest", updated: 0, skipped: 0, removed: 0 };
|
|
2392
2413
|
}
|
|
2393
|
-
const contentSource = await resolveContentSource({
|
|
2414
|
+
const contentSource = sharedSource ?? await resolveContentSource({
|
|
2394
2415
|
source: opts.source ?? "auto",
|
|
2395
2416
|
quiet: opts.quiet
|
|
2396
2417
|
});
|