@skillsmith/cli 0.8.5 → 0.8.6
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 +33 -0
- package/README.md +2 -2
- package/dist/.skillsmith-dist-hash +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli.js +595 -236
- package/package.json +4 -4
package/dist/cli.js
CHANGED
|
@@ -782,7 +782,7 @@ var init_is_inside_container = __esm({
|
|
|
782
782
|
|
|
783
783
|
// ../../node_modules/is-wsl/index.js
|
|
784
784
|
import process4 from "node:process";
|
|
785
|
-
import
|
|
785
|
+
import os5 from "node:os";
|
|
786
786
|
import fs14 from "node:fs";
|
|
787
787
|
var isWsl, is_wsl_default;
|
|
788
788
|
var init_is_wsl = __esm({
|
|
@@ -792,7 +792,7 @@ var init_is_wsl = __esm({
|
|
|
792
792
|
if (process4.platform !== "linux") {
|
|
793
793
|
return false;
|
|
794
794
|
}
|
|
795
|
-
if (
|
|
795
|
+
if (os5.release().toLowerCase().includes("microsoft")) {
|
|
796
796
|
if (isInsideContainer()) {
|
|
797
797
|
return false;
|
|
798
798
|
}
|
|
@@ -1332,19 +1332,19 @@ var init_open = __esm({
|
|
|
1332
1332
|
}
|
|
1333
1333
|
const subprocess = childProcess3.spawn(command, cliArguments, childProcessOptions);
|
|
1334
1334
|
if (options.wait) {
|
|
1335
|
-
return new Promise((
|
|
1335
|
+
return new Promise((resolve20, reject) => {
|
|
1336
1336
|
subprocess.once("error", reject);
|
|
1337
1337
|
subprocess.once("close", (exitCode) => {
|
|
1338
1338
|
if (!options.allowNonzeroExitCode && exitCode !== 0) {
|
|
1339
1339
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
1340
1340
|
return;
|
|
1341
1341
|
}
|
|
1342
|
-
|
|
1342
|
+
resolve20(subprocess);
|
|
1343
1343
|
});
|
|
1344
1344
|
});
|
|
1345
1345
|
}
|
|
1346
1346
|
if (isFallbackAttempt) {
|
|
1347
|
-
return new Promise((
|
|
1347
|
+
return new Promise((resolve20, reject) => {
|
|
1348
1348
|
subprocess.once("error", reject);
|
|
1349
1349
|
subprocess.once("spawn", () => {
|
|
1350
1350
|
subprocess.once("close", (exitCode) => {
|
|
@@ -1354,17 +1354,17 @@ var init_open = __esm({
|
|
|
1354
1354
|
return;
|
|
1355
1355
|
}
|
|
1356
1356
|
subprocess.unref();
|
|
1357
|
-
|
|
1357
|
+
resolve20(subprocess);
|
|
1358
1358
|
});
|
|
1359
1359
|
});
|
|
1360
1360
|
});
|
|
1361
1361
|
}
|
|
1362
1362
|
subprocess.unref();
|
|
1363
|
-
return new Promise((
|
|
1363
|
+
return new Promise((resolve20, reject) => {
|
|
1364
1364
|
subprocess.once("error", reject);
|
|
1365
1365
|
subprocess.once("spawn", () => {
|
|
1366
1366
|
subprocess.off("error", reject);
|
|
1367
|
-
|
|
1367
|
+
resolve20(subprocess);
|
|
1368
1368
|
});
|
|
1369
1369
|
});
|
|
1370
1370
|
};
|
|
@@ -1452,7 +1452,7 @@ import { homedir as homedir8 } from "os";
|
|
|
1452
1452
|
// ../core/dist/src/install/paths.js
|
|
1453
1453
|
import { existsSync } from "node:fs";
|
|
1454
1454
|
import { homedir } from "node:os";
|
|
1455
|
-
import { join } from "node:path";
|
|
1455
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
1456
1456
|
var CLIENT_NATIVE_PATHS = {
|
|
1457
1457
|
"claude-code": join(homedir(), ".claude", "skills"),
|
|
1458
1458
|
cursor: join(homedir(), ".cursor", "skills"),
|
|
@@ -1461,7 +1461,8 @@ var CLIENT_NATIVE_PATHS = {
|
|
|
1461
1461
|
agents: join(homedir(), ".agents", "skills"),
|
|
1462
1462
|
opencode: join(homedir(), ".config", "opencode", "skills"),
|
|
1463
1463
|
hermes: join(homedir(), ".hermes", "skills"),
|
|
1464
|
-
grok: join(homedir(), ".grok", "skills")
|
|
1464
|
+
grok: join(homedir(), ".grok", "skills"),
|
|
1465
|
+
antigravity: join(homedir(), ".gemini", "config", "skills")
|
|
1465
1466
|
};
|
|
1466
1467
|
var CANONICAL_CLIENT = "claude-code";
|
|
1467
1468
|
var CLIENT_DISPLAY_LABELS = {
|
|
@@ -1472,7 +1473,8 @@ var CLIENT_DISPLAY_LABELS = {
|
|
|
1472
1473
|
agents: "your agent",
|
|
1473
1474
|
opencode: "OpenCode",
|
|
1474
1475
|
hermes: "Hermes",
|
|
1475
|
-
grok: "Grok Build"
|
|
1476
|
+
grok: "Grok Build",
|
|
1477
|
+
antigravity: "Antigravity"
|
|
1476
1478
|
};
|
|
1477
1479
|
var CLIENT_IDS = Object.freeze([
|
|
1478
1480
|
"claude-code",
|
|
@@ -1482,7 +1484,8 @@ var CLIENT_IDS = Object.freeze([
|
|
|
1482
1484
|
"agents",
|
|
1483
1485
|
"opencode",
|
|
1484
1486
|
"hermes",
|
|
1485
|
-
"grok"
|
|
1487
|
+
"grok",
|
|
1488
|
+
"antigravity"
|
|
1486
1489
|
]);
|
|
1487
1490
|
function getCanonicalInstallPath() {
|
|
1488
1491
|
return CLIENT_NATIVE_PATHS[CANONICAL_CLIENT];
|
|
@@ -1515,6 +1518,108 @@ function enumerateHarnessPresence() {
|
|
|
1515
1518
|
};
|
|
1516
1519
|
});
|
|
1517
1520
|
}
|
|
1521
|
+
var COMPANION_AGENT_TARGETS = {
|
|
1522
|
+
"claude-code": {
|
|
1523
|
+
dir: join(homedir(), ".claude", "agents"),
|
|
1524
|
+
fileMode: "flat",
|
|
1525
|
+
filenamePattern: "{name}-specialist.md"
|
|
1526
|
+
},
|
|
1527
|
+
cursor: {
|
|
1528
|
+
// AGENT_SHIM_TARGETS.cursor is null (no distinct value) — defaults like
|
|
1529
|
+
// every client with no independent evidence. See doc comment above.
|
|
1530
|
+
dir: join(homedir(), ".claude", "agents"),
|
|
1531
|
+
fileMode: "flat",
|
|
1532
|
+
filenamePattern: "{name}-specialist.md"
|
|
1533
|
+
},
|
|
1534
|
+
copilot: {
|
|
1535
|
+
// PR-review finding (BLOCKING): both dir AND filename are now cited
|
|
1536
|
+
// from AGENT_SHIM_TARGETS.copilot (agent-harness-targets.ts:156,
|
|
1537
|
+
// `skillsmith-agent.agent.md`) and shims.ts's own doc comment ("Copilot
|
|
1538
|
+
// `.agent.md` (Copilot cloud-agent + CLI surfaces, which do not read
|
|
1539
|
+
// `.claude/agents`)") -- this codebase already has independently
|
|
1540
|
+
// verified evidence that Copilot's real companion-agent format is
|
|
1541
|
+
// `<name>.agent.md`, not the generic `-specialist.md` suffix every
|
|
1542
|
+
// other client here defaults to. Writing plain `.md` risked producing
|
|
1543
|
+
// an undiscoverable companion file.
|
|
1544
|
+
dir: join(homedir(), ".copilot", "agents"),
|
|
1545
|
+
fileMode: "flat",
|
|
1546
|
+
filenamePattern: "{name}.agent.md"
|
|
1547
|
+
},
|
|
1548
|
+
windsurf: {
|
|
1549
|
+
// No AGENT_SHIM_TARGETS entry exists for windsurf (not a HarnessId
|
|
1550
|
+
// member) — defaults to today's actual behavior.
|
|
1551
|
+
dir: join(homedir(), ".claude", "agents"),
|
|
1552
|
+
fileMode: "flat",
|
|
1553
|
+
filenamePattern: "{name}-specialist.md"
|
|
1554
|
+
},
|
|
1555
|
+
agents: {
|
|
1556
|
+
// No AGENT_SHIM_TARGETS entry exists for `agents` (not a HarnessId
|
|
1557
|
+
// member) — defaults to today's actual behavior.
|
|
1558
|
+
dir: join(homedir(), ".claude", "agents"),
|
|
1559
|
+
fileMode: "flat",
|
|
1560
|
+
filenamePattern: "{name}-specialist.md"
|
|
1561
|
+
},
|
|
1562
|
+
opencode: {
|
|
1563
|
+
// Directory cited from AGENT_SHIM_TARGETS.opencode (agent-harness-targets.ts)
|
|
1564
|
+
// as independent evidence of OpenCode's own agents-dir convention.
|
|
1565
|
+
// Filename pattern is this map's own naming, not copied from that table.
|
|
1566
|
+
dir: join(homedir(), ".config", "opencode", "agents"),
|
|
1567
|
+
fileMode: "flat",
|
|
1568
|
+
filenamePattern: "{name}-specialist.md"
|
|
1569
|
+
},
|
|
1570
|
+
hermes: {
|
|
1571
|
+
// No AGENT_SHIM_TARGETS entry exists for hermes (not a HarnessId
|
|
1572
|
+
// member) — defaults to today's actual behavior.
|
|
1573
|
+
dir: join(homedir(), ".claude", "agents"),
|
|
1574
|
+
fileMode: "flat",
|
|
1575
|
+
filenamePattern: "{name}-specialist.md"
|
|
1576
|
+
},
|
|
1577
|
+
grok: {
|
|
1578
|
+
// No AGENT_SHIM_TARGETS entry exists for grok (not a HarnessId member)
|
|
1579
|
+
// — defaults to today's actual behavior.
|
|
1580
|
+
dir: join(homedir(), ".claude", "agents"),
|
|
1581
|
+
fileMode: "flat",
|
|
1582
|
+
filenamePattern: "{name}-specialist.md"
|
|
1583
|
+
},
|
|
1584
|
+
antigravity: {
|
|
1585
|
+
// SMI-5982 (Wave 6): directory-package mode, not flat — confirmed via a
|
|
1586
|
+
// live web search against antigravity.google/docs/cli/commands/agents
|
|
1587
|
+
// (2026-08-11): each agent is a directory `<name>/` containing a single
|
|
1588
|
+
// `agent.md` (YAML frontmatter: `name`, `description` only — no
|
|
1589
|
+
// `subagent:` field or equivalent exists in the real schema, confirming
|
|
1590
|
+
// the plan's decision NOT to emit one). `dir` is intentionally a
|
|
1591
|
+
// RELATIVE path (`.agents/agents`, resolved against the process's
|
|
1592
|
+
// invocation directory by Node's fs calls) — project-scoped, per Step 1
|
|
1593
|
+
// of the SMI-5982 plan: this CLI has no existing global-vs-project
|
|
1594
|
+
// install-mode distinction to hook into, so this defaults to
|
|
1595
|
+
// project-scoped rather than inventing scope-detection logic. Global
|
|
1596
|
+
// scope (`~/.gemini/config/agents/`) is an explicit fast-follow.
|
|
1597
|
+
dir: join(".agents", "agents"),
|
|
1598
|
+
fileMode: "directory-package",
|
|
1599
|
+
filenamePattern: "agent.md"
|
|
1600
|
+
}
|
|
1601
|
+
};
|
|
1602
|
+
function getCompanionAgentTarget(client = CANONICAL_CLIENT) {
|
|
1603
|
+
return COMPANION_AGENT_TARGETS[client];
|
|
1604
|
+
}
|
|
1605
|
+
function resolveCompanionAgentDir(client = CANONICAL_CLIENT) {
|
|
1606
|
+
return getCompanionAgentTarget(client).dir;
|
|
1607
|
+
}
|
|
1608
|
+
function resolveCompanionAgentPath(skillName, client = CANONICAL_CLIENT, baseDir) {
|
|
1609
|
+
const target = getCompanionAgentTarget(client);
|
|
1610
|
+
if (target.fileMode === "directory-package" && baseDir === void 0) {
|
|
1611
|
+
throw new Error(`resolveCompanionAgentPath: client "${client}" uses directory-package mode with a relative companion-agent directory, so an explicit baseDir is required \u2014 it cannot safely default to process.cwd() (a long-running MCP server's cwd does not track the calling client's real project; see SMI-5982 PR review).`);
|
|
1612
|
+
}
|
|
1613
|
+
const resolvedDir = isAbsolute(target.dir) ? target.dir : resolve(baseDir, target.dir);
|
|
1614
|
+
if (target.fileMode === "directory-package") {
|
|
1615
|
+
if (skillName === "" || skillName === "." || skillName === ".." || skillName.includes("/") || skillName.includes("\\")) {
|
|
1616
|
+
throw new Error(`Unsafe skill name for directory-package companion path: ${JSON.stringify(skillName)}`);
|
|
1617
|
+
}
|
|
1618
|
+
return join(resolvedDir, skillName, target.filenamePattern);
|
|
1619
|
+
}
|
|
1620
|
+
const filename = target.filenamePattern.replace("{name}", skillName);
|
|
1621
|
+
return join(resolvedDir, filename);
|
|
1622
|
+
}
|
|
1518
1623
|
|
|
1519
1624
|
// ../core/dist/src/install/fan-out.js
|
|
1520
1625
|
import { homedir as homedir2 } from "node:os";
|
|
@@ -2700,12 +2805,12 @@ var AGENT_TOOL_PROFILE_NAMES = [
|
|
|
2700
2805
|
|
|
2701
2806
|
// ../core/dist/src/install/agent-home-relocate.js
|
|
2702
2807
|
import { homedir as homedir4 } from "node:os";
|
|
2703
|
-
import { isAbsolute, join as join6, relative as relative2 } from "node:path";
|
|
2808
|
+
import { isAbsolute as isAbsolute2, join as join6, relative as relative2 } from "node:path";
|
|
2704
2809
|
function relocateUnderHome(absolutePath, homeDir) {
|
|
2705
2810
|
if (!homeDir)
|
|
2706
2811
|
return absolutePath;
|
|
2707
2812
|
const rel = relative2(homedir4(), absolutePath);
|
|
2708
|
-
if (rel.startsWith("..") ||
|
|
2813
|
+
if (rel.startsWith("..") || isAbsolute2(rel))
|
|
2709
2814
|
return absolutePath;
|
|
2710
2815
|
return join6(homeDir, rel);
|
|
2711
2816
|
}
|
|
@@ -3694,7 +3799,7 @@ import { existsSync as existsSync10, readFileSync as readFileSync8, rmdirSync, u
|
|
|
3694
3799
|
|
|
3695
3800
|
// ../core/dist/src/install/agent-manifest-path-guard.js
|
|
3696
3801
|
import { homedir as homedir7 } from "node:os";
|
|
3697
|
-
import { join as join16, relative as relative3, resolve as
|
|
3802
|
+
import { join as join16, relative as relative3, resolve as resolve3, sep } from "node:path";
|
|
3698
3803
|
function computeAllowedPathSuffixes() {
|
|
3699
3804
|
const suffixes = /* @__PURE__ */ new Set();
|
|
3700
3805
|
const home2 = homedir7();
|
|
@@ -3728,7 +3833,7 @@ function allowedPathSuffixes() {
|
|
|
3728
3833
|
return cachedSuffixes;
|
|
3729
3834
|
}
|
|
3730
3835
|
function isAllowedManifestEntryPath(path27) {
|
|
3731
|
-
const normalized =
|
|
3836
|
+
const normalized = resolve3(path27);
|
|
3732
3837
|
for (const suffix of allowedPathSuffixes()) {
|
|
3733
3838
|
if (normalized.endsWith(sep + suffix) || normalized === suffix)
|
|
3734
3839
|
return true;
|
|
@@ -3736,8 +3841,8 @@ function isAllowedManifestEntryPath(path27) {
|
|
|
3736
3841
|
return false;
|
|
3737
3842
|
}
|
|
3738
3843
|
function isAllowedManifestBackupPath(backupPath) {
|
|
3739
|
-
const backupsDir2 =
|
|
3740
|
-
const normalized =
|
|
3844
|
+
const backupsDir2 = resolve3(getAgentInstallBackupsDir());
|
|
3845
|
+
const normalized = resolve3(backupPath);
|
|
3741
3846
|
return normalized === backupsDir2 || normalized.startsWith(backupsDir2 + sep);
|
|
3742
3847
|
}
|
|
3743
3848
|
|
|
@@ -19985,7 +20090,7 @@ function validateUrl(url2) {
|
|
|
19985
20090
|
}
|
|
19986
20091
|
|
|
19987
20092
|
// ../core/dist/src/validation/path-validators.js
|
|
19988
|
-
import { resolve as
|
|
20093
|
+
import { resolve as resolve4 } from "path";
|
|
19989
20094
|
function validatePath(path27, rootDir) {
|
|
19990
20095
|
if (!path27) {
|
|
19991
20096
|
throw new ValidationError("Path cannot be empty", "EMPTY_PATH");
|
|
@@ -19993,8 +20098,8 @@ function validatePath(path27, rootDir) {
|
|
|
19993
20098
|
if (!rootDir) {
|
|
19994
20099
|
throw new ValidationError("Root directory cannot be empty", "EMPTY_ROOT_DIR");
|
|
19995
20100
|
}
|
|
19996
|
-
const normalizedPath =
|
|
19997
|
-
const normalizedRoot =
|
|
20101
|
+
const normalizedPath = resolve4(rootDir, path27);
|
|
20102
|
+
const normalizedRoot = resolve4(rootDir);
|
|
19998
20103
|
const isWithinRoot = normalizedPath.startsWith(normalizedRoot + "/") || normalizedPath === normalizedRoot;
|
|
19999
20104
|
if (!isWithinRoot) {
|
|
20000
20105
|
throw new ValidationError(`Path traversal detected: ${path27}`, "PATH_TRAVERSAL", {
|
|
@@ -22016,12 +22121,12 @@ var logger3 = createLogger("Sanitization");
|
|
|
22016
22121
|
|
|
22017
22122
|
// ../core/dist/src/security/pathValidation.js
|
|
22018
22123
|
init_logger();
|
|
22019
|
-
import { resolve as
|
|
22124
|
+
import { resolve as resolve5, normalize, dirname as dirname10, isAbsolute as isAbsolute3 } from "path";
|
|
22020
22125
|
import { homedir as homedir9 } from "os";
|
|
22021
22126
|
var logger4 = createLogger("PathValidation");
|
|
22022
22127
|
var DEFAULT_ALLOWED_DIRS = [
|
|
22023
|
-
|
|
22024
|
-
|
|
22128
|
+
resolve5(homedir9(), ".skillsmith"),
|
|
22129
|
+
resolve5(homedir9(), ".claude")
|
|
22025
22130
|
];
|
|
22026
22131
|
var TEMP_DIRS = ["/tmp", "/var/tmp", "/private/tmp", process.env.TMPDIR].filter(Boolean);
|
|
22027
22132
|
|
|
@@ -22407,7 +22512,7 @@ var QueueManager = class {
|
|
|
22407
22512
|
onMetricsUpdate(false);
|
|
22408
22513
|
throw new RateLimitQueueFullError(key, this.config.maxQueueSize);
|
|
22409
22514
|
}
|
|
22410
|
-
return new Promise((
|
|
22515
|
+
return new Promise((resolve20, reject) => {
|
|
22411
22516
|
const requestId = randomUUID();
|
|
22412
22517
|
const queuedAt = Date.now();
|
|
22413
22518
|
const timeoutHandle = setTimeout(() => {
|
|
@@ -22421,7 +22526,7 @@ var QueueManager = class {
|
|
|
22421
22526
|
}, this.config.queueTimeoutMs);
|
|
22422
22527
|
const request = {
|
|
22423
22528
|
id: requestId,
|
|
22424
|
-
resolve:
|
|
22529
|
+
resolve: resolve20,
|
|
22425
22530
|
reject,
|
|
22426
22531
|
cost,
|
|
22427
22532
|
queuedAt,
|
|
@@ -22861,7 +22966,7 @@ function calculateDelay(attempt, initialDelayMs, maxDelayMs, backoffMultiplier,
|
|
|
22861
22966
|
return delay;
|
|
22862
22967
|
}
|
|
22863
22968
|
function sleep2(ms) {
|
|
22864
|
-
return new Promise((
|
|
22969
|
+
return new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
22865
22970
|
}
|
|
22866
22971
|
async function withRetry(fn, config2 = {}) {
|
|
22867
22972
|
const { maxRetries = DEFAULT_RETRY_CONFIG.maxRetries, initialDelayMs = DEFAULT_RETRY_CONFIG.initialDelayMs, maxDelayMs = DEFAULT_RETRY_CONFIG.maxDelayMs, backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier, jitter = DEFAULT_RETRY_CONFIG.jitter, isRetryable = isTransientError, onRetry } = config2;
|
|
@@ -23163,7 +23268,7 @@ var BaseSourceAdapter = class {
|
|
|
23163
23268
|
* Delay helper
|
|
23164
23269
|
*/
|
|
23165
23270
|
delay(ms) {
|
|
23166
|
-
return new Promise((
|
|
23271
|
+
return new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
23167
23272
|
}
|
|
23168
23273
|
/**
|
|
23169
23274
|
* Validate configuration
|
|
@@ -23188,7 +23293,7 @@ var log4 = createLogger("RawUrlAdapter");
|
|
|
23188
23293
|
// ../core/dist/src/sources/LocalFilesystemAdapter.js
|
|
23189
23294
|
init_logger();
|
|
23190
23295
|
import { createHash as createHash2 } from "crypto";
|
|
23191
|
-
import { basename as basename2, dirname as dirname12, resolve as
|
|
23296
|
+
import { basename as basename2, dirname as dirname12, resolve as resolve6, join as join19 } from "path";
|
|
23192
23297
|
|
|
23193
23298
|
// ../core/dist/src/sources/LocalFilesystemAdapter.helpers.js
|
|
23194
23299
|
import { promises as fs2 } from "fs";
|
|
@@ -23590,7 +23695,7 @@ var LocalFilesystemAdapter = class extends BaseSourceAdapter {
|
|
|
23590
23695
|
throw new Error("Invalid location: must specify path or repo");
|
|
23591
23696
|
}
|
|
23592
23697
|
validatePath(resolvedPath, this.rootDir);
|
|
23593
|
-
const absolutePath =
|
|
23698
|
+
const absolutePath = resolve6(resolvedPath);
|
|
23594
23699
|
const realResult = await resolveSafeRealpath(absolutePath, this.rootDir, {
|
|
23595
23700
|
allowSymlinksOutsideRoot: this.allowSymlinksOutsideRoot
|
|
23596
23701
|
});
|
|
@@ -24198,7 +24303,7 @@ function isBetterSqlite3Available() {
|
|
|
24198
24303
|
|
|
24199
24304
|
// ../core/dist/src/db/drivers/sqljsDriver.js
|
|
24200
24305
|
import { createRequire as createRequire2 } from "node:module";
|
|
24201
|
-
import { existsSync as existsSync13, readFileSync as readFileSync10, writeFileSync as writeFileSync10 } from "node:fs";
|
|
24306
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, writeFileSync as writeFileSync10, renameSync as renameSync3, unlinkSync as unlinkSync3 } from "node:fs";
|
|
24202
24307
|
|
|
24203
24308
|
// ../core/dist/src/db/drivers/corruption.js
|
|
24204
24309
|
import { existsSync as existsSync12, renameSync as renameSync2 } from "node:fs";
|
|
@@ -24420,12 +24525,31 @@ var SqlJsDatabaseAdapter = class {
|
|
|
24420
24525
|
}
|
|
24421
24526
|
/**
|
|
24422
24527
|
* Persist the in-memory database to file
|
|
24528
|
+
*
|
|
24529
|
+
* SMI-5997: writes atomically (temp file + rename) rather than a direct
|
|
24530
|
+
* writeFileSync to filePath. A direct write truncates the target file
|
|
24531
|
+
* before the new bytes land; a process kill/crash mid-write (OOM, SIGKILL,
|
|
24532
|
+
* machine sleep) during that window leaves a 0-byte file on disk, which
|
|
24533
|
+
* openDatabaseAsync() then silently misclassifies as a fresh/legacy import
|
|
24534
|
+
* instead of a corrupt file — see schema.ts. rename() is atomic on the
|
|
24535
|
+
* same filesystem, so the target is only ever fully-old or fully-new.
|
|
24423
24536
|
*/
|
|
24424
24537
|
persist() {
|
|
24425
24538
|
if (this._memory || !this.filePath)
|
|
24426
24539
|
return;
|
|
24427
24540
|
const data = this.db.export();
|
|
24428
|
-
|
|
24541
|
+
const tmpPath = `${this.filePath}.tmp`;
|
|
24542
|
+
try {
|
|
24543
|
+
writeFileSync10(tmpPath, Buffer.from(data));
|
|
24544
|
+
renameSync3(tmpPath, this.filePath);
|
|
24545
|
+
} catch (error46) {
|
|
24546
|
+
try {
|
|
24547
|
+
if (existsSync13(tmpPath))
|
|
24548
|
+
unlinkSync3(tmpPath);
|
|
24549
|
+
} catch {
|
|
24550
|
+
}
|
|
24551
|
+
throw error46;
|
|
24552
|
+
}
|
|
24429
24553
|
}
|
|
24430
24554
|
/**
|
|
24431
24555
|
* Export the database as a Uint8Array
|
|
@@ -24642,7 +24766,7 @@ function findSimilarBruteForceFromMap(embeddings, queryEmbedding, topK) {
|
|
|
24642
24766
|
}
|
|
24643
24767
|
|
|
24644
24768
|
// ../core/dist/src/embeddings/hnsw-search.js
|
|
24645
|
-
import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync11, renameSync as
|
|
24769
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync11, renameSync as renameSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync11 } from "fs";
|
|
24646
24770
|
import { dirname as dirname13, join as join21 } from "path";
|
|
24647
24771
|
var cachedCtor = null;
|
|
24648
24772
|
async function loadHnswCtor() {
|
|
@@ -24704,7 +24828,7 @@ function readLabels(labelsPath) {
|
|
|
24704
24828
|
function writeAtomic(tmp, final, contents) {
|
|
24705
24829
|
mkdirSync8(dirname13(tmp), { recursive: true });
|
|
24706
24830
|
writeFileSync11(tmp, contents, typeof contents === "string" ? { encoding: "utf-8" } : void 0);
|
|
24707
|
-
|
|
24831
|
+
renameSync4(tmp, final);
|
|
24708
24832
|
}
|
|
24709
24833
|
async function loadOrBuildHnsw(args) {
|
|
24710
24834
|
const Ctor = await loadHnswCtor();
|
|
@@ -24738,11 +24862,11 @@ async function loadOrBuildHnsw(args) {
|
|
|
24738
24862
|
} catch (err) {
|
|
24739
24863
|
try {
|
|
24740
24864
|
if (existsSync14(paths.bin))
|
|
24741
|
-
|
|
24865
|
+
unlinkSync4(paths.bin);
|
|
24742
24866
|
if (existsSync14(paths.meta))
|
|
24743
|
-
|
|
24867
|
+
unlinkSync4(paths.meta);
|
|
24744
24868
|
if (existsSync14(paths.labels))
|
|
24745
|
-
|
|
24869
|
+
unlinkSync4(paths.labels);
|
|
24746
24870
|
} catch {
|
|
24747
24871
|
}
|
|
24748
24872
|
try {
|
|
@@ -24805,7 +24929,7 @@ function createHandle(args) {
|
|
|
24805
24929
|
return;
|
|
24806
24930
|
}
|
|
24807
24931
|
args.index.writeIndexSync(args.paths.binTmp);
|
|
24808
|
-
|
|
24932
|
+
renameSync4(args.paths.binTmp, args.paths.bin);
|
|
24809
24933
|
const labelsArr = Array.from(args.labelToId.entries());
|
|
24810
24934
|
writeAtomic(args.paths.labelsTmp, args.paths.labels, JSON.stringify(labelsArr));
|
|
24811
24935
|
const meta3 = {
|
|
@@ -26298,18 +26422,18 @@ function getState(surface) {
|
|
|
26298
26422
|
return state;
|
|
26299
26423
|
}
|
|
26300
26424
|
function closeStream(stream) {
|
|
26301
|
-
return new Promise((
|
|
26302
|
-
const done = () =>
|
|
26425
|
+
return new Promise((resolve20) => {
|
|
26426
|
+
const done = () => resolve20();
|
|
26303
26427
|
stream.once("error", done);
|
|
26304
26428
|
stream.end(done);
|
|
26305
26429
|
});
|
|
26306
26430
|
}
|
|
26307
26431
|
function openStream(filePath) {
|
|
26308
|
-
return new Promise((
|
|
26432
|
+
return new Promise((resolve20, reject) => {
|
|
26309
26433
|
const stream = createWriteStream(filePath, { flags: "a" });
|
|
26310
26434
|
const onOpen = () => {
|
|
26311
26435
|
cleanup();
|
|
26312
|
-
|
|
26436
|
+
resolve20(stream);
|
|
26313
26437
|
};
|
|
26314
26438
|
const onError = (err) => {
|
|
26315
26439
|
cleanup();
|
|
@@ -26329,12 +26453,12 @@ function openStream(filePath) {
|
|
|
26329
26453
|
});
|
|
26330
26454
|
}
|
|
26331
26455
|
function writeChunk(stream, buf) {
|
|
26332
|
-
return new Promise((
|
|
26456
|
+
return new Promise((resolve20, reject) => {
|
|
26333
26457
|
stream.write(buf, (err) => {
|
|
26334
26458
|
if (err)
|
|
26335
26459
|
reject(err);
|
|
26336
26460
|
else
|
|
26337
|
-
|
|
26461
|
+
resolve20();
|
|
26338
26462
|
});
|
|
26339
26463
|
});
|
|
26340
26464
|
}
|
|
@@ -27420,10 +27544,10 @@ function addEnvironmentDeps(declared, result) {
|
|
|
27420
27544
|
}
|
|
27421
27545
|
}
|
|
27422
27546
|
if (declared.environment.os) {
|
|
27423
|
-
for (const
|
|
27547
|
+
for (const os15 of declared.environment.os) {
|
|
27424
27548
|
result.push({
|
|
27425
27549
|
depType: "env_os",
|
|
27426
|
-
depTarget:
|
|
27550
|
+
depTarget: os15,
|
|
27427
27551
|
depVersion: null,
|
|
27428
27552
|
depSource: "declared",
|
|
27429
27553
|
confidence: 1,
|
|
@@ -27483,7 +27607,6 @@ import { createHash as createHash7 } from "crypto";
|
|
|
27483
27607
|
// ../core/dist/src/services/skill-installation.io.js
|
|
27484
27608
|
import * as fs4 from "fs/promises";
|
|
27485
27609
|
import * as path3 from "path";
|
|
27486
|
-
import * as os2 from "os";
|
|
27487
27610
|
|
|
27488
27611
|
// ../core/dist/src/utils/safe-fs.js
|
|
27489
27612
|
import { open, lstat as lstat2, constants as constants2 } from "fs/promises";
|
|
@@ -27920,7 +28043,7 @@ async function mkdirNoFollow(baseDir, dir) {
|
|
|
27920
28043
|
await ensureDirNoFollow(current);
|
|
27921
28044
|
}
|
|
27922
28045
|
}
|
|
27923
|
-
async function writeInstallFiles(installPath, skillsDir, skillName, finalSkillContent, subSkillFiles, subagentContent) {
|
|
28046
|
+
async function writeInstallFiles(installPath, skillsDir, skillName, finalSkillContent, subSkillFiles, subagentContent, client = CANONICAL_CLIENT, companionBaseDir) {
|
|
27924
28047
|
const writtenFiles = [];
|
|
27925
28048
|
let subagentPath;
|
|
27926
28049
|
const resolvedInstall = path3.resolve(installPath);
|
|
@@ -27952,9 +28075,9 @@ async function writeInstallFiles(installPath, skillsDir, skillName, finalSkillCo
|
|
|
27952
28075
|
}));
|
|
27953
28076
|
}
|
|
27954
28077
|
if (subagentContent) {
|
|
27955
|
-
|
|
28078
|
+
subagentPath = resolveCompanionAgentPath(skillName, client, companionBaseDir);
|
|
28079
|
+
const agentsDir = path3.dirname(subagentPath);
|
|
27956
28080
|
await fs4.mkdir(agentsDir, { recursive: true });
|
|
27957
|
-
subagentPath = path3.join(agentsDir, skillName + "-specialist.md");
|
|
27958
28081
|
await safeWriteFile(subagentPath, subagentContent);
|
|
27959
28082
|
writtenFiles.push(subagentPath);
|
|
27960
28083
|
}
|
|
@@ -27963,6 +28086,10 @@ async function writeInstallFiles(installPath, skillsDir, skillName, finalSkillCo
|
|
|
27963
28086
|
await fs4.unlink(filePath).catch(() => {
|
|
27964
28087
|
});
|
|
27965
28088
|
}
|
|
28089
|
+
if (subagentPath && getCompanionAgentTarget(client).fileMode === "directory-package") {
|
|
28090
|
+
await fs4.rmdir(path3.dirname(subagentPath)).catch(() => {
|
|
28091
|
+
});
|
|
28092
|
+
}
|
|
27966
28093
|
if (pathValidated) {
|
|
27967
28094
|
await fs4.rm(installPath, { recursive: true, force: true }).catch(() => {
|
|
27968
28095
|
});
|
|
@@ -28160,8 +28287,11 @@ async function performUninstall(params) {
|
|
|
28160
28287
|
} catch {
|
|
28161
28288
|
}
|
|
28162
28289
|
onProgress("manifest", "Updating manifest");
|
|
28163
|
-
|
|
28164
|
-
|
|
28290
|
+
await manifest.updateSafely((current) => {
|
|
28291
|
+
const next = { ...current, installedSkills: { ...current.installedSkills } };
|
|
28292
|
+
delete next.installedSkills[manifestKey];
|
|
28293
|
+
return next;
|
|
28294
|
+
});
|
|
28165
28295
|
onProgress("done", "Uninstall complete");
|
|
28166
28296
|
return {
|
|
28167
28297
|
success: true,
|
|
@@ -28225,7 +28355,12 @@ var KNOWN_ERROR_PREFIXES = [
|
|
|
28225
28355
|
"Refusing to write to symlink",
|
|
28226
28356
|
"Refusing to write to hardlinked file",
|
|
28227
28357
|
"Install path escapes skills directory",
|
|
28228
|
-
"Cannot skip security scan"
|
|
28358
|
+
"Cannot skip security scan",
|
|
28359
|
+
// SMI-5982 PR-review follow-up: resolveCompanionAgentPath()'s required-baseDir guard
|
|
28360
|
+
// (install/paths.ts) — must surface verbatim so a directory-package-mode client (e.g.
|
|
28361
|
+
// a private-registry install with no per-call cwd input) fails closed with a
|
|
28362
|
+
// diagnosable message instead of the generic fallback below.
|
|
28363
|
+
"uses directory-package mode"
|
|
28229
28364
|
];
|
|
28230
28365
|
function sanitizeInstallError(error46) {
|
|
28231
28366
|
if (error46 instanceof Error) {
|
|
@@ -28238,7 +28373,7 @@ function sanitizeInstallError(error46) {
|
|
|
28238
28373
|
|
|
28239
28374
|
// ../core/dist/src/services/skill-installation.service.js
|
|
28240
28375
|
import * as path7 from "path";
|
|
28241
|
-
import * as
|
|
28376
|
+
import * as os2 from "os";
|
|
28242
28377
|
|
|
28243
28378
|
// ../core/dist/src/services/skill-installation.types.js
|
|
28244
28379
|
var TRUST_TIER_SCANNER_OPTIONS = {
|
|
@@ -28356,7 +28491,7 @@ function skillNameFromSkillId(skillId) {
|
|
|
28356
28491
|
return name;
|
|
28357
28492
|
}
|
|
28358
28493
|
async function installFromContent(params) {
|
|
28359
|
-
const { db, skillsDir, manifest, client, onProgress, skillId, version: version2, content, force = false } = params;
|
|
28494
|
+
const { db, skillsDir, manifest, client, onProgress, skillId, version: version2, content, force = false, companionBaseDir } = params;
|
|
28360
28495
|
const skillName = skillNameFromSkillId(skillId);
|
|
28361
28496
|
const trustTier = CONTENT_INSTALL_TRUST_TIER;
|
|
28362
28497
|
if (skillName === null) {
|
|
@@ -28433,7 +28568,7 @@ async function installFromContent(params) {
|
|
|
28433
28568
|
const teamAuthoredSubFiles = Object.entries(content).filter(([filename]) => filename !== "SKILL.md").map(([filename, fileContent]) => ({ filename, content: fileContent }));
|
|
28434
28569
|
const generatedNoCollision = subSkillFiles.filter((generated) => !teamAuthoredSubFiles.some((team) => team.filename === generated.filename));
|
|
28435
28570
|
onProgress("write", "Writing skill files");
|
|
28436
|
-
const writeResult = await writeInstallFiles(installPath, skillsDir, skillName, finalSkillContent, [...generatedNoCollision, ...teamAuthoredSubFiles], subagentContent);
|
|
28571
|
+
const writeResult = await writeInstallFiles(installPath, skillsDir, skillName, finalSkillContent, [...generatedNoCollision, ...teamAuthoredSubFiles], subagentContent, client, companionBaseDir);
|
|
28437
28572
|
if (writeResult.subagentPath) {
|
|
28438
28573
|
optimizationInfo.subagentPath = writeResult.subagentPath;
|
|
28439
28574
|
}
|
|
@@ -28506,6 +28641,7 @@ function collectTrendWarnings(params) {
|
|
|
28506
28641
|
// ../core/dist/src/services/skill-manifest.js
|
|
28507
28642
|
import * as fs6 from "fs/promises";
|
|
28508
28643
|
import * as path6 from "path";
|
|
28644
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
28509
28645
|
var MANIFEST_LOCK_TIMEOUT_MS = 3e4;
|
|
28510
28646
|
var MANIFEST_LOCK_RETRY_MS = 100;
|
|
28511
28647
|
var ManifestManager = class {
|
|
@@ -28513,19 +28649,56 @@ var ManifestManager = class {
|
|
|
28513
28649
|
constructor(manifestPath) {
|
|
28514
28650
|
this.manifestPath = manifestPath;
|
|
28515
28651
|
}
|
|
28652
|
+
/**
|
|
28653
|
+
* SMI-6007: distinguishes "no manifest yet" (ENOENT — legitimate first-run
|
|
28654
|
+
* case, safe to synthesize an empty manifest) from "a manifest file exists
|
|
28655
|
+
* but couldn't be read/parsed" (corrupt JSON, permission error, I/O
|
|
28656
|
+
* failure). The latter used to be silently swallowed into the same empty
|
|
28657
|
+
* manifest, which is a real data-loss risk: a caller that then `save()`s
|
|
28658
|
+
* that empty snapshot back out would erase every previously-recorded
|
|
28659
|
+
* install. Now it throws loudly instead, so a corrupt manifest surfaces as
|
|
28660
|
+
* an error rather than silently wiping state on the next write.
|
|
28661
|
+
*/
|
|
28516
28662
|
async load() {
|
|
28663
|
+
let content;
|
|
28664
|
+
try {
|
|
28665
|
+
content = await fs6.readFile(this.manifestPath, "utf-8");
|
|
28666
|
+
} catch (error46) {
|
|
28667
|
+
if (error46.code === "ENOENT") {
|
|
28668
|
+
return { version: "1.0.0", installedSkills: {} };
|
|
28669
|
+
}
|
|
28670
|
+
throw error46;
|
|
28671
|
+
}
|
|
28517
28672
|
try {
|
|
28518
|
-
const content = await fs6.readFile(this.manifestPath, "utf-8");
|
|
28519
28673
|
return JSON.parse(content);
|
|
28520
|
-
} catch {
|
|
28521
|
-
|
|
28674
|
+
} catch (error46) {
|
|
28675
|
+
throw new Error("Manifest file at " + this.manifestPath + " exists but is corrupt/unparseable: " + (error46 instanceof Error ? error46.message : String(error46)));
|
|
28522
28676
|
}
|
|
28523
28677
|
}
|
|
28678
|
+
/**
|
|
28679
|
+
* SMI-6007: the temp filename now includes a `randomUUID()` suffix (not
|
|
28680
|
+
* just `process.pid`) — two concurrent `save()` calls in the same process
|
|
28681
|
+
* previously collided on an identical `.tmp.<pid>` path, letting one
|
|
28682
|
+
* call's temp file win the write while the other's `rename()` either
|
|
28683
|
+
* clobbered it mid-flight or failed outright. Each call now owns a
|
|
28684
|
+
* uniquely-named temp file for its own lifetime. The write+rename is
|
|
28685
|
+
* wrapped in try/catch so a failure best-effort removes only *this
|
|
28686
|
+
* invocation's* temp file before rethrowing the original error (mirrors
|
|
28687
|
+
* `sqljsDriver.ts`'s `persist()`, SMI-5997) — the error is never swallowed.
|
|
28688
|
+
*/
|
|
28524
28689
|
async save(manifest) {
|
|
28525
28690
|
await fs6.mkdir(path6.dirname(this.manifestPath), { recursive: true });
|
|
28526
|
-
const tempPath = this.manifestPath + ".tmp." + process.pid;
|
|
28527
|
-
|
|
28528
|
-
|
|
28691
|
+
const tempPath = this.manifestPath + ".tmp." + process.pid + "." + randomUUID3();
|
|
28692
|
+
try {
|
|
28693
|
+
await fs6.writeFile(tempPath, JSON.stringify(manifest, null, 2));
|
|
28694
|
+
await fs6.rename(tempPath, this.manifestPath);
|
|
28695
|
+
} catch (error46) {
|
|
28696
|
+
try {
|
|
28697
|
+
await fs6.unlink(tempPath);
|
|
28698
|
+
} catch {
|
|
28699
|
+
}
|
|
28700
|
+
throw error46;
|
|
28701
|
+
}
|
|
28529
28702
|
}
|
|
28530
28703
|
async acquireLock() {
|
|
28531
28704
|
const lockPath = this.manifestPath + ".lock";
|
|
@@ -28547,7 +28720,7 @@ var ManifestManager = class {
|
|
|
28547
28720
|
} catch {
|
|
28548
28721
|
continue;
|
|
28549
28722
|
}
|
|
28550
|
-
await new Promise((
|
|
28723
|
+
await new Promise((resolve20) => setTimeout(resolve20, MANIFEST_LOCK_RETRY_MS));
|
|
28551
28724
|
} else {
|
|
28552
28725
|
throw error46;
|
|
28553
28726
|
}
|
|
@@ -28574,8 +28747,8 @@ var ManifestManager = class {
|
|
|
28574
28747
|
};
|
|
28575
28748
|
|
|
28576
28749
|
// ../core/dist/src/services/skill-installation.service.js
|
|
28577
|
-
var DEFAULT_SKILLS_DIR2 = path7.join(
|
|
28578
|
-
var DEFAULT_MANIFEST_PATH2 = path7.join(
|
|
28750
|
+
var DEFAULT_SKILLS_DIR2 = path7.join(os2.homedir(), ".claude", "skills");
|
|
28751
|
+
var DEFAULT_MANIFEST_PATH2 = path7.join(os2.homedir(), ".skillsmith", "manifest.json");
|
|
28579
28752
|
var SkillInstallationService = class {
|
|
28580
28753
|
db;
|
|
28581
28754
|
skillRepo;
|
|
@@ -28590,6 +28763,7 @@ var SkillInstallationService = class {
|
|
|
28590
28763
|
riskHistoryRepo;
|
|
28591
28764
|
aiDefenceFeedback;
|
|
28592
28765
|
client;
|
|
28766
|
+
companionBaseDir;
|
|
28593
28767
|
constructor(params) {
|
|
28594
28768
|
this.db = params.db;
|
|
28595
28769
|
this.skillRepo = params.skillRepo;
|
|
@@ -28605,6 +28779,7 @@ var SkillInstallationService = class {
|
|
|
28605
28779
|
this.aiDefenceFeedback = params.aiDefenceFeedback;
|
|
28606
28780
|
this.sessionInstalledSkillIds = params.sessionInstalledSkillIds ?? [];
|
|
28607
28781
|
this.client = params.client ?? CANONICAL_CLIENT;
|
|
28782
|
+
this.companionBaseDir = params.companionBaseDir;
|
|
28608
28783
|
}
|
|
28609
28784
|
async install(skillId, options = {}) {
|
|
28610
28785
|
let trustTier = "unknown";
|
|
@@ -28780,7 +28955,7 @@ var SkillInstallationService = class {
|
|
|
28780
28955
|
}
|
|
28781
28956
|
this.onProgress("write", "Writing skill files");
|
|
28782
28957
|
const subSkillsNoCollision = subSkillFiles.filter((s) => !optionalFiles.filesToWrite.some((o) => o.filename === s.filename));
|
|
28783
|
-
const writeResult = await writeInstallFiles(installPath, this.skillsDir, skillName, finalSkillContent, [...subSkillsNoCollision, ...optionalFiles.filesToWrite], subagentContent);
|
|
28958
|
+
const writeResult = await writeInstallFiles(installPath, this.skillsDir, skillName, finalSkillContent, [...subSkillsNoCollision, ...optionalFiles.filesToWrite], subagentContent, this.client, this.companionBaseDir);
|
|
28784
28959
|
if (writeResult.subagentPath) {
|
|
28785
28960
|
optimizationInfo.subagentPath = writeResult.subagentPath;
|
|
28786
28961
|
}
|
|
@@ -28878,6 +29053,7 @@ var SkillInstallationService = class {
|
|
|
28878
29053
|
skillsDir: this.skillsDir,
|
|
28879
29054
|
manifest: this.manifest,
|
|
28880
29055
|
client: this.client,
|
|
29056
|
+
companionBaseDir: this.companionBaseDir,
|
|
28881
29057
|
onProgress: this.onProgress
|
|
28882
29058
|
});
|
|
28883
29059
|
}
|
|
@@ -28980,6 +29156,94 @@ function buildEmptyStackGuidance() {
|
|
|
28980
29156
|
return "No technology stack could be derived for recommendations \u2014 this usually means a non-Node project, a stack with no production dependencies, or an unsupported language, not a backend or registry problem. Provide project context (a short description of the project or its tooling) or an explicit list of installed/currently-used skills, then try again.";
|
|
28981
29157
|
}
|
|
28982
29158
|
|
|
29159
|
+
// ../core/dist/src/services/context-words.js
|
|
29160
|
+
var MAX_CONTEXT_WORDS = 5;
|
|
29161
|
+
var CONTEXT_STOPWORDS = /* @__PURE__ */ new Set([
|
|
29162
|
+
// 2-letter
|
|
29163
|
+
"an",
|
|
29164
|
+
"is",
|
|
29165
|
+
"it",
|
|
29166
|
+
"be",
|
|
29167
|
+
"to",
|
|
29168
|
+
"of",
|
|
29169
|
+
"in",
|
|
29170
|
+
"on",
|
|
29171
|
+
"at",
|
|
29172
|
+
"as",
|
|
29173
|
+
"or",
|
|
29174
|
+
"if",
|
|
29175
|
+
"so",
|
|
29176
|
+
"no",
|
|
29177
|
+
"do",
|
|
29178
|
+
"am",
|
|
29179
|
+
"we",
|
|
29180
|
+
"us",
|
|
29181
|
+
"he",
|
|
29182
|
+
"my",
|
|
29183
|
+
"up",
|
|
29184
|
+
// 3-letter
|
|
29185
|
+
"the",
|
|
29186
|
+
"and",
|
|
29187
|
+
"but",
|
|
29188
|
+
"not",
|
|
29189
|
+
"did",
|
|
29190
|
+
"has",
|
|
29191
|
+
"had",
|
|
29192
|
+
"she",
|
|
29193
|
+
"him",
|
|
29194
|
+
"her",
|
|
29195
|
+
"its",
|
|
29196
|
+
"our",
|
|
29197
|
+
"all",
|
|
29198
|
+
"few",
|
|
29199
|
+
"out",
|
|
29200
|
+
"off",
|
|
29201
|
+
"via",
|
|
29202
|
+
"per",
|
|
29203
|
+
"own",
|
|
29204
|
+
"too",
|
|
29205
|
+
"yet",
|
|
29206
|
+
"nor",
|
|
29207
|
+
"you",
|
|
29208
|
+
"are",
|
|
29209
|
+
"was",
|
|
29210
|
+
"for",
|
|
29211
|
+
"may",
|
|
29212
|
+
"who",
|
|
29213
|
+
"why",
|
|
29214
|
+
"how"
|
|
29215
|
+
// Code-review correction (SMI-5986): "any" (TS/SQL keyword), "let"
|
|
29216
|
+
// (JS/Rust keyword), and "can" (CAN-bus acronym) were removed from this
|
|
29217
|
+
// set — each is a real technical term this fix exists to stop dropping,
|
|
29218
|
+
// same class as "git"/"ci"/"aws"/"sql". Leaving them in would have
|
|
29219
|
+
// contradicted this list's own documented promise above.
|
|
29220
|
+
]);
|
|
29221
|
+
function isKeepChar(ch) {
|
|
29222
|
+
return ch >= "a" && ch <= "z" || ch >= "0" && ch <= "9" || ch === "+" || ch === "#";
|
|
29223
|
+
}
|
|
29224
|
+
function hasAlphaNumeric(word) {
|
|
29225
|
+
for (let i = 0; i < word.length; i++) {
|
|
29226
|
+
const ch = word[i];
|
|
29227
|
+
if (ch >= "a" && ch <= "z" || ch >= "0" && ch <= "9")
|
|
29228
|
+
return true;
|
|
29229
|
+
}
|
|
29230
|
+
return false;
|
|
29231
|
+
}
|
|
29232
|
+
function stripEdgePunctuation(word) {
|
|
29233
|
+
let start = 0;
|
|
29234
|
+
while (start < word.length && !isKeepChar(word[start]))
|
|
29235
|
+
start++;
|
|
29236
|
+
let end = word.length;
|
|
29237
|
+
while (end > start && !isKeepChar(word[end - 1]))
|
|
29238
|
+
end--;
|
|
29239
|
+
return word.slice(start, end);
|
|
29240
|
+
}
|
|
29241
|
+
function extractContextWords(projectContext, maxWords = MAX_CONTEXT_WORDS) {
|
|
29242
|
+
if (!projectContext)
|
|
29243
|
+
return [];
|
|
29244
|
+
return projectContext.toLowerCase().split(/\s+/).map(stripEdgePunctuation).filter((word) => word.length >= 2 && hasAlphaNumeric(word) && !(word.length <= 3 && CONTEXT_STOPWORDS.has(word))).slice(0, maxWords);
|
|
29245
|
+
}
|
|
29246
|
+
|
|
28983
29247
|
// ../core/dist/src/db/schema-sql.js
|
|
28984
29248
|
var SCHEMA_SQL = `
|
|
28985
29249
|
-- Enable WAL mode for better concurrent performance
|
|
@@ -29584,7 +29848,7 @@ function runMigrations(db) {
|
|
|
29584
29848
|
throw error46;
|
|
29585
29849
|
}
|
|
29586
29850
|
}
|
|
29587
|
-
db.prepare("INSERT INTO schema_version (version) VALUES (?)").run(migration.version);
|
|
29851
|
+
db.prepare("INSERT OR IGNORE INTO schema_version (version) VALUES (?)").run(migration.version);
|
|
29588
29852
|
migrationsRun++;
|
|
29589
29853
|
}
|
|
29590
29854
|
}
|
|
@@ -29615,7 +29879,7 @@ function runMigrationsSafe(db) {
|
|
|
29615
29879
|
throw error46;
|
|
29616
29880
|
}
|
|
29617
29881
|
}
|
|
29618
|
-
db.prepare("INSERT INTO schema_version (version) VALUES (?)").run(migration.version);
|
|
29882
|
+
db.prepare("INSERT OR IGNORE INTO schema_version (version) VALUES (?)").run(migration.version);
|
|
29619
29883
|
migrationsRun++;
|
|
29620
29884
|
} catch (error46) {
|
|
29621
29885
|
console.warn(`Migration ${migration.version} failed:`, error46);
|
|
@@ -29636,11 +29900,23 @@ function initializeSchema(db) {
|
|
|
29636
29900
|
db.prepare("INSERT OR IGNORE INTO schema_version (version) VALUES (1)").run();
|
|
29637
29901
|
runMigrations(db);
|
|
29638
29902
|
}
|
|
29903
|
+
function assertLegacyImportHasTables(db, path27) {
|
|
29904
|
+
const tableCount = db.prepare("SELECT count(*) as count FROM sqlite_master WHERE type='table'").get();
|
|
29905
|
+
if (!tableCount || tableCount.count === 0) {
|
|
29906
|
+
throw new Error(`[Skillsmith] Database at ${path27} has no tables and no version metadata \u2014 it is empty or corrupt, not a legacy import.
|
|
29907
|
+
[skillsmith] Run this command in the repo root, then reconnect via /mcp:
|
|
29908
|
+
|
|
29909
|
+
mv "${path27}" "${path27}.corrupt-$(date +%s)"
|
|
29910
|
+
|
|
29911
|
+
[skillsmith] (a fresh database will be created automatically on next start)`);
|
|
29912
|
+
}
|
|
29913
|
+
}
|
|
29639
29914
|
function openDatabase(path27) {
|
|
29640
29915
|
const db = createDatabaseSync(path27);
|
|
29641
29916
|
db.pragma("foreign_keys = ON");
|
|
29642
29917
|
const hasSchemaVersion = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='schema_version'").get();
|
|
29643
29918
|
if (!hasSchemaVersion) {
|
|
29919
|
+
assertLegacyImportHasTables(db, path27);
|
|
29644
29920
|
db.exec(`
|
|
29645
29921
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
29646
29922
|
version INTEGER PRIMARY KEY,
|
|
@@ -29654,7 +29930,7 @@ function openDatabase(path27) {
|
|
|
29654
29930
|
}
|
|
29655
29931
|
|
|
29656
29932
|
// ../core/dist/src/repositories/SkillRepository.js
|
|
29657
|
-
import { randomUUID as
|
|
29933
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
29658
29934
|
var SkillRepository = class {
|
|
29659
29935
|
db;
|
|
29660
29936
|
constructor(db) {
|
|
@@ -29740,7 +30016,7 @@ var SkillRepository = class {
|
|
|
29740
30016
|
* Create a new skill
|
|
29741
30017
|
*/
|
|
29742
30018
|
create(input7) {
|
|
29743
|
-
const id = input7.id ||
|
|
30019
|
+
const id = input7.id || randomUUID4();
|
|
29744
30020
|
const tags = JSON.stringify(input7.tags || []);
|
|
29745
30021
|
this.stmts.insert.run(
|
|
29746
30022
|
id,
|
|
@@ -29771,7 +30047,7 @@ var SkillRepository = class {
|
|
|
29771
30047
|
const insertMany = this.db.transaction((skills) => {
|
|
29772
30048
|
const created = [];
|
|
29773
30049
|
for (const input7 of skills) {
|
|
29774
|
-
const id = input7.id ||
|
|
30050
|
+
const id = input7.id || randomUUID4();
|
|
29775
30051
|
const tags = JSON.stringify(input7.tags || []);
|
|
29776
30052
|
try {
|
|
29777
30053
|
this.stmts.insert.run(
|
|
@@ -30092,7 +30368,7 @@ function rowToEntry(row) {
|
|
|
30092
30368
|
}
|
|
30093
30369
|
|
|
30094
30370
|
// ../core/dist/src/repositories/quarantine/QuarantineRepository.js
|
|
30095
|
-
import { randomUUID as
|
|
30371
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
30096
30372
|
var QuarantineRepository = class {
|
|
30097
30373
|
db;
|
|
30098
30374
|
auditLogger;
|
|
@@ -30146,7 +30422,7 @@ var QuarantineRepository = class {
|
|
|
30146
30422
|
* @returns Created quarantine entry
|
|
30147
30423
|
*/
|
|
30148
30424
|
create(input7) {
|
|
30149
|
-
const id = input7.id ||
|
|
30425
|
+
const id = input7.id || randomUUID5();
|
|
30150
30426
|
const patterns = JSON.stringify(input7.detectedPatterns || []);
|
|
30151
30427
|
this.stmts.insert.run(
|
|
30152
30428
|
id,
|
|
@@ -30599,17 +30875,17 @@ var MS_PER_DAY = 24 * 60 * 60 * 1e3;
|
|
|
30599
30875
|
|
|
30600
30876
|
// ../core/dist/src/analytics/storage.js
|
|
30601
30877
|
import { join as join29, dirname as dirname16 } from "path";
|
|
30602
|
-
import { homedir as
|
|
30603
|
-
var ANALYTICS_DIR = join29(
|
|
30878
|
+
import { homedir as homedir13 } from "os";
|
|
30879
|
+
var ANALYTICS_DIR = join29(homedir13(), ".skillsmith");
|
|
30604
30880
|
var ANALYTICS_DB = join29(ANALYTICS_DIR, "analytics.db");
|
|
30605
30881
|
|
|
30606
30882
|
// ../core/dist/src/analytics/usage-tracker.js
|
|
30607
30883
|
var SESSION_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
30608
30884
|
|
|
30609
30885
|
// ../core/dist/src/analytics/metrics-exporter.js
|
|
30610
|
-
import { join as join30, resolve as
|
|
30611
|
-
import { homedir as
|
|
30612
|
-
var DEFAULT_EXPORT_DIR = join30(
|
|
30886
|
+
import { join as join30, resolve as resolve10, isAbsolute as isAbsolute4 } from "path";
|
|
30887
|
+
import { homedir as homedir14 } from "os";
|
|
30888
|
+
var DEFAULT_EXPORT_DIR = join30(homedir14(), ".skillsmith", "exports");
|
|
30613
30889
|
|
|
30614
30890
|
// ../core/dist/src/repositories/SkillVersionRepository.js
|
|
30615
30891
|
var SkillVersionRepository = class {
|
|
@@ -31343,8 +31619,8 @@ var EventBatcher = class {
|
|
|
31343
31619
|
return;
|
|
31344
31620
|
} catch {
|
|
31345
31621
|
}
|
|
31346
|
-
await new Promise((
|
|
31347
|
-
const t = setTimeout(
|
|
31622
|
+
await new Promise((resolve20) => {
|
|
31623
|
+
const t = setTimeout(resolve20, this.retryDelayMs);
|
|
31348
31624
|
if (typeof t.unref === "function") {
|
|
31349
31625
|
;
|
|
31350
31626
|
t.unref();
|
|
@@ -31377,8 +31653,8 @@ var EventBatcher = class {
|
|
|
31377
31653
|
}
|
|
31378
31654
|
drainHandler = () => {
|
|
31379
31655
|
const drain = this.flush();
|
|
31380
|
-
const timeout = new Promise((
|
|
31381
|
-
const t = setTimeout(
|
|
31656
|
+
const timeout = new Promise((resolve20) => {
|
|
31657
|
+
const t = setTimeout(resolve20, this.drainTimeoutMs);
|
|
31382
31658
|
if (typeof t.unref === "function") {
|
|
31383
31659
|
;
|
|
31384
31660
|
t.unref();
|
|
@@ -31863,7 +32139,7 @@ var SkillsmithApiClient = class {
|
|
|
31863
32139
|
if (attempt < this.maxRetries) {
|
|
31864
32140
|
const delay = calculateBackoff(attempt);
|
|
31865
32141
|
this.log(`Retrying in ${delay}ms...`);
|
|
31866
|
-
await new Promise((
|
|
32142
|
+
await new Promise((resolve20) => setTimeout(resolve20, delay));
|
|
31867
32143
|
}
|
|
31868
32144
|
}
|
|
31869
32145
|
}
|
|
@@ -31888,6 +32164,9 @@ var SkillsmithApiClient = class {
|
|
|
31888
32164
|
if (options.maxRiskScore !== void 0 && options.maxRiskScore !== null) {
|
|
31889
32165
|
params.set("max_risk", String(options.maxRiskScore));
|
|
31890
32166
|
}
|
|
32167
|
+
if (options.compatibility && options.compatibility.length > 0) {
|
|
32168
|
+
params.set("compatibility", options.compatibility.join(","));
|
|
32169
|
+
}
|
|
31891
32170
|
const endpoint = `/skills-search?${params.toString()}`;
|
|
31892
32171
|
return withResponseCache(this.responseCache, "search", endpoint, callOptions?.cache === "no-store", () => this.request(endpoint, {}, SearchResponseSchema));
|
|
31893
32172
|
}
|
|
@@ -32525,7 +32804,7 @@ function trackSkillInvoke(params) {
|
|
|
32525
32804
|
|
|
32526
32805
|
// ../core/dist/src/telemetry/wrap.js
|
|
32527
32806
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
32528
|
-
import { randomUUID as
|
|
32807
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
32529
32808
|
var wrapped = /* @__PURE__ */ new Set();
|
|
32530
32809
|
var emissionGateStorage = new AsyncLocalStorage2();
|
|
32531
32810
|
var emissionGate;
|
|
@@ -32547,7 +32826,7 @@ function truncateErrorMessage(message) {
|
|
|
32547
32826
|
}
|
|
32548
32827
|
function withTelemetry(handler, opts) {
|
|
32549
32828
|
const wrappedFn = async (...args) => {
|
|
32550
|
-
return runWithCorrelationId(getCorrelationId() ??
|
|
32829
|
+
return runWithCorrelationId(getCorrelationId() ?? randomUUID6(), async () => {
|
|
32551
32830
|
const start = Date.now();
|
|
32552
32831
|
const skillId = opts.extractSkillId(args);
|
|
32553
32832
|
const framework = opts.extractFramework?.(args) ?? "unknown";
|
|
@@ -32996,11 +33275,11 @@ async function scanLocalSkills(skillsRoot) {
|
|
|
32996
33275
|
}
|
|
32997
33276
|
|
|
32998
33277
|
// ../core/dist/src/provenance/SourceRecoveryService.js
|
|
32999
|
-
import * as
|
|
33278
|
+
import * as os3 from "os";
|
|
33000
33279
|
import * as path12 from "path";
|
|
33001
33280
|
var frontmatterParser = new SkillParser({ requireName: false });
|
|
33002
33281
|
function defaultSkillsRoot() {
|
|
33003
|
-
return path12.join(
|
|
33282
|
+
return path12.join(os3.homedir(), ".claude", "skills");
|
|
33004
33283
|
}
|
|
33005
33284
|
function candidateSource(candidate) {
|
|
33006
33285
|
return { owner: candidate.owner, repo: candidate.repo, url: candidate.url };
|
|
@@ -33178,7 +33457,7 @@ var SourceRecoveryService = class {
|
|
|
33178
33457
|
// ../core/dist/src/provenance/backfill.js
|
|
33179
33458
|
import { existsSync as existsSync19 } from "fs";
|
|
33180
33459
|
import * as fs11 from "fs/promises";
|
|
33181
|
-
import * as
|
|
33460
|
+
import * as os4 from "os";
|
|
33182
33461
|
import * as path13 from "path";
|
|
33183
33462
|
var CONFIDENCE_RANK = {
|
|
33184
33463
|
unknown: 0,
|
|
@@ -33189,7 +33468,7 @@ var CONFIDENCE_RANK = {
|
|
|
33189
33468
|
"user-specified": 5
|
|
33190
33469
|
};
|
|
33191
33470
|
function defaultManifestPath() {
|
|
33192
|
-
return path13.join(
|
|
33471
|
+
return path13.join(os4.homedir(), ".skillsmith", "manifest.json");
|
|
33193
33472
|
}
|
|
33194
33473
|
function nonEmpty(value) {
|
|
33195
33474
|
return typeof value === "string" && value.trim().length > 0;
|
|
@@ -33474,8 +33753,8 @@ async function probeEmbeddingCapability(opts = {}) {
|
|
|
33474
33753
|
try {
|
|
33475
33754
|
const result = await Promise.race([
|
|
33476
33755
|
EmbeddingService.checkAvailability(),
|
|
33477
|
-
new Promise((
|
|
33478
|
-
timeoutHandle = setTimeout(() =>
|
|
33756
|
+
new Promise((resolve20) => {
|
|
33757
|
+
timeoutHandle = setTimeout(() => resolve20(TIMEOUT_SENTINEL), timeoutMs);
|
|
33479
33758
|
})
|
|
33480
33759
|
]);
|
|
33481
33760
|
if (result === TIMEOUT_SENTINEL) {
|
|
@@ -33567,11 +33846,11 @@ import ora from "ora";
|
|
|
33567
33846
|
import * as path14 from "node:path";
|
|
33568
33847
|
|
|
33569
33848
|
// src/utils/sanitize.ts
|
|
33570
|
-
import { homedir as
|
|
33849
|
+
import { homedir as homedir17 } from "os";
|
|
33571
33850
|
var logger9 = getCliLogger();
|
|
33572
33851
|
function sanitizeError(error46) {
|
|
33573
33852
|
const message = error46 instanceof Error ? error46.message : String(error46);
|
|
33574
|
-
const home2 =
|
|
33853
|
+
const home2 = homedir17();
|
|
33575
33854
|
const escapedHome = home2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
33576
33855
|
let sanitized = message.replace(new RegExp(escapedHome, "g"), "~");
|
|
33577
33856
|
sanitized = sanitized.replace(/\/Users\/[^/]+\//g, "~/");
|
|
@@ -33582,7 +33861,7 @@ function sanitizeError(error46) {
|
|
|
33582
33861
|
|
|
33583
33862
|
// src/commands/install.ts
|
|
33584
33863
|
var logger10 = getCliLogger();
|
|
33585
|
-
var VALID_CLIENT_HINT = "Valid IDs: claude-code | cursor | copilot | windsurf | agents | opencode | hermes (Codex users pass --client agents).";
|
|
33864
|
+
var VALID_CLIENT_HINT = "Valid IDs: claude-code | cursor | copilot | windsurf | agents | opencode | hermes | grok | antigravity (Codex users pass --client agents).";
|
|
33586
33865
|
function parseAlsoLink(raw, defaultClient) {
|
|
33587
33866
|
if (!raw || raw.trim() === "") return [];
|
|
33588
33867
|
const ids = raw.split(",").map((s) => s.trim()).filter((s) => s !== "");
|
|
@@ -33749,6 +34028,13 @@ async function installActionImpl(skillId, opts) {
|
|
|
33749
34028
|
manifestPath: DEFAULT_MANIFEST_PATH,
|
|
33750
34029
|
registryLookup,
|
|
33751
34030
|
client,
|
|
34031
|
+
// SMI-5982 PR-review follow-up: explicit now that
|
|
34032
|
+
// resolveCompanionAgentPath() no longer defaults a missing baseDir to
|
|
34033
|
+
// process.cwd() itself — this CLI command's real "cwd" IS the
|
|
34034
|
+
// process's invocation directory, so this restores today's exact
|
|
34035
|
+
// behavior explicitly instead of relying on a now-removed implicit
|
|
34036
|
+
// default.
|
|
34037
|
+
companionBaseDir: process.cwd(),
|
|
33752
34038
|
onProgress: (_stage, detail) => {
|
|
33753
34039
|
if (spinner) {
|
|
33754
34040
|
spinner.text = detail;
|
|
@@ -34165,6 +34451,13 @@ ${outcome.message}`));
|
|
|
34165
34451
|
registryLookup,
|
|
34166
34452
|
skillsDir: getInstallPath(client),
|
|
34167
34453
|
client,
|
|
34454
|
+
// SMI-5982 PR-review follow-up: explicit now that
|
|
34455
|
+
// resolveCompanionAgentPath() no longer defaults a missing
|
|
34456
|
+
// baseDir to process.cwd() itself — this CLI command's real
|
|
34457
|
+
// "cwd" IS the process's invocation directory, so this
|
|
34458
|
+
// restores today's exact behavior explicitly instead of
|
|
34459
|
+
// relying on a now-removed implicit default.
|
|
34460
|
+
companionBaseDir: process.cwd(),
|
|
34168
34461
|
onProgress: (_stage, detail) => {
|
|
34169
34462
|
installSpinner.text = detail;
|
|
34170
34463
|
}
|
|
@@ -34566,11 +34859,11 @@ import { readFile as readFile8 } from "fs/promises";
|
|
|
34566
34859
|
import { basename as basename6, join as join41 } from "path";
|
|
34567
34860
|
|
|
34568
34861
|
// src/utils/manifest.ts
|
|
34569
|
-
import { createHash as createHash9, randomUUID as
|
|
34570
|
-
import { readFile as readFile7, writeFile as writeFile4, mkdir as mkdir5, rename as rename3 } from "fs/promises";
|
|
34862
|
+
import { createHash as createHash9, randomUUID as randomUUID7 } from "crypto";
|
|
34863
|
+
import { readFile as readFile7, writeFile as writeFile4, mkdir as mkdir5, rename as rename3, unlink as unlink5 } from "fs/promises";
|
|
34571
34864
|
import { join as join40, dirname as dirname19 } from "path";
|
|
34572
|
-
import { homedir as
|
|
34573
|
-
var SKILLSMITH_DIR = join40(
|
|
34865
|
+
import { homedir as homedir18 } from "os";
|
|
34866
|
+
var SKILLSMITH_DIR = join40(homedir18(), ".skillsmith");
|
|
34574
34867
|
var MANIFEST_PATH = join40(SKILLSMITH_DIR, "manifest.json");
|
|
34575
34868
|
async function loadManifest2() {
|
|
34576
34869
|
try {
|
|
@@ -34582,9 +34875,17 @@ async function loadManifest2() {
|
|
|
34582
34875
|
}
|
|
34583
34876
|
async function saveManifest2(manifest) {
|
|
34584
34877
|
await mkdir5(dirname19(MANIFEST_PATH), { recursive: true });
|
|
34585
|
-
const tmpPath = `${MANIFEST_PATH}.tmp.${process.pid}`;
|
|
34586
|
-
|
|
34587
|
-
|
|
34878
|
+
const tmpPath = `${MANIFEST_PATH}.tmp.${process.pid}.${randomUUID7()}`;
|
|
34879
|
+
try {
|
|
34880
|
+
await writeFile4(tmpPath, JSON.stringify(manifest, null, 2));
|
|
34881
|
+
await rename3(tmpPath, MANIFEST_PATH);
|
|
34882
|
+
} catch (error46) {
|
|
34883
|
+
try {
|
|
34884
|
+
await unlink5(tmpPath);
|
|
34885
|
+
} catch {
|
|
34886
|
+
}
|
|
34887
|
+
throw error46;
|
|
34888
|
+
}
|
|
34588
34889
|
}
|
|
34589
34890
|
async function updateManifestEntry(updateFn) {
|
|
34590
34891
|
const manifest = await loadManifest2();
|
|
@@ -34595,7 +34896,7 @@ var ROTATION_DAYS = 365;
|
|
|
34595
34896
|
var OVERLAP_DAYS = 7;
|
|
34596
34897
|
var MS_PER_DAY2 = 864e5;
|
|
34597
34898
|
function generateAnonymousId2() {
|
|
34598
|
-
return createHash9("sha256").update(
|
|
34899
|
+
return createHash9("sha256").update(randomUUID7()).digest("hex");
|
|
34599
34900
|
}
|
|
34600
34901
|
function shouldRotateAnonymousId(manifest) {
|
|
34601
34902
|
const createdAt = manifest.telemetry?.anonymousIdCreatedAt;
|
|
@@ -34811,6 +35112,13 @@ Changes for ${skillName}:`));
|
|
|
34811
35112
|
manifestPath: DEFAULT_MANIFEST_PATH,
|
|
34812
35113
|
registryLookup,
|
|
34813
35114
|
client,
|
|
35115
|
+
// SMI-5982 PR-review follow-up: explicit now that
|
|
35116
|
+
// resolveCompanionAgentPath() no longer defaults a missing baseDir to
|
|
35117
|
+
// process.cwd() itself — this CLI command's real "cwd" IS the
|
|
35118
|
+
// process's invocation directory, so this restores today's exact
|
|
35119
|
+
// behavior explicitly instead of relying on a now-removed implicit
|
|
35120
|
+
// default.
|
|
35121
|
+
companionBaseDir: process.cwd(),
|
|
34814
35122
|
onProgress: (_stage, detail) => {
|
|
34815
35123
|
updateSpinner.text = detail;
|
|
34816
35124
|
}
|
|
@@ -35113,7 +35421,7 @@ var InitSkillError = class _InitSkillError extends Error {
|
|
|
35113
35421
|
import { input as input2, confirm as confirm3, select as select2 } from "@inquirer/prompts";
|
|
35114
35422
|
import ora5 from "ora";
|
|
35115
35423
|
import { mkdir as mkdir9, writeFile as writeFile6, readFile as readFile9, stat as stat7, readdir as readdir7 } from "fs/promises";
|
|
35116
|
-
import { dirname as dirname21, join as
|
|
35424
|
+
import { dirname as dirname21, join as join43, resolve as resolve12 } from "path";
|
|
35117
35425
|
import { createHash as createHash10 } from "crypto";
|
|
35118
35426
|
|
|
35119
35427
|
// src/utils/skill-name.ts
|
|
@@ -35129,8 +35437,8 @@ function validateSkillName(name) {
|
|
|
35129
35437
|
// src/commands/author/utils.ts
|
|
35130
35438
|
import { access as access3 } from "fs/promises";
|
|
35131
35439
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
35132
|
-
import {
|
|
35133
|
-
import { homedir as
|
|
35440
|
+
import { resolve as resolve11 } from "path";
|
|
35441
|
+
import { homedir as homedir19 } from "os";
|
|
35134
35442
|
function printValidationResult(result, filePath) {
|
|
35135
35443
|
console.log(source_default.bold(`
|
|
35136
35444
|
Validation Result for ${filePath}:
|
|
@@ -35162,8 +35470,8 @@ async function fileExists(path27) {
|
|
|
35162
35470
|
return false;
|
|
35163
35471
|
}
|
|
35164
35472
|
}
|
|
35165
|
-
async function ensureAgentsDirectory(customPath) {
|
|
35166
|
-
const agentsDir = customPath ?
|
|
35473
|
+
async function ensureAgentsDirectory(customPath, client) {
|
|
35474
|
+
const agentsDir = customPath ? resolve11(customPath.replace(/^~/, homedir19())) : resolveCompanionAgentDir(client);
|
|
35167
35475
|
await mkdir7(agentsDir, { recursive: true });
|
|
35168
35476
|
return agentsDir;
|
|
35169
35477
|
}
|
|
@@ -35218,7 +35526,7 @@ function validateSubagentDefinition(content) {
|
|
|
35218
35526
|
|
|
35219
35527
|
// src/commands/author/init.helpers.ts
|
|
35220
35528
|
import { mkdir as mkdir8, writeFile as writeFile5, rm as rm4 } from "fs/promises";
|
|
35221
|
-
import { join as
|
|
35529
|
+
import { join as join42 } from "path";
|
|
35222
35530
|
|
|
35223
35531
|
// src/templates/skill.md.template.ts
|
|
35224
35532
|
var SKILL_MD_TEMPLATE = `---
|
|
@@ -35734,6 +36042,30 @@ args = ["-y", "{{name}}"]
|
|
|
35734
36042
|
[mcp_servers.{{name}}.env]
|
|
35735
36043
|
SKILLSMITH_API_KEY = "sk_live_..."`,
|
|
35736
36044
|
notes: "Grok Build uses TOML under the [mcp_servers.<name>] table, mirroring the Codex CLI convention above \u2014 confirmed against docs.x.ai for the command/args shape; the env sub-table follows the same pattern as the Codex entry."
|
|
36045
|
+
},
|
|
36046
|
+
// SMI-5982 Wave 6: antigravity added to ClientId (paths.ts); this
|
|
36047
|
+
// Record<SnippetClientId, ClientSnippet> is exhaustive over ClientId, so
|
|
36048
|
+
// this entry is required for the type to compile. Path + shape verified
|
|
36049
|
+
// 2026-08-11 via live web search (antigravity.google/docs/mcp, corroborated
|
|
36050
|
+
// by an independent third-party source): global config at
|
|
36051
|
+
// ~/.gemini/config/mcp_config.json, standard `mcpServers` object shape
|
|
36052
|
+
// (same command/args/env fields every non-Codex/non-OpenCode client uses).
|
|
36053
|
+
antigravity: {
|
|
36054
|
+
label: "Google Antigravity",
|
|
36055
|
+
configPath: "~/.gemini/config/mcp_config.json",
|
|
36056
|
+
format: "json",
|
|
36057
|
+
body: `{
|
|
36058
|
+
"mcpServers": {
|
|
36059
|
+
"{{name}}": {
|
|
36060
|
+
"command": "npx",
|
|
36061
|
+
"args": ["-y", "{{name}}"],
|
|
36062
|
+
"env": {
|
|
36063
|
+
"SKILLSMITH_API_KEY": "sk_live_..."
|
|
36064
|
+
}
|
|
36065
|
+
}
|
|
36066
|
+
}
|
|
36067
|
+
}`,
|
|
36068
|
+
notes: "One config file is shared across Antigravity CLI, IDE, and 2.0. A workspace-scoped alternative also exists at .agents/mcp_config.json (project root) if you prefer not to register the server globally."
|
|
35737
36069
|
}
|
|
35738
36070
|
};
|
|
35739
36071
|
function renderSnippet(client, packageName) {
|
|
@@ -35769,7 +36101,8 @@ var SNIPPET_DISPLAY_ORDER = Object.freeze([
|
|
|
35769
36101
|
"agents",
|
|
35770
36102
|
"opencode",
|
|
35771
36103
|
"hermes",
|
|
35772
|
-
"grok"
|
|
36104
|
+
"grok",
|
|
36105
|
+
"antigravity"
|
|
35773
36106
|
]);
|
|
35774
36107
|
|
|
35775
36108
|
// src/templates/mcp-server.template.ts
|
|
@@ -36115,15 +36448,15 @@ function renderMcpServerTemplates(data) {
|
|
|
36115
36448
|
async function scaffoldSkillDirectory(input7) {
|
|
36116
36449
|
const { skillDir, skillName, description, author, category, createdFresh } = input7;
|
|
36117
36450
|
try {
|
|
36118
|
-
await mkdir8(
|
|
36119
|
-
await mkdir8(
|
|
36451
|
+
await mkdir8(join42(skillDir, "scripts"), { recursive: true });
|
|
36452
|
+
await mkdir8(join42(skillDir, "resources"), { recursive: true });
|
|
36120
36453
|
const skillMdContent = SKILL_MD_TEMPLATE.replace(/\{\{name\}\}/g, skillName).replace(/\{\{description\}\}/g, description).replace(/\{\{author\}\}/g, author).replace(/\{\{category\}\}/g, category).replace(/\{\{date\}\}/g, (/* @__PURE__ */ new Date()).toISOString().split("T")[0] || "").replace(/\{\{behavioralClassification\}\}/g, "");
|
|
36121
|
-
await writeFile5(
|
|
36454
|
+
await writeFile5(join42(skillDir, "SKILL.md"), skillMdContent, "utf-8");
|
|
36122
36455
|
const readmeContent = README_MD_TEMPLATE.replace(/\{\{name\}\}/g, skillName).replace(
|
|
36123
36456
|
/\{\{description\}\}/g,
|
|
36124
36457
|
description
|
|
36125
36458
|
);
|
|
36126
|
-
await writeFile5(
|
|
36459
|
+
await writeFile5(join42(skillDir, "README.md"), readmeContent, "utf-8");
|
|
36127
36460
|
const placeholderScript = `#!/usr/bin/env node
|
|
36128
36461
|
/**
|
|
36129
36462
|
* ${skillName} - Example Script
|
|
@@ -36133,7 +36466,7 @@ async function scaffoldSkillDirectory(input7) {
|
|
|
36133
36466
|
|
|
36134
36467
|
console.log('${skillName} script executed');
|
|
36135
36468
|
`;
|
|
36136
|
-
await writeFile5(
|
|
36469
|
+
await writeFile5(join42(skillDir, "scripts", "example.js"), placeholderScript, "utf-8");
|
|
36137
36470
|
const gitignore = `# Dependencies
|
|
36138
36471
|
node_modules/
|
|
36139
36472
|
|
|
@@ -36148,7 +36481,7 @@ dist/
|
|
|
36148
36481
|
.DS_Store
|
|
36149
36482
|
Thumbs.db
|
|
36150
36483
|
`;
|
|
36151
|
-
await writeFile5(
|
|
36484
|
+
await writeFile5(join42(skillDir, ".gitignore"), gitignore, "utf-8");
|
|
36152
36485
|
return { ok: true };
|
|
36153
36486
|
} catch (error46) {
|
|
36154
36487
|
await rollbackPartialScaffold(skillDir, createdFresh);
|
|
@@ -36208,7 +36541,7 @@ async function initSkill(name, targetPath, options = {}) {
|
|
|
36208
36541
|
{ name: "Other", value: "other" }
|
|
36209
36542
|
]
|
|
36210
36543
|
});
|
|
36211
|
-
const skillDir =
|
|
36544
|
+
const skillDir = resolve12(targetPath, skillName);
|
|
36212
36545
|
let skillDirPreExisted = false;
|
|
36213
36546
|
try {
|
|
36214
36547
|
await stat7(skillDir);
|
|
@@ -36260,15 +36593,15 @@ async function initSkill(name, targetPath, options = {}) {
|
|
|
36260
36593
|
async function validateSkill(skillPath) {
|
|
36261
36594
|
const spinner = ora5("Validating skill...").start();
|
|
36262
36595
|
try {
|
|
36263
|
-
let filePath =
|
|
36596
|
+
let filePath = resolve12(skillPath);
|
|
36264
36597
|
try {
|
|
36265
36598
|
const stats = await stat7(filePath);
|
|
36266
36599
|
if (stats.isDirectory()) {
|
|
36267
|
-
filePath =
|
|
36600
|
+
filePath = join43(filePath, "SKILL.md");
|
|
36268
36601
|
}
|
|
36269
36602
|
} catch {
|
|
36270
36603
|
if (!filePath.endsWith(".md")) {
|
|
36271
|
-
filePath =
|
|
36604
|
+
filePath = join43(filePath, "SKILL.md");
|
|
36272
36605
|
}
|
|
36273
36606
|
}
|
|
36274
36607
|
const content = await readFile9(filePath, "utf-8");
|
|
@@ -36305,7 +36638,7 @@ async function validateSkill(skillPath) {
|
|
|
36305
36638
|
async function publishSkill(skillPath, options = {}) {
|
|
36306
36639
|
const spinner = ora5("Preparing skill for publishing...").start();
|
|
36307
36640
|
try {
|
|
36308
|
-
let dirPath =
|
|
36641
|
+
let dirPath = resolve12(skillPath || ".");
|
|
36309
36642
|
try {
|
|
36310
36643
|
const stats = await stat7(dirPath);
|
|
36311
36644
|
if (!stats.isDirectory()) {
|
|
@@ -36315,7 +36648,7 @@ async function publishSkill(skillPath, options = {}) {
|
|
|
36315
36648
|
spinner.fail(`Directory not found: ${dirPath}`);
|
|
36316
36649
|
return false;
|
|
36317
36650
|
}
|
|
36318
|
-
const skillMdPath =
|
|
36651
|
+
const skillMdPath = join43(dirPath, "SKILL.md");
|
|
36319
36652
|
spinner.text = "Validating skill...";
|
|
36320
36653
|
const content = await readFile9(skillMdPath, "utf-8");
|
|
36321
36654
|
const parser2 = new SkillParser({ requireName: true });
|
|
@@ -36361,7 +36694,7 @@ async function publishSkill(skillPath, options = {}) {
|
|
|
36361
36694
|
}).filter((p) => p !== null);
|
|
36362
36695
|
let totalWarnings = 0;
|
|
36363
36696
|
for (const mdFile of mdFiles) {
|
|
36364
|
-
const filePath =
|
|
36697
|
+
const filePath = join43(dirPath, mdFile);
|
|
36365
36698
|
const fileContent = await readFile9(filePath, "utf-8");
|
|
36366
36699
|
const result = SkillParser.checkReferences(fileContent, customPatterns);
|
|
36367
36700
|
if (result.matches.length > 0) {
|
|
@@ -36390,7 +36723,7 @@ async function publishSkill(skillPath, options = {}) {
|
|
|
36390
36723
|
spinner.start();
|
|
36391
36724
|
}
|
|
36392
36725
|
}
|
|
36393
|
-
const manifestPath =
|
|
36726
|
+
const manifestPath = join43(dirPath, ".skillsmith-publish.json");
|
|
36394
36727
|
await writeFile6(manifestPath, JSON.stringify(publishInfo, null, 2), "utf-8");
|
|
36395
36728
|
spinner.succeed("Skill prepared for publishing");
|
|
36396
36729
|
console.log(source_default.bold("\nPublish Information:"));
|
|
@@ -36497,7 +36830,7 @@ function createPublishCommand() {
|
|
|
36497
36830
|
import { Command as Command5 } from "commander";
|
|
36498
36831
|
import ora6 from "ora";
|
|
36499
36832
|
import { readFile as readFile10, writeFile as writeFile7, stat as stat8 } from "fs/promises";
|
|
36500
|
-
import { basename as basename7, dirname as dirname22, join as
|
|
36833
|
+
import { basename as basename7, dirname as dirname22, join as join44, resolve as resolve13 } from "path";
|
|
36501
36834
|
|
|
36502
36835
|
// src/utils/tool-analyzer.ts
|
|
36503
36836
|
var TOOL_PATTERNS3 = {
|
|
@@ -36621,18 +36954,18 @@ var logger14 = getCliLogger();
|
|
|
36621
36954
|
async function generateSubagent2(skillPath, options) {
|
|
36622
36955
|
const spinner = ora6("Generating subagent...").start();
|
|
36623
36956
|
try {
|
|
36624
|
-
let dirPath =
|
|
36957
|
+
let dirPath = resolve13(skillPath || ".");
|
|
36625
36958
|
let skillMdPath;
|
|
36626
36959
|
try {
|
|
36627
36960
|
const stats = await stat8(dirPath);
|
|
36628
36961
|
if (stats.isDirectory()) {
|
|
36629
|
-
skillMdPath =
|
|
36962
|
+
skillMdPath = join44(dirPath, "SKILL.md");
|
|
36630
36963
|
} else {
|
|
36631
36964
|
skillMdPath = dirPath;
|
|
36632
36965
|
dirPath = dirname22(dirPath);
|
|
36633
36966
|
}
|
|
36634
36967
|
} catch {
|
|
36635
|
-
skillMdPath = dirPath.endsWith(".md") ? dirPath :
|
|
36968
|
+
skillMdPath = dirPath.endsWith(".md") ? dirPath : join44(dirPath, "SKILL.md");
|
|
36636
36969
|
}
|
|
36637
36970
|
spinner.text = "Reading SKILL.md...";
|
|
36638
36971
|
const content = await readFile10(skillMdPath, "utf-8");
|
|
@@ -36679,7 +37012,11 @@ async function generateSubagent2(skillPath, options) {
|
|
|
36679
37012
|
return;
|
|
36680
37013
|
}
|
|
36681
37014
|
const agentsDir = await ensureAgentsDirectory(options.output);
|
|
36682
|
-
const
|
|
37015
|
+
const subagentFilename = getCompanionAgentTarget().filenamePattern.replace(
|
|
37016
|
+
"{name}",
|
|
37017
|
+
basename7(metadata.name)
|
|
37018
|
+
);
|
|
37019
|
+
const subagentPath = join44(agentsDir, subagentFilename);
|
|
36683
37020
|
if (await fileExists(subagentPath)) {
|
|
36684
37021
|
if (!options.force) {
|
|
36685
37022
|
spinner.warn(`Subagent already exists: ${subagentPath}`);
|
|
@@ -36739,32 +37076,31 @@ var subagentAction = withTelemetry(subagentActionImpl, {
|
|
|
36739
37076
|
extractFramework: () => "cli"
|
|
36740
37077
|
});
|
|
36741
37078
|
function createSubagentCommand() {
|
|
36742
|
-
return new Command5("subagent").description("Generate a companion subagent for a skill").argument("[path]", "Path to skill directory", ".").option("-o, --output <path>", "Output directory
|
|
37079
|
+
return new Command5("subagent").description("Generate a companion subagent for a skill").argument("[path]", "Path to skill directory", ".").option("-o, --output <path>", "Output directory (default: ~/.claude/agents)").option("--tools <tools>", "Override detected tools (comma-separated)").option("--model <model>", "Model for subagent: sonnet|opus|haiku", "sonnet").option("--skip-claude-md", "Skip CLAUDE.md snippet generation").option("--force", "Overwrite existing subagent definition").action(subagentAction);
|
|
36743
37080
|
}
|
|
36744
37081
|
|
|
36745
37082
|
// src/commands/author/transform.ts
|
|
36746
37083
|
import { Command as Command6 } from "commander";
|
|
36747
37084
|
import ora7 from "ora";
|
|
36748
37085
|
import { readFile as readFile11, readdir as readdir8 } from "fs/promises";
|
|
36749
|
-
import { join as
|
|
36750
|
-
import { homedir as homedir21 } from "os";
|
|
37086
|
+
import { join as join45, resolve as resolve14 } from "path";
|
|
36751
37087
|
var logger15 = getCliLogger();
|
|
36752
37088
|
async function transformSkill2(skillPath, options) {
|
|
36753
37089
|
const spinner = ora7("Transforming skill...").start();
|
|
36754
37090
|
try {
|
|
36755
|
-
const dirPath =
|
|
37091
|
+
const dirPath = resolve14(skillPath || ".");
|
|
36756
37092
|
if (options.batch) {
|
|
36757
37093
|
spinner.text = "Processing batch...";
|
|
36758
37094
|
let skillDirs = [];
|
|
36759
37095
|
if (dirPath.includes(",")) {
|
|
36760
|
-
skillDirs = dirPath.split(",").map((p) =>
|
|
37096
|
+
skillDirs = dirPath.split(",").map((p) => resolve14(p.trim()));
|
|
36761
37097
|
} else {
|
|
36762
37098
|
const subdirs = await readdir8(dirPath, { withFileTypes: true });
|
|
36763
37099
|
for (const entry of subdirs) {
|
|
36764
37100
|
if (entry.isDirectory()) {
|
|
36765
|
-
const skillMdPath2 =
|
|
37101
|
+
const skillMdPath2 = join45(dirPath, entry.name, "SKILL.md");
|
|
36766
37102
|
if (await fileExists(skillMdPath2)) {
|
|
36767
|
-
skillDirs.push(
|
|
37103
|
+
skillDirs.push(join45(dirPath, entry.name));
|
|
36768
37104
|
}
|
|
36769
37105
|
}
|
|
36770
37106
|
}
|
|
@@ -36786,7 +37122,7 @@ Processing: ${skillDir}`));
|
|
|
36786
37122
|
}
|
|
36787
37123
|
return;
|
|
36788
37124
|
}
|
|
36789
|
-
const skillMdPath =
|
|
37125
|
+
const skillMdPath = join45(dirPath, "SKILL.md");
|
|
36790
37126
|
if (!await fileExists(skillMdPath)) {
|
|
36791
37127
|
spinner.fail(`No SKILL.md found at: ${skillMdPath}`);
|
|
36792
37128
|
throw new Error(`No SKILL.md found at: ${skillMdPath}`);
|
|
@@ -36800,8 +37136,7 @@ Processing: ${skillDir}`));
|
|
|
36800
37136
|
printValidationResult(validation, skillMdPath);
|
|
36801
37137
|
return;
|
|
36802
37138
|
}
|
|
36803
|
-
const
|
|
36804
|
-
const subagentPath = join46(agentsDir, `${metadata.name}-specialist.md`);
|
|
37139
|
+
const subagentPath = resolveCompanionAgentPath(metadata.name);
|
|
36805
37140
|
if (await fileExists(subagentPath)) {
|
|
36806
37141
|
if (!options.force) {
|
|
36807
37142
|
spinner.warn(`Subagent already exists: ${subagentPath}`);
|
|
@@ -36859,7 +37194,7 @@ import { Command as Command7 } from "commander";
|
|
|
36859
37194
|
import { input as input3, confirm as confirm4 } from "@inquirer/prompts";
|
|
36860
37195
|
import ora8 from "ora";
|
|
36861
37196
|
import { mkdir as mkdir10, writeFile as writeFile8, stat as stat9 } from "fs/promises";
|
|
36862
|
-
import { dirname as dirname23, join as
|
|
37197
|
+
import { dirname as dirname23, join as join46, resolve as resolve15 } from "path";
|
|
36863
37198
|
var logger16 = getCliLogger();
|
|
36864
37199
|
async function initMcpServer(name, options) {
|
|
36865
37200
|
const serverName = name || await input3({
|
|
@@ -36948,7 +37283,7 @@ async function initMcpServer(name, options) {
|
|
|
36948
37283
|
}
|
|
36949
37284
|
}
|
|
36950
37285
|
}
|
|
36951
|
-
const targetDir = options.output ?
|
|
37286
|
+
const targetDir = options.output ? resolve15(options.output) : resolve15(".", serverName);
|
|
36952
37287
|
try {
|
|
36953
37288
|
await stat9(targetDir);
|
|
36954
37289
|
if (!options.force) {
|
|
@@ -36972,10 +37307,10 @@ async function initMcpServer(name, options) {
|
|
|
36972
37307
|
author
|
|
36973
37308
|
});
|
|
36974
37309
|
await mkdir10(targetDir, { recursive: true });
|
|
36975
|
-
await mkdir10(
|
|
36976
|
-
await mkdir10(
|
|
37310
|
+
await mkdir10(join46(targetDir, "src"), { recursive: true });
|
|
37311
|
+
await mkdir10(join46(targetDir, "src", "tools"), { recursive: true });
|
|
36977
37312
|
for (const [filePath, content] of files) {
|
|
36978
|
-
const fullPath =
|
|
37313
|
+
const fullPath = join46(targetDir, filePath);
|
|
36979
37314
|
const dir = dirname23(fullPath);
|
|
36980
37315
|
await mkdir10(dir, { recursive: true });
|
|
36981
37316
|
await writeFile8(fullPath, content, "utf-8");
|
|
@@ -36995,7 +37330,7 @@ async function initMcpServer(name, options) {
|
|
|
36995
37330
|
"mcpServers": {
|
|
36996
37331
|
"${serverName}": {
|
|
36997
37332
|
"command": "npx",
|
|
36998
|
-
"args": ["tsx", "${
|
|
37333
|
+
"args": ["tsx", "${join46(targetDir, "src", "index.ts")}"]
|
|
36999
37334
|
}
|
|
37000
37335
|
}
|
|
37001
37336
|
}`)
|
|
@@ -37177,7 +37512,7 @@ import ora9 from "ora";
|
|
|
37177
37512
|
|
|
37178
37513
|
// src/commands/recommend.helpers.ts
|
|
37179
37514
|
import { existsSync as existsSync21, readdirSync as readdirSync2, readFileSync as readFileSync18, statSync as statSync4 } from "node:fs";
|
|
37180
|
-
import { join as
|
|
37515
|
+
import { join as join47 } from "node:path";
|
|
37181
37516
|
|
|
37182
37517
|
// src/commands/recommend.types.ts
|
|
37183
37518
|
var VALID_TRUST_TIERS = [
|
|
@@ -37504,7 +37839,7 @@ function getInstalledSkills2() {
|
|
|
37504
37839
|
try {
|
|
37505
37840
|
const entries = readdirSync2(skillsDir);
|
|
37506
37841
|
for (const entry of entries) {
|
|
37507
|
-
const skillPath =
|
|
37842
|
+
const skillPath = join47(skillsDir, entry);
|
|
37508
37843
|
const stat13 = statSync4(skillPath);
|
|
37509
37844
|
if (!stat13.isDirectory()) continue;
|
|
37510
37845
|
const skill = {
|
|
@@ -37513,7 +37848,7 @@ function getInstalledSkills2() {
|
|
|
37513
37848
|
tags: [],
|
|
37514
37849
|
category: null
|
|
37515
37850
|
};
|
|
37516
|
-
const skillMdPath =
|
|
37851
|
+
const skillMdPath = join47(skillPath, "SKILL.md");
|
|
37517
37852
|
if (existsSync21(skillMdPath)) {
|
|
37518
37853
|
try {
|
|
37519
37854
|
const content = readFileSync18(skillMdPath, "utf-8");
|
|
@@ -37560,8 +37895,7 @@ async function runRecommend(targetPath, options) {
|
|
|
37560
37895
|
spinner.start("Finding skill recommendations...");
|
|
37561
37896
|
const stack = buildStackFromAnalysis(codebaseContext);
|
|
37562
37897
|
if (options.context) {
|
|
37563
|
-
|
|
37564
|
-
stack.push(...contextWords);
|
|
37898
|
+
stack.push(...extractContextWords(options.context));
|
|
37565
37899
|
}
|
|
37566
37900
|
if (options.installed?.length) {
|
|
37567
37901
|
stack.push(...options.installed.map((id) => id.toLowerCase().split("/").pop() ?? id));
|
|
@@ -38169,7 +38503,7 @@ function createSyncCommand() {
|
|
|
38169
38503
|
|
|
38170
38504
|
// src/commands/merge.ts
|
|
38171
38505
|
import { Command as Command11 } from "commander";
|
|
38172
|
-
import { resolve as
|
|
38506
|
+
import { resolve as resolve16 } from "path";
|
|
38173
38507
|
import { existsSync as existsSync22 } from "fs";
|
|
38174
38508
|
var logger20 = getCliLogger();
|
|
38175
38509
|
function formatMergeResult(result) {
|
|
@@ -38201,8 +38535,8 @@ async function mergeActionImpl(sourcePath, targetPath, options) {
|
|
|
38201
38535
|
logger20.error(`Valid strategies: ${validStrategies.join(", ")}`);
|
|
38202
38536
|
process.exit(1);
|
|
38203
38537
|
}
|
|
38204
|
-
const resolvedSource =
|
|
38205
|
-
const resolvedTarget = targetPath ?
|
|
38538
|
+
const resolvedSource = resolve16(sourcePath);
|
|
38539
|
+
const resolvedTarget = targetPath ? resolve16(targetPath) : getDefaultDbPath();
|
|
38206
38540
|
if (!existsSync22(resolvedSource)) {
|
|
38207
38541
|
logger20.error(`Source database not found: ${resolvedSource}`);
|
|
38208
38542
|
process.exit(1);
|
|
@@ -38393,6 +38727,13 @@ ${message}`));
|
|
|
38393
38727
|
skillsDir,
|
|
38394
38728
|
manifestPath: DEFAULT_MANIFEST_PATH,
|
|
38395
38729
|
client,
|
|
38730
|
+
// SMI-5982 PR-review follow-up: explicit now that
|
|
38731
|
+
// resolveCompanionAgentPath() no longer defaults a missing baseDir to
|
|
38732
|
+
// process.cwd() itself — this CLI command's real "cwd" IS the
|
|
38733
|
+
// process's invocation directory, so this restores today's exact
|
|
38734
|
+
// behavior explicitly instead of relying on a now-removed implicit
|
|
38735
|
+
// default.
|
|
38736
|
+
companionBaseDir: process.cwd(),
|
|
38396
38737
|
onProgress: (_stage, detail) => {
|
|
38397
38738
|
if (spinner) {
|
|
38398
38739
|
spinner.text = detail;
|
|
@@ -38465,13 +38806,13 @@ function createRegistryCommand() {
|
|
|
38465
38806
|
import { Command as Command13 } from "commander";
|
|
38466
38807
|
import ora12 from "ora";
|
|
38467
38808
|
import { mkdir as mkdir11, copyFile as copyFile2, stat as stat10, readdir as readdir9 } from "fs/promises";
|
|
38468
|
-
import { join as
|
|
38809
|
+
import { join as join48, dirname as dirname24 } from "path";
|
|
38469
38810
|
var logger22 = getCliLogger();
|
|
38470
38811
|
function getAssetsPath() {
|
|
38471
|
-
return
|
|
38812
|
+
return join48(packageRoot(), "assets", "skillsmith-skill");
|
|
38472
38813
|
}
|
|
38473
38814
|
function getTargetPath() {
|
|
38474
|
-
return
|
|
38815
|
+
return join48(getCanonicalInstallPath(), "skillsmith");
|
|
38475
38816
|
}
|
|
38476
38817
|
async function directoryExists(path27) {
|
|
38477
38818
|
try {
|
|
@@ -38488,8 +38829,8 @@ async function copyDirectory(src, dest) {
|
|
|
38488
38829
|
if (entry.isSymbolicLink()) {
|
|
38489
38830
|
continue;
|
|
38490
38831
|
}
|
|
38491
|
-
const srcPath =
|
|
38492
|
-
const destPath =
|
|
38832
|
+
const srcPath = join48(src, entry.name);
|
|
38833
|
+
const destPath = join48(dest, entry.name);
|
|
38493
38834
|
if (entry.isDirectory()) {
|
|
38494
38835
|
await mkdir11(destPath, { recursive: true });
|
|
38495
38836
|
filesCopied += await copyDirectory(srcPath, destPath);
|
|
@@ -38822,11 +39163,11 @@ async function loginActionImpl(options) {
|
|
|
38822
39163
|
output: process.stdout,
|
|
38823
39164
|
terminal: false
|
|
38824
39165
|
});
|
|
38825
|
-
const choice = await new Promise((
|
|
39166
|
+
const choice = await new Promise((resolve20) => {
|
|
38826
39167
|
process.stdout.write("Choice [a]: ");
|
|
38827
39168
|
rl.once("line", (line) => {
|
|
38828
39169
|
rl.close();
|
|
38829
|
-
|
|
39170
|
+
resolve20(line.trim().toLowerCase());
|
|
38830
39171
|
});
|
|
38831
39172
|
});
|
|
38832
39173
|
if (choice === "" || choice === "a") {
|
|
@@ -38933,21 +39274,35 @@ function createWhoamiCommand() {
|
|
|
38933
39274
|
// src/commands/diff.ts
|
|
38934
39275
|
import { Command as Command17 } from "commander";
|
|
38935
39276
|
import { readFile as readFile12 } from "fs/promises";
|
|
38936
|
-
import { join as
|
|
39277
|
+
import { join as join49 } from "path";
|
|
38937
39278
|
|
|
38938
39279
|
// src/utils/license-types.ts
|
|
38939
39280
|
var TIER_FEATURES = {
|
|
38940
39281
|
community: ["basic_search", "skill_install", "local_validation"],
|
|
38941
|
-
individual: [
|
|
39282
|
+
individual: [
|
|
39283
|
+
"basic_analytics",
|
|
39284
|
+
"email_support",
|
|
39285
|
+
// SMI-5949: pre-existing drift fix — version_tracking is part of
|
|
39286
|
+
// INDIVIDUAL_FEATURES in the canonical @smith-horn/enterprise package
|
|
39287
|
+
// (packages/enterprise/src/license/FeatureFlags.ts) and was silently
|
|
39288
|
+
// missing here (this file has no compiler backstop, unlike the
|
|
39289
|
+
// Record<FeatureFlag, ...> mirrors in toolFeatureMapping.ts). Caught by
|
|
39290
|
+
// the new TIER_FEATURES.enterprise parity regression test.
|
|
39291
|
+
"version_tracking"
|
|
39292
|
+
],
|
|
38942
39293
|
team: [
|
|
38943
39294
|
// Individual features (inherited)
|
|
38944
39295
|
"basic_analytics",
|
|
38945
39296
|
"email_support",
|
|
39297
|
+
"version_tracking",
|
|
38946
39298
|
// Team features
|
|
38947
39299
|
"team_workspaces",
|
|
38948
39300
|
"private_skills",
|
|
38949
39301
|
"usage_analytics",
|
|
38950
39302
|
"priority_support",
|
|
39303
|
+
// SMI-5949: pre-existing drift fix — skill_security_audit is part of
|
|
39304
|
+
// TEAM_FEATURES in the canonical package and was silently missing here.
|
|
39305
|
+
"skill_security_audit",
|
|
38951
39306
|
// SMI-3140: expanded to Team + Enterprise (2026-07-14)
|
|
38952
39307
|
"compliance_reports"
|
|
38953
39308
|
],
|
|
@@ -38955,11 +39310,13 @@ var TIER_FEATURES = {
|
|
|
38955
39310
|
// Individual features (inherited)
|
|
38956
39311
|
"basic_analytics",
|
|
38957
39312
|
"email_support",
|
|
39313
|
+
"version_tracking",
|
|
38958
39314
|
// Team features (inherited)
|
|
38959
39315
|
"team_workspaces",
|
|
38960
39316
|
"private_skills",
|
|
38961
39317
|
"usage_analytics",
|
|
38962
39318
|
"priority_support",
|
|
39319
|
+
"skill_security_audit",
|
|
38963
39320
|
"compliance_reports",
|
|
38964
39321
|
// Enterprise-only features (canonical names from enterprise package)
|
|
38965
39322
|
"sso_saml",
|
|
@@ -38968,7 +39325,9 @@ var TIER_FEATURES = {
|
|
|
38968
39325
|
"siem_export",
|
|
38969
39326
|
"private_registry",
|
|
38970
39327
|
"custom_integrations",
|
|
38971
|
-
"advanced_analytics"
|
|
39328
|
+
"advanced_analytics",
|
|
39329
|
+
// SMI-5949: separately-flagged approval gate for private_registry_publish (D-11)
|
|
39330
|
+
"registry_approval"
|
|
38972
39331
|
]
|
|
38973
39332
|
};
|
|
38974
39333
|
|
|
@@ -39123,7 +39482,7 @@ function diffSections(oldContent, newContent) {
|
|
|
39123
39482
|
return { added, removed, modified };
|
|
39124
39483
|
}
|
|
39125
39484
|
async function readInstalledSkillContent(skillName) {
|
|
39126
|
-
const skillPath =
|
|
39485
|
+
const skillPath = join49(getCanonicalInstallPath(), skillName, "SKILL.md");
|
|
39127
39486
|
try {
|
|
39128
39487
|
return await readFile12(skillPath, "utf-8");
|
|
39129
39488
|
} catch {
|
|
@@ -39334,15 +39693,15 @@ import { Command as Command22 } from "commander";
|
|
|
39334
39693
|
// src/commands/audit-collisions.ts
|
|
39335
39694
|
import * as crypto12 from "node:crypto";
|
|
39336
39695
|
import * as fs34 from "node:fs";
|
|
39337
|
-
import { homedir as
|
|
39338
|
-
import { join as
|
|
39696
|
+
import { homedir as homedir28 } from "node:os";
|
|
39697
|
+
import { join as join61 } from "node:path";
|
|
39339
39698
|
import { Command as Command19 } from "commander";
|
|
39340
39699
|
import { input as input4, select as select3 } from "@inquirer/prompts";
|
|
39341
39700
|
|
|
39342
39701
|
// ../mcp-server/dist/src/audit/audit-history.js
|
|
39343
39702
|
import * as crypto3 from "node:crypto";
|
|
39344
39703
|
import * as fs17 from "node:fs/promises";
|
|
39345
|
-
import * as
|
|
39704
|
+
import * as os6 from "node:os";
|
|
39346
39705
|
import * as path16 from "node:path";
|
|
39347
39706
|
|
|
39348
39707
|
// ../mcp-server/node_modules/ulid/dist/node/index.js
|
|
@@ -39441,7 +39800,7 @@ function ulid3(seedTime, prng) {
|
|
|
39441
39800
|
}
|
|
39442
39801
|
|
|
39443
39802
|
// ../mcp-server/dist/src/audit/audit-history.js
|
|
39444
|
-
var DEFAULT_AUDITS_DIR = path16.join(
|
|
39803
|
+
var DEFAULT_AUDITS_DIR = path16.join(os6.homedir(), ".skillsmith", "audits");
|
|
39445
39804
|
function newAuditId() {
|
|
39446
39805
|
return ulid3();
|
|
39447
39806
|
}
|
|
@@ -44552,24 +44911,24 @@ function formatTokens(tokens) {
|
|
|
44552
44911
|
// ../mcp-server/dist/src/audit/security-audit.js
|
|
44553
44912
|
import * as crypto6 from "node:crypto";
|
|
44554
44913
|
import * as fs22 from "node:fs";
|
|
44555
|
-
import * as
|
|
44914
|
+
import * as os10 from "node:os";
|
|
44556
44915
|
|
|
44557
44916
|
// ../mcp-server/dist/src/utils/local-inventory.js
|
|
44558
44917
|
import * as fs20 from "node:fs";
|
|
44559
|
-
import * as
|
|
44918
|
+
import * as os7 from "node:os";
|
|
44560
44919
|
import * as path18 from "node:path";
|
|
44561
|
-
var DEFAULT_HOME_CLAUDE_DIR = path18.join(
|
|
44562
|
-
var DEFAULT_MANIFEST_PATH3 = path18.join(
|
|
44920
|
+
var DEFAULT_HOME_CLAUDE_DIR = path18.join(os7.homedir(), ".claude");
|
|
44921
|
+
var DEFAULT_MANIFEST_PATH3 = path18.join(os7.homedir(), ".skillsmith", "manifest.json");
|
|
44563
44922
|
async function scanLocalInventory(opts = {}) {
|
|
44564
44923
|
const startedAt = process.hrtime.bigint();
|
|
44565
|
-
const homeDir = opts.homeDir ??
|
|
44924
|
+
const homeDir = opts.homeDir ?? os7.homedir();
|
|
44566
44925
|
const claudeDir = opts.homeDir ? path18.join(opts.homeDir, ".claude") : DEFAULT_HOME_CLAUDE_DIR;
|
|
44567
44926
|
const manifestPath = opts.manifestPath ?? DEFAULT_MANIFEST_PATH3;
|
|
44568
44927
|
const warnings = [];
|
|
44569
44928
|
const entries = [];
|
|
44570
44929
|
const manifest = loadManifest3(manifestPath);
|
|
44571
44930
|
entries.push(...scanSkills(path18.join(claudeDir, "skills"), manifest, warnings));
|
|
44572
|
-
const agentsSkillsDir = opts.homeDir ? path18.join(opts.homeDir, ".agents", "skills") : path18.join(
|
|
44931
|
+
const agentsSkillsDir = opts.homeDir ? path18.join(opts.homeDir, ".agents", "skills") : path18.join(os7.homedir(), ".agents", "skills");
|
|
44573
44932
|
entries.push(...scanSkills(agentsSkillsDir, manifest, warnings));
|
|
44574
44933
|
entries.push(...scanCommands(path18.join(claudeDir, "commands"), warnings));
|
|
44575
44934
|
entries.push(...scanAgents(path18.join(claudeDir, "agents"), warnings));
|
|
@@ -44704,7 +45063,7 @@ function coerceDescription2(value) {
|
|
|
44704
45063
|
// ../mcp-server/dist/src/audit/security-acceptance.js
|
|
44705
45064
|
import * as crypto5 from "node:crypto";
|
|
44706
45065
|
import { closeSync as closeSync2, fstatSync as fstatSync2, openSync as openSync2, readSync as readSync2 } from "node:fs";
|
|
44707
|
-
import * as
|
|
45066
|
+
import * as os8 from "node:os";
|
|
44708
45067
|
import * as path19 from "node:path";
|
|
44709
45068
|
|
|
44710
45069
|
// ../mcp-server/dist/src/audit/security-acceptance.types.js
|
|
@@ -44716,7 +45075,7 @@ function emptyAcceptanceStore() {
|
|
|
44716
45075
|
}
|
|
44717
45076
|
|
|
44718
45077
|
// ../mcp-server/dist/src/audit/security-acceptance.js
|
|
44719
|
-
function defaultAcceptancePath(homeDir =
|
|
45078
|
+
function defaultAcceptancePath(homeDir = os8.homedir()) {
|
|
44720
45079
|
return path19.join(homeDir, ".skillsmith", "audits", "security-acceptance.json");
|
|
44721
45080
|
}
|
|
44722
45081
|
function fingerprintTuple(f) {
|
|
@@ -44954,10 +45313,10 @@ function isAcceptDisabled() {
|
|
|
44954
45313
|
|
|
44955
45314
|
// ../mcp-server/dist/src/audit/security-baseline.js
|
|
44956
45315
|
import * as fs21 from "node:fs";
|
|
44957
|
-
import * as
|
|
45316
|
+
import * as os9 from "node:os";
|
|
44958
45317
|
import * as path20 from "node:path";
|
|
44959
45318
|
var SECURITY_BASELINE_VERSION = 1;
|
|
44960
|
-
function defaultBaselinePath(homeDir =
|
|
45319
|
+
function defaultBaselinePath(homeDir = os9.homedir()) {
|
|
44961
45320
|
return path20.join(homeDir, ".skillsmith", "audits", "security-baseline.json");
|
|
44962
45321
|
}
|
|
44963
45322
|
function emptyBaseline() {
|
|
@@ -45045,7 +45404,7 @@ function buildFinding(params) {
|
|
|
45045
45404
|
}
|
|
45046
45405
|
async function runSecurityAudit(opts = {}) {
|
|
45047
45406
|
const startedAt = process.hrtime.bigint();
|
|
45048
|
-
const homeDir = opts.homeDir ??
|
|
45407
|
+
const homeDir = opts.homeDir ?? os10.homedir();
|
|
45049
45408
|
const auditId = opts.auditId ?? newAuditId();
|
|
45050
45409
|
const threshold = opts.riskThreshold ?? DEFAULT_RISK_THRESHOLD;
|
|
45051
45410
|
const readContent = opts.readContent ?? defaultReadContent;
|
|
@@ -45348,7 +45707,7 @@ function hashDigest(payload) {
|
|
|
45348
45707
|
// ../mcp-server/dist/src/audit/namespace-overrides.js
|
|
45349
45708
|
import * as crypto8 from "node:crypto";
|
|
45350
45709
|
import * as fs24 from "node:fs/promises";
|
|
45351
|
-
import * as
|
|
45710
|
+
import * as os11 from "node:os";
|
|
45352
45711
|
import * as path22 from "node:path";
|
|
45353
45712
|
|
|
45354
45713
|
// ../mcp-server/dist/src/audit/namespace-overrides.types.js
|
|
@@ -45356,7 +45715,7 @@ var CURRENT_VERSION = 1;
|
|
|
45356
45715
|
|
|
45357
45716
|
// ../mcp-server/dist/src/audit/namespace-overrides.js
|
|
45358
45717
|
function defaultLedgerPath() {
|
|
45359
|
-
return path22.join(
|
|
45718
|
+
return path22.join(os11.homedir(), ".skillsmith", "namespace-overrides.json");
|
|
45360
45719
|
}
|
|
45361
45720
|
var ULID_PREFIX = "ovr_";
|
|
45362
45721
|
function emptyLedger() {
|
|
@@ -45524,7 +45883,7 @@ async function copyDirectory2(src, dest) {
|
|
|
45524
45883
|
|
|
45525
45884
|
// ../mcp-server/dist/src/audit/rename-engine.apply-paths.js
|
|
45526
45885
|
import * as fs26 from "node:fs/promises";
|
|
45527
|
-
import * as
|
|
45886
|
+
import * as os12 from "node:os";
|
|
45528
45887
|
import * as path24 from "node:path";
|
|
45529
45888
|
function actionToKind(action) {
|
|
45530
45889
|
switch (action) {
|
|
@@ -45571,7 +45930,7 @@ async function pathExists2(target) {
|
|
|
45571
45930
|
}
|
|
45572
45931
|
}
|
|
45573
45932
|
async function stageSingleFileForBackup(srcFile) {
|
|
45574
|
-
const tmp = await fs26.mkdtemp(path24.join(
|
|
45933
|
+
const tmp = await fs26.mkdtemp(path24.join(os12.tmpdir(), "skillsmith-rename-stage-"));
|
|
45575
45934
|
await fs26.copyFile(srcFile, path24.join(tmp, path24.basename(srcFile)));
|
|
45576
45935
|
return tmp;
|
|
45577
45936
|
}
|
|
@@ -46298,15 +46657,15 @@ var V1_TEMPLATE_PATTERNS = V1_TEMPLATES.map((t) => t.pattern);
|
|
|
46298
46657
|
var MS_PER_DAY3 = 24 * 60 * 60 * 1e3;
|
|
46299
46658
|
|
|
46300
46659
|
// ../mcp-server/dist/src/audit/run-inventory-audit.js
|
|
46301
|
-
import * as
|
|
46660
|
+
import * as os14 from "node:os";
|
|
46302
46661
|
|
|
46303
46662
|
// ../core/dist/src/audit/exclusions.js
|
|
46304
46663
|
import { promises as fs30 } from "node:fs";
|
|
46305
|
-
import { join as
|
|
46664
|
+
import { join as join59 } from "node:path";
|
|
46306
46665
|
var EXCLUSIONS_FILE = "audit-exclusions.json";
|
|
46307
46666
|
var EMPTY_CONFIG = { version: 1, exclusions: [] };
|
|
46308
46667
|
function getExclusionsPath(opts) {
|
|
46309
|
-
return
|
|
46668
|
+
return join59(opts?.configDir ?? getConfigDir(), EXCLUSIONS_FILE);
|
|
46310
46669
|
}
|
|
46311
46670
|
async function loadExclusions(opts = {}) {
|
|
46312
46671
|
const path27 = opts.configPath ?? getExclusionsPath();
|
|
@@ -46379,9 +46738,9 @@ function tierAllowsAuditMode(tier, mode) {
|
|
|
46379
46738
|
|
|
46380
46739
|
// ../mcp-server/dist/src/audit/audit-suggestions.js
|
|
46381
46740
|
import * as fs31 from "node:fs/promises";
|
|
46382
|
-
import * as
|
|
46741
|
+
import * as os13 from "node:os";
|
|
46383
46742
|
import * as path26 from "node:path";
|
|
46384
|
-
var DEFAULT_AUDITS_DIR2 = path26.join(
|
|
46743
|
+
var DEFAULT_AUDITS_DIR2 = path26.join(os13.homedir(), ".skillsmith", "audits");
|
|
46385
46744
|
async function writeAuditSuggestions(auditId, renameSuggestions, recommendedEdits, opts = {}) {
|
|
46386
46745
|
const auditsDir = opts.auditsDir ?? DEFAULT_AUDITS_DIR2;
|
|
46387
46746
|
const auditDir = path26.join(auditsDir, auditId);
|
|
@@ -46586,7 +46945,7 @@ function hashFileContent(filePath) {
|
|
|
46586
46945
|
// ../mcp-server/dist/src/audit/run-inventory-audit.js
|
|
46587
46946
|
async function runInventoryAudit(opts = {}) {
|
|
46588
46947
|
const startedAt = process.hrtime.bigint();
|
|
46589
|
-
const homeDir = opts.homeDir ??
|
|
46948
|
+
const homeDir = opts.homeDir ?? os14.homedir();
|
|
46590
46949
|
const scan = await scanLocalInventory({
|
|
46591
46950
|
homeDir,
|
|
46592
46951
|
...opts.projectDir !== void 0 ? { projectDir: opts.projectDir } : {}
|
|
@@ -46768,10 +47127,10 @@ async function requireConfirmationPhrase(expected, prompt) {
|
|
|
46768
47127
|
}
|
|
46769
47128
|
}
|
|
46770
47129
|
function ledgerPath() {
|
|
46771
|
-
return
|
|
47130
|
+
return join61(homedir28(), ".skillsmith", "namespace-overrides.json");
|
|
46772
47131
|
}
|
|
46773
47132
|
function backupsDir() {
|
|
46774
|
-
return
|
|
47133
|
+
return join61(homedir28(), ".skillsmith", "backups");
|
|
46775
47134
|
}
|
|
46776
47135
|
function backupLedgerForReset() {
|
|
46777
47136
|
const src = ledgerPath();
|
|
@@ -46780,7 +47139,7 @@ function backupLedgerForReset() {
|
|
|
46780
47139
|
fs34.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
46781
47140
|
const ts2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
46782
47141
|
const suffix = crypto12.randomBytes(4).toString("hex");
|
|
46783
|
-
const backupFile =
|
|
47142
|
+
const backupFile = join61(dir, `ledger-${ts2}-${suffix}.json`);
|
|
46784
47143
|
fs34.copyFileSync(src, backupFile);
|
|
46785
47144
|
return backupFile;
|
|
46786
47145
|
}
|
|
@@ -47817,7 +48176,7 @@ import { Command as Command23 } from "commander";
|
|
|
47817
48176
|
import { input as input6, confirm as confirm6, select as select4 } from "@inquirer/prompts";
|
|
47818
48177
|
import ora13 from "ora";
|
|
47819
48178
|
import { mkdir as mkdir17, writeFile as writeFile15, stat as stat12 } from "fs/promises";
|
|
47820
|
-
import { join as
|
|
48179
|
+
import { join as join62 } from "path";
|
|
47821
48180
|
var logger30 = getCliLogger();
|
|
47822
48181
|
var VALID_TYPES = ["basic", "intermediate", "advanced"];
|
|
47823
48182
|
var VALID_BEHAVIORS = ["autonomous", "guided", "interactive", "configurable"];
|
|
@@ -47953,7 +48312,7 @@ async function createSkill(name, options = {}) {
|
|
|
47953
48312
|
default: false
|
|
47954
48313
|
});
|
|
47955
48314
|
const outputDir = options.output ?? getCanonicalInstallPath();
|
|
47956
|
-
const skillDir =
|
|
48315
|
+
const skillDir = join62(outputDir, skillName);
|
|
47957
48316
|
let exists = false;
|
|
47958
48317
|
try {
|
|
47959
48318
|
await stat12(skillDir);
|
|
@@ -48027,16 +48386,16 @@ Thumbs.db
|
|
|
48027
48386
|
const spinner = ora13("Scaffolding skill...").start();
|
|
48028
48387
|
try {
|
|
48029
48388
|
await mkdir17(skillDir, { recursive: true });
|
|
48030
|
-
await mkdir17(
|
|
48389
|
+
await mkdir17(join62(skillDir, "resources"), { recursive: true });
|
|
48031
48390
|
if (includeScripts) {
|
|
48032
|
-
await mkdir17(
|
|
48391
|
+
await mkdir17(join62(skillDir, "scripts"), { recursive: true });
|
|
48033
48392
|
}
|
|
48034
|
-
await writeFile15(
|
|
48035
|
-
await writeFile15(
|
|
48036
|
-
await writeFile15(
|
|
48037
|
-
await writeFile15(
|
|
48393
|
+
await writeFile15(join62(skillDir, "SKILL.md"), skillMdContent, "utf-8");
|
|
48394
|
+
await writeFile15(join62(skillDir, "README.md"), readmeContent, "utf-8");
|
|
48395
|
+
await writeFile15(join62(skillDir, "CHANGELOG.md"), changelogContent, "utf-8");
|
|
48396
|
+
await writeFile15(join62(skillDir, ".gitignore"), gitignoreContent, "utf-8");
|
|
48038
48397
|
if (includeScripts) {
|
|
48039
|
-
await writeFile15(
|
|
48398
|
+
await writeFile15(join62(skillDir, "scripts", "example.js"), scriptContent, "utf-8");
|
|
48040
48399
|
}
|
|
48041
48400
|
spinner.succeed(`Skill scaffolded at ${skillDir}`);
|
|
48042
48401
|
} catch (error46) {
|
|
@@ -48197,7 +48556,7 @@ var RATE_LIMIT_DELAY = 6e4;
|
|
|
48197
48556
|
var DEFAULT_IMPORT_DELAY_MS = 150;
|
|
48198
48557
|
var IMPORT_DELAY_MS = parseInt(process.env["SKILLSMITH_IMPORT_DELAY_MS"] || "", 10) || DEFAULT_IMPORT_DELAY_MS;
|
|
48199
48558
|
function sleep3(ms) {
|
|
48200
|
-
return new Promise((
|
|
48559
|
+
return new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
48201
48560
|
}
|
|
48202
48561
|
function getBackoffDelay(attempt, baseDelay = 1e3) {
|
|
48203
48562
|
return Math.min(baseDelay * Math.pow(2, attempt), 3e4);
|
|
@@ -48409,13 +48768,13 @@ function createImportCommand() {
|
|
|
48409
48768
|
|
|
48410
48769
|
// src/commands/import-local.ts
|
|
48411
48770
|
import { Command as Command26 } from "commander";
|
|
48412
|
-
import { resolve as
|
|
48771
|
+
import { resolve as resolve18 } from "node:path";
|
|
48413
48772
|
import { promises as fs36 } from "node:fs";
|
|
48414
48773
|
|
|
48415
48774
|
// src/commands/import-local.helpers.ts
|
|
48416
48775
|
import { createHash as createHash19 } from "node:crypto";
|
|
48417
48776
|
import { promises as fs35 } from "node:fs";
|
|
48418
|
-
import { join as
|
|
48777
|
+
import { join as join63, resolve as resolve17, dirname as dirname29, basename as basename10, sep as sep5, relative as relative7 } from "node:path";
|
|
48419
48778
|
import matter from "gray-matter";
|
|
48420
48779
|
var SKILL_FILENAME = "SKILL.md";
|
|
48421
48780
|
var MAX_DEPTH = 8;
|
|
@@ -48423,7 +48782,7 @@ function localSkillId(canonicalPath) {
|
|
|
48423
48782
|
return createHash19("sha256").update(canonicalPath).digest("hex").slice(0, 32);
|
|
48424
48783
|
}
|
|
48425
48784
|
async function walkSkillFiles(rootDir) {
|
|
48426
|
-
const canonicalRoot = await fs35.realpath(rootDir).catch(() =>
|
|
48785
|
+
const canonicalRoot = await fs35.realpath(rootDir).catch(() => resolve17(rootDir));
|
|
48427
48786
|
const files = [];
|
|
48428
48787
|
const skipped = [];
|
|
48429
48788
|
const visited = /* @__PURE__ */ new Set();
|
|
@@ -48436,7 +48795,7 @@ async function walkSkillFiles(rootDir) {
|
|
|
48436
48795
|
return;
|
|
48437
48796
|
}
|
|
48438
48797
|
for (const entry of entries) {
|
|
48439
|
-
const entryPath =
|
|
48798
|
+
const entryPath = join63(dir, entry.name);
|
|
48440
48799
|
if (entry.isSymbolicLink()) {
|
|
48441
48800
|
let realPath;
|
|
48442
48801
|
try {
|
|
@@ -48536,7 +48895,7 @@ function toStringArray(value) {
|
|
|
48536
48895
|
var logger33 = getCliLogger();
|
|
48537
48896
|
var WATCH_DEBOUNCE_MS = 500;
|
|
48538
48897
|
function resolveRoot(opts) {
|
|
48539
|
-
if (opts.path) return
|
|
48898
|
+
if (opts.path) return resolve18(opts.path);
|
|
48540
48899
|
if (opts.client) return getInstallPath(opts.client);
|
|
48541
48900
|
return getCanonicalInstallPath();
|
|
48542
48901
|
}
|
|
@@ -48744,8 +49103,8 @@ function printHumanSummary(result) {
|
|
|
48744
49103
|
// src/commands/config.ts
|
|
48745
49104
|
import * as crypto13 from "node:crypto";
|
|
48746
49105
|
import * as fs37 from "node:fs";
|
|
48747
|
-
import { homedir as
|
|
48748
|
-
import { join as
|
|
49106
|
+
import { homedir as homedir29 } from "node:os";
|
|
49107
|
+
import { join as join64, dirname as dirname30 } from "node:path";
|
|
48749
49108
|
import { Command as Command27 } from "commander";
|
|
48750
49109
|
var logger34 = getCliLogger();
|
|
48751
49110
|
var CONFIG_DIR3 = ".skillsmith";
|
|
@@ -48769,7 +49128,7 @@ function isSupportedKey(key) {
|
|
|
48769
49128
|
return SUPPORTED_KEYS.includes(key);
|
|
48770
49129
|
}
|
|
48771
49130
|
function configPath() {
|
|
48772
|
-
return
|
|
49131
|
+
return join64(homedir29(), CONFIG_DIR3, CONFIG_FILE3);
|
|
48773
49132
|
}
|
|
48774
49133
|
function readConfigFile2() {
|
|
48775
49134
|
const path27 = configPath();
|
|
@@ -48887,15 +49246,15 @@ import { Command as Command28 } from "commander";
|
|
|
48887
49246
|
|
|
48888
49247
|
// src/commands/telemetry.action.ts
|
|
48889
49248
|
import { existsSync as existsSync28, copyFileSync as copyFileSync2, chmodSync as chmodSync9, mkdirSync as mkdirSync14 } from "node:fs";
|
|
48890
|
-
import { homedir as
|
|
48891
|
-
import { join as
|
|
48892
|
-
import { readdirSync as readdirSync4, unlinkSync as
|
|
49249
|
+
import { homedir as homedir31 } from "node:os";
|
|
49250
|
+
import { join as join66, dirname as dirname32 } from "node:path";
|
|
49251
|
+
import { readdirSync as readdirSync4, unlinkSync as unlinkSync5, statSync as statSync6 } from "node:fs";
|
|
48893
49252
|
|
|
48894
49253
|
// src/commands/telemetry.helpers.ts
|
|
48895
49254
|
import * as crypto14 from "node:crypto";
|
|
48896
49255
|
import * as fs38 from "node:fs";
|
|
48897
|
-
import { join as
|
|
48898
|
-
import { homedir as
|
|
49256
|
+
import { join as join65, dirname as dirname31 } from "node:path";
|
|
49257
|
+
import { homedir as homedir30 } from "node:os";
|
|
48899
49258
|
var TelemetryHookError = class extends Error {
|
|
48900
49259
|
constructor(code, message) {
|
|
48901
49260
|
super(message);
|
|
@@ -48906,9 +49265,9 @@ var TelemetryHookError = class extends Error {
|
|
|
48906
49265
|
};
|
|
48907
49266
|
function resolveSettingsPath(scope) {
|
|
48908
49267
|
if (scope === "user") {
|
|
48909
|
-
return
|
|
49268
|
+
return join65(homedir30(), ".claude", "settings.json");
|
|
48910
49269
|
}
|
|
48911
|
-
return
|
|
49270
|
+
return join65(process.cwd(), ".claude", "settings.json");
|
|
48912
49271
|
}
|
|
48913
49272
|
function loadClaudeSettings(scope) {
|
|
48914
49273
|
const path27 = resolveSettingsPath(scope);
|
|
@@ -49000,10 +49359,10 @@ var PRIVACY_URL = "https://skillsmith.app/privacy#telemetry";
|
|
|
49000
49359
|
var DEFAULT_ENDPOINT = "https://vrcnzpmndtroqxxoqkzy.supabase.co/functions/v1/events";
|
|
49001
49360
|
var ORPHAN_TTL_MS = 60 * 60 * 1e3;
|
|
49002
49361
|
function hookScriptPath() {
|
|
49003
|
-
return
|
|
49362
|
+
return join66(homedir31(), ".skillsmith", "hooks", "skill-telemetry.sh");
|
|
49004
49363
|
}
|
|
49005
49364
|
function runDir() {
|
|
49006
|
-
return
|
|
49365
|
+
return join66(homedir31(), ".skillsmith", "run");
|
|
49007
49366
|
}
|
|
49008
49367
|
function idTail(id) {
|
|
49009
49368
|
if (!id) return "(none)";
|
|
@@ -49016,10 +49375,10 @@ function gcOrphanRunFiles() {
|
|
|
49016
49375
|
const now = Date.now();
|
|
49017
49376
|
for (const f of readdirSync4(dir)) {
|
|
49018
49377
|
if (!f.startsWith("skill-")) continue;
|
|
49019
|
-
const fp =
|
|
49378
|
+
const fp = join66(dir, f);
|
|
49020
49379
|
try {
|
|
49021
49380
|
const st = statSync6(fp);
|
|
49022
|
-
if (now - st.mtimeMs > ORPHAN_TTL_MS)
|
|
49381
|
+
if (now - st.mtimeMs > ORPHAN_TTL_MS) unlinkSync5(fp);
|
|
49023
49382
|
} catch {
|
|
49024
49383
|
}
|
|
49025
49384
|
}
|
|
@@ -49116,7 +49475,7 @@ async function runStatus() {
|
|
|
49116
49475
|
}
|
|
49117
49476
|
}
|
|
49118
49477
|
async function runInstallHook(options) {
|
|
49119
|
-
const templateSrc =
|
|
49478
|
+
const templateSrc = join66(packageRoot(), "templates", "skill-telemetry.sh");
|
|
49120
49479
|
if (!existsSync28(templateSrc)) {
|
|
49121
49480
|
throw new Error(
|
|
49122
49481
|
"skill-telemetry.sh template not found. Ensure the CLI package is fully built: npm run build"
|
|
@@ -49160,7 +49519,7 @@ async function runUninstallHook(options) {
|
|
|
49160
49519
|
writeClaudeSettings(scope, updated);
|
|
49161
49520
|
try {
|
|
49162
49521
|
const scriptPath = hookScriptPath();
|
|
49163
|
-
if (existsSync28(scriptPath))
|
|
49522
|
+
if (existsSync28(scriptPath)) unlinkSync5(scriptPath);
|
|
49164
49523
|
} catch {
|
|
49165
49524
|
}
|
|
49166
49525
|
const scopeLabel = scope === "user" ? "~/.claude/settings.json" : "./.claude/settings.json";
|
|
@@ -49580,13 +49939,13 @@ function createAgentCommand() {
|
|
|
49580
49939
|
|
|
49581
49940
|
// src/commands/diagnose.ts
|
|
49582
49941
|
import { mkdirSync as mkdirSync15, readFileSync as readFileSync26, writeFileSync as writeFileSync16 } from "node:fs";
|
|
49583
|
-
import { basename as basename11, dirname as dirname33, resolve as
|
|
49942
|
+
import { basename as basename11, dirname as dirname33, resolve as resolve19 } from "node:path";
|
|
49584
49943
|
import { Command as Command31 } from "commander";
|
|
49585
49944
|
|
|
49586
49945
|
// src/commands/log-records.helpers.ts
|
|
49587
49946
|
import { existsSync as existsSync29, readFileSync as readFileSync25, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
|
|
49588
|
-
import { homedir as
|
|
49589
|
-
import { join as
|
|
49947
|
+
import { homedir as homedir32 } from "node:os";
|
|
49948
|
+
import { join as join67 } from "node:path";
|
|
49590
49949
|
var LOG_FILE_PATTERN = /^skillsmith-[a-z]+-\d{4}-\d{2}-\d{2}\.jsonl(\.\d+)?$/;
|
|
49591
49950
|
var LOG_LEVEL_ORDER = {
|
|
49592
49951
|
debug: 0,
|
|
@@ -49599,12 +49958,12 @@ function isLogLevel(value) {
|
|
|
49599
49958
|
return VALID_LEVELS.has(value);
|
|
49600
49959
|
}
|
|
49601
49960
|
function resolveLogDir() {
|
|
49602
|
-
return process.env["SKILLSMITH_LOG_DIR"] ||
|
|
49961
|
+
return process.env["SKILLSMITH_LOG_DIR"] || join67(homedir32(), ".skillsmith", "logs");
|
|
49603
49962
|
}
|
|
49604
49963
|
function listLogFiles(dir) {
|
|
49605
49964
|
if (!existsSync29(dir)) return [];
|
|
49606
49965
|
try {
|
|
49607
|
-
return readdirSync5(dir).filter((name) => LOG_FILE_PATTERN.test(name)).sort().map((name) =>
|
|
49966
|
+
return readdirSync5(dir).filter((name) => LOG_FILE_PATTERN.test(name)).sort().map((name) => join67(dir, name));
|
|
49608
49967
|
} catch {
|
|
49609
49968
|
return [];
|
|
49610
49969
|
}
|
|
@@ -49728,7 +50087,7 @@ function buildBundleContent(summary, files) {
|
|
|
49728
50087
|
}
|
|
49729
50088
|
function writeBundle(bundleOption, summary, files) {
|
|
49730
50089
|
const rawPath = typeof bundleOption === "string" && bundleOption.length > 0 ? bundleOption : defaultBundlePath();
|
|
49731
|
-
const targetPath =
|
|
50090
|
+
const targetPath = resolve19(rawPath);
|
|
49732
50091
|
const content = buildBundleContent(summary, files);
|
|
49733
50092
|
mkdirSync15(dirname33(targetPath), { recursive: true });
|
|
49734
50093
|
writeFileSync16(targetPath, content, "utf8");
|
|
@@ -49790,7 +50149,7 @@ function createDiagnoseCommand() {
|
|
|
49790
50149
|
|
|
49791
50150
|
// src/commands/logs.ts
|
|
49792
50151
|
import { existsSync as existsSync30, readFileSync as readFileSync27, statSync as statSync8 } from "node:fs";
|
|
49793
|
-
import { join as
|
|
50152
|
+
import { join as join68 } from "node:path";
|
|
49794
50153
|
import { Command as Command32 } from "commander";
|
|
49795
50154
|
var logger39 = getCliLogger();
|
|
49796
50155
|
var TAIL_SURFACES = ["cli", "mcp", "vscode", "doc-retrieval"];
|
|
@@ -49799,7 +50158,7 @@ function todayDateString2() {
|
|
|
49799
50158
|
}
|
|
49800
50159
|
function todaysFilePaths(dir) {
|
|
49801
50160
|
const date5 = todayDateString2();
|
|
49802
|
-
return TAIL_SURFACES.map((surface) =>
|
|
50161
|
+
return TAIL_SURFACES.map((surface) => join68(dir, `skillsmith-${surface}-${date5}.jsonl`));
|
|
49803
50162
|
}
|
|
49804
50163
|
function resolveLevel(raw) {
|
|
49805
50164
|
if (raw === void 0) return void 0;
|
|
@@ -49854,8 +50213,8 @@ async function startTail(dir, level, opts = {}) {
|
|
|
49854
50213
|
usePolling: true,
|
|
49855
50214
|
interval: 100
|
|
49856
50215
|
});
|
|
49857
|
-
await new Promise((
|
|
49858
|
-
watcher.once("ready",
|
|
50216
|
+
await new Promise((resolve20) => {
|
|
50217
|
+
watcher.once("ready", resolve20);
|
|
49859
50218
|
});
|
|
49860
50219
|
const handleEvent = (path27) => {
|
|
49861
50220
|
let size;
|
|
@@ -49942,10 +50301,10 @@ function shouldShowStartupHeader(commandPath, isTTY) {
|
|
|
49942
50301
|
|
|
49943
50302
|
// src/utils/node-version.ts
|
|
49944
50303
|
import { readFileSync as readFileSync28 } from "fs";
|
|
49945
|
-
import { join as
|
|
50304
|
+
import { join as join69 } from "path";
|
|
49946
50305
|
function loadMinNodeVersion() {
|
|
49947
50306
|
try {
|
|
49948
|
-
const packageJsonPath2 =
|
|
50307
|
+
const packageJsonPath2 = join69(packageRoot(), "package.json");
|
|
49949
50308
|
const packageJson2 = JSON.parse(readFileSync28(packageJsonPath2, "utf-8"));
|
|
49950
50309
|
const engineConstraint = packageJson2.engines?.node ?? ">=22.22.0";
|
|
49951
50310
|
return engineConstraint.replace(/[>=<^~\s]/g, "");
|
|
@@ -50018,14 +50377,14 @@ function checkNodeVersion() {
|
|
|
50018
50377
|
|
|
50019
50378
|
// src/index.ts
|
|
50020
50379
|
import { readFileSync as readFileSync29 } from "fs";
|
|
50021
|
-
import { join as
|
|
50380
|
+
import { join as join70 } from "path";
|
|
50022
50381
|
var logger40 = getCliLogger();
|
|
50023
50382
|
var versionError = checkNodeVersion();
|
|
50024
50383
|
if (versionError) {
|
|
50025
50384
|
logger40.error(versionError);
|
|
50026
50385
|
process.exit(1);
|
|
50027
50386
|
}
|
|
50028
|
-
var packageJsonPath =
|
|
50387
|
+
var packageJsonPath = join70(packageRoot(), "package.json");
|
|
50029
50388
|
var packageJson = JSON.parse(readFileSync29(packageJsonPath, "utf-8"));
|
|
50030
50389
|
var CLI_VERSION = packageJson.version;
|
|
50031
50390
|
var program = new Command33();
|