claude-code-arcane 2.9.3 → 2.9.4
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 +8 -0
- package/dist/cli.js +83 -49
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## [2.9.4](https://github.com/SebastianLuser/claude-code-arcane/compare/v2.9.3...v2.9.4) (2026-09-07)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **add:** keep content_hashes instead of rebuilding the manifest ([1ecce98](https://github.com/SebastianLuser/claude-code-arcane/commit/1ecce98ebcb8a480dd4b748f41606badec9fb0fd))
|
|
7
|
+
* **cache:** resolve the arcane home in one place, honouring ARCANE_HOME ([4a7a24d](https://github.com/SebastianLuser/claude-code-arcane/commit/4a7a24d6a28df1abfe94be75f590c79d8428dca5))
|
|
8
|
+
|
|
1
9
|
## [2.9.3](https://github.com/SebastianLuser/claude-code-arcane/compare/v2.9.2...v2.9.3) (2026-09-07)
|
|
2
10
|
|
|
3
11
|
|
package/dist/cli.js
CHANGED
|
@@ -391,6 +391,10 @@ import path8 from "path";
|
|
|
391
391
|
import { fileURLToPath } from "url";
|
|
392
392
|
import path3 from "path";
|
|
393
393
|
import fs3 from "fs";
|
|
394
|
+
import os from "os";
|
|
395
|
+
function arcaneHome() {
|
|
396
|
+
return process.env.ARCANE_HOME ?? path3.join(os.homedir(), ".arcane");
|
|
397
|
+
}
|
|
394
398
|
function getPackageRoot() {
|
|
395
399
|
const thisFile = fileURLToPath(import.meta.url);
|
|
396
400
|
return path3.resolve(path3.dirname(thisFile), "..");
|
|
@@ -1310,15 +1314,18 @@ import os2 from "os";
|
|
|
1310
1314
|
// src/cache.ts
|
|
1311
1315
|
import fs8 from "fs";
|
|
1312
1316
|
import path9 from "path";
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1317
|
+
function cacheDir() {
|
|
1318
|
+
return path9.join(arcaneHome(), "cache");
|
|
1319
|
+
}
|
|
1316
1320
|
function getCachePath(version) {
|
|
1317
|
-
return path9.join(
|
|
1321
|
+
return path9.join(cacheDir(), version);
|
|
1322
|
+
}
|
|
1323
|
+
function isUsableContentRoot(dir) {
|
|
1324
|
+
return fs8.existsSync(path9.join(dir, "profiles")) && fs8.existsSync(path9.join(dir, "skills"));
|
|
1318
1325
|
}
|
|
1319
1326
|
function isCached(version) {
|
|
1320
1327
|
const versionDir = getCachePath(version);
|
|
1321
|
-
return fs8.existsSync(versionDir) && fs8.existsSync(path9.join(versionDir, ".cache-meta.json"));
|
|
1328
|
+
return fs8.existsSync(versionDir) && fs8.existsSync(path9.join(versionDir, ".cache-meta.json")) && isUsableContentRoot(versionDir);
|
|
1322
1329
|
}
|
|
1323
1330
|
function getCachedContentRoot(version) {
|
|
1324
1331
|
if (!isCached(version)) return null;
|
|
@@ -1347,9 +1354,9 @@ function storeInCache(version, contentDir) {
|
|
|
1347
1354
|
return versionDir;
|
|
1348
1355
|
}
|
|
1349
1356
|
function pruneCache(keepCount = 3) {
|
|
1350
|
-
if (!fs8.existsSync(
|
|
1351
|
-
const entries = fs8.readdirSync(
|
|
1352
|
-
const metaPath = path9.join(
|
|
1357
|
+
if (!fs8.existsSync(cacheDir())) return;
|
|
1358
|
+
const entries = fs8.readdirSync(cacheDir(), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => {
|
|
1359
|
+
const metaPath = path9.join(cacheDir(), e.name, ".cache-meta.json");
|
|
1353
1360
|
let cachedAt = 0;
|
|
1354
1361
|
if (fs8.existsSync(metaPath)) {
|
|
1355
1362
|
try {
|
|
@@ -1362,9 +1369,24 @@ function pruneCache(keepCount = 3) {
|
|
|
1362
1369
|
return { name: e.name, cachedAt };
|
|
1363
1370
|
}).sort((a, b) => b.cachedAt - a.cachedAt);
|
|
1364
1371
|
for (const entry of entries.slice(keepCount)) {
|
|
1365
|
-
fs8.rmSync(path9.join(
|
|
1372
|
+
fs8.rmSync(path9.join(cacheDir(), entry.name), { recursive: true, force: true });
|
|
1366
1373
|
}
|
|
1367
1374
|
}
|
|
1375
|
+
function listCachedVersions() {
|
|
1376
|
+
if (!fs8.existsSync(cacheDir())) return [];
|
|
1377
|
+
return fs8.readdirSync(cacheDir(), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => {
|
|
1378
|
+
const metaPath = path9.join(cacheDir(), e.name, ".cache-meta.json");
|
|
1379
|
+
let cachedAt = "unknown";
|
|
1380
|
+
if (fs8.existsSync(metaPath)) {
|
|
1381
|
+
try {
|
|
1382
|
+
const meta = JSON.parse(fs8.readFileSync(metaPath, "utf-8"));
|
|
1383
|
+
cachedAt = meta.cached_at;
|
|
1384
|
+
} catch {
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
return { version: e.name, cachedAt };
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1368
1390
|
function copyDirRecursive(src, dest) {
|
|
1369
1391
|
fs8.mkdirSync(dest, { recursive: true });
|
|
1370
1392
|
for (const entry of fs8.readdirSync(src, { withFileTypes: true })) {
|
|
@@ -1595,31 +1617,16 @@ async function resolveContentSourceForVersion(version, opts = {}) {
|
|
|
1595
1617
|
return source;
|
|
1596
1618
|
}
|
|
1597
1619
|
function findLatestCache() {
|
|
1598
|
-
const
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
if (fs9.existsSync(metaPath)) {
|
|
1604
|
-
try {
|
|
1605
|
-
const meta = JSON.parse(fs9.readFileSync(metaPath, "utf-8"));
|
|
1606
|
-
cachedAt = new Date(meta.cached_at).getTime();
|
|
1607
|
-
} catch {
|
|
1608
|
-
cachedAt = 0;
|
|
1609
|
-
}
|
|
1610
|
-
}
|
|
1611
|
-
return { name: e.name, cachedAt };
|
|
1612
|
-
}).sort((a, b) => b.cachedAt - a.cachedAt);
|
|
1613
|
-
return entries.length > 0 ? entries[0].name : null;
|
|
1620
|
+
const usable = listCachedVersions().filter((entry) => isCached(entry.version)).map((entry) => ({
|
|
1621
|
+
version: entry.version,
|
|
1622
|
+
cachedAt: new Date(entry.cachedAt).getTime() || 0
|
|
1623
|
+
})).sort((a, b) => b.cachedAt - a.cachedAt);
|
|
1624
|
+
return usable.length > 0 ? usable[0].version : null;
|
|
1614
1625
|
}
|
|
1615
1626
|
|
|
1616
1627
|
// src/registry.ts
|
|
1617
1628
|
import path11 from "path";
|
|
1618
|
-
import os3 from "os";
|
|
1619
1629
|
var REGISTRY_VERSION = 1;
|
|
1620
|
-
function arcaneHome() {
|
|
1621
|
-
return process.env.ARCANE_HOME ?? path11.join(os3.homedir(), ".arcane");
|
|
1622
|
-
}
|
|
1623
1630
|
function registryPath() {
|
|
1624
1631
|
return path11.join(arcaneHome(), "installations.json");
|
|
1625
1632
|
}
|
|
@@ -1898,16 +1905,11 @@ async function addCommand(items = []) {
|
|
|
1898
1905
|
manifest.installed_skills.push(...added);
|
|
1899
1906
|
manifest.total_skills = manifest.installed_skills.length;
|
|
1900
1907
|
manifest.total_rules = manifest.installed_rules.length;
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
hooks: [],
|
|
1907
|
-
output_styles: [],
|
|
1908
|
-
permissions: { allow: [], deny: [] }
|
|
1909
|
-
};
|
|
1910
|
-
writeManifest(target, merged, manifest.profile_command, root);
|
|
1908
|
+
persistAdditions(target, claudeDir, manifest, {
|
|
1909
|
+
skills: added,
|
|
1910
|
+
rules: addedRules,
|
|
1911
|
+
agents: addedAgents
|
|
1912
|
+
});
|
|
1911
1913
|
const totalAdded = added.length + addedRules.length + addedAgents.length + (statuslineAdded ? 1 : 0);
|
|
1912
1914
|
console.log(
|
|
1913
1915
|
chalk3.bold(
|
|
@@ -1932,6 +1934,35 @@ Added ${totalAdded} items:`
|
|
|
1932
1934
|
);
|
|
1933
1935
|
}
|
|
1934
1936
|
}
|
|
1937
|
+
function persistAdditions(target, claudeDir, manifest, addedItems) {
|
|
1938
|
+
const updates = {
|
|
1939
|
+
profiles: manifest.profiles,
|
|
1940
|
+
profile_command: manifest.profile_command,
|
|
1941
|
+
installed_skills: manifest.installed_skills,
|
|
1942
|
+
installed_rules: manifest.installed_rules,
|
|
1943
|
+
installed_agents: manifest.installed_agents,
|
|
1944
|
+
total_skills: manifest.total_skills,
|
|
1945
|
+
total_rules: manifest.total_rules,
|
|
1946
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z")
|
|
1947
|
+
};
|
|
1948
|
+
const hashes = manifest.content_hashes;
|
|
1949
|
+
if (hashes) {
|
|
1950
|
+
const fresh = computeContentHashes(claudeDir);
|
|
1951
|
+
for (const skill of addedItems.skills) {
|
|
1952
|
+
if (fresh.skills[skill]) hashes.skills[skill] = fresh.skills[skill];
|
|
1953
|
+
}
|
|
1954
|
+
for (const rule of addedItems.rules) {
|
|
1955
|
+
const key = rule.endsWith(".md") ? rule : `${rule}.md`;
|
|
1956
|
+
if (fresh.rules[key]) hashes.rules[key] = fresh.rules[key];
|
|
1957
|
+
}
|
|
1958
|
+
for (const entry of addedItems.agents) {
|
|
1959
|
+
const { division } = parseAgentEntry(entry);
|
|
1960
|
+
if (fresh.agents[division]) hashes.agents[division] = fresh.agents[division];
|
|
1961
|
+
}
|
|
1962
|
+
updates.content_hashes = hashes;
|
|
1963
|
+
}
|
|
1964
|
+
updateManifestFields(target, updates);
|
|
1965
|
+
}
|
|
1935
1966
|
function printCatalog(root, installedProfiles, installedSkills) {
|
|
1936
1967
|
const profiles = listProfiles(path14.join(root, "profiles")).filter(
|
|
1937
1968
|
(pr) => !installedProfiles.includes(pr.name)
|
|
@@ -2278,7 +2309,7 @@ async function statusCommand() {
|
|
|
2278
2309
|
// src/commands/update.ts
|
|
2279
2310
|
import fs14 from "fs";
|
|
2280
2311
|
import path17 from "path";
|
|
2281
|
-
import
|
|
2312
|
+
import os3 from "os";
|
|
2282
2313
|
import chalk7 from "chalk";
|
|
2283
2314
|
|
|
2284
2315
|
// src/self-update.ts
|
|
@@ -2358,7 +2389,7 @@ async function updateCommand(opts) {
|
|
|
2358
2389
|
registerInstallation(cwd);
|
|
2359
2390
|
}
|
|
2360
2391
|
const targets = pruneRegistry().map((e) => e.path);
|
|
2361
|
-
const globalTarget =
|
|
2392
|
+
const globalTarget = os3.homedir();
|
|
2362
2393
|
if (!process.env.VITEST && fs14.existsSync(manifestPath(globalTarget)) && !targets.includes(globalTarget)) {
|
|
2363
2394
|
targets.push(globalTarget);
|
|
2364
2395
|
}
|
|
@@ -3022,9 +3053,9 @@ async function worktreeCommand(branch, opts) {
|
|
|
3022
3053
|
// src/commands/global.ts
|
|
3023
3054
|
import fs16 from "fs";
|
|
3024
3055
|
import path19 from "path";
|
|
3025
|
-
import
|
|
3056
|
+
import os4 from "os";
|
|
3026
3057
|
import chalk10 from "chalk";
|
|
3027
|
-
var CLAUDE_HOME = path19.join(
|
|
3058
|
+
var CLAUDE_HOME = path19.join(os4.homedir(), ".claude");
|
|
3028
3059
|
var SCRIPTS_DIR = path19.join(CLAUDE_HOME, "scripts", "worktree-isolation");
|
|
3029
3060
|
var SETTINGS_PATH = path19.join(CLAUDE_HOME, "settings.json");
|
|
3030
3061
|
async function globalCommand(opts) {
|
|
@@ -3191,9 +3222,10 @@ function removeHookFromSettings() {
|
|
|
3191
3222
|
// src/update-check.ts
|
|
3192
3223
|
import fs17 from "fs";
|
|
3193
3224
|
import path20 from "path";
|
|
3194
|
-
import os6 from "os";
|
|
3195
3225
|
import chalk11 from "chalk";
|
|
3196
|
-
|
|
3226
|
+
function checkFile() {
|
|
3227
|
+
return path20.join(arcaneHome(), "last-check.json");
|
|
3228
|
+
}
|
|
3197
3229
|
var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
3198
3230
|
var GITHUB_OWNER2 = "SebastianLuser";
|
|
3199
3231
|
var GITHUB_REPO2 = "Claude-Code-Arcane";
|
|
@@ -3318,19 +3350,21 @@ async function getLatestNpmVersion() {
|
|
|
3318
3350
|
}
|
|
3319
3351
|
function readCachedCheck() {
|
|
3320
3352
|
try {
|
|
3321
|
-
|
|
3322
|
-
|
|
3353
|
+
const file = checkFile();
|
|
3354
|
+
if (!fs17.existsSync(file)) return null;
|
|
3355
|
+
return JSON.parse(fs17.readFileSync(file, "utf-8"));
|
|
3323
3356
|
} catch {
|
|
3324
3357
|
return null;
|
|
3325
3358
|
}
|
|
3326
3359
|
}
|
|
3327
3360
|
function writeCachedCheck(result) {
|
|
3328
3361
|
try {
|
|
3329
|
-
const
|
|
3362
|
+
const file = checkFile();
|
|
3363
|
+
const dir = path20.dirname(file);
|
|
3330
3364
|
if (!fs17.existsSync(dir)) {
|
|
3331
3365
|
fs17.mkdirSync(dir, { recursive: true });
|
|
3332
3366
|
}
|
|
3333
|
-
fs17.writeFileSync(
|
|
3367
|
+
fs17.writeFileSync(file, JSON.stringify(result, null, 2) + "\n");
|
|
3334
3368
|
} catch {
|
|
3335
3369
|
}
|
|
3336
3370
|
}
|