agentinit 1.20.0 → 1.20.2
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 +15 -0
- package/README.md +17 -3
- package/dist/cli.js +871 -315
- package/dist/commands/lock.d.ts.map +1 -1
- package/dist/commands/lock.js +2 -14
- package/dist/commands/lock.js.map +1 -1
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +79 -37
- package/dist/commands/skills.js.map +1 -1
- package/dist/core/skillSecurityScanner.d.ts +28 -0
- package/dist/core/skillSecurityScanner.d.ts.map +1 -0
- package/dist/core/skillSecurityScanner.js +167 -0
- package/dist/core/skillSecurityScanner.js.map +1 -0
- package/dist/core/skillsManager.d.ts +11 -0
- package/dist/core/skillsManager.d.ts.map +1 -1
- package/dist/core/skillsManager.js +286 -10
- package/dist/core/skillsManager.js.map +1 -1
- package/dist/types/lockfile.d.ts +2 -1
- package/dist/types/lockfile.d.ts.map +1 -1
- package/dist/types/plugins.d.ts +1 -1
- package/dist/types/plugins.d.ts.map +1 -1
- package/dist/types/skills.d.ts +4 -1
- package/dist/types/skills.d.ts.map +1 -1
- package/dist/utils/lockSource.d.ts +9 -0
- package/dist/utils/lockSource.d.ts.map +1 -0
- package/dist/utils/lockSource.js +59 -0
- package/dist/utils/lockSource.js.map +1 -0
- package/dist/utils/promptUtils.d.ts +30 -3
- package/dist/utils/promptUtils.d.ts.map +1 -1
- package/dist/utils/promptUtils.js +69 -27
- package/dist/utils/promptUtils.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -17098,6 +17098,174 @@ var init_marketplaceRegistry = __esm(() => {
|
|
|
17098
17098
|
CUSTOM_MARKETPLACE_CACHE_TTL_MS = 3600000;
|
|
17099
17099
|
});
|
|
17100
17100
|
|
|
17101
|
+
// dist/core/skillSecurityScanner.js
|
|
17102
|
+
import {promises as fs22} from "fs";
|
|
17103
|
+
import {join as join4, relative as relative2} from "path";
|
|
17104
|
+
|
|
17105
|
+
class SkillSecurityScanner {
|
|
17106
|
+
async scanSkill(skill) {
|
|
17107
|
+
const findings = skill.generatedContent ? this.scanText(skill.generatedContent, "SKILL.md") : await this.scanDirectory(skill.path);
|
|
17108
|
+
const stats = findings.reduce((acc, finding) => {
|
|
17109
|
+
acc[finding.severity] += 1;
|
|
17110
|
+
return acc;
|
|
17111
|
+
}, { high: 0, medium: 0, low: 0 });
|
|
17112
|
+
return {
|
|
17113
|
+
blocked: findings.some((finding) => finding.blocking),
|
|
17114
|
+
findings,
|
|
17115
|
+
stats
|
|
17116
|
+
};
|
|
17117
|
+
}
|
|
17118
|
+
formatShortSummary(result) {
|
|
17119
|
+
const parts = [
|
|
17120
|
+
result.stats.high ? `${result.stats.high} high` : null,
|
|
17121
|
+
result.stats.medium ? `${result.stats.medium} medium` : null,
|
|
17122
|
+
result.stats.low ? `${result.stats.low} low` : null
|
|
17123
|
+
].filter((value) => !!value);
|
|
17124
|
+
return parts.length > 0 ? parts.join(", ") : "no findings";
|
|
17125
|
+
}
|
|
17126
|
+
formatBlockingReason(result) {
|
|
17127
|
+
const finding = result.findings.find((entry) => entry.blocking) || result.findings.find((entry) => entry.severity === "high") || result.findings[0];
|
|
17128
|
+
if (!finding) {
|
|
17129
|
+
return "Security scan failed";
|
|
17130
|
+
}
|
|
17131
|
+
return `Security scan failed: ${finding.title} (${finding.ruleId}) at ${finding.filePath}:${finding.line}`;
|
|
17132
|
+
}
|
|
17133
|
+
async scanDirectory(rootPath) {
|
|
17134
|
+
const findings = [];
|
|
17135
|
+
await this.walk(rootPath, rootPath, findings);
|
|
17136
|
+
return findings;
|
|
17137
|
+
}
|
|
17138
|
+
async walk(rootPath, currentPath, findings) {
|
|
17139
|
+
const entries = await fs22.readdir(currentPath, { withFileTypes: true });
|
|
17140
|
+
for (const entry of entries) {
|
|
17141
|
+
if (entry.name === ".git" || entry.name === "node_modules") {
|
|
17142
|
+
continue;
|
|
17143
|
+
}
|
|
17144
|
+
const entryPath = join4(currentPath, entry.name);
|
|
17145
|
+
if (entry.isDirectory()) {
|
|
17146
|
+
await this.walk(rootPath, entryPath, findings);
|
|
17147
|
+
continue;
|
|
17148
|
+
}
|
|
17149
|
+
const relativePath = relative2(rootPath, entryPath).replace(/\\/g, "/");
|
|
17150
|
+
const content = await this.readTextFile(entryPath);
|
|
17151
|
+
if (content === null) {
|
|
17152
|
+
continue;
|
|
17153
|
+
}
|
|
17154
|
+
findings.push(...this.scanText(content, relativePath, {
|
|
17155
|
+
blockHighRisk: this.isExecutableTextFile(entryPath, content)
|
|
17156
|
+
}));
|
|
17157
|
+
}
|
|
17158
|
+
}
|
|
17159
|
+
async readTextFile(filePath) {
|
|
17160
|
+
const extension = filePath.includes(".") ? filePath.slice(filePath.lastIndexOf(".")).toLowerCase() : "";
|
|
17161
|
+
if (!SCANNED_TEXT_EXTENSIONS.has(extension)) {
|
|
17162
|
+
return null;
|
|
17163
|
+
}
|
|
17164
|
+
const buffer = await fs22.readFile(filePath);
|
|
17165
|
+
if (buffer.length > MAX_TEXT_FILE_BYTES || buffer.includes(0)) {
|
|
17166
|
+
return null;
|
|
17167
|
+
}
|
|
17168
|
+
return buffer.toString("utf8");
|
|
17169
|
+
}
|
|
17170
|
+
isExecutableTextFile(filePath, content) {
|
|
17171
|
+
const extension = filePath.includes(".") ? filePath.slice(filePath.lastIndexOf(".")).toLowerCase() : "";
|
|
17172
|
+
return EXECUTABLE_TEXT_EXTENSIONS.has(extension) || content.startsWith("#!");
|
|
17173
|
+
}
|
|
17174
|
+
scanText(content, filePath, options2 = {}) {
|
|
17175
|
+
const findings = [];
|
|
17176
|
+
const lines = content.split(/\r?\n/);
|
|
17177
|
+
lines.forEach((line, index) => {
|
|
17178
|
+
for (const rule of SCAN_RULES) {
|
|
17179
|
+
rule.regex.lastIndex = 0;
|
|
17180
|
+
if (!rule.regex.test(line)) {
|
|
17181
|
+
continue;
|
|
17182
|
+
}
|
|
17183
|
+
findings.push({
|
|
17184
|
+
ruleId: rule.id,
|
|
17185
|
+
title: rule.title,
|
|
17186
|
+
severity: rule.severity,
|
|
17187
|
+
filePath,
|
|
17188
|
+
line: index + 1,
|
|
17189
|
+
snippet: line.trim().slice(0, 160),
|
|
17190
|
+
blocking: rule.severity === "high" && options2.blockHighRisk === true
|
|
17191
|
+
});
|
|
17192
|
+
}
|
|
17193
|
+
});
|
|
17194
|
+
return findings;
|
|
17195
|
+
}
|
|
17196
|
+
}
|
|
17197
|
+
var SCAN_RULES, MAX_TEXT_FILE_BYTES, SCANNED_TEXT_EXTENSIONS, EXECUTABLE_TEXT_EXTENSIONS;
|
|
17198
|
+
var init_skillSecurityScanner = __esm(() => {
|
|
17199
|
+
SCAN_RULES = [
|
|
17200
|
+
{
|
|
17201
|
+
id: "AI001",
|
|
17202
|
+
title: "Prompt override language",
|
|
17203
|
+
severity: "medium",
|
|
17204
|
+
regex: /\b(ignore|disregard|override|bypass)\b.{0,40}\b(previous|prior|system|safety|guardrails?|instructions?)\b/i
|
|
17205
|
+
},
|
|
17206
|
+
{
|
|
17207
|
+
id: "AI002",
|
|
17208
|
+
title: "Secret or credential exfiltration",
|
|
17209
|
+
severity: "high",
|
|
17210
|
+
regex: /\b(exfiltrat\w*|upload|send|post|curl|wget)\b.{0,80}\b(secret|token|key|credential|cookie|session|\.ssh|id_rsa|env(?:ironment)? variables?)\b/i
|
|
17211
|
+
},
|
|
17212
|
+
{
|
|
17213
|
+
id: "AI003",
|
|
17214
|
+
title: "Destructive shell command",
|
|
17215
|
+
severity: "high",
|
|
17216
|
+
regex: /\b(rm\s+-rf\s+\/|sudo\s+rm\s+-rf|mkfs\b|dd\s+if=\/dev\/zero|chmod\s+-R\s+777\s+\/)\b/i
|
|
17217
|
+
},
|
|
17218
|
+
{
|
|
17219
|
+
id: "AI004",
|
|
17220
|
+
title: "Remote shell execution pipeline",
|
|
17221
|
+
severity: "high",
|
|
17222
|
+
regex: /\b(curl|wget)\b[^\n|]{0,160}\|\s*(sh|bash|zsh)\b/i
|
|
17223
|
+
},
|
|
17224
|
+
{
|
|
17225
|
+
id: "AI005",
|
|
17226
|
+
title: "Hardcoded credential material",
|
|
17227
|
+
severity: "low",
|
|
17228
|
+
regex: /\b(api[_-]?key|token|secret|password)\b\s*[:=]\s*['"][^'"]{8,}['"]/i
|
|
17229
|
+
},
|
|
17230
|
+
{
|
|
17231
|
+
id: "AI006",
|
|
17232
|
+
title: "Unicode bidi control characters",
|
|
17233
|
+
severity: "low",
|
|
17234
|
+
regex: /[\u202A-\u202E\u2066-\u2069]/
|
|
17235
|
+
}
|
|
17236
|
+
];
|
|
17237
|
+
MAX_TEXT_FILE_BYTES = 1024 * 1024;
|
|
17238
|
+
SCANNED_TEXT_EXTENSIONS = new Set([
|
|
17239
|
+
"",
|
|
17240
|
+
".md",
|
|
17241
|
+
".txt",
|
|
17242
|
+
".json",
|
|
17243
|
+
".yaml",
|
|
17244
|
+
".yml",
|
|
17245
|
+
".toml",
|
|
17246
|
+
".js",
|
|
17247
|
+
".ts",
|
|
17248
|
+
".mjs",
|
|
17249
|
+
".cjs",
|
|
17250
|
+
".sh",
|
|
17251
|
+
".bash",
|
|
17252
|
+
".zsh",
|
|
17253
|
+
".py",
|
|
17254
|
+
".ps1"
|
|
17255
|
+
]);
|
|
17256
|
+
EXECUTABLE_TEXT_EXTENSIONS = new Set([
|
|
17257
|
+
".js",
|
|
17258
|
+
".ts",
|
|
17259
|
+
".mjs",
|
|
17260
|
+
".cjs",
|
|
17261
|
+
".sh",
|
|
17262
|
+
".bash",
|
|
17263
|
+
".zsh",
|
|
17264
|
+
".py",
|
|
17265
|
+
".ps1"
|
|
17266
|
+
]);
|
|
17267
|
+
});
|
|
17268
|
+
|
|
17101
17269
|
// dist/types/skills.js
|
|
17102
17270
|
var SHARED_SKILLS_TARGET_ID, SHARED_SKILLS_TARGET_NAME;
|
|
17103
17271
|
var init_skills = __esm(() => {
|
|
@@ -17106,9 +17274,9 @@ var init_skills = __esm(() => {
|
|
|
17106
17274
|
});
|
|
17107
17275
|
|
|
17108
17276
|
// dist/core/installLock.js
|
|
17109
|
-
import {promises as
|
|
17277
|
+
import {promises as fs23} from "fs";
|
|
17110
17278
|
import {homedir as homedir4} from "os";
|
|
17111
|
-
import {dirname as dirname2, join as
|
|
17279
|
+
import {dirname as dirname2, join as join5, resolve as resolve7} from "path";
|
|
17112
17280
|
import {createHash, randomUUID} from "crypto";
|
|
17113
17281
|
function getLockEntryTargetLabel(entry) {
|
|
17114
17282
|
return entry.scope === "global" ? "Global scope" : entry.projectPath;
|
|
@@ -17122,16 +17290,16 @@ async function hashDirectory(rootPath) {
|
|
|
17122
17290
|
return null;
|
|
17123
17291
|
const hash = createHash("sha256");
|
|
17124
17292
|
const walk = async (currentPath, relativePath) => {
|
|
17125
|
-
const stat = await
|
|
17293
|
+
const stat = await fs23.stat(currentPath);
|
|
17126
17294
|
if (stat.isDirectory()) {
|
|
17127
17295
|
hash.update(`dir:${relativePath}\n`);
|
|
17128
|
-
const entries = await
|
|
17296
|
+
const entries = await fs23.readdir(currentPath);
|
|
17129
17297
|
entries.sort();
|
|
17130
17298
|
for (const entry of entries) {
|
|
17131
|
-
await walk(
|
|
17299
|
+
await walk(join5(currentPath, entry), `${relativePath}/${entry}`);
|
|
17132
17300
|
}
|
|
17133
17301
|
} else {
|
|
17134
|
-
const content = await
|
|
17302
|
+
const content = await fs23.readFile(currentPath);
|
|
17135
17303
|
hash.update(`file:${relativePath}\n`);
|
|
17136
17304
|
hash.update(content);
|
|
17137
17305
|
hash.update("\n");
|
|
@@ -17167,12 +17335,12 @@ class InstallLock {
|
|
|
17167
17335
|
if (!this.state)
|
|
17168
17336
|
return;
|
|
17169
17337
|
const lockPath = getLockPath();
|
|
17170
|
-
await
|
|
17171
|
-
await
|
|
17338
|
+
await fs23.mkdir(dirname2(lockPath), { recursive: true });
|
|
17339
|
+
await fs23.writeFile(lockPath, JSON.stringify(this.state, null, 2) + "\n", {
|
|
17172
17340
|
encoding: "utf8",
|
|
17173
17341
|
mode: 384
|
|
17174
17342
|
});
|
|
17175
|
-
await
|
|
17343
|
+
await fs23.chmod(lockPath, 384).catch(() => {
|
|
17176
17344
|
});
|
|
17177
17345
|
}
|
|
17178
17346
|
async recordSkill(params) {
|
|
@@ -17351,7 +17519,7 @@ var init_installLock = __esm(() => {
|
|
|
17351
17519
|
init_fs();
|
|
17352
17520
|
init_logger();
|
|
17353
17521
|
getLockPath = function() {
|
|
17354
|
-
return
|
|
17522
|
+
return join5(homedir4(), ".agentinit", LOCK_FILE);
|
|
17355
17523
|
};
|
|
17356
17524
|
getEntryTargetKey = function(entry) {
|
|
17357
17525
|
return entry.scope === "global" ? GLOBAL_TARGET_KEY : entry.projectPath;
|
|
@@ -17493,8 +17661,8 @@ __export(exports_pluginManager, {
|
|
|
17493
17661
|
}
|
|
17494
17662
|
}
|
|
17495
17663
|
});
|
|
17496
|
-
import {resolve as resolve8, join as
|
|
17497
|
-
import {promises as
|
|
17664
|
+
import {resolve as resolve8, join as join6, basename as basename2, relative as relative3, dirname as dirname3} from "path";
|
|
17665
|
+
import {promises as fs25} from "fs";
|
|
17498
17666
|
import {homedir as homedir5} from "os";
|
|
17499
17667
|
|
|
17500
17668
|
class MultipleBundlePluginsError extends Error {
|
|
@@ -17539,7 +17707,7 @@ class PluginManager {
|
|
|
17539
17707
|
}
|
|
17540
17708
|
async cleanupLoadedPluginContext(context) {
|
|
17541
17709
|
if (context?.tempDir) {
|
|
17542
|
-
await
|
|
17710
|
+
await fs25.rm(context.tempDir, { recursive: true, force: true }).catch(() => {
|
|
17543
17711
|
});
|
|
17544
17712
|
}
|
|
17545
17713
|
}
|
|
@@ -17617,7 +17785,7 @@ class PluginManager {
|
|
|
17617
17785
|
return "unverified";
|
|
17618
17786
|
}
|
|
17619
17787
|
async resolvePreparedPluginDir(pluginDir, source) {
|
|
17620
|
-
const claudeMarketplaceManifestPath =
|
|
17788
|
+
const claudeMarketplaceManifestPath = join6(pluginDir, ".claude-plugin", "marketplace.json");
|
|
17621
17789
|
if (!await fileExists(claudeMarketplaceManifestPath)) {
|
|
17622
17790
|
return { pluginDir, warnings: [] };
|
|
17623
17791
|
}
|
|
@@ -17653,7 +17821,7 @@ class PluginManager {
|
|
|
17653
17821
|
selectedEntry = matched;
|
|
17654
17822
|
}
|
|
17655
17823
|
const selectedPluginDir = resolve8(pluginDir, selectedEntry.source);
|
|
17656
|
-
const relativePath =
|
|
17824
|
+
const relativePath = relative3(resolve8(pluginDir), selectedPluginDir);
|
|
17657
17825
|
if (relativePath.startsWith("..") || relativePath.includes("/../") || relativePath.includes("\\..\\")) {
|
|
17658
17826
|
throw new Error(`Invalid bundled plugin source path "${selectedEntry.source}" in ${claudeMarketplaceManifestPath}`);
|
|
17659
17827
|
}
|
|
@@ -17765,15 +17933,15 @@ class PluginManager {
|
|
|
17765
17933
|
}
|
|
17766
17934
|
async getClaudeNativeFeatureKinds(pluginDir, manifest) {
|
|
17767
17935
|
const featureChecks = await Promise.all([
|
|
17768
|
-
(async () => !!manifest.commands || await isDirectory(
|
|
17769
|
-
(async () => !!manifest.hooks || await isDirectory(
|
|
17770
|
-
(async () => !!manifest.agents || await isDirectory(
|
|
17771
|
-
isDirectory(
|
|
17772
|
-
(async () => !!manifest.mcpServers || await fileExists(
|
|
17773
|
-
isDirectory(
|
|
17774
|
-
isDirectory(
|
|
17775
|
-
isDirectory(
|
|
17776
|
-
isDirectory(
|
|
17936
|
+
(async () => !!manifest.commands || await isDirectory(join6(pluginDir, "commands")))(),
|
|
17937
|
+
(async () => !!manifest.hooks || await isDirectory(join6(pluginDir, "hooks")))(),
|
|
17938
|
+
(async () => !!manifest.agents || await isDirectory(join6(pluginDir, "agents")))(),
|
|
17939
|
+
isDirectory(join6(pluginDir, "skills")),
|
|
17940
|
+
(async () => !!manifest.mcpServers || await fileExists(join6(pluginDir, ".mcp.json")))(),
|
|
17941
|
+
isDirectory(join6(pluginDir, "prompts")),
|
|
17942
|
+
isDirectory(join6(pluginDir, "schemas")),
|
|
17943
|
+
isDirectory(join6(pluginDir, "scripts")),
|
|
17944
|
+
isDirectory(join6(pluginDir, "templates"))
|
|
17777
17945
|
]);
|
|
17778
17946
|
return [
|
|
17779
17947
|
...featureChecks[0] ? ["commands"] : [],
|
|
@@ -17791,7 +17959,7 @@ class PluginManager {
|
|
|
17791
17959
|
if (plugin.format !== "claude") {
|
|
17792
17960
|
return null;
|
|
17793
17961
|
}
|
|
17794
|
-
const manifestContent = await readFileIfExists(
|
|
17962
|
+
const manifestContent = await readFileIfExists(join6(pluginDir, ".claude-plugin", "plugin.json"));
|
|
17795
17963
|
if (!manifestContent) {
|
|
17796
17964
|
return null;
|
|
17797
17965
|
}
|
|
@@ -17811,7 +17979,7 @@ class PluginManager {
|
|
|
17811
17979
|
return {
|
|
17812
17980
|
namespace,
|
|
17813
17981
|
pluginKey: `${plugin.name}@${namespace}`,
|
|
17814
|
-
installPath:
|
|
17982
|
+
installPath: join6(homedir5(), ".claude", "plugins", "cache", namespace, plugin.name, versionDir),
|
|
17815
17983
|
marketplacePath: getClaudeMarketplaceInstallPath(namespace),
|
|
17816
17984
|
features
|
|
17817
17985
|
};
|
|
@@ -17877,7 +18045,7 @@ class PluginManager {
|
|
|
17877
18045
|
async findClaudeMarketplaceRoot(pluginDir) {
|
|
17878
18046
|
let currentDir = resolve8(pluginDir);
|
|
17879
18047
|
while (true) {
|
|
17880
|
-
if (await fileExists(
|
|
18048
|
+
if (await fileExists(join6(currentDir, ".claude-plugin", "marketplace.json"))) {
|
|
17881
18049
|
return currentDir;
|
|
17882
18050
|
}
|
|
17883
18051
|
const parentDir = dirname3(currentDir);
|
|
@@ -17888,7 +18056,7 @@ class PluginManager {
|
|
|
17888
18056
|
}
|
|
17889
18057
|
}
|
|
17890
18058
|
async readClaudeMarketplaceManifest(marketplaceDir) {
|
|
17891
|
-
const manifestContent = await readFileIfExists(
|
|
18059
|
+
const manifestContent = await readFileIfExists(join6(marketplaceDir, ".claude-plugin", "marketplace.json"));
|
|
17892
18060
|
if (!manifestContent) {
|
|
17893
18061
|
return null;
|
|
17894
18062
|
}
|
|
@@ -17907,19 +18075,19 @@ class PluginManager {
|
|
|
17907
18075
|
}
|
|
17908
18076
|
}
|
|
17909
18077
|
async saveClaudeMarketplaceManifest(marketplaceDir, manifest) {
|
|
17910
|
-
await
|
|
17911
|
-
await writeFile(
|
|
18078
|
+
await fs25.mkdir(join6(marketplaceDir, ".claude-plugin"), { recursive: true });
|
|
18079
|
+
await writeFile(join6(marketplaceDir, ".claude-plugin", "marketplace.json"), JSON.stringify(manifest, null, 2));
|
|
17912
18080
|
}
|
|
17913
18081
|
resolveMarketplaceSourcePath(baseDir, relativePath) {
|
|
17914
18082
|
const resolvedPath = resolve8(baseDir, relativePath);
|
|
17915
|
-
const relativePathFromBase =
|
|
18083
|
+
const relativePathFromBase = relative3(resolve8(baseDir), resolvedPath);
|
|
17916
18084
|
if (relativePathFromBase.startsWith("..") || relativePathFromBase.includes("/../") || relativePathFromBase.includes("\\..\\")) {
|
|
17917
18085
|
throw new Error(`Invalid marketplace source path "${relativePath}" in ${baseDir}`);
|
|
17918
18086
|
}
|
|
17919
18087
|
return resolvedPath;
|
|
17920
18088
|
}
|
|
17921
18089
|
async readClaudePluginMetadata(pluginDir) {
|
|
17922
|
-
const manifestContent = await readFileIfExists(
|
|
18090
|
+
const manifestContent = await readFileIfExists(join6(pluginDir, ".claude-plugin", "plugin.json"));
|
|
17923
18091
|
if (!manifestContent) {
|
|
17924
18092
|
return {};
|
|
17925
18093
|
}
|
|
@@ -17935,11 +18103,11 @@ class PluginManager {
|
|
|
17935
18103
|
}
|
|
17936
18104
|
}
|
|
17937
18105
|
async copyClaudeMarketplacePlugin(sourcePluginDir, marketplacePath, pluginName) {
|
|
17938
|
-
const marketplacePluginPath =
|
|
17939
|
-
await
|
|
17940
|
-
await
|
|
18106
|
+
const marketplacePluginPath = join6(marketplacePath, "plugins", pluginName);
|
|
18107
|
+
await fs25.mkdir(dirname3(marketplacePluginPath), { recursive: true });
|
|
18108
|
+
await fs25.rm(marketplacePluginPath, { recursive: true, force: true }).catch(() => {
|
|
17941
18109
|
});
|
|
17942
|
-
await
|
|
18110
|
+
await fs25.cp(sourcePluginDir, marketplacePluginPath, { recursive: true, dereference: true });
|
|
17943
18111
|
return marketplacePluginPath;
|
|
17944
18112
|
}
|
|
17945
18113
|
getClaudeMarketplaceSource(plugin, marketplaceRoot, marketplacePath) {
|
|
@@ -17971,7 +18139,7 @@ class PluginManager {
|
|
|
17971
18139
|
async materializeClaudeMarketplace(plugin, pluginDir, target) {
|
|
17972
18140
|
const marketplaceRoot = await this.findClaudeMarketplaceRoot(pluginDir);
|
|
17973
18141
|
const marketplaceSource = this.getClaudeMarketplaceSource(plugin, marketplaceRoot, target.marketplacePath);
|
|
17974
|
-
await
|
|
18142
|
+
await fs25.mkdir(target.marketplacePath, { recursive: true });
|
|
17975
18143
|
const existingManifest = await this.readClaudeMarketplaceManifest(target.marketplacePath);
|
|
17976
18144
|
const sourceManifest = marketplaceRoot ? await this.readClaudeMarketplaceManifest(marketplaceRoot) : null;
|
|
17977
18145
|
const mergedManifest = {
|
|
@@ -18043,10 +18211,10 @@ class PluginManager {
|
|
|
18043
18211
|
warnings.push(`Skipped native Claude plugin install because Claude already has "${plugin.name}" installed as ${conflictingKey}.`);
|
|
18044
18212
|
return { installed, skipped, warnings };
|
|
18045
18213
|
}
|
|
18046
|
-
await
|
|
18214
|
+
await fs25.rm(nativeTarget.installPath, { recursive: true, force: true }).catch(() => {
|
|
18047
18215
|
});
|
|
18048
|
-
await
|
|
18049
|
-
await
|
|
18216
|
+
await fs25.mkdir(dirname3(nativeTarget.installPath), { recursive: true });
|
|
18217
|
+
await fs25.cp(pluginDir, nativeTarget.installPath, { recursive: true, dereference: true });
|
|
18050
18218
|
const marketplace = await this.materializeClaudeMarketplace(plugin, pluginDir, nativeTarget);
|
|
18051
18219
|
const now = new Date().toISOString();
|
|
18052
18220
|
claudeInstalled.plugins[nativeTarget.pluginKey] = [{
|
|
@@ -18086,7 +18254,7 @@ class PluginManager {
|
|
|
18086
18254
|
};
|
|
18087
18255
|
await this.saveClaudeKnownMarketplaces(knownMarketplaces);
|
|
18088
18256
|
for (const entry of legacyEntries) {
|
|
18089
|
-
await
|
|
18257
|
+
await fs25.rm(entry.installPath, { recursive: true, force: true }).catch(() => {
|
|
18090
18258
|
});
|
|
18091
18259
|
}
|
|
18092
18260
|
for (const legacyKey of legacyKeys) {
|
|
@@ -18134,7 +18302,7 @@ class PluginManager {
|
|
|
18134
18302
|
delete knownMarketplaces[marketplaceNamespace];
|
|
18135
18303
|
await this.saveClaudeKnownMarketplaces(knownMarketplaces);
|
|
18136
18304
|
}
|
|
18137
|
-
await
|
|
18305
|
+
await fs25.rm(getClaudeMarketplaceInstallPath(marketplaceNamespace), { recursive: true, force: true }).catch(() => {
|
|
18138
18306
|
});
|
|
18139
18307
|
} else if (marketplaceNamespace) {
|
|
18140
18308
|
const pluginName = component.pluginKey.split("@")[0] || "";
|
|
@@ -18142,14 +18310,14 @@ class PluginManager {
|
|
|
18142
18310
|
const manifest = await this.readClaudeMarketplaceManifest(marketplacePath);
|
|
18143
18311
|
if (pluginName && manifest) {
|
|
18144
18312
|
manifest.plugins = (manifest.plugins || []).filter((entry) => entry.name !== pluginName);
|
|
18145
|
-
const marketplacePluginPath =
|
|
18146
|
-
await
|
|
18313
|
+
const marketplacePluginPath = join6(marketplacePath, "plugins", pluginName);
|
|
18314
|
+
await fs25.rm(marketplacePluginPath, { recursive: true, force: true }).catch(() => {
|
|
18147
18315
|
});
|
|
18148
18316
|
await this.saveClaudeMarketplaceManifest(marketplacePath, manifest);
|
|
18149
18317
|
}
|
|
18150
18318
|
}
|
|
18151
18319
|
await this.saveClaudeSettings(claudeSettings);
|
|
18152
|
-
await
|
|
18320
|
+
await fs25.rm(component.installPath, { recursive: true, force: true }).catch(() => {
|
|
18153
18321
|
});
|
|
18154
18322
|
return true;
|
|
18155
18323
|
}
|
|
@@ -18222,7 +18390,7 @@ class PluginManager {
|
|
|
18222
18390
|
throw new Error(`Unknown marketplace: ${registryId}. Available: ${this.getMarketplaceIds().join(", ")}`);
|
|
18223
18391
|
}
|
|
18224
18392
|
const cacheDir = getMarketplaceCacheDir(registryId);
|
|
18225
|
-
const cacheMetaPath =
|
|
18393
|
+
const cacheMetaPath = join6(cacheDir, ".agentinit-cache-meta.json");
|
|
18226
18394
|
const cacheMeta = await this.readMarketplaceCacheMeta(cacheMetaPath);
|
|
18227
18395
|
if (cacheMeta?.repoUrl === registry.repoUrl) {
|
|
18228
18396
|
const age = Date.now() - cacheMeta.fetchedAt;
|
|
@@ -18230,10 +18398,10 @@ class PluginManager {
|
|
|
18230
18398
|
return cacheDir;
|
|
18231
18399
|
}
|
|
18232
18400
|
}
|
|
18233
|
-
if (await fileExists(
|
|
18401
|
+
if (await fileExists(join6(cacheDir, ".git"))) {
|
|
18234
18402
|
const originUrl = await this.getMarketplaceCacheOriginUrl(cacheDir);
|
|
18235
18403
|
if (originUrl !== registry.repoUrl) {
|
|
18236
|
-
await
|
|
18404
|
+
await fs25.rm(cacheDir, { recursive: true, force: true });
|
|
18237
18405
|
await this.cloneMarketplace(registry.repoUrl, cacheDir);
|
|
18238
18406
|
} else {
|
|
18239
18407
|
const { execFile } = await import("child_process");
|
|
@@ -18242,15 +18410,15 @@ class PluginManager {
|
|
|
18242
18410
|
try {
|
|
18243
18411
|
await exec("git", ["pull", "--ff-only"], { cwd: cacheDir, timeout: 30000 });
|
|
18244
18412
|
} catch {
|
|
18245
|
-
await
|
|
18413
|
+
await fs25.rm(cacheDir, { recursive: true, force: true });
|
|
18246
18414
|
await this.cloneMarketplace(registry.repoUrl, cacheDir);
|
|
18247
18415
|
}
|
|
18248
18416
|
}
|
|
18249
18417
|
} else {
|
|
18250
18418
|
await this.cloneMarketplace(registry.repoUrl, cacheDir);
|
|
18251
18419
|
}
|
|
18252
|
-
await
|
|
18253
|
-
await
|
|
18420
|
+
await fs25.mkdir(cacheDir, { recursive: true });
|
|
18421
|
+
await fs25.writeFile(cacheMetaPath, JSON.stringify({
|
|
18254
18422
|
fetchedAt: Date.now(),
|
|
18255
18423
|
repoUrl: registry.repoUrl
|
|
18256
18424
|
}));
|
|
@@ -18261,7 +18429,7 @@ class PluginManager {
|
|
|
18261
18429
|
return null;
|
|
18262
18430
|
}
|
|
18263
18431
|
try {
|
|
18264
|
-
const meta = JSON.parse(await
|
|
18432
|
+
const meta = JSON.parse(await fs25.readFile(cacheMetaPath, "utf8"));
|
|
18265
18433
|
if (typeof meta.fetchedAt !== "number") {
|
|
18266
18434
|
return null;
|
|
18267
18435
|
}
|
|
@@ -18289,11 +18457,11 @@ class PluginManager {
|
|
|
18289
18457
|
}
|
|
18290
18458
|
}
|
|
18291
18459
|
async cloneMarketplace(repoUrl, dest) {
|
|
18292
|
-
await
|
|
18460
|
+
await fs25.mkdir(dest, { recursive: true });
|
|
18293
18461
|
const { execFile } = await import("child_process");
|
|
18294
18462
|
const { promisify } = await import("util");
|
|
18295
18463
|
const exec = promisify(execFile);
|
|
18296
|
-
await
|
|
18464
|
+
await fs25.rm(dest, { recursive: true, force: true }).catch(() => {
|
|
18297
18465
|
});
|
|
18298
18466
|
await exec("git", ["clone", "--depth", "1", repoUrl, dest], { timeout: 60000 });
|
|
18299
18467
|
}
|
|
@@ -18303,7 +18471,7 @@ class PluginManager {
|
|
|
18303
18471
|
throw new Error(`Unknown marketplace: ${registryId}`);
|
|
18304
18472
|
const cacheDir = await this.ensureMarketplaceCache(registryId);
|
|
18305
18473
|
for (const dir of registry.pluginDirs) {
|
|
18306
|
-
const pluginPath =
|
|
18474
|
+
const pluginPath = join6(cacheDir, dir, name);
|
|
18307
18475
|
if (await isDirectory(pluginPath)) {
|
|
18308
18476
|
return pluginPath;
|
|
18309
18477
|
}
|
|
@@ -18319,7 +18487,7 @@ class PluginManager {
|
|
|
18319
18487
|
const cacheDir = await this.ensureMarketplaceCache(registryId);
|
|
18320
18488
|
const results = [];
|
|
18321
18489
|
for (const dir of registry.pluginDirs) {
|
|
18322
|
-
const fullDir =
|
|
18490
|
+
const fullDir = join6(cacheDir, dir);
|
|
18323
18491
|
if (!await isDirectory(fullDir))
|
|
18324
18492
|
continue;
|
|
18325
18493
|
const cat = getMarketplaceCategoryForDir(dir);
|
|
@@ -18329,26 +18497,26 @@ class PluginManager {
|
|
|
18329
18497
|
for (const entry of entries) {
|
|
18330
18498
|
if (entry.startsWith("."))
|
|
18331
18499
|
continue;
|
|
18332
|
-
const entryPath =
|
|
18500
|
+
const entryPath = join6(fullDir, entry);
|
|
18333
18501
|
if (!await isDirectory(entryPath))
|
|
18334
18502
|
continue;
|
|
18335
|
-
const manifestPath =
|
|
18503
|
+
const manifestPath = join6(entryPath, ".claude-plugin", "plugin.json");
|
|
18336
18504
|
let name = entry;
|
|
18337
18505
|
let description = "";
|
|
18338
18506
|
let version = "0.0.0";
|
|
18339
18507
|
if (await fileExists(manifestPath)) {
|
|
18340
18508
|
try {
|
|
18341
|
-
const manifest = JSON.parse(await
|
|
18509
|
+
const manifest = JSON.parse(await fs25.readFile(manifestPath, "utf8"));
|
|
18342
18510
|
name = manifest.name || entry;
|
|
18343
18511
|
description = manifest.description || "";
|
|
18344
18512
|
version = manifest.version || "0.0.0";
|
|
18345
18513
|
} catch {
|
|
18346
18514
|
}
|
|
18347
18515
|
} else {
|
|
18348
|
-
const skillMdPath =
|
|
18516
|
+
const skillMdPath = join6(entryPath, "SKILL.md");
|
|
18349
18517
|
if (await fileExists(skillMdPath)) {
|
|
18350
18518
|
try {
|
|
18351
|
-
const parsed = import_gray_matter.default(await
|
|
18519
|
+
const parsed = import_gray_matter.default(await fs25.readFile(skillMdPath, "utf8"));
|
|
18352
18520
|
if (parsed.data.name)
|
|
18353
18521
|
name = parsed.data.name;
|
|
18354
18522
|
if (parsed.data.description)
|
|
@@ -18356,10 +18524,10 @@ class PluginManager {
|
|
|
18356
18524
|
} catch {
|
|
18357
18525
|
}
|
|
18358
18526
|
} else {
|
|
18359
|
-
const mcpPath =
|
|
18527
|
+
const mcpPath = join6(entryPath, ".mcp.json");
|
|
18360
18528
|
if (await fileExists(mcpPath)) {
|
|
18361
18529
|
try {
|
|
18362
|
-
const mcpConfig = JSON.parse(await
|
|
18530
|
+
const mcpConfig = JSON.parse(await fs25.readFile(mcpPath, "utf8"));
|
|
18363
18531
|
const serverNames = Object.keys(mcpConfig.mcpServers || mcpConfig);
|
|
18364
18532
|
if (serverNames.length > 0) {
|
|
18365
18533
|
description = `MCP server(s): ${serverNames.join(", ")}`;
|
|
@@ -18381,10 +18549,10 @@ class PluginManager {
|
|
|
18381
18549
|
return results.sort((a, b) => a.name.localeCompare(b.name));
|
|
18382
18550
|
}
|
|
18383
18551
|
async detectFormat(pluginDir) {
|
|
18384
|
-
if (await fileExists(
|
|
18552
|
+
if (await fileExists(join6(pluginDir, ".claude-plugin", "plugin.json"))) {
|
|
18385
18553
|
return "claude";
|
|
18386
18554
|
}
|
|
18387
|
-
if (await fileExists(
|
|
18555
|
+
if (await fileExists(join6(pluginDir, ".cursor-plugin", "plugin.json"))) {
|
|
18388
18556
|
return "cursor";
|
|
18389
18557
|
}
|
|
18390
18558
|
return "generic";
|
|
@@ -18401,7 +18569,7 @@ class PluginManager {
|
|
|
18401
18569
|
}
|
|
18402
18570
|
}
|
|
18403
18571
|
async parseClaudePlugin(pluginDir, source) {
|
|
18404
|
-
const manifestPath =
|
|
18572
|
+
const manifestPath = join6(pluginDir, ".claude-plugin", "plugin.json");
|
|
18405
18573
|
const manifestContent = await readFileIfExists(manifestPath);
|
|
18406
18574
|
if (!manifestContent) {
|
|
18407
18575
|
throw new Error(`Missing .claude-plugin/plugin.json in ${pluginDir}`);
|
|
@@ -18412,10 +18580,10 @@ class PluginManager {
|
|
|
18412
18580
|
const convertedSkills = await this.convertCommandsToSkills(pluginDir, manifest);
|
|
18413
18581
|
skills.push(...convertedSkills);
|
|
18414
18582
|
const mcpServers = await this.parseMcpJson(pluginDir);
|
|
18415
|
-
if (await isDirectory(
|
|
18583
|
+
if (await isDirectory(join6(pluginDir, "hooks")) || manifest.hooks) {
|
|
18416
18584
|
warnings.push("Hooks (hooks/) are Claude Code-specific");
|
|
18417
18585
|
}
|
|
18418
|
-
if (await isDirectory(
|
|
18586
|
+
if (await isDirectory(join6(pluginDir, "agents")) || manifest.agents) {
|
|
18419
18587
|
warnings.push("Agent definitions (agents/) are Claude Code-specific");
|
|
18420
18588
|
}
|
|
18421
18589
|
return {
|
|
@@ -18430,7 +18598,7 @@ class PluginManager {
|
|
|
18430
18598
|
};
|
|
18431
18599
|
}
|
|
18432
18600
|
async parseCursorPlugin(pluginDir, source) {
|
|
18433
|
-
const manifestPath =
|
|
18601
|
+
const manifestPath = join6(pluginDir, ".cursor-plugin", "plugin.json");
|
|
18434
18602
|
const manifestContent = await readFileIfExists(manifestPath);
|
|
18435
18603
|
if (!manifestContent) {
|
|
18436
18604
|
throw new Error(`Missing .cursor-plugin/plugin.json in ${pluginDir}`);
|
|
@@ -18469,7 +18637,7 @@ class PluginManager {
|
|
|
18469
18637
|
};
|
|
18470
18638
|
}
|
|
18471
18639
|
async parseMcpJson(pluginDir) {
|
|
18472
|
-
const mcpPath =
|
|
18640
|
+
const mcpPath = join6(pluginDir, ".mcp.json");
|
|
18473
18641
|
const content = await readFileIfExists(mcpPath);
|
|
18474
18642
|
if (!content)
|
|
18475
18643
|
return [];
|
|
@@ -18516,7 +18684,7 @@ class PluginManager {
|
|
|
18516
18684
|
commandsDirs.push(resolve8(pluginDir, cmd));
|
|
18517
18685
|
}
|
|
18518
18686
|
} else {
|
|
18519
|
-
commandsDirs.push(
|
|
18687
|
+
commandsDirs.push(join6(pluginDir, "commands"));
|
|
18520
18688
|
}
|
|
18521
18689
|
for (const commandsDir of commandsDirs) {
|
|
18522
18690
|
if (!await isDirectory(commandsDir))
|
|
@@ -18525,7 +18693,7 @@ class PluginManager {
|
|
|
18525
18693
|
for (const entry of entries) {
|
|
18526
18694
|
if (!entry.endsWith(".md"))
|
|
18527
18695
|
continue;
|
|
18528
|
-
const cmdPath =
|
|
18696
|
+
const cmdPath = join6(commandsDir, entry);
|
|
18529
18697
|
const skill = await this.convertSingleCommandToSkill(cmdPath, manifest.name);
|
|
18530
18698
|
if (skill)
|
|
18531
18699
|
skills.push(skill);
|
|
@@ -18839,7 +19007,7 @@ ${body.trim()}
|
|
|
18839
19007
|
}
|
|
18840
19008
|
if (!removedSkillPaths.has(skill.path)) {
|
|
18841
19009
|
try {
|
|
18842
|
-
await
|
|
19010
|
+
await fs25.rm(skill.path, { recursive: true, force: true });
|
|
18843
19011
|
removedSkillPaths.add(skill.path);
|
|
18844
19012
|
} catch {
|
|
18845
19013
|
details.push(`Could not remove skill path: ${skill.path}`);
|
|
@@ -18848,7 +19016,7 @@ ${body.trim()}
|
|
|
18848
19016
|
}
|
|
18849
19017
|
if (skill.canonicalPath && skill.canonicalPath !== skill.path && !removedCanonicalPaths.has(skill.canonicalPath) && !sharedCanonicalPath) {
|
|
18850
19018
|
try {
|
|
18851
|
-
await
|
|
19019
|
+
await fs25.rm(skill.canonicalPath, { recursive: true, force: true });
|
|
18852
19020
|
removedCanonicalPaths.add(skill.canonicalPath);
|
|
18853
19021
|
} catch {
|
|
18854
19022
|
details.push(`Could not remove canonical skill path: ${skill.canonicalPath}`);
|
|
@@ -18954,31 +19122,31 @@ var init_pluginManager = __esm(() => {
|
|
|
18954
19122
|
init_skillsManager();
|
|
18955
19123
|
init_userConfig();
|
|
18956
19124
|
getMarketplaceCacheDir = function(registryId) {
|
|
18957
|
-
return
|
|
19125
|
+
return join6(homedir5(), ".agentinit", "marketplace-cache", registryId);
|
|
18958
19126
|
};
|
|
18959
19127
|
getRegistryPath = function(projectPath, global3) {
|
|
18960
19128
|
if (global3) {
|
|
18961
|
-
return
|
|
19129
|
+
return join6(homedir5(), ".agentinit", "plugins.json");
|
|
18962
19130
|
}
|
|
18963
|
-
return
|
|
19131
|
+
return join6(projectPath, ".agentinit", "plugins.json");
|
|
18964
19132
|
};
|
|
18965
19133
|
getClaudeInstalledPluginsPath = function() {
|
|
18966
|
-
return
|
|
19134
|
+
return join6(homedir5(), ".claude", "plugins", "installed_plugins.json");
|
|
18967
19135
|
};
|
|
18968
19136
|
getClaudeKnownMarketplacesPath = function() {
|
|
18969
|
-
return
|
|
19137
|
+
return join6(homedir5(), ".claude", "plugins", "known_marketplaces.json");
|
|
18970
19138
|
};
|
|
18971
19139
|
getClaudeMarketplaceInstallPath = function(namespace) {
|
|
18972
|
-
return
|
|
19140
|
+
return join6(homedir5(), ".claude", "plugins", "marketplaces", namespace);
|
|
18973
19141
|
};
|
|
18974
19142
|
getClaudeSettingsPath = function() {
|
|
18975
|
-
return
|
|
19143
|
+
return join6(homedir5(), ".claude", "settings.json");
|
|
18976
19144
|
};
|
|
18977
19145
|
});
|
|
18978
19146
|
|
|
18979
19147
|
// dist/core/skillsManager.js
|
|
18980
|
-
import {resolve as resolve9, join as
|
|
18981
|
-
import {promises as
|
|
19148
|
+
import {resolve as resolve9, join as join7, relative as relative4, basename as basename3, dirname as dirname4} from "path";
|
|
19149
|
+
import {promises as fs27} from "fs";
|
|
18982
19150
|
import {homedir as homedir6, tmpdir} from "os";
|
|
18983
19151
|
import {execFile} from "child_process";
|
|
18984
19152
|
import {createHash as createHash2} from "crypto";
|
|
@@ -18987,6 +19155,7 @@ import {promisify} from "util";
|
|
|
18987
19155
|
class SkillsManager {
|
|
18988
19156
|
agentManager;
|
|
18989
19157
|
preparedSourceContexts = new Map;
|
|
19158
|
+
skillScanner = new SkillSecurityScanner;
|
|
18990
19159
|
constructor(agentManager3) {
|
|
18991
19160
|
this.agentManager = agentManager3 || new AgentManager;
|
|
18992
19161
|
}
|
|
@@ -18994,11 +19163,15 @@ class SkillsManager {
|
|
|
18994
19163
|
if (source.startsWith(".") || source.startsWith("/") || source.startsWith("~")) {
|
|
18995
19164
|
return { type: "local", path: source };
|
|
18996
19165
|
}
|
|
18997
|
-
const
|
|
18998
|
-
if (
|
|
18999
|
-
return
|
|
19166
|
+
const httpSource = this.parseHttpRepositorySource(source);
|
|
19167
|
+
if (httpSource) {
|
|
19168
|
+
return httpSource;
|
|
19000
19169
|
}
|
|
19001
|
-
|
|
19170
|
+
const sshSource = this.parseSshRepositorySource(source);
|
|
19171
|
+
if (sshSource) {
|
|
19172
|
+
return sshSource;
|
|
19173
|
+
}
|
|
19174
|
+
if (source.endsWith(".git")) {
|
|
19002
19175
|
return { type: "github", url: source };
|
|
19003
19176
|
}
|
|
19004
19177
|
if (options2?.from) {
|
|
@@ -19011,6 +19184,14 @@ class SkillsManager {
|
|
|
19011
19184
|
pluginName: source
|
|
19012
19185
|
};
|
|
19013
19186
|
}
|
|
19187
|
+
const gitLabShorthandSource = this.parseGitLabShorthandSource(source);
|
|
19188
|
+
if (gitLabShorthandSource) {
|
|
19189
|
+
return gitLabShorthandSource;
|
|
19190
|
+
}
|
|
19191
|
+
const bitbucketShorthandSource = this.parseBitbucketShorthandSource(source);
|
|
19192
|
+
if (bitbucketShorthandSource) {
|
|
19193
|
+
return bitbucketShorthandSource;
|
|
19194
|
+
}
|
|
19014
19195
|
const githubShorthandSource = this.parseGitHubShorthandSource(source);
|
|
19015
19196
|
if (githubShorthandSource?.subpath) {
|
|
19016
19197
|
return githubShorthandSource;
|
|
@@ -19100,6 +19281,106 @@ class SkillsManager {
|
|
|
19100
19281
|
return null;
|
|
19101
19282
|
}
|
|
19102
19283
|
}
|
|
19284
|
+
parseGitLabHttpSource(source) {
|
|
19285
|
+
if (!source.startsWith("https://gitlab.com/") && !source.startsWith("http://gitlab.com/")) {
|
|
19286
|
+
return null;
|
|
19287
|
+
}
|
|
19288
|
+
try {
|
|
19289
|
+
const parsedUrl = new URL(source);
|
|
19290
|
+
const segments = parsedUrl.pathname.replace(/\/+$/, "").split("/").filter(Boolean);
|
|
19291
|
+
const dashIndex = segments.indexOf("-");
|
|
19292
|
+
const repoBoundary = dashIndex >= 0 ? dashIndex : segments.length;
|
|
19293
|
+
if (repoBoundary < 2) {
|
|
19294
|
+
return null;
|
|
19295
|
+
}
|
|
19296
|
+
const repo = segments[repoBoundary - 1];
|
|
19297
|
+
const owner = segments.slice(0, repoBoundary - 1).join("/");
|
|
19298
|
+
if (!owner || !repo) {
|
|
19299
|
+
return null;
|
|
19300
|
+
}
|
|
19301
|
+
let subpath;
|
|
19302
|
+
if (dashIndex >= 0) {
|
|
19303
|
+
const marker = segments[dashIndex + 1];
|
|
19304
|
+
if ((marker === "tree" || marker === "blob") && segments.length > dashIndex + 3) {
|
|
19305
|
+
subpath = segments.slice(dashIndex + 3).join("/");
|
|
19306
|
+
}
|
|
19307
|
+
}
|
|
19308
|
+
return {
|
|
19309
|
+
type: "gitlab",
|
|
19310
|
+
url: `https://gitlab.com/${owner}/${repo}.git`,
|
|
19311
|
+
owner,
|
|
19312
|
+
repo,
|
|
19313
|
+
...subpath ? { subpath } : {}
|
|
19314
|
+
};
|
|
19315
|
+
} catch {
|
|
19316
|
+
return null;
|
|
19317
|
+
}
|
|
19318
|
+
}
|
|
19319
|
+
parseBitbucketHttpSource(source) {
|
|
19320
|
+
if (!source.startsWith("https://bitbucket.org/") && !source.startsWith("http://bitbucket.org/")) {
|
|
19321
|
+
return null;
|
|
19322
|
+
}
|
|
19323
|
+
try {
|
|
19324
|
+
const parsedUrl = new URL(source);
|
|
19325
|
+
const segments = parsedUrl.pathname.replace(/\/+$/, "").split("/").filter(Boolean);
|
|
19326
|
+
if (segments.length < 2) {
|
|
19327
|
+
return null;
|
|
19328
|
+
}
|
|
19329
|
+
const [owner, repo, marker, _commitish, ...rest] = segments;
|
|
19330
|
+
if (!owner || !repo) {
|
|
19331
|
+
return null;
|
|
19332
|
+
}
|
|
19333
|
+
let subpath;
|
|
19334
|
+
if (marker === "src" && rest.length > 0) {
|
|
19335
|
+
subpath = rest.join("/");
|
|
19336
|
+
}
|
|
19337
|
+
return {
|
|
19338
|
+
type: "bitbucket",
|
|
19339
|
+
url: `https://bitbucket.org/${owner}/${repo}.git`,
|
|
19340
|
+
owner,
|
|
19341
|
+
repo,
|
|
19342
|
+
...subpath ? { subpath } : {}
|
|
19343
|
+
};
|
|
19344
|
+
} catch {
|
|
19345
|
+
return null;
|
|
19346
|
+
}
|
|
19347
|
+
}
|
|
19348
|
+
parseHttpRepositorySource(source) {
|
|
19349
|
+
return this.parseGitHubHttpSource(source) || this.parseGitLabHttpSource(source) || this.parseBitbucketHttpSource(source);
|
|
19350
|
+
}
|
|
19351
|
+
parseSshRepositorySource(source) {
|
|
19352
|
+
const githubMatch = source.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
19353
|
+
if (githubMatch) {
|
|
19354
|
+
const [, owner, repo] = githubMatch;
|
|
19355
|
+
return {
|
|
19356
|
+
type: "github",
|
|
19357
|
+
url: `git@github.com:${owner}/${repo}.git`,
|
|
19358
|
+
owner,
|
|
19359
|
+
repo
|
|
19360
|
+
};
|
|
19361
|
+
}
|
|
19362
|
+
const gitlabMatch = source.match(/^git@gitlab\.com:(.+)\/([^/]+?)(?:\.git)?$/);
|
|
19363
|
+
if (gitlabMatch) {
|
|
19364
|
+
const [, owner, repo] = gitlabMatch;
|
|
19365
|
+
return {
|
|
19366
|
+
type: "gitlab",
|
|
19367
|
+
url: `git@gitlab.com:${owner}/${repo}.git`,
|
|
19368
|
+
owner,
|
|
19369
|
+
repo
|
|
19370
|
+
};
|
|
19371
|
+
}
|
|
19372
|
+
const bitbucketMatch = source.match(/^git@bitbucket\.org:([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
19373
|
+
if (bitbucketMatch) {
|
|
19374
|
+
const [, owner, repo] = bitbucketMatch;
|
|
19375
|
+
return {
|
|
19376
|
+
type: "bitbucket",
|
|
19377
|
+
url: `git@bitbucket.org:${owner}/${repo}.git`,
|
|
19378
|
+
owner,
|
|
19379
|
+
repo
|
|
19380
|
+
};
|
|
19381
|
+
}
|
|
19382
|
+
return null;
|
|
19383
|
+
}
|
|
19103
19384
|
parseGitHubShorthandSource(source) {
|
|
19104
19385
|
const githubShorthandMatch = source.match(/^([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)(?:\/(.+))?$/);
|
|
19105
19386
|
if (!githubShorthandMatch) {
|
|
@@ -19114,6 +19395,50 @@ class SkillsManager {
|
|
|
19114
19395
|
...subpath ? { subpath } : {}
|
|
19115
19396
|
};
|
|
19116
19397
|
}
|
|
19398
|
+
parseGitLabShorthandSource(source) {
|
|
19399
|
+
const normalized = source.startsWith("gitlab:") ? source.slice("gitlab:".length) : source.startsWith("gitlab.com/") ? source.slice("gitlab.com/".length) : null;
|
|
19400
|
+
if (!normalized) {
|
|
19401
|
+
return null;
|
|
19402
|
+
}
|
|
19403
|
+
const [repoSpec = normalized, subpathSpec] = normalized.split("//", 2);
|
|
19404
|
+
const segments = repoSpec.split("/").filter(Boolean);
|
|
19405
|
+
if (segments.length < 2) {
|
|
19406
|
+
return null;
|
|
19407
|
+
}
|
|
19408
|
+
const repo = segments[segments.length - 1];
|
|
19409
|
+
const owner = segments.slice(0, segments.length - 1).join("/");
|
|
19410
|
+
if (!owner || !repo) {
|
|
19411
|
+
return null;
|
|
19412
|
+
}
|
|
19413
|
+
return {
|
|
19414
|
+
type: "gitlab",
|
|
19415
|
+
url: `https://gitlab.com/${owner}/${repo}.git`,
|
|
19416
|
+
owner,
|
|
19417
|
+
repo,
|
|
19418
|
+
...subpathSpec ? { subpath: subpathSpec } : {}
|
|
19419
|
+
};
|
|
19420
|
+
}
|
|
19421
|
+
parseBitbucketShorthandSource(source) {
|
|
19422
|
+
const normalized = source.startsWith("bitbucket:") ? source.slice("bitbucket:".length) : source.startsWith("bitbucket.org/") ? source.slice("bitbucket.org/".length) : null;
|
|
19423
|
+
if (!normalized) {
|
|
19424
|
+
return null;
|
|
19425
|
+
}
|
|
19426
|
+
const segments = normalized.split("/").filter(Boolean);
|
|
19427
|
+
if (segments.length < 2) {
|
|
19428
|
+
return null;
|
|
19429
|
+
}
|
|
19430
|
+
const [owner, repo, ...rest] = segments;
|
|
19431
|
+
if (!owner || !repo) {
|
|
19432
|
+
return null;
|
|
19433
|
+
}
|
|
19434
|
+
return {
|
|
19435
|
+
type: "bitbucket",
|
|
19436
|
+
url: `https://bitbucket.org/${owner}/${repo}.git`,
|
|
19437
|
+
owner,
|
|
19438
|
+
repo,
|
|
19439
|
+
...rest.length > 0 ? { subpath: rest.join("/") } : {}
|
|
19440
|
+
};
|
|
19441
|
+
}
|
|
19117
19442
|
async parseSkillMd(filePath) {
|
|
19118
19443
|
const content = await readFileIfExists(filePath);
|
|
19119
19444
|
if (!content)
|
|
@@ -19135,7 +19460,7 @@ class SkillsManager {
|
|
|
19135
19460
|
const fullDir = resolve9(repoPath, searchDir);
|
|
19136
19461
|
if (!await fileExists(fullDir))
|
|
19137
19462
|
continue;
|
|
19138
|
-
const directSkillMd =
|
|
19463
|
+
const directSkillMd = join7(fullDir, "SKILL.md");
|
|
19139
19464
|
if (await fileExists(directSkillMd)) {
|
|
19140
19465
|
const parsed = await this.parseSkillMd(directSkillMd);
|
|
19141
19466
|
if (parsed && !seen.has(parsed.name)) {
|
|
@@ -19143,7 +19468,7 @@ class SkillsManager {
|
|
|
19143
19468
|
skills2.push({ ...parsed, path: resolve9(fullDir) });
|
|
19144
19469
|
}
|
|
19145
19470
|
}
|
|
19146
|
-
const directSkillMdLower =
|
|
19471
|
+
const directSkillMdLower = join7(fullDir, "skill.md");
|
|
19147
19472
|
if (await fileExists(directSkillMdLower)) {
|
|
19148
19473
|
const parsed = await this.parseSkillMd(directSkillMdLower);
|
|
19149
19474
|
if (parsed && !seen.has(parsed.name)) {
|
|
@@ -19155,11 +19480,11 @@ class SkillsManager {
|
|
|
19155
19480
|
continue;
|
|
19156
19481
|
const entries = await listFiles(fullDir);
|
|
19157
19482
|
for (const entry of entries) {
|
|
19158
|
-
const entryPath =
|
|
19483
|
+
const entryPath = join7(fullDir, entry);
|
|
19159
19484
|
if (!await isDirectory(entryPath))
|
|
19160
19485
|
continue;
|
|
19161
|
-
const skillMdPath =
|
|
19162
|
-
const skillMdPathLower =
|
|
19486
|
+
const skillMdPath = join7(entryPath, "SKILL.md");
|
|
19487
|
+
const skillMdPathLower = join7(entryPath, "skill.md");
|
|
19163
19488
|
const skillFile = await fileExists(skillMdPath) ? skillMdPath : await fileExists(skillMdPathLower) ? skillMdPathLower : null;
|
|
19164
19489
|
if (!skillFile)
|
|
19165
19490
|
continue;
|
|
@@ -19173,14 +19498,14 @@ class SkillsManager {
|
|
|
19173
19498
|
return skills2;
|
|
19174
19499
|
}
|
|
19175
19500
|
async cloneRepo(url) {
|
|
19176
|
-
const tempDir = await
|
|
19177
|
-
await
|
|
19501
|
+
const tempDir = await fs27.mkdtemp(join7(tmpdir(), "agentinit-skills-"));
|
|
19502
|
+
await fs27.rm(tempDir, { recursive: true, force: true });
|
|
19178
19503
|
try {
|
|
19179
19504
|
await execFileAsync("git", ["clone", "--depth", "1", url, tempDir], {
|
|
19180
19505
|
timeout: 60000
|
|
19181
19506
|
});
|
|
19182
19507
|
} catch (error) {
|
|
19183
|
-
await
|
|
19508
|
+
await fs27.rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
19184
19509
|
});
|
|
19185
19510
|
throw new Error(`Failed to clone ${url}: ${error.message}`);
|
|
19186
19511
|
}
|
|
@@ -19238,12 +19563,12 @@ class SkillsManager {
|
|
|
19238
19563
|
if (!tempDir) {
|
|
19239
19564
|
return;
|
|
19240
19565
|
}
|
|
19241
|
-
await
|
|
19566
|
+
await fs27.rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
19242
19567
|
});
|
|
19243
19568
|
}
|
|
19244
19569
|
async resolveDiscoveryRoot(repoPath, source, sourceLabel) {
|
|
19245
19570
|
const resolvedRepoPath = resolve9(repoPath);
|
|
19246
|
-
if (source.type !== "github" || !source.subpath) {
|
|
19571
|
+
if (source.type !== "github" && source.type !== "gitlab" && source.type !== "bitbucket" || !source.subpath) {
|
|
19247
19572
|
return resolvedRepoPath;
|
|
19248
19573
|
}
|
|
19249
19574
|
const discoveryRoot = resolve9(resolvedRepoPath, source.subpath);
|
|
@@ -19288,7 +19613,7 @@ class SkillsManager {
|
|
|
19288
19613
|
};
|
|
19289
19614
|
}
|
|
19290
19615
|
let repoPath;
|
|
19291
|
-
if (resolved.type === "github") {
|
|
19616
|
+
if (resolved.type === "github" || resolved.type === "gitlab" || resolved.type === "bitbucket") {
|
|
19292
19617
|
if (!resolved.url) {
|
|
19293
19618
|
throw new Error(`Invalid source: ${source}`);
|
|
19294
19619
|
}
|
|
@@ -19382,26 +19707,26 @@ class SkillsManager {
|
|
|
19382
19707
|
async installSkill(skillPath, skillName, targetDir, copy = false) {
|
|
19383
19708
|
const normalizedSkillName = this.normalizeSkillName(skillName);
|
|
19384
19709
|
const destPath = this.resolveInstallPath(targetDir, normalizedSkillName);
|
|
19385
|
-
await
|
|
19710
|
+
await fs27.mkdir(resolve9(targetDir), { recursive: true });
|
|
19386
19711
|
if (await fileExists(destPath)) {
|
|
19387
|
-
await
|
|
19712
|
+
await fs27.rm(destPath, { recursive: true, force: true });
|
|
19388
19713
|
}
|
|
19389
19714
|
if (copy) {
|
|
19390
19715
|
await this.copyDir(skillPath, destPath);
|
|
19391
19716
|
} else {
|
|
19392
|
-
await
|
|
19717
|
+
await fs27.symlink(skillPath, destPath, "dir");
|
|
19393
19718
|
}
|
|
19394
19719
|
return destPath;
|
|
19395
19720
|
}
|
|
19396
19721
|
async installSkillFromContent(skillName, skillContent, targetDir) {
|
|
19397
19722
|
const normalizedSkillName = this.normalizeSkillName(skillName);
|
|
19398
19723
|
const destPath = this.resolveInstallPath(targetDir, normalizedSkillName);
|
|
19399
|
-
await
|
|
19724
|
+
await fs27.mkdir(resolve9(targetDir), { recursive: true });
|
|
19400
19725
|
if (await fileExists(destPath)) {
|
|
19401
|
-
await
|
|
19726
|
+
await fs27.rm(destPath, { recursive: true, force: true });
|
|
19402
19727
|
}
|
|
19403
|
-
await
|
|
19404
|
-
await
|
|
19728
|
+
await fs27.mkdir(destPath, { recursive: true });
|
|
19729
|
+
await fs27.writeFile(join7(destPath, "SKILL.md"), skillContent, "utf8");
|
|
19405
19730
|
return destPath;
|
|
19406
19731
|
}
|
|
19407
19732
|
getCanonicalSkillsDir(projectPath, global3 = false) {
|
|
@@ -19495,7 +19820,7 @@ class SkillsManager {
|
|
|
19495
19820
|
throw new Error(`Missing canonical path for ${skillName}`);
|
|
19496
19821
|
}
|
|
19497
19822
|
await this.cleanAndCreateDirectory(canonicalPath);
|
|
19498
|
-
await
|
|
19823
|
+
await fs27.writeFile(join7(canonicalPath, "SKILL.md"), skillContent, "utf8");
|
|
19499
19824
|
if (plan.path === canonicalPath) {
|
|
19500
19825
|
return plan;
|
|
19501
19826
|
}
|
|
@@ -19518,7 +19843,7 @@ class SkillsManager {
|
|
|
19518
19843
|
async installSkillFromContentToCanonicalStore(skillName, skillContent, projectPath, options2 = {}) {
|
|
19519
19844
|
const plan = this.getCanonicalInstallPlan(skillName, projectPath, options2);
|
|
19520
19845
|
await this.cleanAndCreateDirectory(plan.path);
|
|
19521
|
-
await
|
|
19846
|
+
await fs27.writeFile(join7(plan.path, "SKILL.md"), skillContent, "utf8");
|
|
19522
19847
|
return plan;
|
|
19523
19848
|
}
|
|
19524
19849
|
getCanonicalInstallPlan(skillName, projectPath, options2 = {}) {
|
|
@@ -19530,6 +19855,76 @@ class SkillsManager {
|
|
|
19530
19855
|
mode: "symlink"
|
|
19531
19856
|
};
|
|
19532
19857
|
}
|
|
19858
|
+
normalizeSkillPrefix(prefix) {
|
|
19859
|
+
const normalized = prefix?.trim() ?? "";
|
|
19860
|
+
if (normalized.includes("/") || normalized.includes("\\")) {
|
|
19861
|
+
throw new Error(`Invalid skill prefix: ${prefix}`);
|
|
19862
|
+
}
|
|
19863
|
+
return normalized;
|
|
19864
|
+
}
|
|
19865
|
+
withSkillPrefix(skillName, prefix) {
|
|
19866
|
+
const normalizedPrefix = this.normalizeSkillPrefix(prefix);
|
|
19867
|
+
return normalizedPrefix ? `${normalizedPrefix}${skillName}` : skillName;
|
|
19868
|
+
}
|
|
19869
|
+
async rewriteSkillFileName(filePath, skillName) {
|
|
19870
|
+
const content = await fs27.readFile(filePath, "utf8");
|
|
19871
|
+
const parsed = import_gray_matter2.default(content);
|
|
19872
|
+
const nextContent = import_gray_matter2.default.stringify(parsed.content, {
|
|
19873
|
+
...parsed.data,
|
|
19874
|
+
name: skillName
|
|
19875
|
+
});
|
|
19876
|
+
await fs27.writeFile(filePath, nextContent, "utf8");
|
|
19877
|
+
}
|
|
19878
|
+
async applyPrefixToSkills(skills2, prefix) {
|
|
19879
|
+
const normalizedPrefix = this.normalizeSkillPrefix(prefix);
|
|
19880
|
+
if (!normalizedPrefix) {
|
|
19881
|
+
return { skills: skills2, cleanup: async () => {
|
|
19882
|
+
} };
|
|
19883
|
+
}
|
|
19884
|
+
const tempDirs = [];
|
|
19885
|
+
try {
|
|
19886
|
+
const prefixedSkills = await Promise.all(skills2.map(async (skill) => {
|
|
19887
|
+
const name = this.withSkillPrefix(skill.name, normalizedPrefix);
|
|
19888
|
+
if (skill.generatedContent) {
|
|
19889
|
+
return {
|
|
19890
|
+
...skill,
|
|
19891
|
+
name,
|
|
19892
|
+
generatedContent: import_gray_matter2.default.stringify(import_gray_matter2.default(skill.generatedContent).content, {
|
|
19893
|
+
...import_gray_matter2.default(skill.generatedContent).data,
|
|
19894
|
+
name
|
|
19895
|
+
})
|
|
19896
|
+
};
|
|
19897
|
+
}
|
|
19898
|
+
const tempRoot = await fs27.mkdtemp(join7(tmpdir(), "agentinit-prefixed-skill-"));
|
|
19899
|
+
const tempSkillPath = join7(tempRoot, basename3(skill.path));
|
|
19900
|
+
tempDirs.push(tempRoot);
|
|
19901
|
+
await this.copyDir(skill.path, tempSkillPath);
|
|
19902
|
+
const skillMdPath = join7(tempSkillPath, "SKILL.md");
|
|
19903
|
+
const skillMdPathLower = join7(tempSkillPath, "skill.md");
|
|
19904
|
+
const skillFile = await fileExists(skillMdPath) ? skillMdPath : await fileExists(skillMdPathLower) ? skillMdPathLower : null;
|
|
19905
|
+
if (!skillFile) {
|
|
19906
|
+
throw new Error(`Skill "${skill.name}" is missing SKILL.md`);
|
|
19907
|
+
}
|
|
19908
|
+
await this.rewriteSkillFileName(skillFile, name);
|
|
19909
|
+
return {
|
|
19910
|
+
...skill,
|
|
19911
|
+
name,
|
|
19912
|
+
path: tempSkillPath
|
|
19913
|
+
};
|
|
19914
|
+
}));
|
|
19915
|
+
return {
|
|
19916
|
+
skills: prefixedSkills,
|
|
19917
|
+
cleanup: async () => {
|
|
19918
|
+
await Promise.all(tempDirs.map((dir) => fs27.rm(dir, { recursive: true, force: true }).catch(() => {
|
|
19919
|
+
})));
|
|
19920
|
+
}
|
|
19921
|
+
};
|
|
19922
|
+
} catch (error) {
|
|
19923
|
+
await Promise.all(tempDirs.map((dir) => fs27.rm(dir, { recursive: true, force: true }).catch(() => {
|
|
19924
|
+
})));
|
|
19925
|
+
throw error;
|
|
19926
|
+
}
|
|
19927
|
+
}
|
|
19533
19928
|
normalizeSkillName(skillName) {
|
|
19534
19929
|
const normalized = skillName.trim();
|
|
19535
19930
|
if (!normalized) {
|
|
@@ -19543,7 +19938,7 @@ class SkillsManager {
|
|
|
19543
19938
|
resolveInstallPath(targetDir, skillName) {
|
|
19544
19939
|
const resolvedTargetDir = resolve9(targetDir);
|
|
19545
19940
|
const destPath = resolve9(resolvedTargetDir, skillName);
|
|
19546
|
-
const relativePath =
|
|
19941
|
+
const relativePath = relative4(resolvedTargetDir, destPath);
|
|
19547
19942
|
if (relativePath === "" || relativePath.startsWith("..") || relativePath.includes("/../") || relativePath.includes("\\..\\")) {
|
|
19548
19943
|
throw new Error(`Refusing to install skill outside target directory: ${skillName}`);
|
|
19549
19944
|
}
|
|
@@ -19562,16 +19957,16 @@ class SkillsManager {
|
|
|
19562
19957
|
return null;
|
|
19563
19958
|
const hash = createHash2("sha256");
|
|
19564
19959
|
const walk = async (currentPath, relativePath) => {
|
|
19565
|
-
const stat = await
|
|
19960
|
+
const stat = await fs27.stat(currentPath);
|
|
19566
19961
|
if (!stat.isDirectory()) {
|
|
19567
|
-
const content = await
|
|
19962
|
+
const content = await fs27.readFile(currentPath);
|
|
19568
19963
|
this.updateSnapshotWithFile(hash, relativePath, content);
|
|
19569
19964
|
return;
|
|
19570
19965
|
}
|
|
19571
19966
|
hash.update(`dir:${relativePath || "."}\n`);
|
|
19572
|
-
const entries = (await
|
|
19967
|
+
const entries = (await fs27.readdir(currentPath)).sort((left, right) => left.localeCompare(right));
|
|
19573
19968
|
for (const entry of entries) {
|
|
19574
|
-
await walk(
|
|
19969
|
+
await walk(join7(currentPath, entry), relativePath ? join7(relativePath, entry) : entry);
|
|
19575
19970
|
}
|
|
19576
19971
|
};
|
|
19577
19972
|
await walk(rootPath, "");
|
|
@@ -19616,22 +20011,25 @@ class SkillsManager {
|
|
|
19616
20011
|
return existingAtCanonical === incoming ? "new" : "changed";
|
|
19617
20012
|
}
|
|
19618
20013
|
async cleanAndCreateDirectory(path) {
|
|
19619
|
-
await
|
|
20014
|
+
await fs27.rm(path, { recursive: true, force: true }).catch(() => {
|
|
19620
20015
|
});
|
|
19621
|
-
await
|
|
20016
|
+
await fs27.mkdir(path, { recursive: true });
|
|
19622
20017
|
}
|
|
19623
20018
|
isWithinPath(basePath, targetPath) {
|
|
19624
|
-
const relativePath =
|
|
20019
|
+
const relativePath = relative4(resolve9(basePath), resolve9(targetPath));
|
|
19625
20020
|
return relativePath === "" || !relativePath.startsWith("..") && !relativePath.includes("/../") && !relativePath.includes("\\..\\");
|
|
19626
20021
|
}
|
|
19627
20022
|
async copyDir(src, dest) {
|
|
19628
|
-
await
|
|
20023
|
+
await fs27.cp(src, dest, { recursive: true, dereference: true });
|
|
19629
20024
|
}
|
|
19630
20025
|
async addFromSource(source, projectPath, options2 = {}) {
|
|
20026
|
+
const normalizedPrefix = this.normalizeSkillPrefix(options2.prefix);
|
|
19631
20027
|
const context = this.takePreparedSourceContext(source, projectPath, options2.from) || await this.loadDiscoveredSkillsContext(source, projectPath, {
|
|
19632
20028
|
...options2.from !== undefined ? { from: options2.from } : {},
|
|
19633
20029
|
...options2.pluginName !== undefined ? { pluginName: options2.pluginName } : {}
|
|
19634
20030
|
});
|
|
20031
|
+
let prefixedCleanup = async () => {
|
|
20032
|
+
};
|
|
19635
20033
|
try {
|
|
19636
20034
|
let skills2 = context.skills;
|
|
19637
20035
|
if (skills2.length === 0) {
|
|
@@ -19639,7 +20037,34 @@ class SkillsManager {
|
|
|
19639
20037
|
}
|
|
19640
20038
|
if (options2.skills && options2.skills.length > 0) {
|
|
19641
20039
|
const names = new Set(options2.skills.map((skill) => skill.toLowerCase()));
|
|
19642
|
-
skills2 = skills2.filter((skill) => names.has(skill.name.toLowerCase()));
|
|
20040
|
+
skills2 = skills2.filter((skill) => names.has(skill.name.toLowerCase()) || names.has(this.withSkillPrefix(skill.name, normalizedPrefix).toLowerCase()));
|
|
20041
|
+
}
|
|
20042
|
+
const prefixed = await this.applyPrefixToSkills(skills2, normalizedPrefix);
|
|
20043
|
+
skills2 = prefixed.skills;
|
|
20044
|
+
prefixedCleanup = prefixed.cleanup;
|
|
20045
|
+
const result = { installed: [], updated: [], unchanged: [], skipped: [], warnings: [...context.warnings] };
|
|
20046
|
+
if (options2.scan !== false) {
|
|
20047
|
+
const scannedWarnings = new Set;
|
|
20048
|
+
const scannableSkills = [];
|
|
20049
|
+
for (const skill of skills2) {
|
|
20050
|
+
const scan = await this.skillScanner.scanSkill(skill);
|
|
20051
|
+
if (scan.findings.length === 0) {
|
|
20052
|
+
scannableSkills.push(skill);
|
|
20053
|
+
continue;
|
|
20054
|
+
}
|
|
20055
|
+
if (scan.blocked && !options2.allowRisky) {
|
|
20056
|
+
result.skipped.push({
|
|
20057
|
+
skill,
|
|
20058
|
+
reason: this.skillScanner.formatBlockingReason(scan)
|
|
20059
|
+
});
|
|
20060
|
+
continue;
|
|
20061
|
+
}
|
|
20062
|
+
const summary = this.skillScanner.formatShortSummary(scan);
|
|
20063
|
+
scannedWarnings.add(scan.blocked ? `Proceeding with "${skill.name}" despite high-risk findings: ${summary}` : `Security warnings for "${skill.name}": ${summary}`);
|
|
20064
|
+
scannableSkills.push(skill);
|
|
20065
|
+
}
|
|
20066
|
+
skills2 = scannableSkills;
|
|
20067
|
+
result.warnings.push(...scannedWarnings);
|
|
19643
20068
|
}
|
|
19644
20069
|
const installToSharedStore = options2.agents?.includes(SHARED_SKILLS_TARGET_ID) ?? false;
|
|
19645
20070
|
const agents = await this.getTargetAgents(projectPath, options2);
|
|
@@ -19648,11 +20073,13 @@ class SkillsManager {
|
|
|
19648
20073
|
installed: [],
|
|
19649
20074
|
updated: [],
|
|
19650
20075
|
unchanged: [],
|
|
19651
|
-
skipped:
|
|
19652
|
-
|
|
20076
|
+
skipped: [
|
|
20077
|
+
...result.skipped,
|
|
20078
|
+
...skills2.map((skill) => ({ skill, reason: "No target agents found" }))
|
|
20079
|
+
],
|
|
20080
|
+
warnings: result.warnings
|
|
19653
20081
|
};
|
|
19654
20082
|
}
|
|
19655
|
-
const result = { installed: [], updated: [], unchanged: [], skipped: [], warnings: context.warnings };
|
|
19656
20083
|
const installableAgents = [];
|
|
19657
20084
|
const comparisonCache = new Map;
|
|
19658
20085
|
const pendingUpdates = [];
|
|
@@ -19762,6 +20189,7 @@ class SkillsManager {
|
|
|
19762
20189
|
type: resolvedSource.type,
|
|
19763
20190
|
...resolvedSource.marketplace ? { marketplace: resolvedSource.marketplace } : {},
|
|
19764
20191
|
...resolvedSource.pluginName ? { pluginName: resolvedSource.pluginName } : {},
|
|
20192
|
+
...normalizedPrefix ? { prefix: normalizedPrefix } : {},
|
|
19765
20193
|
...resolvedSource.url ? { url: resolvedSource.url } : {},
|
|
19766
20194
|
...resolvedSource.path ? { path: resolve9(projectPath, expandTilde(resolvedSource.path)) } : {},
|
|
19767
20195
|
...resolvedSource.owner ? { owner: resolvedSource.owner } : {},
|
|
@@ -19793,6 +20221,7 @@ class SkillsManager {
|
|
|
19793
20221
|
}
|
|
19794
20222
|
return result;
|
|
19795
20223
|
} finally {
|
|
20224
|
+
await prefixedCleanup();
|
|
19796
20225
|
await context.cleanup();
|
|
19797
20226
|
}
|
|
19798
20227
|
}
|
|
@@ -19815,11 +20244,11 @@ class SkillsManager {
|
|
|
19815
20244
|
continue;
|
|
19816
20245
|
const entries = await listFiles(dir);
|
|
19817
20246
|
for (const entry of entries) {
|
|
19818
|
-
const entryPath =
|
|
20247
|
+
const entryPath = join7(dir, entry);
|
|
19819
20248
|
if (!await isDirectory(entryPath))
|
|
19820
20249
|
continue;
|
|
19821
|
-
const skillMdPath =
|
|
19822
|
-
const skillMdPathLower =
|
|
20250
|
+
const skillMdPath = join7(entryPath, "SKILL.md");
|
|
20251
|
+
const skillMdPathLower = join7(entryPath, "skill.md");
|
|
19823
20252
|
const skillFile = await fileExists(skillMdPath) ? skillMdPath : await fileExists(skillMdPathLower) ? skillMdPathLower : null;
|
|
19824
20253
|
if (!skillFile)
|
|
19825
20254
|
continue;
|
|
@@ -19829,7 +20258,7 @@ class SkillsManager {
|
|
|
19829
20258
|
let isSymlink = false;
|
|
19830
20259
|
let canonicalPath;
|
|
19831
20260
|
try {
|
|
19832
|
-
const stat = await
|
|
20261
|
+
const stat = await fs27.lstat(entryPath);
|
|
19833
20262
|
isSymlink = stat.isSymbolicLink();
|
|
19834
20263
|
const canonicalBase = this.getCanonicalSkillsDir(projectPath, scope === "global");
|
|
19835
20264
|
const [resolvedEntryPath, resolvedCanonicalBase] = await Promise.all([
|
|
@@ -19866,14 +20295,14 @@ class SkillsManager {
|
|
|
19866
20295
|
continue;
|
|
19867
20296
|
const entries = await listFiles(canonicalDir);
|
|
19868
20297
|
for (const entry of entries) {
|
|
19869
|
-
const entryPath =
|
|
20298
|
+
const entryPath = join7(canonicalDir, entry);
|
|
19870
20299
|
if (!await isDirectory(entryPath))
|
|
19871
20300
|
continue;
|
|
19872
20301
|
const resolvedEntryPath = resolve9(entryPath);
|
|
19873
20302
|
if (referencedCanonicalPaths.has(resolvedEntryPath))
|
|
19874
20303
|
continue;
|
|
19875
|
-
const skillMdPath =
|
|
19876
|
-
const skillMdPathLower =
|
|
20304
|
+
const skillMdPath = join7(entryPath, "SKILL.md");
|
|
20305
|
+
const skillMdPathLower = join7(entryPath, "skill.md");
|
|
19877
20306
|
const skillFile = await fileExists(skillMdPath) ? skillMdPath : await fileExists(skillMdPathLower) ? skillMdPathLower : null;
|
|
19878
20307
|
if (!skillFile)
|
|
19879
20308
|
continue;
|
|
@@ -19940,7 +20369,7 @@ class SkillsManager {
|
|
|
19940
20369
|
}
|
|
19941
20370
|
if (!removedPaths.has(entry.path)) {
|
|
19942
20371
|
try {
|
|
19943
|
-
await
|
|
20372
|
+
await fs27.rm(entry.path, { recursive: true, force: true });
|
|
19944
20373
|
removedPaths.add(entry.path);
|
|
19945
20374
|
} catch {
|
|
19946
20375
|
skipped.push({
|
|
@@ -19953,7 +20382,7 @@ class SkillsManager {
|
|
|
19953
20382
|
if (entry.canonicalPath && entry.canonicalPath !== entry.path && !removedCanonicalPaths.has(entry.canonicalPath)) {
|
|
19954
20383
|
const stillReferenced = remainingEntries.some((other) => other.name.toLowerCase() === entry.name.toLowerCase() && other.canonicalPath === entry.canonicalPath);
|
|
19955
20384
|
if (!stillReferenced) {
|
|
19956
|
-
await
|
|
20385
|
+
await fs27.rm(entry.canonicalPath, { recursive: true, force: true }).catch(() => {
|
|
19957
20386
|
});
|
|
19958
20387
|
removedCanonicalPaths.add(entry.canonicalPath);
|
|
19959
20388
|
}
|
|
@@ -19999,6 +20428,7 @@ var init_skillsManager = __esm(() => {
|
|
|
19999
20428
|
init_paths();
|
|
20000
20429
|
init_agentManager();
|
|
20001
20430
|
init_marketplaceRegistry();
|
|
20431
|
+
init_skillSecurityScanner();
|
|
20002
20432
|
init_skills();
|
|
20003
20433
|
init_installLock();
|
|
20004
20434
|
execFileAsync = promisify(execFile);
|
|
@@ -20884,51 +21314,51 @@ var require_uri_all = __commonJS((exports, module) => {
|
|
|
20884
21314
|
}
|
|
20885
21315
|
return uriTokens.join("");
|
|
20886
21316
|
}
|
|
20887
|
-
function resolveComponents(base2,
|
|
21317
|
+
function resolveComponents(base2, relative7) {
|
|
20888
21318
|
var options2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
20889
21319
|
var skipNormalization = arguments[3];
|
|
20890
21320
|
var target = {};
|
|
20891
21321
|
if (!skipNormalization) {
|
|
20892
21322
|
base2 = parse4(serialize(base2, options2), options2);
|
|
20893
|
-
|
|
21323
|
+
relative7 = parse4(serialize(relative7, options2), options2);
|
|
20894
21324
|
}
|
|
20895
21325
|
options2 = options2 || {};
|
|
20896
|
-
if (!options2.tolerant &&
|
|
20897
|
-
target.scheme =
|
|
20898
|
-
target.userinfo =
|
|
20899
|
-
target.host =
|
|
20900
|
-
target.port =
|
|
20901
|
-
target.path = removeDotSegments(
|
|
20902
|
-
target.query =
|
|
21326
|
+
if (!options2.tolerant && relative7.scheme) {
|
|
21327
|
+
target.scheme = relative7.scheme;
|
|
21328
|
+
target.userinfo = relative7.userinfo;
|
|
21329
|
+
target.host = relative7.host;
|
|
21330
|
+
target.port = relative7.port;
|
|
21331
|
+
target.path = removeDotSegments(relative7.path || "");
|
|
21332
|
+
target.query = relative7.query;
|
|
20903
21333
|
} else {
|
|
20904
|
-
if (
|
|
20905
|
-
target.userinfo =
|
|
20906
|
-
target.host =
|
|
20907
|
-
target.port =
|
|
20908
|
-
target.path = removeDotSegments(
|
|
20909
|
-
target.query =
|
|
21334
|
+
if (relative7.userinfo !== undefined || relative7.host !== undefined || relative7.port !== undefined) {
|
|
21335
|
+
target.userinfo = relative7.userinfo;
|
|
21336
|
+
target.host = relative7.host;
|
|
21337
|
+
target.port = relative7.port;
|
|
21338
|
+
target.path = removeDotSegments(relative7.path || "");
|
|
21339
|
+
target.query = relative7.query;
|
|
20910
21340
|
} else {
|
|
20911
|
-
if (!
|
|
21341
|
+
if (!relative7.path) {
|
|
20912
21342
|
target.path = base2.path;
|
|
20913
|
-
if (
|
|
20914
|
-
target.query =
|
|
21343
|
+
if (relative7.query !== undefined) {
|
|
21344
|
+
target.query = relative7.query;
|
|
20915
21345
|
} else {
|
|
20916
21346
|
target.query = base2.query;
|
|
20917
21347
|
}
|
|
20918
21348
|
} else {
|
|
20919
|
-
if (
|
|
20920
|
-
target.path = removeDotSegments(
|
|
21349
|
+
if (relative7.path.charAt(0) === "/") {
|
|
21350
|
+
target.path = removeDotSegments(relative7.path);
|
|
20921
21351
|
} else {
|
|
20922
21352
|
if ((base2.userinfo !== undefined || base2.host !== undefined || base2.port !== undefined) && !base2.path) {
|
|
20923
|
-
target.path = "/" +
|
|
21353
|
+
target.path = "/" + relative7.path;
|
|
20924
21354
|
} else if (!base2.path) {
|
|
20925
|
-
target.path =
|
|
21355
|
+
target.path = relative7.path;
|
|
20926
21356
|
} else {
|
|
20927
|
-
target.path = base2.path.slice(0, base2.path.lastIndexOf("/") + 1) +
|
|
21357
|
+
target.path = base2.path.slice(0, base2.path.lastIndexOf("/") + 1) + relative7.path;
|
|
20928
21358
|
}
|
|
20929
21359
|
target.path = removeDotSegments(target.path);
|
|
20930
21360
|
}
|
|
20931
|
-
target.query =
|
|
21361
|
+
target.query = relative7.query;
|
|
20932
21362
|
}
|
|
20933
21363
|
target.userinfo = base2.userinfo;
|
|
20934
21364
|
target.host = base2.host;
|
|
@@ -20936,7 +21366,7 @@ var require_uri_all = __commonJS((exports, module) => {
|
|
|
20936
21366
|
}
|
|
20937
21367
|
target.scheme = base2.scheme;
|
|
20938
21368
|
}
|
|
20939
|
-
target.fragment =
|
|
21369
|
+
target.fragment = relative7.fragment;
|
|
20940
21370
|
return target;
|
|
20941
21371
|
}
|
|
20942
21372
|
function resolve13(baseURI, relativeURI, options2) {
|
|
@@ -26215,27 +26645,27 @@ var require_windows = __commonJS((exports, module) => {
|
|
|
26215
26645
|
return checkPathExt(path, options2);
|
|
26216
26646
|
};
|
|
26217
26647
|
var isexe = function(path, options2, cb) {
|
|
26218
|
-
|
|
26648
|
+
fs34.stat(path, function(er, stat) {
|
|
26219
26649
|
cb(er, er ? false : checkStat(stat, path, options2));
|
|
26220
26650
|
});
|
|
26221
26651
|
};
|
|
26222
26652
|
var sync = function(path, options2) {
|
|
26223
|
-
return checkStat(
|
|
26653
|
+
return checkStat(fs34.statSync(path), path, options2);
|
|
26224
26654
|
};
|
|
26225
26655
|
module.exports = isexe;
|
|
26226
26656
|
isexe.sync = sync;
|
|
26227
|
-
var
|
|
26657
|
+
var fs34 = __require("fs");
|
|
26228
26658
|
});
|
|
26229
26659
|
|
|
26230
26660
|
// node_modules/isexe/mode.js
|
|
26231
26661
|
var require_mode = __commonJS((exports, module) => {
|
|
26232
26662
|
var isexe = function(path, options2, cb) {
|
|
26233
|
-
|
|
26663
|
+
fs34.stat(path, function(er, stat) {
|
|
26234
26664
|
cb(er, er ? false : checkStat(stat, options2));
|
|
26235
26665
|
});
|
|
26236
26666
|
};
|
|
26237
26667
|
var sync = function(path, options2) {
|
|
26238
|
-
return checkStat(
|
|
26668
|
+
return checkStat(fs34.statSync(path), options2);
|
|
26239
26669
|
};
|
|
26240
26670
|
var checkStat = function(stat, options2) {
|
|
26241
26671
|
return stat.isFile() && checkMode(stat, options2);
|
|
@@ -26255,7 +26685,7 @@ var require_mode = __commonJS((exports, module) => {
|
|
|
26255
26685
|
};
|
|
26256
26686
|
module.exports = isexe;
|
|
26257
26687
|
isexe.sync = sync;
|
|
26258
|
-
var
|
|
26688
|
+
var fs34 = __require("fs");
|
|
26259
26689
|
});
|
|
26260
26690
|
|
|
26261
26691
|
// node_modules/isexe/index.js
|
|
@@ -26300,7 +26730,7 @@ var require_isexe = __commonJS((exports, module) => {
|
|
|
26300
26730
|
}
|
|
26301
26731
|
}
|
|
26302
26732
|
};
|
|
26303
|
-
var
|
|
26733
|
+
var fs34 = __require("fs");
|
|
26304
26734
|
var core2;
|
|
26305
26735
|
if (process.platform === "win32" || global.TESTING_WINDOWS) {
|
|
26306
26736
|
core2 = require_windows();
|
|
@@ -26507,14 +26937,14 @@ var require_readShebang = __commonJS((exports, module) => {
|
|
|
26507
26937
|
const buffer = Buffer.alloc(size);
|
|
26508
26938
|
let fd;
|
|
26509
26939
|
try {
|
|
26510
|
-
fd =
|
|
26511
|
-
|
|
26512
|
-
|
|
26940
|
+
fd = fs34.openSync(command, "r");
|
|
26941
|
+
fs34.readSync(fd, buffer, 0, size, 0);
|
|
26942
|
+
fs34.closeSync(fd);
|
|
26513
26943
|
} catch (e) {
|
|
26514
26944
|
}
|
|
26515
26945
|
return shebangCommand(buffer.toString());
|
|
26516
26946
|
};
|
|
26517
|
-
var
|
|
26947
|
+
var fs34 = __require("fs");
|
|
26518
26948
|
var shebangCommand = require_shebang_command();
|
|
26519
26949
|
module.exports = readShebang;
|
|
26520
26950
|
});
|
|
@@ -28698,11 +29128,11 @@ async function detectCommand(options2) {
|
|
|
28698
29128
|
|
|
28699
29129
|
// dist/commands/sync.js
|
|
28700
29130
|
init_logger();
|
|
28701
|
-
import {relative as
|
|
29131
|
+
import {relative as relative6} from "path";
|
|
28702
29132
|
|
|
28703
29133
|
// dist/core/propagator.js
|
|
28704
29134
|
var import_gray_matter3 = __toESM(require_gray_matter(), 1);
|
|
28705
|
-
import {promises as
|
|
29135
|
+
import {promises as fs29} from "fs";
|
|
28706
29136
|
import {resolve as resolve10} from "path";
|
|
28707
29137
|
|
|
28708
29138
|
// node_modules/js-yaml/dist/js-yaml.mjs
|
|
@@ -31470,7 +31900,7 @@ class Propagator {
|
|
|
31470
31900
|
resolvedTargets: []
|
|
31471
31901
|
};
|
|
31472
31902
|
const exists = await fileExists(generatedFile.path);
|
|
31473
|
-
const existingStats = exists ? await
|
|
31903
|
+
const existingStats = exists ? await fs29.lstat(generatedFile.path).catch(() => null) : null;
|
|
31474
31904
|
const existingContent = exists && !existingStats?.isSymbolicLink() ? await readFileIfExists(generatedFile.path) : null;
|
|
31475
31905
|
const existingTarget = existingStats?.isSymbolicLink() ? await readSymlinkTarget(generatedFile.path) : null;
|
|
31476
31906
|
if (options2.managedState && !options2.dryRun) {
|
|
@@ -31501,7 +31931,7 @@ class Propagator {
|
|
|
31501
31931
|
if (!options2.dryRun) {
|
|
31502
31932
|
if (generatedFile.kind === "file") {
|
|
31503
31933
|
if (existingStats?.isSymbolicLink()) {
|
|
31504
|
-
await
|
|
31934
|
+
await fs29.rm(generatedFile.path, { force: true }).catch(() => {
|
|
31505
31935
|
});
|
|
31506
31936
|
}
|
|
31507
31937
|
await writeFile(generatedFile.path, generatedFile.content || "");
|
|
@@ -31678,14 +32108,14 @@ ${content}
|
|
|
31678
32108
|
|
|
31679
32109
|
// dist/core/managedState.js
|
|
31680
32110
|
init_fs();
|
|
31681
|
-
import {promises as
|
|
31682
|
-
import {dirname as dirname5, join as
|
|
32111
|
+
import {promises as fs31} from "fs";
|
|
32112
|
+
import {dirname as dirname5, join as join8, relative as relative5, resolve as resolve11} from "path";
|
|
31683
32113
|
var toPosixPath = function(value) {
|
|
31684
32114
|
return value.replace(/\\/g, "/");
|
|
31685
32115
|
};
|
|
31686
32116
|
async function pathType(targetPath) {
|
|
31687
32117
|
try {
|
|
31688
|
-
const stat = await
|
|
32118
|
+
const stat = await fs31.lstat(targetPath);
|
|
31689
32119
|
if (stat.isSymbolicLink()) {
|
|
31690
32120
|
return "symlink";
|
|
31691
32121
|
}
|
|
@@ -31695,20 +32125,20 @@ async function pathType(targetPath) {
|
|
|
31695
32125
|
}
|
|
31696
32126
|
}
|
|
31697
32127
|
async function copyDirectory(src, dest) {
|
|
31698
|
-
await
|
|
31699
|
-
const entries = await
|
|
32128
|
+
await fs31.mkdir(dest, { recursive: true });
|
|
32129
|
+
const entries = await fs31.readdir(src, { withFileTypes: true });
|
|
31700
32130
|
for (const entry of entries) {
|
|
31701
|
-
const srcPath =
|
|
31702
|
-
const destPath =
|
|
32131
|
+
const srcPath = join8(src, entry.name);
|
|
32132
|
+
const destPath = join8(dest, entry.name);
|
|
31703
32133
|
if (entry.isDirectory()) {
|
|
31704
32134
|
await copyDirectory(srcPath, destPath);
|
|
31705
32135
|
} else if (entry.isSymbolicLink()) {
|
|
31706
|
-
const target = await
|
|
31707
|
-
await
|
|
31708
|
-
await
|
|
32136
|
+
const target = await fs31.readlink(srcPath);
|
|
32137
|
+
await fs31.mkdir(dirname5(destPath), { recursive: true });
|
|
32138
|
+
await fs31.symlink(target, destPath);
|
|
31709
32139
|
} else {
|
|
31710
|
-
await
|
|
31711
|
-
await
|
|
32140
|
+
await fs31.mkdir(dirname5(destPath), { recursive: true });
|
|
32141
|
+
await fs31.copyFile(srcPath, destPath);
|
|
31712
32142
|
}
|
|
31713
32143
|
}
|
|
31714
32144
|
}
|
|
@@ -31717,14 +32147,14 @@ async function copyPath(src, dest) {
|
|
|
31717
32147
|
if (!type2) {
|
|
31718
32148
|
return;
|
|
31719
32149
|
}
|
|
31720
|
-
await
|
|
32150
|
+
await fs31.mkdir(dirname5(dest), { recursive: true });
|
|
31721
32151
|
if (type2 === "symlink") {
|
|
31722
|
-
const target = await
|
|
31723
|
-
await
|
|
32152
|
+
const target = await fs31.readlink(src);
|
|
32153
|
+
await fs31.symlink(target, dest);
|
|
31724
32154
|
} else if (type2 === "directory") {
|
|
31725
32155
|
await copyDirectory(src, dest);
|
|
31726
32156
|
} else {
|
|
31727
|
-
await
|
|
32157
|
+
await fs31.copyFile(src, dest);
|
|
31728
32158
|
}
|
|
31729
32159
|
}
|
|
31730
32160
|
var MANAGED_STATE_FILE = "managed-state.json";
|
|
@@ -31738,11 +32168,11 @@ class ManagedStateStore {
|
|
|
31738
32168
|
this.state = state;
|
|
31739
32169
|
}
|
|
31740
32170
|
static async open(projectPath) {
|
|
31741
|
-
const agentInitDir =
|
|
31742
|
-
const statePath =
|
|
32171
|
+
const agentInitDir = join8(projectPath, ".agentinit");
|
|
32172
|
+
const statePath = join8(agentInitDir, MANAGED_STATE_FILE);
|
|
31743
32173
|
const emptyState = { version: 1, entries: [] };
|
|
31744
32174
|
try {
|
|
31745
|
-
const raw = await
|
|
32175
|
+
const raw = await fs31.readFile(statePath, "utf8");
|
|
31746
32176
|
const parsed = JSON.parse(raw);
|
|
31747
32177
|
if (!parsed || parsed.version !== 1 || !Array.isArray(parsed.entries)) {
|
|
31748
32178
|
return new ManagedStateStore(projectPath, emptyState);
|
|
@@ -31753,17 +32183,17 @@ class ManagedStateStore {
|
|
|
31753
32183
|
}
|
|
31754
32184
|
}
|
|
31755
32185
|
get agentInitDir() {
|
|
31756
|
-
return
|
|
32186
|
+
return join8(this.projectPath, ".agentinit");
|
|
31757
32187
|
}
|
|
31758
32188
|
get stateFilePath() {
|
|
31759
|
-
return
|
|
32189
|
+
return join8(this.agentInitDir, MANAGED_STATE_FILE);
|
|
31760
32190
|
}
|
|
31761
32191
|
get backupsDir() {
|
|
31762
|
-
return
|
|
32192
|
+
return join8(this.agentInitDir, BACKUPS_DIR);
|
|
31763
32193
|
}
|
|
31764
32194
|
normalizeRelativePath(targetPath, preserveTrailingSlash = false) {
|
|
31765
32195
|
const hasTrailingSlash = preserveTrailingSlash && /[\\/]$/.test(targetPath);
|
|
31766
|
-
const relativePath =
|
|
32196
|
+
const relativePath = relative5(this.projectPath, resolve11(targetPath));
|
|
31767
32197
|
const normalizedPath = toPosixPath(relativePath);
|
|
31768
32198
|
if (hasTrailingSlash && normalizedPath) {
|
|
31769
32199
|
return normalizedPath.endsWith("/") ? normalizedPath : `${normalizedPath}/`;
|
|
@@ -31781,14 +32211,14 @@ class ManagedStateStore {
|
|
|
31781
32211
|
}
|
|
31782
32212
|
if (type2 === "symlink") {
|
|
31783
32213
|
try {
|
|
31784
|
-
const backupLinkTarget = await
|
|
32214
|
+
const backupLinkTarget = await fs31.readlink(targetPath);
|
|
31785
32215
|
return { backupLinkTarget };
|
|
31786
32216
|
} catch {
|
|
31787
32217
|
return {};
|
|
31788
32218
|
}
|
|
31789
32219
|
}
|
|
31790
32220
|
const relativeTargetPath = this.normalizeRelativePath(targetPath);
|
|
31791
|
-
const backupPath =
|
|
32221
|
+
const backupPath = join8(this.backupsDir, relativeTargetPath);
|
|
31792
32222
|
if (!await fileExists(backupPath)) {
|
|
31793
32223
|
await copyPath(targetPath, backupPath);
|
|
31794
32224
|
}
|
|
@@ -31835,8 +32265,8 @@ class ManagedStateStore {
|
|
|
31835
32265
|
return [...paths6];
|
|
31836
32266
|
}
|
|
31837
32267
|
async save() {
|
|
31838
|
-
await
|
|
31839
|
-
await
|
|
32268
|
+
await fs31.mkdir(this.agentInitDir, { recursive: true });
|
|
32269
|
+
await fs31.writeFile(this.stateFilePath, JSON.stringify(this.state, null, 2), "utf8");
|
|
31840
32270
|
}
|
|
31841
32271
|
async revertAll(options2 = {}) {
|
|
31842
32272
|
const summary = {
|
|
@@ -31851,29 +32281,29 @@ class ManagedStateStore {
|
|
|
31851
32281
|
const backupLinkTarget = entry.backupLinkTarget;
|
|
31852
32282
|
if (entry.existedBefore && backupLinkTarget !== undefined) {
|
|
31853
32283
|
if (!options2.dryRun) {
|
|
31854
|
-
await
|
|
32284
|
+
await fs31.rm(absolutePath, { recursive: true, force: true }).catch(() => {
|
|
31855
32285
|
});
|
|
31856
|
-
await
|
|
31857
|
-
await
|
|
32286
|
+
await fs31.mkdir(dirname5(absolutePath), { recursive: true });
|
|
32287
|
+
await fs31.symlink(backupLinkTarget, absolutePath);
|
|
31858
32288
|
}
|
|
31859
32289
|
summary.restored++;
|
|
31860
32290
|
} else if (entry.existedBefore && backupPath && await fileExists(backupPath)) {
|
|
31861
32291
|
if (!options2.dryRun) {
|
|
31862
|
-
await
|
|
32292
|
+
await fs31.rm(absolutePath, { recursive: true, force: true }).catch(() => {
|
|
31863
32293
|
});
|
|
31864
32294
|
await copyPath(backupPath, absolutePath);
|
|
31865
32295
|
}
|
|
31866
32296
|
summary.restored++;
|
|
31867
32297
|
} else {
|
|
31868
32298
|
if (!options2.dryRun) {
|
|
31869
|
-
await
|
|
32299
|
+
await fs31.rm(absolutePath, { recursive: true, force: true }).catch(() => {
|
|
31870
32300
|
});
|
|
31871
32301
|
}
|
|
31872
32302
|
summary.removed++;
|
|
31873
32303
|
}
|
|
31874
32304
|
if (!options2.keepBackups && backupPath && await fileExists(backupPath)) {
|
|
31875
32305
|
if (!options2.dryRun) {
|
|
31876
|
-
await
|
|
32306
|
+
await fs31.rm(backupPath, { recursive: true, force: true }).catch(() => {
|
|
31877
32307
|
});
|
|
31878
32308
|
}
|
|
31879
32309
|
summary.backupsRemoved++;
|
|
@@ -31881,16 +32311,16 @@ class ManagedStateStore {
|
|
|
31881
32311
|
}
|
|
31882
32312
|
if (!options2.dryRun) {
|
|
31883
32313
|
this.state.entries.length = 0;
|
|
31884
|
-
await
|
|
32314
|
+
await fs31.rm(this.stateFilePath, { force: true }).catch(() => {
|
|
31885
32315
|
});
|
|
31886
32316
|
if (!options2.keepBackups) {
|
|
31887
|
-
await
|
|
32317
|
+
await fs31.rm(this.backupsDir, { recursive: true, force: true }).catch(() => {
|
|
31888
32318
|
});
|
|
31889
32319
|
}
|
|
31890
32320
|
try {
|
|
31891
|
-
const remainingEntries = await
|
|
32321
|
+
const remainingEntries = await fs31.readdir(this.agentInitDir);
|
|
31892
32322
|
if (remainingEntries.length === 0) {
|
|
31893
|
-
await
|
|
32323
|
+
await fs31.rm(this.agentInitDir, { recursive: true, force: true });
|
|
31894
32324
|
}
|
|
31895
32325
|
} catch {
|
|
31896
32326
|
}
|
|
@@ -31940,7 +32370,7 @@ async function syncCommand(options2) {
|
|
|
31940
32370
|
for (const change of result.changes) {
|
|
31941
32371
|
const action = change.action === "created" ? "\u2795" : change.action === "updated" ? "\uD83D\uDCDD" : "\uD83D\uDCBE";
|
|
31942
32372
|
const names = change.agents.map((id) => agentManager5.getAgentById(id)?.name || id).join(", ");
|
|
31943
|
-
logger.info(` ${action} ${
|
|
32373
|
+
logger.info(` ${action} ${relative6(cwd, change.file) || change.file}`);
|
|
31944
32374
|
logger.info(` Agents: ${names}`);
|
|
31945
32375
|
}
|
|
31946
32376
|
if (options2.backup && result.changes.some((c) => c.action === "backed_up")) {
|
|
@@ -31971,7 +32401,7 @@ async function syncCommand(options2) {
|
|
|
31971
32401
|
// dist/commands/apply.js
|
|
31972
32402
|
init_colors();
|
|
31973
32403
|
init_logger();
|
|
31974
|
-
import {relative as
|
|
32404
|
+
import {relative as relative7} from "path";
|
|
31975
32405
|
|
|
31976
32406
|
// dist/types/index.js
|
|
31977
32407
|
var MCPServerType;
|
|
@@ -32237,12 +32667,12 @@ class MCPParser {
|
|
|
32237
32667
|
// dist/constants/mcp.js
|
|
32238
32668
|
import {readFileSync as readFileSync2} from "fs";
|
|
32239
32669
|
import {fileURLToPath} from "url";
|
|
32240
|
-
import {dirname as dirname6, join as
|
|
32670
|
+
import {dirname as dirname6, join as join9} from "path";
|
|
32241
32671
|
var getPackageVersion = function() {
|
|
32242
32672
|
try {
|
|
32243
32673
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
32244
32674
|
const __dirname2 = dirname6(__filename2);
|
|
32245
|
-
const packageJsonPath =
|
|
32675
|
+
const packageJsonPath = join9(__dirname2, "../../package.json");
|
|
32246
32676
|
const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
|
|
32247
32677
|
return packageJson.version || "1.0.0";
|
|
32248
32678
|
} catch {
|
|
@@ -40515,11 +40945,11 @@ class MCPVerifier {
|
|
|
40515
40945
|
}
|
|
40516
40946
|
|
|
40517
40947
|
// dist/core/gitignoreManager.js
|
|
40518
|
-
import {promises as
|
|
40519
|
-
import {dirname as dirname8, join as
|
|
40948
|
+
import {promises as fs34} from "fs";
|
|
40949
|
+
import {dirname as dirname8, join as join10} from "path";
|
|
40520
40950
|
var normalizeIgnorePath = function(projectPath, value) {
|
|
40521
|
-
const
|
|
40522
|
-
const normalized =
|
|
40951
|
+
const relative7 = value.startsWith(projectPath) ? value.slice(projectPath.length + 1) : value;
|
|
40952
|
+
const normalized = relative7.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
40523
40953
|
if (!normalized) {
|
|
40524
40954
|
return normalized;
|
|
40525
40955
|
}
|
|
@@ -40563,12 +40993,12 @@ var updateManagedBlock = function(existingContent, entries) {
|
|
|
40563
40993
|
return content;
|
|
40564
40994
|
};
|
|
40565
40995
|
async function updateManagedIgnoreFile(projectPath, paths6, options2 = {}) {
|
|
40566
|
-
const ignoreFile = options2.local ?
|
|
40567
|
-
const ignoreFilePath =
|
|
40996
|
+
const ignoreFile = options2.local ? join10(".git", "info", "exclude") : ".gitignore";
|
|
40997
|
+
const ignoreFilePath = join10(projectPath, ignoreFile);
|
|
40568
40998
|
if (options2.local) {
|
|
40569
|
-
const gitDir =
|
|
40999
|
+
const gitDir = join10(projectPath, ".git");
|
|
40570
41000
|
try {
|
|
40571
|
-
const stat = await
|
|
41001
|
+
const stat = await fs34.stat(gitDir);
|
|
40572
41002
|
if (!stat.isDirectory()) {
|
|
40573
41003
|
throw new Error;
|
|
40574
41004
|
}
|
|
@@ -40579,21 +41009,21 @@ async function updateManagedIgnoreFile(projectPath, paths6, options2 = {}) {
|
|
|
40579
41009
|
const normalizedPaths = [...new Set(paths6.map((path) => normalizeIgnorePath(projectPath, path)).filter(Boolean))].sort();
|
|
40580
41010
|
let existingContent = "";
|
|
40581
41011
|
try {
|
|
40582
|
-
existingContent = await
|
|
41012
|
+
existingContent = await fs34.readFile(ignoreFilePath, "utf8");
|
|
40583
41013
|
} catch {
|
|
40584
41014
|
existingContent = "";
|
|
40585
41015
|
}
|
|
40586
41016
|
const updatedContent = updateManagedBlock(existingContent, normalizedPaths);
|
|
40587
|
-
await
|
|
40588
|
-
await
|
|
41017
|
+
await fs34.mkdir(dirname8(ignoreFilePath), { recursive: true });
|
|
41018
|
+
await fs34.writeFile(ignoreFilePath, updatedContent, "utf8");
|
|
40589
41019
|
return ignoreFilePath;
|
|
40590
41020
|
}
|
|
40591
41021
|
async function removeManagedIgnoreBlock(projectPath, options2 = {}) {
|
|
40592
|
-
const ignoreFile = options2.local ?
|
|
40593
|
-
const ignoreFilePath =
|
|
41022
|
+
const ignoreFile = options2.local ? join10(".git", "info", "exclude") : ".gitignore";
|
|
41023
|
+
const ignoreFilePath = join10(projectPath, ignoreFile);
|
|
40594
41024
|
let content;
|
|
40595
41025
|
try {
|
|
40596
|
-
content = await
|
|
41026
|
+
content = await fs34.readFile(ignoreFilePath, "utf8");
|
|
40597
41027
|
} catch {
|
|
40598
41028
|
return false;
|
|
40599
41029
|
}
|
|
@@ -40609,13 +41039,13 @@ async function removeManagedIgnoreBlock(projectPath, options2 = {}) {
|
|
|
40609
41039
|
const afterBlock = content.slice(endIndex + END_MARKER.length).replace(/^\n+/, "");
|
|
40610
41040
|
let nextContent = `${beforeBlock}${afterBlock}`.replace(/\n{3,}/g, "\n\n").replace(/^\n+/, "");
|
|
40611
41041
|
if (nextContent.trim() === "") {
|
|
40612
|
-
await
|
|
41042
|
+
await fs34.rm(ignoreFilePath, { force: true }).catch(() => {
|
|
40613
41043
|
});
|
|
40614
41044
|
} else {
|
|
40615
41045
|
if (!nextContent.endsWith("\n")) {
|
|
40616
41046
|
nextContent += "\n";
|
|
40617
41047
|
}
|
|
40618
|
-
await
|
|
41048
|
+
await fs34.writeFile(ignoreFilePath, nextContent, "utf8");
|
|
40619
41049
|
}
|
|
40620
41050
|
return true;
|
|
40621
41051
|
}
|
|
@@ -40626,12 +41056,12 @@ var END_MARKER = "# END AgentInit Generated Files";
|
|
|
40626
41056
|
init_agentManager();
|
|
40627
41057
|
init_skillsManager();
|
|
40628
41058
|
init_fs();
|
|
40629
|
-
import {dirname as dirname9, join as
|
|
41059
|
+
import {dirname as dirname9, join as join11} from "path";
|
|
40630
41060
|
async function discoverProjectSkills(projectPath, skillsManager4) {
|
|
40631
41061
|
const sources = [];
|
|
40632
41062
|
const skills2 = new Map;
|
|
40633
41063
|
for (const sourceDir of PROJECT_SKILL_SOURCE_DIRS) {
|
|
40634
|
-
const absoluteSourceDir =
|
|
41064
|
+
const absoluteSourceDir = join11(projectPath, sourceDir);
|
|
40635
41065
|
if (!await fileExists(absoluteSourceDir)) {
|
|
40636
41066
|
continue;
|
|
40637
41067
|
}
|
|
@@ -40815,7 +41245,7 @@ async function applyProjectCommand(options2) {
|
|
|
40815
41245
|
if (change.action === "backed_up")
|
|
40816
41246
|
return;
|
|
40817
41247
|
const names = change.agents.map((id) => agentManager7.getAgentById(id)?.name || id).join(", ");
|
|
40818
|
-
logger.info(` ${
|
|
41248
|
+
logger.info(` ${relative7(cwd, change.file) || change.file}`);
|
|
40819
41249
|
logger.info(` Agents: ${names}`);
|
|
40820
41250
|
});
|
|
40821
41251
|
}
|
|
@@ -40833,7 +41263,7 @@ async function applyProjectCommand(options2) {
|
|
|
40833
41263
|
installsByPath.set(item.path, existing);
|
|
40834
41264
|
}
|
|
40835
41265
|
for (const [path, details] of installsByPath) {
|
|
40836
|
-
logger.info(` ${
|
|
41266
|
+
logger.info(` ${relative7(cwd, path) || path}`);
|
|
40837
41267
|
logger.info(` Agents: ${[...details.agents].join(", ")}`);
|
|
40838
41268
|
logger.info(` Skills: ${[...details.skills].join(", ")}`);
|
|
40839
41269
|
}
|
|
@@ -41720,44 +42150,87 @@ var import_prompts3 = __toESM(require_prompts3(), 1);
|
|
|
41720
42150
|
init_colors();
|
|
41721
42151
|
init_logger();
|
|
41722
42152
|
import {homedir as homedir7} from "os";
|
|
41723
|
-
import {relative as
|
|
42153
|
+
import {relative as relative8, resolve as resolve13} from "path";
|
|
41724
42154
|
|
|
41725
42155
|
// dist/utils/promptUtils.js
|
|
41726
42156
|
var import_prompts2 = __toESM(require_prompts3(), 1);
|
|
41727
|
-
import {createRequire as createRequire2} from "module";
|
|
41728
42157
|
init_logger();
|
|
41729
|
-
function enableUppercaseToggleAllForMultiselectPrompt() {
|
|
41730
|
-
if (
|
|
42158
|
+
function enableUppercaseToggleAllForMultiselectPrompt(prompt) {
|
|
42159
|
+
if (prompt.__agentinitUppercaseToggleAllPatched || typeof prompt._ !== "function") {
|
|
41731
42160
|
return;
|
|
41732
42161
|
}
|
|
41733
|
-
|
|
41734
|
-
|
|
41735
|
-
|
|
41736
|
-
const prototype = MultiselectPrompt?.prototype;
|
|
41737
|
-
if (!prototype || typeof prototype._ !== "function" || prototype.__agentinitUppercaseToggleAllPatched) {
|
|
42162
|
+
const originalHandler = prompt._;
|
|
42163
|
+
prompt._ = function agentinitMultiselectHandler(input, key) {
|
|
42164
|
+
if (this.__agentinitHotkeyBusy) {
|
|
41738
42165
|
return;
|
|
41739
42166
|
}
|
|
41740
|
-
const
|
|
41741
|
-
|
|
41742
|
-
|
|
41743
|
-
|
|
41744
|
-
|
|
41745
|
-
|
|
41746
|
-
|
|
41747
|
-
|
|
41748
|
-
|
|
41749
|
-
}
|
|
41750
|
-
|
|
41751
|
-
}
|
|
42167
|
+
const normalizedInput = input === "A" ? "a" : input;
|
|
42168
|
+
const hotkeyHandler = this.__agentinitHotkeys?.[normalizedInput] || this.__agentinitHotkeys?.[input];
|
|
42169
|
+
if (hotkeyHandler) {
|
|
42170
|
+
this.__agentinitHotkeyBusy = true;
|
|
42171
|
+
Promise.resolve(hotkeyHandler(this, normalizedInput, key)).finally(() => {
|
|
42172
|
+
this.__agentinitHotkeyBusy = false;
|
|
42173
|
+
this.render?.();
|
|
42174
|
+
});
|
|
42175
|
+
return;
|
|
42176
|
+
}
|
|
42177
|
+
return originalHandler.call(this, normalizedInput, key);
|
|
42178
|
+
};
|
|
42179
|
+
Object.defineProperty(prompt, "__agentinitUppercaseToggleAllPatched", {
|
|
42180
|
+
value: true,
|
|
42181
|
+
configurable: false,
|
|
42182
|
+
enumerable: false,
|
|
42183
|
+
writable: false
|
|
42184
|
+
});
|
|
41752
42185
|
}
|
|
41753
42186
|
async function promptMultiselect(options2) {
|
|
41754
|
-
|
|
41755
|
-
|
|
42187
|
+
const userOnRender = options2.onRenderPrompt;
|
|
42188
|
+
const hint = options2.hint;
|
|
42189
|
+
let requestedAction;
|
|
42190
|
+
let promptInstance;
|
|
42191
|
+
const closeWithCurrentSelection = (prompt) => {
|
|
42192
|
+
if (typeof prompt.close !== "function") {
|
|
42193
|
+
return false;
|
|
42194
|
+
}
|
|
42195
|
+
prompt.done = true;
|
|
42196
|
+
prompt.aborted = false;
|
|
42197
|
+
prompt.fire?.();
|
|
42198
|
+
prompt.render?.();
|
|
42199
|
+
prompt.out?.write("\n");
|
|
42200
|
+
prompt.close();
|
|
42201
|
+
return true;
|
|
42202
|
+
};
|
|
42203
|
+
const hotkeys = options2.hotkeys ? Object.fromEntries(Object.entries(options2.hotkeys).map(([key, handler]) => [
|
|
42204
|
+
key,
|
|
42205
|
+
(prompt, input, pressedKey) => handler({
|
|
42206
|
+
prompt,
|
|
42207
|
+
requestAction: (action) => {
|
|
42208
|
+
requestedAction = action;
|
|
42209
|
+
},
|
|
42210
|
+
closeWithCurrentSelection: () => closeWithCurrentSelection(prompt)
|
|
42211
|
+
}, input, pressedKey)
|
|
42212
|
+
])) : undefined;
|
|
42213
|
+
const response = await import_prompts2.default({
|
|
41756
42214
|
...options2,
|
|
41757
42215
|
type: "multiselect",
|
|
41758
42216
|
instructions: options2.instructions ?? false,
|
|
41759
|
-
hint:
|
|
42217
|
+
hint: typeof hint === "function" ? hint() : hint ?? MULTISELECT_TOGGLE_ALL_HINT,
|
|
42218
|
+
onRender() {
|
|
42219
|
+
enableUppercaseToggleAllForMultiselectPrompt(this);
|
|
42220
|
+
promptInstance = this;
|
|
42221
|
+
if (hotkeys) {
|
|
42222
|
+
this.__agentinitHotkeys = hotkeys;
|
|
42223
|
+
} else {
|
|
42224
|
+
delete this.__agentinitHotkeys;
|
|
42225
|
+
}
|
|
42226
|
+
this.hint = typeof hint === "function" ? hint() : hint ?? MULTISELECT_TOGGLE_ALL_HINT;
|
|
42227
|
+
userOnRender?.(this);
|
|
42228
|
+
}
|
|
41760
42229
|
});
|
|
42230
|
+
if (requestedAction) {
|
|
42231
|
+
response.__agentinitAction = requestedAction;
|
|
42232
|
+
}
|
|
42233
|
+
return response;
|
|
41761
42234
|
}
|
|
41762
42235
|
async function selectBundlePlugins(entries, actionLabel, options2 = {}) {
|
|
41763
42236
|
if (options2.selectAll) {
|
|
@@ -41781,9 +42254,7 @@ async function selectBundlePlugins(entries, actionLabel, options2 = {}) {
|
|
|
41781
42254
|
}
|
|
41782
42255
|
return response.plugins;
|
|
41783
42256
|
}
|
|
41784
|
-
var require2 = createRequire2(import.meta.url);
|
|
41785
42257
|
var MULTISELECT_TOGGLE_ALL_HINT = "Press Space to select, A to select or deselect all, then Enter to confirm.";
|
|
41786
|
-
var uppercaseToggleAllPatched = false;
|
|
41787
42258
|
|
|
41788
42259
|
// dist/commands/skills.js
|
|
41789
42260
|
init_skillsManager();
|
|
@@ -41792,11 +42263,84 @@ init_marketplaceRegistry();
|
|
|
41792
42263
|
init_agentManager();
|
|
41793
42264
|
init_installLock();
|
|
41794
42265
|
init_fs();
|
|
42266
|
+
|
|
42267
|
+
// dist/utils/lockSource.js
|
|
42268
|
+
function lockSourceToSpecifier(source) {
|
|
42269
|
+
if (source.type === "marketplace" && source.marketplace && source.pluginName) {
|
|
42270
|
+
return {
|
|
42271
|
+
source: source.pluginName,
|
|
42272
|
+
from: source.marketplace,
|
|
42273
|
+
...source.prefix ? { prefix: source.prefix } : {}
|
|
42274
|
+
};
|
|
42275
|
+
}
|
|
42276
|
+
if (source.type === "github") {
|
|
42277
|
+
if (source.owner && source.repo) {
|
|
42278
|
+
return {
|
|
42279
|
+
source: source.subpath ? `${source.owner}/${source.repo}/${source.subpath}` : `${source.owner}/${source.repo}`,
|
|
42280
|
+
...source.prefix ? { prefix: source.prefix } : {}
|
|
42281
|
+
};
|
|
42282
|
+
}
|
|
42283
|
+
if (source.url) {
|
|
42284
|
+
return { source: source.url, ...source.prefix ? { prefix: source.prefix } : {} };
|
|
42285
|
+
}
|
|
42286
|
+
}
|
|
42287
|
+
if (source.type === "gitlab") {
|
|
42288
|
+
if (source.owner && source.repo) {
|
|
42289
|
+
const prefix = `gitlab:${source.owner}/${source.repo}`;
|
|
42290
|
+
return {
|
|
42291
|
+
source: source.subpath ? `${prefix}//${source.subpath}` : prefix,
|
|
42292
|
+
...source.prefix ? { prefix: source.prefix } : {}
|
|
42293
|
+
};
|
|
42294
|
+
}
|
|
42295
|
+
if (source.url) {
|
|
42296
|
+
return { source: source.url, ...source.prefix ? { prefix: source.prefix } : {} };
|
|
42297
|
+
}
|
|
42298
|
+
}
|
|
42299
|
+
if (source.type === "bitbucket") {
|
|
42300
|
+
if (source.owner && source.repo) {
|
|
42301
|
+
const prefix = `bitbucket:${source.owner}/${source.repo}`;
|
|
42302
|
+
return {
|
|
42303
|
+
source: source.subpath ? `${prefix}/${source.subpath}` : prefix,
|
|
42304
|
+
...source.prefix ? { prefix: source.prefix } : {}
|
|
42305
|
+
};
|
|
42306
|
+
}
|
|
42307
|
+
if (source.url) {
|
|
42308
|
+
return { source: source.url, ...source.prefix ? { prefix: source.prefix } : {} };
|
|
42309
|
+
}
|
|
42310
|
+
}
|
|
42311
|
+
if (source.type === "local" && source.path) {
|
|
42312
|
+
return { source: source.path, ...source.prefix ? { prefix: source.prefix } : {} };
|
|
42313
|
+
}
|
|
42314
|
+
return null;
|
|
42315
|
+
}
|
|
42316
|
+
function formatLockSource(source) {
|
|
42317
|
+
const specifier = lockSourceToSpecifier(source);
|
|
42318
|
+
if (!specifier) {
|
|
42319
|
+
return source.type;
|
|
42320
|
+
}
|
|
42321
|
+
const formatted = specifier.from ? `${specifier.from}/${specifier.source}` : specifier.source;
|
|
42322
|
+
return specifier.prefix ? `${formatted} [prefix: ${specifier.prefix}]` : formatted;
|
|
42323
|
+
}
|
|
42324
|
+
|
|
42325
|
+
// dist/commands/skills.js
|
|
41795
42326
|
init_skills();
|
|
42327
|
+
var normalizeSkillPrefix = function(prefix) {
|
|
42328
|
+
return prefix?.trim() ?? "";
|
|
42329
|
+
};
|
|
42330
|
+
var matchesSelectedSkillName = function(skillName, selectedNames, prefix) {
|
|
42331
|
+
if (selectedNames.has(skillName.toLowerCase())) {
|
|
42332
|
+
return true;
|
|
42333
|
+
}
|
|
42334
|
+
const normalizedPrefix = normalizeSkillPrefix(prefix);
|
|
42335
|
+
if (!normalizedPrefix) {
|
|
42336
|
+
return false;
|
|
42337
|
+
}
|
|
42338
|
+
return selectedNames.has(`${normalizedPrefix}${skillName}`.toLowerCase());
|
|
42339
|
+
};
|
|
41796
42340
|
function registerSkillsCommand(program2) {
|
|
41797
42341
|
const marketplaceHelp = getMarketplaceIds().join(", ");
|
|
41798
42342
|
const skills3 = program2.command("skills").description("Manage agent skills");
|
|
41799
|
-
skills3.command("add <source>").description("Add skills from a marketplace,
|
|
42343
|
+
skills3.command("add <source>").description("Add skills from a marketplace, hosted Git repo, or local path").option("--from <marketplace>", `Marketplace source override (available: ${marketplaceHelp})`).option("-g, --global", "Install skills globally").option("-a, --agent <agents...>", "Target specific agent(s)").option("-s, --skill <names...>", "Install only specific skills by name").option("-l, --list", "List available skills from the source without installing").option("--all", "Select all bundled plugins when the source contains multiple plugins").option("--copy", "Copy skill files instead of symlinking").option("--prefix <prefix>", "Prefix installed skill names").option("--no-scan", "Skip security scanning before installation").option("--allow-risky", "Install even if scanning finds high-risk patterns").option("-y, --yes", "Skip prompts, auto-detect project-configured agents, and apply available skill updates").action(async (source, options2) => {
|
|
41800
42344
|
logger.titleBox("AgentInit Skills");
|
|
41801
42345
|
const agentManager9 = new AgentManager;
|
|
41802
42346
|
const skillsManager5 = new SkillsManager(agentManager9);
|
|
@@ -41875,11 +42419,12 @@ function registerSkillsCommand(program2) {
|
|
|
41875
42419
|
let targetAgents = options2.agent;
|
|
41876
42420
|
let targetGlobal = options2.global;
|
|
41877
42421
|
let selectedSkillNames = options2.skill;
|
|
42422
|
+
let installPrefix = options2.prefix;
|
|
41878
42423
|
if (!options2.yes && (!selectedSkillNames || selectedSkillNames.length === 0) && preparedSkills.length > 1) {
|
|
41879
42424
|
if (selectedPluginNames && selectedPluginNames.length > 1) {
|
|
41880
42425
|
logger.info("Multiple bundled plugins selected; installing all skills from each selected plugin. Use --skill to filter by skill name.");
|
|
41881
42426
|
} else {
|
|
41882
|
-
const skillSelection = await resolveInteractiveSkillSelection(preparedSkills);
|
|
42427
|
+
const skillSelection = await resolveInteractiveSkillSelection(preparedSkills, installPrefix);
|
|
41883
42428
|
if (skillSelection.aborted) {
|
|
41884
42429
|
await skillsManager5.discardPreparedSource(source, process.cwd(), {
|
|
41885
42430
|
from: options2.from
|
|
@@ -41887,11 +42432,12 @@ function registerSkillsCommand(program2) {
|
|
|
41887
42432
|
return;
|
|
41888
42433
|
}
|
|
41889
42434
|
selectedSkillNames = skillSelection.skills;
|
|
42435
|
+
installPrefix = skillSelection.prefix;
|
|
41890
42436
|
}
|
|
41891
42437
|
}
|
|
41892
42438
|
if (!targetAgents && !options2.yes) {
|
|
41893
42439
|
const selectedSkillNameSet = selectedSkillNames && selectedSkillNames.length > 0 ? new Set(selectedSkillNames.map((name) => name.toLowerCase())) : undefined;
|
|
41894
|
-
const filteredPreviewSkills = selectedSkillNameSet ? preparedSkills.filter((skill) =>
|
|
42440
|
+
const filteredPreviewSkills = selectedSkillNameSet ? preparedSkills.filter((skill) => matchesSelectedSkillName(skill.name, selectedSkillNameSet, installPrefix)) : preparedSkills;
|
|
41895
42441
|
const selection = await resolveInteractiveSkillTargets(skillsManager5, agentManager9, source, process.cwd(), {
|
|
41896
42442
|
from: options2.from,
|
|
41897
42443
|
global: options2.global,
|
|
@@ -41924,7 +42470,10 @@ function registerSkillsCommand(program2) {
|
|
|
41924
42470
|
...targetGlobal !== undefined ? { global: targetGlobal } : {},
|
|
41925
42471
|
...targetAgents !== undefined ? { agents: targetAgents } : {},
|
|
41926
42472
|
...selectedSkillNames !== undefined ? { skills: selectedSkillNames } : {},
|
|
42473
|
+
...installPrefix !== undefined ? { prefix: installPrefix } : {},
|
|
41927
42474
|
...options2.copy !== undefined ? { copy: options2.copy } : {},
|
|
42475
|
+
...options2.scan !== undefined ? { scan: options2.scan } : {},
|
|
42476
|
+
...options2.allowRisky !== undefined ? { allowRisky: options2.allowRisky } : {},
|
|
41928
42477
|
...pluginName !== undefined ? { pluginName } : {},
|
|
41929
42478
|
...options2.yes !== undefined ? { yes: options2.yes } : {},
|
|
41930
42479
|
...confirmUpdate !== undefined ? { confirmUpdate } : {}
|
|
@@ -41983,7 +42532,7 @@ function registerSkillsCommand(program2) {
|
|
|
41983
42532
|
const mode = skill.mode === "symlink" ? " (canonical)" : "";
|
|
41984
42533
|
const scope = skill.scope === "global" ? " [global]" : "";
|
|
41985
42534
|
logger.info(`\n ${green(skill.name)} - ${skill.description}${scope}${mode}`);
|
|
41986
|
-
logger.info(` Path: ${
|
|
42535
|
+
logger.info(` Path: ${relative8(process.cwd(), skill.path) || skill.path}`);
|
|
41987
42536
|
logger.info(` Agents: ${[...skill.agents].join(", ")}`);
|
|
41988
42537
|
}
|
|
41989
42538
|
});
|
|
@@ -42081,6 +42630,7 @@ Dry run \u2014 no changes made.`));
|
|
|
42081
42630
|
const skillsManager5 = new SkillsManager(agentManager9);
|
|
42082
42631
|
const result = await skillsManager5.addFromSource(sourceString.source, entry.projectPath, {
|
|
42083
42632
|
...sourceString.from ? { from: sourceString.from } : {},
|
|
42633
|
+
...sourceString.prefix ? { prefix: sourceString.prefix } : {},
|
|
42084
42634
|
agents: entry.agents,
|
|
42085
42635
|
global: entry.scope === "global",
|
|
42086
42636
|
skills: [name],
|
|
@@ -42147,6 +42697,7 @@ Dry run \u2014 no changes made.`));
|
|
|
42147
42697
|
try {
|
|
42148
42698
|
const result = await skillsManager5.addFromSource(sourceString.source, cwd, {
|
|
42149
42699
|
...sourceString.from ? { from: sourceString.from } : {},
|
|
42700
|
+
...sourceString.prefix ? { prefix: sourceString.prefix } : {},
|
|
42150
42701
|
agents: entry.agents,
|
|
42151
42702
|
global: entry.scope === "global",
|
|
42152
42703
|
skills: [name],
|
|
@@ -42197,6 +42748,7 @@ Dry run \u2014 no changes made.`));
|
|
|
42197
42748
|
try {
|
|
42198
42749
|
const result = await skillsManager5.addFromSource(sourceString.source, cwd, {
|
|
42199
42750
|
...sourceString.from ? { from: sourceString.from } : {},
|
|
42751
|
+
...sourceString.prefix ? { prefix: sourceString.prefix } : {},
|
|
42200
42752
|
agents: entry.agents,
|
|
42201
42753
|
global: entry.scope === "global",
|
|
42202
42754
|
skills: [entry.name],
|
|
@@ -42218,24 +42770,7 @@ Dry run \u2014 no changes made.`));
|
|
|
42218
42770
|
});
|
|
42219
42771
|
}
|
|
42220
42772
|
var lockSourceToString = function(source) {
|
|
42221
|
-
|
|
42222
|
-
return { source: source.pluginName, from: source.marketplace };
|
|
42223
|
-
}
|
|
42224
|
-
if (source.type === "github") {
|
|
42225
|
-
if (source.owner && source.repo) {
|
|
42226
|
-
if (source.subpath) {
|
|
42227
|
-
return { source: `${source.owner}/${source.repo}/${source.subpath}` };
|
|
42228
|
-
}
|
|
42229
|
-
return { source: `${source.owner}/${source.repo}` };
|
|
42230
|
-
}
|
|
42231
|
-
if (source.url) {
|
|
42232
|
-
return { source: source.url };
|
|
42233
|
-
}
|
|
42234
|
-
}
|
|
42235
|
-
if (source.type === "local" && source.path) {
|
|
42236
|
-
return { source: source.path };
|
|
42237
|
-
}
|
|
42238
|
-
return null;
|
|
42773
|
+
return lockSourceToSpecifier(source);
|
|
42239
42774
|
};
|
|
42240
42775
|
async function resolveInteractiveSkillTargets(skillsManager5, agentManager9, source, projectPath, options2) {
|
|
42241
42776
|
let installGlobal = !!options2.global;
|
|
@@ -42309,23 +42844,57 @@ async function resolveInteractiveSkillTargets(skillsManager5, agentManager9, sou
|
|
|
42309
42844
|
}
|
|
42310
42845
|
return selection;
|
|
42311
42846
|
}
|
|
42312
|
-
|
|
42313
|
-
|
|
42314
|
-
|
|
42315
|
-
|
|
42316
|
-
|
|
42317
|
-
|
|
42318
|
-
|
|
42319
|
-
|
|
42320
|
-
|
|
42321
|
-
|
|
42322
|
-
|
|
42323
|
-
|
|
42324
|
-
|
|
42325
|
-
|
|
42326
|
-
|
|
42847
|
+
var formatSkillSelectionHint = function(prefix) {
|
|
42848
|
+
return `Press Space to select, A to select or deselect all, p to edit prefix, then Enter to confirm. Prefix: "${prefix}"`;
|
|
42849
|
+
};
|
|
42850
|
+
async function resolveInteractiveSkillSelection(skills3, initialPrefix) {
|
|
42851
|
+
let prefix = initialPrefix ?? "";
|
|
42852
|
+
let selectedSkills = new Set(skills3.map((skill) => skill.name));
|
|
42853
|
+
const promptForPrefix = async () => {
|
|
42854
|
+
const response = await import_prompts3.default({
|
|
42855
|
+
type: "text",
|
|
42856
|
+
name: "prefix",
|
|
42857
|
+
message: "Prefix to prepend to installed skill names:",
|
|
42858
|
+
initial: prefix
|
|
42859
|
+
});
|
|
42860
|
+
if (typeof response.prefix === "string") {
|
|
42861
|
+
prefix = response.prefix;
|
|
42862
|
+
}
|
|
42863
|
+
};
|
|
42864
|
+
const requestPrefixEdit = (controls) => {
|
|
42865
|
+
controls.requestAction("edit-prefix");
|
|
42866
|
+
controls.closeWithCurrentSelection();
|
|
42867
|
+
};
|
|
42868
|
+
while (true) {
|
|
42869
|
+
const response = await promptMultiselect({
|
|
42870
|
+
name: "skills",
|
|
42871
|
+
message: `Select skills to install (${skills3.length} found):`,
|
|
42872
|
+
min: 1,
|
|
42873
|
+
hint: () => formatSkillSelectionHint(prefix),
|
|
42874
|
+
hotkeys: {
|
|
42875
|
+
p: requestPrefixEdit,
|
|
42876
|
+
P: requestPrefixEdit
|
|
42877
|
+
},
|
|
42878
|
+
choices: skills3.map((skill) => ({
|
|
42879
|
+
title: skill.name,
|
|
42880
|
+
value: skill.name,
|
|
42881
|
+
description: skill.description,
|
|
42882
|
+
selected: selectedSkills.has(skill.name)
|
|
42883
|
+
}))
|
|
42884
|
+
});
|
|
42885
|
+
if (response.skills && response.skills.length > 0) {
|
|
42886
|
+
selectedSkills = new Set(response.skills);
|
|
42887
|
+
}
|
|
42888
|
+
if (response.__agentinitAction === "edit-prefix") {
|
|
42889
|
+
await promptForPrefix();
|
|
42890
|
+
continue;
|
|
42891
|
+
}
|
|
42892
|
+
if (!response.skills || response.skills.length === 0) {
|
|
42893
|
+
logger.info("No skills selected. Aborting.");
|
|
42894
|
+
return { aborted: true };
|
|
42895
|
+
}
|
|
42896
|
+
return { skills: response.skills, prefix };
|
|
42327
42897
|
}
|
|
42328
|
-
return { skills: response.skills };
|
|
42329
42898
|
}
|
|
42330
42899
|
async function getDetectedSkillGroups(agentManager9, projectPath, global3) {
|
|
42331
42900
|
const detectedAgents = (await agentManager9.detectAgents(projectPath)).map((entry) => entry.agent);
|
|
@@ -42421,7 +42990,7 @@ var formatSkillsDir = function(projectPath, dir) {
|
|
|
42421
42990
|
const normalizedProjectPath = projectPath.replace(/\\/g, "/");
|
|
42422
42991
|
const normalizedHome = homedir7().replace(/\\/g, "/");
|
|
42423
42992
|
if (normalizedDir.startsWith(`${normalizedProjectPath}/`)) {
|
|
42424
|
-
return `${
|
|
42993
|
+
return `${relative8(projectPath, dir).replace(/\\/g, "/").replace(/\/?$/, "/")}`;
|
|
42425
42994
|
}
|
|
42426
42995
|
if (normalizedDir.startsWith(`${normalizedHome}/`)) {
|
|
42427
42996
|
return normalizedDir.replace(normalizedHome, "~");
|
|
@@ -42633,7 +43202,7 @@ var displayInstallResult = function(result, spinner, agentManager9, skillsManage
|
|
|
42633
43202
|
byPath.set(path, existing);
|
|
42634
43203
|
}
|
|
42635
43204
|
for (const [path, details] of byPath) {
|
|
42636
|
-
logger.info(` ${
|
|
43205
|
+
logger.info(` ${relative8(process.cwd(), path) || path}`);
|
|
42637
43206
|
logger.info(` Agents: ${[...details.agents].join(", ")}`);
|
|
42638
43207
|
logger.info(` Skills: ${green(String(details.skills.size))} installed (${[...details.skills].join(", ")})`);
|
|
42639
43208
|
}
|
|
@@ -42649,7 +43218,7 @@ var displayInstallResult = function(result, spinner, agentManager9, skillsManage
|
|
|
42649
43218
|
byPathUpdated.set(path, existing);
|
|
42650
43219
|
}
|
|
42651
43220
|
for (const [path, details] of byPathUpdated) {
|
|
42652
|
-
logger.info(` ${
|
|
43221
|
+
logger.info(` ${relative8(process.cwd(), path) || path}`);
|
|
42653
43222
|
logger.info(` Agents: ${[...details.agents].join(", ")}`);
|
|
42654
43223
|
logger.info(` Skills: ${yellow(String(details.skills.size))} updated (${[...details.skills].join(", ")})`);
|
|
42655
43224
|
}
|
|
@@ -42875,7 +43444,7 @@ var registerAddCommand = function(mcp) {
|
|
|
42875
43444
|
});
|
|
42876
43445
|
try {
|
|
42877
43446
|
const lock = new InstallLock;
|
|
42878
|
-
const
|
|
43447
|
+
const lockSource2 = { type: "local" };
|
|
42879
43448
|
for (const plan of plans) {
|
|
42880
43449
|
for (const server of plan.servers) {
|
|
42881
43450
|
await lock.recordMcp({
|
|
@@ -42884,7 +43453,7 @@ var registerAddCommand = function(mcp) {
|
|
|
42884
43453
|
projectPath: cwd,
|
|
42885
43454
|
agents: [plan.agent.id],
|
|
42886
43455
|
scope: plan.isGlobal ? "global" : "project",
|
|
42887
|
-
source:
|
|
43456
|
+
source: lockSource2,
|
|
42888
43457
|
configPath: plan.configPath,
|
|
42889
43458
|
serverType: server.type,
|
|
42890
43459
|
...server.command ? { command: server.command } : {},
|
|
@@ -43572,7 +44141,7 @@ function registerRulesCommand(program2) {
|
|
|
43572
44141
|
// dist/commands/plugins.js
|
|
43573
44142
|
var import_prompts4 = __toESM(require_prompts3(), 1);
|
|
43574
44143
|
import {homedir as homedir8} from "os";
|
|
43575
|
-
import {dirname as dirname10, relative as
|
|
44144
|
+
import {dirname as dirname10, relative as relative9, resolve as resolve14} from "path";
|
|
43576
44145
|
init_logger();
|
|
43577
44146
|
init_pluginManager();
|
|
43578
44147
|
init_agentManager();
|
|
@@ -43925,7 +44494,7 @@ function registerPluginsCommand(program2) {
|
|
|
43925
44494
|
}
|
|
43926
44495
|
var formatPathForDisplay = function(pathValue, projectPath) {
|
|
43927
44496
|
if (pathValue.startsWith(`${projectPath}/`)) {
|
|
43928
|
-
return
|
|
44497
|
+
return relative9(projectPath, pathValue) || ".";
|
|
43929
44498
|
}
|
|
43930
44499
|
const homePrefix = `${process.env.HOME || ""}/`;
|
|
43931
44500
|
if (homePrefix !== "/" && pathValue.startsWith(homePrefix)) {
|
|
@@ -44327,20 +44896,7 @@ var formatKind = function(kind) {
|
|
|
44327
44896
|
}
|
|
44328
44897
|
};
|
|
44329
44898
|
var formatSource = function(entry) {
|
|
44330
|
-
|
|
44331
|
-
if (src.type === "marketplace" && src.marketplace) {
|
|
44332
|
-
return `${src.marketplace}/${src.pluginName || ""}`;
|
|
44333
|
-
}
|
|
44334
|
-
if (src.type === "github") {
|
|
44335
|
-
if (src.owner && src.repo) {
|
|
44336
|
-
return src.subpath ? `${src.owner}/${src.repo}/${src.subpath}` : `${src.owner}/${src.repo}`;
|
|
44337
|
-
}
|
|
44338
|
-
return src.url || "github";
|
|
44339
|
-
}
|
|
44340
|
-
if (src.type === "local" && src.path) {
|
|
44341
|
-
return src.path;
|
|
44342
|
-
}
|
|
44343
|
-
return src.type;
|
|
44899
|
+
return formatLockSource(entry.source);
|
|
44344
44900
|
};
|
|
44345
44901
|
function registerLockCommand(program2) {
|
|
44346
44902
|
const lock = program2.command("lock").description("View and manage the global install lockfile");
|