allagents 1.11.5-next.1 → 1.11.7-next.1
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/dist/index.js +1846 -1617
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15693,13 +15693,14 @@ var init_esm = __esm(() => {
|
|
|
15693
15693
|
});
|
|
15694
15694
|
|
|
15695
15695
|
// src/core/git-errors.ts
|
|
15696
|
-
function classifyError(error, url) {
|
|
15696
|
+
function classifyError(error, url, timeoutMs = 60000) {
|
|
15697
15697
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
15698
15698
|
const isTimeout = errorMessage.includes("block timeout") || errorMessage.includes("timed out");
|
|
15699
15699
|
const isAuthError = errorMessage.includes("Authentication failed") || errorMessage.includes("could not read Username") || errorMessage.includes("Permission denied") || errorMessage.includes("Repository not found");
|
|
15700
15700
|
const isServerError = /returned error: 5\d\d/.test(errorMessage) || errorMessage.includes("Internal Server Error");
|
|
15701
15701
|
if (isTimeout) {
|
|
15702
|
-
|
|
15702
|
+
const timeoutSeconds = Math.round(timeoutMs / 1000);
|
|
15703
|
+
return new GitCloneError(`Clone timed out after ${timeoutSeconds}s for ${url}.
|
|
15703
15704
|
Check your network connection and repository access.
|
|
15704
15705
|
For SSH: ssh-add -l (to check loaded keys)
|
|
15705
15706
|
For HTTPS: Check your git credentials`, url, true, false);
|
|
@@ -15732,38 +15733,50 @@ var init_git_errors = __esm(() => {
|
|
|
15732
15733
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
15733
15734
|
import { tmpdir } from "node:os";
|
|
15734
15735
|
import { join, normalize as normalize2, resolve, sep } from "node:path";
|
|
15736
|
+
function createGit(baseDir) {
|
|
15737
|
+
return esm_default(baseDir, {
|
|
15738
|
+
timeout: { block: CLONE_TIMEOUT_MS },
|
|
15739
|
+
config: [
|
|
15740
|
+
"filter.lfs.required=false",
|
|
15741
|
+
"filter.lfs.smudge=",
|
|
15742
|
+
"filter.lfs.clean=",
|
|
15743
|
+
"filter.lfs.process="
|
|
15744
|
+
]
|
|
15745
|
+
}).env({
|
|
15746
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
15747
|
+
GIT_LFS_SKIP_SMUDGE: "1"
|
|
15748
|
+
});
|
|
15749
|
+
}
|
|
15735
15750
|
function gitHubUrl(owner, repo) {
|
|
15736
15751
|
return `https://github.com/${owner}/${repo}.git`;
|
|
15737
15752
|
}
|
|
15738
15753
|
async function cloneToTemp(url, ref) {
|
|
15739
15754
|
const tempDir = await mkdtemp(join(tmpdir(), "allagents-"));
|
|
15740
|
-
const git =
|
|
15755
|
+
const git = createGit();
|
|
15741
15756
|
const cloneOptions = ref ? ["--depth", "1", "--branch", ref] : ["--depth", "1"];
|
|
15742
15757
|
try {
|
|
15743
15758
|
await git.clone(url, tempDir, cloneOptions);
|
|
15744
15759
|
return tempDir;
|
|
15745
15760
|
} catch (error) {
|
|
15746
15761
|
await rm(tempDir, { recursive: true, force: true }).catch(() => {});
|
|
15747
|
-
throw classifyError(error, url);
|
|
15762
|
+
throw classifyError(error, url, CLONE_TIMEOUT_MS);
|
|
15748
15763
|
}
|
|
15749
15764
|
}
|
|
15750
15765
|
async function cloneTo(url, dest, ref) {
|
|
15751
|
-
const git =
|
|
15766
|
+
const git = createGit();
|
|
15752
15767
|
const cloneOptions = ref ? ["--depth", "1", "--branch", ref] : ["--depth", "1"];
|
|
15753
15768
|
try {
|
|
15754
15769
|
await git.clone(url, dest, cloneOptions);
|
|
15755
15770
|
} catch (error) {
|
|
15756
|
-
throw classifyError(error, url);
|
|
15771
|
+
throw classifyError(error, url, CLONE_TIMEOUT_MS);
|
|
15757
15772
|
}
|
|
15758
15773
|
}
|
|
15759
15774
|
async function pull(repoPath) {
|
|
15760
|
-
const git =
|
|
15761
|
-
timeout: { block: CLONE_TIMEOUT_MS }
|
|
15762
|
-
});
|
|
15775
|
+
const git = createGit(repoPath);
|
|
15763
15776
|
await git.pull();
|
|
15764
15777
|
}
|
|
15765
15778
|
async function repoExists(url) {
|
|
15766
|
-
const git =
|
|
15779
|
+
const git = createGit();
|
|
15767
15780
|
try {
|
|
15768
15781
|
await git.listRemote([url]);
|
|
15769
15782
|
return true;
|
|
@@ -15772,7 +15785,7 @@ async function repoExists(url) {
|
|
|
15772
15785
|
}
|
|
15773
15786
|
}
|
|
15774
15787
|
async function refExists(url, ref) {
|
|
15775
|
-
const git =
|
|
15788
|
+
const git = createGit();
|
|
15776
15789
|
try {
|
|
15777
15790
|
const result = await git.listRemote([
|
|
15778
15791
|
"--refs",
|
|
@@ -15792,10 +15805,17 @@ async function cleanupTempDir(dir) {
|
|
|
15792
15805
|
}
|
|
15793
15806
|
await rm(dir, { recursive: true, force: true });
|
|
15794
15807
|
}
|
|
15795
|
-
var
|
|
15808
|
+
var DEFAULT_CLONE_TIMEOUT_MS = 300000, CLONE_TIMEOUT_MS;
|
|
15796
15809
|
var init_git = __esm(() => {
|
|
15797
15810
|
init_esm();
|
|
15798
15811
|
init_git_errors();
|
|
15812
|
+
CLONE_TIMEOUT_MS = (() => {
|
|
15813
|
+
const raw = process.env.ALLAGENTS_CLONE_TIMEOUT_MS;
|
|
15814
|
+
if (!raw)
|
|
15815
|
+
return DEFAULT_CLONE_TIMEOUT_MS;
|
|
15816
|
+
const parsed = Number.parseInt(raw, 10);
|
|
15817
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_CLONE_TIMEOUT_MS;
|
|
15818
|
+
})();
|
|
15799
15819
|
});
|
|
15800
15820
|
|
|
15801
15821
|
// src/utils/plugin-path.ts
|
|
@@ -25580,794 +25600,939 @@ var init_skill = __esm(() => {
|
|
|
25580
25600
|
import_gray_matter = __toESM(require_gray_matter(), 1);
|
|
25581
25601
|
});
|
|
25582
25602
|
|
|
25583
|
-
// src/
|
|
25584
|
-
|
|
25603
|
+
// src/models/marketplace-manifest.ts
|
|
25604
|
+
var UrlSourceSchema, GitHubSourceSchema, PluginSourceRefSchema, ContactSchema, LspServerSchema, MarketplacePluginEntrySchema, MarketplaceManifestSchema, MarketplaceManifestLenientSchema;
|
|
25605
|
+
var init_marketplace_manifest = __esm(() => {
|
|
25606
|
+
init_zod();
|
|
25607
|
+
UrlSourceSchema = exports_external.object({
|
|
25608
|
+
source: exports_external.literal("url"),
|
|
25609
|
+
url: exports_external.string().url()
|
|
25610
|
+
});
|
|
25611
|
+
GitHubSourceSchema = exports_external.object({
|
|
25612
|
+
source: exports_external.literal("github"),
|
|
25613
|
+
repo: exports_external.string().min(1)
|
|
25614
|
+
}).transform((val) => ({
|
|
25615
|
+
source: "url",
|
|
25616
|
+
url: `https://github.com/${val.repo}`
|
|
25617
|
+
}));
|
|
25618
|
+
PluginSourceRefSchema = exports_external.union([exports_external.string(), UrlSourceSchema, GitHubSourceSchema]);
|
|
25619
|
+
ContactSchema = exports_external.object({
|
|
25620
|
+
name: exports_external.string(),
|
|
25621
|
+
email: exports_external.string().optional()
|
|
25622
|
+
});
|
|
25623
|
+
LspServerSchema = exports_external.object({
|
|
25624
|
+
command: exports_external.string(),
|
|
25625
|
+
args: exports_external.array(exports_external.string()).optional(),
|
|
25626
|
+
extensionToLanguage: exports_external.record(exports_external.string()).optional(),
|
|
25627
|
+
startupTimeout: exports_external.number().optional()
|
|
25628
|
+
});
|
|
25629
|
+
MarketplacePluginEntrySchema = exports_external.object({
|
|
25630
|
+
name: exports_external.string().min(1),
|
|
25631
|
+
description: exports_external.string().min(1),
|
|
25632
|
+
source: PluginSourceRefSchema,
|
|
25633
|
+
version: exports_external.string().optional(),
|
|
25634
|
+
author: ContactSchema.optional(),
|
|
25635
|
+
category: exports_external.string().optional(),
|
|
25636
|
+
homepage: exports_external.string().optional(),
|
|
25637
|
+
strict: exports_external.boolean().optional(),
|
|
25638
|
+
tags: exports_external.array(exports_external.string()).optional(),
|
|
25639
|
+
skills: exports_external.array(exports_external.string()).optional(),
|
|
25640
|
+
lspServers: exports_external.record(LspServerSchema).optional()
|
|
25641
|
+
});
|
|
25642
|
+
MarketplaceManifestSchema = exports_external.object({
|
|
25643
|
+
$schema: exports_external.string().optional(),
|
|
25644
|
+
name: exports_external.string().min(1),
|
|
25645
|
+
version: exports_external.string().optional(),
|
|
25646
|
+
description: exports_external.string().min(1),
|
|
25647
|
+
owner: ContactSchema.optional(),
|
|
25648
|
+
plugins: exports_external.array(MarketplacePluginEntrySchema)
|
|
25649
|
+
});
|
|
25650
|
+
MarketplaceManifestLenientSchema = exports_external.object({
|
|
25651
|
+
name: exports_external.string().optional(),
|
|
25652
|
+
plugins: exports_external.array(exports_external.unknown())
|
|
25653
|
+
}).passthrough();
|
|
25654
|
+
});
|
|
25655
|
+
|
|
25656
|
+
// src/utils/marketplace-manifest-parser.ts
|
|
25657
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
25585
25658
|
import { existsSync as existsSync4 } from "node:fs";
|
|
25586
|
-
import { join as join7,
|
|
25587
|
-
async function
|
|
25588
|
-
const
|
|
25589
|
-
|
|
25590
|
-
|
|
25591
|
-
|
|
25592
|
-
|
|
25593
|
-
|
|
25594
|
-
return;
|
|
25659
|
+
import { join as join7, resolve as resolve5 } from "node:path";
|
|
25660
|
+
async function parseMarketplaceManifest(marketplacePath) {
|
|
25661
|
+
const manifestPath = join7(marketplacePath, MANIFEST_PATH);
|
|
25662
|
+
if (!existsSync4(manifestPath)) {
|
|
25663
|
+
return {
|
|
25664
|
+
success: false,
|
|
25665
|
+
error: `Marketplace manifest not found: ${manifestPath}`
|
|
25666
|
+
};
|
|
25595
25667
|
}
|
|
25596
|
-
|
|
25597
|
-
|
|
25598
|
-
|
|
25599
|
-
|
|
25600
|
-
|
|
25601
|
-
|
|
25602
|
-
|
|
25603
|
-
|
|
25604
|
-
await writeFile(filePath, content + rulesContent, "utf-8");
|
|
25668
|
+
let raw;
|
|
25669
|
+
try {
|
|
25670
|
+
raw = await readFile3(manifestPath, "utf-8");
|
|
25671
|
+
} catch (err) {
|
|
25672
|
+
return {
|
|
25673
|
+
success: false,
|
|
25674
|
+
error: `Failed to read marketplace manifest: ${err instanceof Error ? err.message : String(err)}`
|
|
25675
|
+
};
|
|
25605
25676
|
}
|
|
25677
|
+
let json2;
|
|
25678
|
+
try {
|
|
25679
|
+
json2 = JSON.parse(raw);
|
|
25680
|
+
} catch {
|
|
25681
|
+
return {
|
|
25682
|
+
success: false,
|
|
25683
|
+
error: "Failed to parse marketplace.json as JSON: invalid syntax"
|
|
25684
|
+
};
|
|
25685
|
+
}
|
|
25686
|
+
const strictResult = MarketplaceManifestSchema.safeParse(json2);
|
|
25687
|
+
if (strictResult.success) {
|
|
25688
|
+
return { success: true, data: strictResult.data, warnings: [] };
|
|
25689
|
+
}
|
|
25690
|
+
return parseLeniently(json2);
|
|
25606
25691
|
}
|
|
25607
|
-
function
|
|
25608
|
-
|
|
25609
|
-
|
|
25610
|
-
|
|
25611
|
-
|
|
25612
|
-
|
|
25613
|
-
|
|
25614
|
-
|
|
25615
|
-
const
|
|
25616
|
-
|
|
25617
|
-
|
|
25618
|
-
|
|
25619
|
-
|
|
25692
|
+
function parseLeniently(json2) {
|
|
25693
|
+
const lenientResult = MarketplaceManifestLenientSchema.safeParse(json2);
|
|
25694
|
+
if (!lenientResult.success) {
|
|
25695
|
+
return {
|
|
25696
|
+
success: false,
|
|
25697
|
+
error: 'Marketplace manifest must contain a "plugins" array'
|
|
25698
|
+
};
|
|
25699
|
+
}
|
|
25700
|
+
const raw = lenientResult.data;
|
|
25701
|
+
const warnings = [];
|
|
25702
|
+
const obj = json2;
|
|
25703
|
+
const validPlugins = [];
|
|
25704
|
+
for (let i2 = 0;i2 < raw.plugins.length; i2++) {
|
|
25705
|
+
const entry = raw.plugins[i2];
|
|
25706
|
+
const entryResult = MarketplacePluginEntrySchema.safeParse(entry);
|
|
25707
|
+
if (entryResult.success) {
|
|
25708
|
+
validPlugins.push(entryResult.data);
|
|
25620
25709
|
continue;
|
|
25621
25710
|
}
|
|
25622
|
-
|
|
25623
|
-
|
|
25624
|
-
|
|
25625
|
-
await cp(sourcePath, destPath);
|
|
25711
|
+
const extracted = extractPluginEntry(entry, i2, warnings);
|
|
25712
|
+
if (extracted) {
|
|
25713
|
+
validPlugins.push(extracted);
|
|
25626
25714
|
}
|
|
25627
25715
|
}
|
|
25716
|
+
const data = {
|
|
25717
|
+
name: typeof raw.name === "string" ? raw.name : "unknown",
|
|
25718
|
+
description: typeof obj.description === "string" ? obj.description : "",
|
|
25719
|
+
plugins: validPlugins
|
|
25720
|
+
};
|
|
25721
|
+
return { success: true, data, warnings };
|
|
25628
25722
|
}
|
|
25629
|
-
function
|
|
25630
|
-
|
|
25723
|
+
function extractPluginEntry(entry, index, warnings) {
|
|
25724
|
+
if (!entry || typeof entry !== "object") {
|
|
25725
|
+
warnings.push(`plugins[${index}]: not an object, skipped`);
|
|
25726
|
+
return null;
|
|
25727
|
+
}
|
|
25728
|
+
const obj = entry;
|
|
25729
|
+
const name = typeof obj.name === "string" && obj.name ? obj.name : undefined;
|
|
25730
|
+
if (!name) {
|
|
25731
|
+
warnings.push(`plugins[${index}]: missing "name" field, skipped`);
|
|
25732
|
+
return null;
|
|
25733
|
+
}
|
|
25734
|
+
let description = "";
|
|
25735
|
+
if (typeof obj.description === "string" && obj.description) {
|
|
25736
|
+
description = obj.description;
|
|
25737
|
+
} else if (obj.metadata && typeof obj.metadata === "object" && typeof obj.metadata.description === "string") {
|
|
25738
|
+
description = obj.metadata.description;
|
|
25739
|
+
warnings.push(`plugins[${index}] ("${name}"): "description" found in metadata instead of top level`);
|
|
25740
|
+
} else {
|
|
25741
|
+
warnings.push(`plugins[${index}] ("${name}"): missing "description" field`);
|
|
25742
|
+
}
|
|
25743
|
+
let source = "";
|
|
25744
|
+
const sourceResult = PluginSourceRefSchema.safeParse(obj.source);
|
|
25745
|
+
if (sourceResult.success) {
|
|
25746
|
+
source = sourceResult.data;
|
|
25747
|
+
} else {
|
|
25748
|
+
warnings.push(`plugins[${index}] ("${name}"): missing or invalid "source" field`);
|
|
25749
|
+
}
|
|
25750
|
+
return {
|
|
25751
|
+
name,
|
|
25752
|
+
description,
|
|
25753
|
+
source,
|
|
25754
|
+
...typeof obj.version === "string" && { version: obj.version },
|
|
25755
|
+
...typeof obj.category === "string" && { category: obj.category },
|
|
25756
|
+
...typeof obj.homepage === "string" && { homepage: obj.homepage },
|
|
25757
|
+
...Array.isArray(obj.skills) && obj.skills.every((s) => typeof s === "string") && { skills: obj.skills }
|
|
25758
|
+
};
|
|
25631
25759
|
}
|
|
25632
|
-
|
|
25633
|
-
|
|
25634
|
-
|
|
25635
|
-
const results = [];
|
|
25636
|
-
if (!mapping.commandsPath) {
|
|
25637
|
-
return results;
|
|
25760
|
+
function resolvePluginSourcePath(source, marketplacePath) {
|
|
25761
|
+
if (typeof source === "object") {
|
|
25762
|
+
return source.url;
|
|
25638
25763
|
}
|
|
25639
|
-
|
|
25640
|
-
|
|
25641
|
-
|
|
25764
|
+
return resolve5(marketplacePath, source);
|
|
25765
|
+
}
|
|
25766
|
+
var MANIFEST_PATH = ".claude-plugin/marketplace.json";
|
|
25767
|
+
var init_marketplace_manifest_parser = __esm(() => {
|
|
25768
|
+
init_marketplace_manifest();
|
|
25769
|
+
});
|
|
25770
|
+
|
|
25771
|
+
// src/core/workspace-modify.ts
|
|
25772
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
25773
|
+
import { mkdir as mkdir3, readFile as readFile4, writeFile } from "node:fs/promises";
|
|
25774
|
+
import { join as join8 } from "node:path";
|
|
25775
|
+
async function setClients(clients, workspacePath = process.cwd()) {
|
|
25776
|
+
try {
|
|
25777
|
+
await ensureWorkspace(workspacePath);
|
|
25778
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
25779
|
+
const content = await readFile4(configPath, "utf-8");
|
|
25780
|
+
const config = load(content);
|
|
25781
|
+
config.clients = clients;
|
|
25782
|
+
await writeFile(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
25783
|
+
return { success: true };
|
|
25784
|
+
} catch (error) {
|
|
25785
|
+
return {
|
|
25786
|
+
success: false,
|
|
25787
|
+
error: error instanceof Error ? error.message : String(error)
|
|
25788
|
+
};
|
|
25642
25789
|
}
|
|
25643
|
-
|
|
25644
|
-
|
|
25645
|
-
|
|
25790
|
+
}
|
|
25791
|
+
async function ensureWorkspace(workspacePath, clients) {
|
|
25792
|
+
const configDir = join8(workspacePath, CONFIG_DIR);
|
|
25793
|
+
const configPath = join8(configDir, WORKSPACE_CONFIG_FILE);
|
|
25794
|
+
if (existsSync5(configPath))
|
|
25795
|
+
return;
|
|
25796
|
+
const defaultConfig = {
|
|
25797
|
+
repositories: [],
|
|
25798
|
+
plugins: [],
|
|
25799
|
+
clients: clients ?? [...DEFAULT_PROJECT_CLIENTS]
|
|
25800
|
+
};
|
|
25801
|
+
await mkdir3(configDir, { recursive: true });
|
|
25802
|
+
await writeFile(configPath, dump(defaultConfig, { lineWidth: -1 }), "utf-8");
|
|
25803
|
+
}
|
|
25804
|
+
async function addPlugin(plugin, workspacePath = process.cwd(), force) {
|
|
25805
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
25806
|
+
await ensureWorkspace(workspacePath);
|
|
25807
|
+
if (isPluginSpec(plugin)) {
|
|
25808
|
+
const resolved = await resolvePluginSpecWithAutoRegister(plugin, { workspacePath });
|
|
25809
|
+
if (!resolved.success) {
|
|
25810
|
+
return {
|
|
25811
|
+
success: false,
|
|
25812
|
+
error: resolved.error || "Unknown error"
|
|
25813
|
+
};
|
|
25814
|
+
}
|
|
25815
|
+
return await addPluginToConfig(resolved.registeredAs ? plugin.replace(/@[^@]+$/, `@${resolved.registeredAs}`) : plugin, configPath, resolved.registeredAs, force);
|
|
25646
25816
|
}
|
|
25647
|
-
|
|
25648
|
-
|
|
25649
|
-
|
|
25650
|
-
|
|
25651
|
-
|
|
25652
|
-
|
|
25653
|
-
|
|
25817
|
+
if (isGitHubUrl(plugin)) {
|
|
25818
|
+
const validation = validatePluginSource(plugin);
|
|
25819
|
+
if (!validation.valid) {
|
|
25820
|
+
return {
|
|
25821
|
+
success: false,
|
|
25822
|
+
error: validation.error || "Invalid GitHub URL"
|
|
25823
|
+
};
|
|
25654
25824
|
}
|
|
25655
|
-
|
|
25656
|
-
|
|
25657
|
-
await writeFile(destPath, content, "utf-8");
|
|
25658
|
-
return { source: sourcePath, destination: destPath, action: "copied" };
|
|
25659
|
-
} catch (error) {
|
|
25825
|
+
const verifyResult = await verifyGitHubUrlExists(plugin);
|
|
25826
|
+
if (!verifyResult.exists) {
|
|
25660
25827
|
return {
|
|
25661
|
-
|
|
25662
|
-
|
|
25663
|
-
action: "failed",
|
|
25664
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
25828
|
+
success: false,
|
|
25829
|
+
error: verifyResult.error || `GitHub URL not found: ${plugin}`
|
|
25665
25830
|
};
|
|
25666
25831
|
}
|
|
25667
|
-
});
|
|
25668
|
-
return Promise.all(copyPromises);
|
|
25669
|
-
}
|
|
25670
|
-
async function copySkills(pluginPath, workspacePath, client, options2 = {}) {
|
|
25671
|
-
const { dryRun = false, skillNameMap, syncMode = "copy", canonicalSkillsPath } = options2;
|
|
25672
|
-
const mapping = getMapping(client, options2);
|
|
25673
|
-
const results = [];
|
|
25674
|
-
if (!mapping.skillsPath) {
|
|
25675
|
-
return results;
|
|
25676
|
-
}
|
|
25677
|
-
const skillsDir = join7(pluginPath, "skills");
|
|
25678
|
-
let skillSources;
|
|
25679
|
-
if (existsSync4(skillsDir)) {
|
|
25680
|
-
const entries = await readdir2(skillsDir, { withFileTypes: true });
|
|
25681
|
-
skillSources = entries.filter((e) => e.isDirectory()).filter((e) => !isExcluded(pluginPath, join7(skillsDir, e.name), options2.exclude)).map((e) => ({ name: e.name, sourcePath: join7(skillsDir, e.name), isRootLevel: false }));
|
|
25682
25832
|
} else {
|
|
25683
|
-
const
|
|
25684
|
-
|
|
25685
|
-
for (const entry of entries) {
|
|
25686
|
-
if (!entry.isDirectory())
|
|
25687
|
-
continue;
|
|
25688
|
-
const skillMdPath = join7(pluginPath, entry.name, "SKILL.md");
|
|
25689
|
-
if (existsSync4(skillMdPath)) {
|
|
25690
|
-
flatSkills.push({ name: entry.name, sourcePath: join7(pluginPath, entry.name), isRootLevel: false });
|
|
25691
|
-
}
|
|
25692
|
-
}
|
|
25693
|
-
if (flatSkills.length > 0) {
|
|
25694
|
-
skillSources = flatSkills;
|
|
25695
|
-
} else {
|
|
25696
|
-
const rootSkillMd = join7(pluginPath, "SKILL.md");
|
|
25697
|
-
if (existsSync4(rootSkillMd)) {
|
|
25698
|
-
const content = await readFile3(rootSkillMd, "utf-8");
|
|
25699
|
-
const metadata = parseSkillMetadata(content);
|
|
25700
|
-
const skillName = metadata?.name ?? basename2(pluginPath);
|
|
25701
|
-
skillSources = [{ name: skillName, sourcePath: pluginPath, isRootLevel: true }];
|
|
25702
|
-
} else {
|
|
25703
|
-
return results;
|
|
25704
|
-
}
|
|
25705
|
-
}
|
|
25706
|
-
}
|
|
25707
|
-
if (skillNameMap) {
|
|
25708
|
-
skillSources = skillSources.filter((s) => skillNameMap.has(s.name));
|
|
25709
|
-
}
|
|
25710
|
-
if (skillSources.length === 0) {
|
|
25711
|
-
return results;
|
|
25712
|
-
}
|
|
25713
|
-
const destDir = join7(workspacePath, mapping.skillsPath);
|
|
25714
|
-
if (!dryRun) {
|
|
25715
|
-
await mkdir3(destDir, { recursive: true });
|
|
25716
|
-
}
|
|
25717
|
-
const useSymlinks = syncMode === "symlink" && !isUniversalClient(client) && canonicalSkillsPath;
|
|
25718
|
-
const copyPromises = skillSources.map(async (skill) => {
|
|
25719
|
-
const resolvedName = skillNameMap?.get(skill.name) ?? skill.name;
|
|
25720
|
-
const skillDestPath = join7(destDir, resolvedName);
|
|
25721
|
-
if (dryRun) {
|
|
25833
|
+
const fullPath = join8(workspacePath, plugin);
|
|
25834
|
+
if (!existsSync5(fullPath) && !existsSync5(plugin)) {
|
|
25722
25835
|
return {
|
|
25723
|
-
|
|
25724
|
-
|
|
25725
|
-
action: "copied"
|
|
25836
|
+
success: false,
|
|
25837
|
+
error: `Plugin not found at ${plugin}`
|
|
25726
25838
|
};
|
|
25727
25839
|
}
|
|
25728
|
-
|
|
25729
|
-
|
|
25730
|
-
|
|
25731
|
-
|
|
25840
|
+
}
|
|
25841
|
+
return await addPluginToConfig(plugin, configPath, undefined, force);
|
|
25842
|
+
}
|
|
25843
|
+
async function addPluginToConfig(plugin, configPath, autoRegistered, force) {
|
|
25844
|
+
try {
|
|
25845
|
+
const content = await readFile4(configPath, "utf-8");
|
|
25846
|
+
const config = load(content);
|
|
25847
|
+
const existingExactIndex = config.plugins.findIndex((entry) => getPluginSource(entry) === plugin);
|
|
25848
|
+
if (existingExactIndex !== -1) {
|
|
25849
|
+
if (!force) {
|
|
25732
25850
|
return {
|
|
25733
|
-
|
|
25734
|
-
|
|
25735
|
-
action: "copied"
|
|
25851
|
+
success: false,
|
|
25852
|
+
error: `Plugin already exists in .allagents/workspace.yaml: ${plugin}`
|
|
25736
25853
|
};
|
|
25737
25854
|
}
|
|
25738
25855
|
}
|
|
25739
|
-
|
|
25740
|
-
|
|
25741
|
-
|
|
25742
|
-
|
|
25743
|
-
|
|
25744
|
-
|
|
25745
|
-
|
|
25746
|
-
|
|
25747
|
-
|
|
25748
|
-
|
|
25749
|
-
|
|
25750
|
-
|
|
25751
|
-
|
|
25752
|
-
};
|
|
25753
|
-
} catch (error) {
|
|
25754
|
-
return {
|
|
25755
|
-
source: skill.sourcePath,
|
|
25756
|
-
destination: skillDestPath,
|
|
25757
|
-
action: "failed",
|
|
25758
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
25759
|
-
};
|
|
25760
|
-
}
|
|
25761
|
-
});
|
|
25762
|
-
return Promise.all(copyPromises);
|
|
25763
|
-
}
|
|
25764
|
-
async function collectPluginSkills(pluginPath, pluginSource, disabledSkills, pluginName, enabledSkills, pluginSkillsConfig) {
|
|
25765
|
-
const skillsDir = join7(pluginPath, "skills");
|
|
25766
|
-
const hasEnabledEntries = !pluginSkillsConfig && enabledSkills && pluginName && [...enabledSkills].some((s) => s.startsWith(`${pluginName}:`));
|
|
25767
|
-
let candidateDirs;
|
|
25768
|
-
if (existsSync4(skillsDir)) {
|
|
25769
|
-
const entries = await readdir2(skillsDir, { withFileTypes: true });
|
|
25770
|
-
candidateDirs = entries.filter((e) => e.isDirectory()).map((e) => ({ name: e.name, path: join7(skillsDir, e.name) }));
|
|
25771
|
-
} else {
|
|
25772
|
-
const entries = await readdir2(pluginPath, { withFileTypes: true });
|
|
25773
|
-
const flatDirs = [];
|
|
25774
|
-
for (const entry of entries) {
|
|
25775
|
-
if (!entry.isDirectory())
|
|
25776
|
-
continue;
|
|
25777
|
-
const skillMdPath = join7(pluginPath, entry.name, "SKILL.md");
|
|
25778
|
-
if (existsSync4(skillMdPath)) {
|
|
25779
|
-
flatDirs.push({ name: entry.name, path: join7(pluginPath, entry.name) });
|
|
25856
|
+
if (!force) {
|
|
25857
|
+
const newIdentity = await resolveGitHubIdentity(plugin);
|
|
25858
|
+
if (newIdentity) {
|
|
25859
|
+
for (const existing of config.plugins) {
|
|
25860
|
+
const existingSource = getPluginSource(existing);
|
|
25861
|
+
const existingIdentity = await resolveGitHubIdentity(existingSource);
|
|
25862
|
+
if (existingIdentity === newIdentity) {
|
|
25863
|
+
return {
|
|
25864
|
+
success: false,
|
|
25865
|
+
error: `Plugin duplicates existing entry '${existingSource}': both resolve to ${newIdentity}`
|
|
25866
|
+
};
|
|
25867
|
+
}
|
|
25868
|
+
}
|
|
25780
25869
|
}
|
|
25781
25870
|
}
|
|
25782
|
-
|
|
25783
|
-
|
|
25784
|
-
|
|
25785
|
-
const rootSkillMd = join7(pluginPath, "SKILL.md");
|
|
25786
|
-
if (existsSync4(rootSkillMd)) {
|
|
25787
|
-
const content = await readFile3(rootSkillMd, "utf-8");
|
|
25788
|
-
const metadata = parseSkillMetadata(content);
|
|
25789
|
-
const skillName = metadata?.name ?? basename2(pluginPath);
|
|
25790
|
-
candidateDirs = [{ name: skillName, path: pluginPath }];
|
|
25791
|
-
} else {
|
|
25792
|
-
candidateDirs = [];
|
|
25793
|
-
}
|
|
25871
|
+
const wasReplaced = force && existingExactIndex !== -1;
|
|
25872
|
+
if (wasReplaced) {
|
|
25873
|
+
config.plugins.splice(existingExactIndex, 1);
|
|
25794
25874
|
}
|
|
25795
|
-
|
|
25796
|
-
|
|
25797
|
-
|
|
25798
|
-
|
|
25799
|
-
|
|
25800
|
-
|
|
25801
|
-
|
|
25875
|
+
config.plugins.push(plugin);
|
|
25876
|
+
const newContent = dump(config, { lineWidth: -1 });
|
|
25877
|
+
await writeFile(configPath, newContent, "utf-8");
|
|
25878
|
+
const result = {
|
|
25879
|
+
success: true,
|
|
25880
|
+
normalizedPlugin: plugin
|
|
25881
|
+
};
|
|
25882
|
+
if (autoRegistered) {
|
|
25883
|
+
result.autoRegistered = autoRegistered;
|
|
25802
25884
|
}
|
|
25803
|
-
|
|
25804
|
-
|
|
25805
|
-
filteredDirs = candidateDirs.filter((e) => enabledSkills?.has(`${pluginName}:${e.name}`));
|
|
25806
|
-
} else if (disabledSkills) {
|
|
25807
|
-
filteredDirs = candidateDirs.filter((e) => !disabledSkills.has(`${pluginName}:${e.name}`));
|
|
25808
|
-
} else {
|
|
25809
|
-
filteredDirs = candidateDirs;
|
|
25885
|
+
if (wasReplaced) {
|
|
25886
|
+
result.replaced = true;
|
|
25810
25887
|
}
|
|
25811
|
-
|
|
25812
|
-
|
|
25888
|
+
return result;
|
|
25889
|
+
} catch (error) {
|
|
25890
|
+
return {
|
|
25891
|
+
success: false,
|
|
25892
|
+
error: error instanceof Error ? error.message : String(error)
|
|
25893
|
+
};
|
|
25813
25894
|
}
|
|
25814
|
-
return filteredDirs.map((entry) => ({
|
|
25815
|
-
folderName: entry.name,
|
|
25816
|
-
skillPath: entry.path,
|
|
25817
|
-
pluginPath,
|
|
25818
|
-
pluginSource
|
|
25819
|
-
}));
|
|
25820
25895
|
}
|
|
25821
|
-
async function
|
|
25822
|
-
const
|
|
25823
|
-
|
|
25824
|
-
|
|
25825
|
-
if (!mapping.hooksPath) {
|
|
25826
|
-
return results;
|
|
25827
|
-
}
|
|
25828
|
-
const sourceDir = join7(pluginPath, "hooks");
|
|
25829
|
-
if (!existsSync4(sourceDir)) {
|
|
25830
|
-
return results;
|
|
25831
|
-
}
|
|
25832
|
-
const destDir = join7(workspacePath, mapping.hooksPath);
|
|
25833
|
-
if (dryRun) {
|
|
25834
|
-
results.push({ source: sourceDir, destination: destDir, action: "copied" });
|
|
25835
|
-
return results;
|
|
25836
|
-
}
|
|
25837
|
-
await mkdir3(destDir, { recursive: true });
|
|
25896
|
+
async function hasPlugin(plugin, workspacePath = process.cwd()) {
|
|
25897
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
25898
|
+
if (!existsSync5(configPath))
|
|
25899
|
+
return false;
|
|
25838
25900
|
try {
|
|
25839
|
-
|
|
25840
|
-
|
|
25841
|
-
|
|
25842
|
-
|
|
25901
|
+
const content = await readFile4(configPath, "utf-8");
|
|
25902
|
+
const config = load(content);
|
|
25903
|
+
if (config.plugins.some((entry) => getPluginSource(entry) === plugin))
|
|
25904
|
+
return true;
|
|
25905
|
+
if (!isPluginSpec(plugin)) {
|
|
25906
|
+
return config.plugins.some((entry) => {
|
|
25907
|
+
const source = getPluginSource(entry);
|
|
25908
|
+
return source.startsWith(`${plugin}@`) || source === plugin;
|
|
25909
|
+
});
|
|
25843
25910
|
}
|
|
25844
|
-
|
|
25845
|
-
} catch
|
|
25846
|
-
|
|
25847
|
-
source: sourceDir,
|
|
25848
|
-
destination: destDir,
|
|
25849
|
-
action: "failed",
|
|
25850
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
25851
|
-
});
|
|
25911
|
+
return false;
|
|
25912
|
+
} catch {
|
|
25913
|
+
return false;
|
|
25852
25914
|
}
|
|
25853
|
-
return results;
|
|
25854
25915
|
}
|
|
25855
|
-
async function
|
|
25856
|
-
const
|
|
25857
|
-
|
|
25858
|
-
|
|
25859
|
-
|
|
25860
|
-
|
|
25861
|
-
|
|
25862
|
-
|
|
25863
|
-
if (!existsSync4(sourceDir)) {
|
|
25864
|
-
return results;
|
|
25865
|
-
}
|
|
25866
|
-
const destDir = join7(workspacePath, mapping.agentsPath);
|
|
25867
|
-
if (!dryRun) {
|
|
25868
|
-
await mkdir3(destDir, { recursive: true });
|
|
25916
|
+
async function removePlugin(plugin, workspacePath = process.cwd()) {
|
|
25917
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
25918
|
+
if (!existsSync5(configPath)) {
|
|
25919
|
+
return {
|
|
25920
|
+
success: false,
|
|
25921
|
+
error: `${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE} not found in ${workspacePath}
|
|
25922
|
+
Run 'allagents workspace init <path>' to create a new workspace`
|
|
25923
|
+
};
|
|
25869
25924
|
}
|
|
25870
|
-
|
|
25871
|
-
|
|
25872
|
-
|
|
25873
|
-
|
|
25874
|
-
|
|
25875
|
-
|
|
25876
|
-
|
|
25925
|
+
try {
|
|
25926
|
+
const content = await readFile4(configPath, "utf-8");
|
|
25927
|
+
const config = load(content);
|
|
25928
|
+
let index = config.plugins.findIndex((entry) => getPluginSource(entry) === plugin);
|
|
25929
|
+
if (index === -1 && isPluginSpec(plugin) === false) {
|
|
25930
|
+
index = config.plugins.findIndex((entry) => {
|
|
25931
|
+
const source = getPluginSource(entry);
|
|
25932
|
+
return source.startsWith(`${plugin}@`) || source === plugin;
|
|
25933
|
+
});
|
|
25877
25934
|
}
|
|
25878
|
-
|
|
25879
|
-
const
|
|
25880
|
-
|
|
25881
|
-
|
|
25882
|
-
|
|
25935
|
+
if (index === -1) {
|
|
25936
|
+
const identity = await resolveGitHubIdentity(plugin);
|
|
25937
|
+
if (identity) {
|
|
25938
|
+
for (let i2 = 0;i2 < config.plugins.length; i2++) {
|
|
25939
|
+
const p = config.plugins[i2];
|
|
25940
|
+
if (!p)
|
|
25941
|
+
continue;
|
|
25942
|
+
const existing = await resolveGitHubIdentity(getPluginSource(p));
|
|
25943
|
+
if (existing === identity) {
|
|
25944
|
+
index = i2;
|
|
25945
|
+
break;
|
|
25946
|
+
}
|
|
25947
|
+
}
|
|
25948
|
+
}
|
|
25949
|
+
}
|
|
25950
|
+
if (index === -1) {
|
|
25883
25951
|
return {
|
|
25884
|
-
|
|
25885
|
-
|
|
25886
|
-
action: "failed",
|
|
25887
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
25952
|
+
success: false,
|
|
25953
|
+
error: `Plugin not found in .allagents/workspace.yaml: ${plugin}`
|
|
25888
25954
|
};
|
|
25889
25955
|
}
|
|
25890
|
-
|
|
25891
|
-
|
|
25956
|
+
const removedEntry = getPluginSource(config.plugins[index]);
|
|
25957
|
+
config.plugins.splice(index, 1);
|
|
25958
|
+
pruneDisabledSkillsForPlugin(config, removedEntry);
|
|
25959
|
+
pruneEnabledSkillsForPlugin(config, removedEntry);
|
|
25960
|
+
const newContent = dump(config, { lineWidth: -1 });
|
|
25961
|
+
await writeFile(configPath, newContent, "utf-8");
|
|
25962
|
+
return { success: true };
|
|
25963
|
+
} catch (error) {
|
|
25964
|
+
return {
|
|
25965
|
+
success: false,
|
|
25966
|
+
error: error instanceof Error ? error.message : String(error)
|
|
25967
|
+
};
|
|
25968
|
+
}
|
|
25892
25969
|
}
|
|
25893
|
-
|
|
25894
|
-
|
|
25895
|
-
|
|
25896
|
-
|
|
25897
|
-
|
|
25898
|
-
|
|
25899
|
-
|
|
25900
|
-
|
|
25901
|
-
|
|
25902
|
-
|
|
25903
|
-
|
|
25904
|
-
|
|
25905
|
-
|
|
25906
|
-
|
|
25907
|
-
|
|
25908
|
-
|
|
25909
|
-
|
|
25910
|
-
|
|
25911
|
-
|
|
25912
|
-
|
|
25913
|
-
|
|
25914
|
-
|
|
25915
|
-
|
|
25916
|
-
|
|
25970
|
+
function pruneDisabledSkillsForPlugin(config, pluginEntry) {
|
|
25971
|
+
if (!config.disabledSkills?.length)
|
|
25972
|
+
return;
|
|
25973
|
+
const names = extractPluginNames(pluginEntry);
|
|
25974
|
+
if (names.length === 0)
|
|
25975
|
+
return;
|
|
25976
|
+
const prefixes = names.map((n) => `${n}:`);
|
|
25977
|
+
config.disabledSkills = config.disabledSkills.filter((s) => !prefixes.some((p) => s.startsWith(p)));
|
|
25978
|
+
if (config.disabledSkills.length === 0) {
|
|
25979
|
+
config.disabledSkills = undefined;
|
|
25980
|
+
}
|
|
25981
|
+
}
|
|
25982
|
+
function extractPluginNames(pluginSource) {
|
|
25983
|
+
if (isPluginSpec(pluginSource)) {
|
|
25984
|
+
const parsed = parsePluginSpec(pluginSource);
|
|
25985
|
+
if (!parsed)
|
|
25986
|
+
return [];
|
|
25987
|
+
const names = [parsed.plugin];
|
|
25988
|
+
if (parsed.marketplaceName && parsed.marketplaceName !== parsed.plugin) {
|
|
25989
|
+
names.push(parsed.marketplaceName);
|
|
25990
|
+
}
|
|
25991
|
+
return names;
|
|
25992
|
+
}
|
|
25993
|
+
if (isGitHubUrl(pluginSource)) {
|
|
25994
|
+
const parsed = parseGitHubUrl(pluginSource);
|
|
25995
|
+
if (parsed) {
|
|
25996
|
+
const names = [];
|
|
25997
|
+
const ownerRepo = `${parsed.owner}-${parsed.repo}`;
|
|
25998
|
+
if (ownerRepo !== parsed.repo)
|
|
25999
|
+
names.push(ownerRepo);
|
|
26000
|
+
if (parsed.subpath) {
|
|
26001
|
+
const subpathName = parsed.subpath.split("/").filter(Boolean).pop();
|
|
26002
|
+
if (subpathName && !names.includes(subpathName))
|
|
26003
|
+
names.push(subpathName);
|
|
26004
|
+
}
|
|
26005
|
+
if (!names.includes(parsed.repo))
|
|
26006
|
+
names.push(parsed.repo);
|
|
26007
|
+
if (!names.includes(ownerRepo))
|
|
26008
|
+
names.push(ownerRepo);
|
|
26009
|
+
return names;
|
|
25917
26010
|
}
|
|
25918
26011
|
}
|
|
26012
|
+
const parts = pluginSource.split(/[/\\]/).filter(Boolean);
|
|
26013
|
+
const last2 = parts[parts.length - 1];
|
|
26014
|
+
if (!last2)
|
|
26015
|
+
return [];
|
|
26016
|
+
return [last2.replace(/\.git$/, "")];
|
|
25919
26017
|
}
|
|
25920
|
-
|
|
25921
|
-
|
|
25922
|
-
|
|
25923
|
-
|
|
25924
|
-
|
|
25925
|
-
|
|
26018
|
+
function findPluginEntryByName(config, pluginName) {
|
|
26019
|
+
return config.plugins.findIndex((entry) => extractPluginNames(getPluginSource(entry)).includes(pluginName));
|
|
26020
|
+
}
|
|
26021
|
+
function ensureObjectPluginEntry(config, index) {
|
|
26022
|
+
const entry = config.plugins[index];
|
|
26023
|
+
if (entry === undefined)
|
|
26024
|
+
throw new Error(`Plugin entry at index ${index} not found`);
|
|
26025
|
+
if (typeof entry === "string") {
|
|
26026
|
+
const objectEntry = { source: entry };
|
|
26027
|
+
config.plugins[index] = objectEntry;
|
|
26028
|
+
return objectEntry;
|
|
25926
26029
|
}
|
|
25927
|
-
|
|
25928
|
-
|
|
25929
|
-
|
|
26030
|
+
return entry;
|
|
26031
|
+
}
|
|
26032
|
+
function uniqueSkillNames(skillNames) {
|
|
26033
|
+
const unique = [];
|
|
26034
|
+
const seen = new Set;
|
|
26035
|
+
for (const skillName of skillNames) {
|
|
26036
|
+
if (seen.has(skillName))
|
|
26037
|
+
continue;
|
|
26038
|
+
seen.add(skillName);
|
|
26039
|
+
unique.push(skillName);
|
|
26040
|
+
}
|
|
26041
|
+
return unique;
|
|
26042
|
+
}
|
|
26043
|
+
function formatGitHubSource(parsed, styleSource) {
|
|
26044
|
+
const basePath = `${parsed.owner}/${parsed.repo}`;
|
|
26045
|
+
if (styleSource.startsWith("http://") || styleSource.startsWith("https://") || styleSource.startsWith("github.com/")) {
|
|
26046
|
+
const baseUrl = `https://github.com/${basePath}`;
|
|
26047
|
+
if (!parsed.branch)
|
|
26048
|
+
return baseUrl;
|
|
26049
|
+
return parsed.subpath ? `${baseUrl}/tree/${parsed.branch}/${parsed.subpath}` : `${baseUrl}/tree/${parsed.branch}`;
|
|
26050
|
+
}
|
|
26051
|
+
if (!parsed.branch) {
|
|
26052
|
+
return parsed.subpath ? `${basePath}/${parsed.subpath}` : basePath;
|
|
26053
|
+
}
|
|
26054
|
+
return parsed.subpath ? `${basePath}@${parsed.branch}/${parsed.subpath}` : `${basePath}@${parsed.branch}`;
|
|
26055
|
+
}
|
|
26056
|
+
function canonicalizeGitHubPluginSource(currentSource, nextSource) {
|
|
26057
|
+
const current = parseGitHubUrl(currentSource);
|
|
26058
|
+
const next = parseGitHubUrl(nextSource);
|
|
26059
|
+
if (!current || !next)
|
|
26060
|
+
return nextSource;
|
|
26061
|
+
if (current.owner.toLowerCase() !== next.owner.toLowerCase() || current.repo.toLowerCase() !== next.repo.toLowerCase()) {
|
|
26062
|
+
return nextSource;
|
|
26063
|
+
}
|
|
26064
|
+
if (current.branch && next.branch && current.branch !== next.branch) {
|
|
26065
|
+
return currentSource;
|
|
26066
|
+
}
|
|
26067
|
+
const currentParts = current.subpath?.split("/").filter(Boolean) ?? [];
|
|
26068
|
+
const nextParts = next.subpath?.split("/").filter(Boolean) ?? [];
|
|
26069
|
+
const sharedParts = [];
|
|
26070
|
+
const sharedLength = Math.min(currentParts.length, nextParts.length);
|
|
26071
|
+
for (let i2 = 0;i2 < sharedLength; i2++) {
|
|
26072
|
+
if (currentParts[i2] !== nextParts[i2])
|
|
26073
|
+
break;
|
|
26074
|
+
sharedParts.push(currentParts[i2]);
|
|
26075
|
+
}
|
|
26076
|
+
return formatGitHubSource({
|
|
26077
|
+
owner: current.owner,
|
|
26078
|
+
repo: current.repo,
|
|
26079
|
+
...current.branch || next.branch ? { branch: current.branch ?? next.branch } : {},
|
|
26080
|
+
...sharedParts.length > 0 ? { subpath: sharedParts.join("/") } : {}
|
|
26081
|
+
}, currentSource);
|
|
26082
|
+
}
|
|
26083
|
+
async function findPluginEntryByGitHubIdentity(config, source) {
|
|
26084
|
+
const identity = await resolveGitHubIdentity(source);
|
|
26085
|
+
if (!identity)
|
|
26086
|
+
return -1;
|
|
26087
|
+
for (let i2 = 0;i2 < config.plugins.length; i2++) {
|
|
26088
|
+
const entry = config.plugins[i2];
|
|
26089
|
+
if (!entry)
|
|
26090
|
+
continue;
|
|
26091
|
+
const existingIdentity = await resolveGitHubIdentity(getPluginSource(entry));
|
|
26092
|
+
if (existingIdentity === identity)
|
|
26093
|
+
return i2;
|
|
25930
26094
|
}
|
|
25931
|
-
|
|
25932
|
-
|
|
25933
|
-
|
|
25934
|
-
|
|
26095
|
+
return -1;
|
|
26096
|
+
}
|
|
26097
|
+
async function upsertGitHubPluginSourceAllowlistInConfig(config, source, skillNames) {
|
|
26098
|
+
const normalizedSkills = uniqueSkillNames(skillNames);
|
|
26099
|
+
const exactIndex = config.plugins.findIndex((entry2) => getPluginSource(entry2) === source);
|
|
26100
|
+
if (exactIndex !== -1) {
|
|
26101
|
+
const entry2 = ensureObjectPluginEntry(config, exactIndex);
|
|
26102
|
+
entry2.source = source;
|
|
26103
|
+
entry2.skills = normalizedSkills;
|
|
26104
|
+
return { success: true, normalizedPlugin: source };
|
|
26105
|
+
}
|
|
26106
|
+
const semanticIndex = await findPluginEntryByGitHubIdentity(config, source);
|
|
26107
|
+
if (semanticIndex === -1) {
|
|
26108
|
+
config.plugins.push({ source, skills: normalizedSkills });
|
|
26109
|
+
return { success: true, normalizedPlugin: source };
|
|
26110
|
+
}
|
|
26111
|
+
const entry = ensureObjectPluginEntry(config, semanticIndex);
|
|
26112
|
+
const normalizedSource = canonicalizeGitHubPluginSource(entry.source, source);
|
|
26113
|
+
entry.source = normalizedSource;
|
|
26114
|
+
entry.skills = normalizedSkills;
|
|
26115
|
+
return { success: true, normalizedPlugin: normalizedSource };
|
|
26116
|
+
}
|
|
26117
|
+
function parseSkillKey(skillKey) {
|
|
26118
|
+
const colonIdx = skillKey.indexOf(":");
|
|
26119
|
+
if (colonIdx === -1)
|
|
26120
|
+
return null;
|
|
26121
|
+
return {
|
|
26122
|
+
pluginName: skillKey.slice(0, colonIdx),
|
|
26123
|
+
skillName: skillKey.slice(colonIdx + 1)
|
|
26124
|
+
};
|
|
26125
|
+
}
|
|
26126
|
+
async function addDisabledSkill(skillKey, workspacePath = process.cwd()) {
|
|
26127
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
26128
|
+
if (!existsSync5(configPath)) {
|
|
26129
|
+
return {
|
|
26130
|
+
success: false,
|
|
26131
|
+
error: `${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE} not found in ${workspacePath}`
|
|
26132
|
+
};
|
|
25935
26133
|
}
|
|
26134
|
+
const parsed = parseSkillKey(skillKey);
|
|
26135
|
+
if (!parsed) {
|
|
26136
|
+
return {
|
|
26137
|
+
success: false,
|
|
26138
|
+
error: `Invalid skill key format: '${skillKey}' (expected pluginName:skillName)`
|
|
26139
|
+
};
|
|
26140
|
+
}
|
|
26141
|
+
const { pluginName, skillName } = parsed;
|
|
25936
26142
|
try {
|
|
25937
|
-
|
|
25938
|
-
|
|
25939
|
-
|
|
25940
|
-
|
|
26143
|
+
const content = await readFile4(configPath, "utf-8");
|
|
26144
|
+
const config = load(content);
|
|
26145
|
+
const index = findPluginEntryByName(config, pluginName);
|
|
26146
|
+
if (index === -1) {
|
|
26147
|
+
return {
|
|
26148
|
+
success: false,
|
|
26149
|
+
error: `Plugin '${pluginName}' not found in workspace config`
|
|
26150
|
+
};
|
|
25941
26151
|
}
|
|
25942
|
-
|
|
26152
|
+
const entry = ensureObjectPluginEntry(config, index);
|
|
26153
|
+
if (Array.isArray(entry.skills)) {
|
|
26154
|
+
return {
|
|
26155
|
+
success: false,
|
|
26156
|
+
error: `Plugin '${pluginName}' is in allowlist mode; use removeEnabledSkill to disable a skill`
|
|
26157
|
+
};
|
|
26158
|
+
}
|
|
26159
|
+
const existing = entry.skills?.exclude ?? [];
|
|
26160
|
+
if (existing.includes(skillName)) {
|
|
26161
|
+
return {
|
|
26162
|
+
success: false,
|
|
26163
|
+
error: `Skill '${skillKey}' is already disabled`
|
|
26164
|
+
};
|
|
26165
|
+
}
|
|
26166
|
+
entry.skills = { exclude: [...existing, skillName] };
|
|
26167
|
+
await writeFile(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
26168
|
+
return { success: true };
|
|
25943
26169
|
} catch (error) {
|
|
25944
|
-
|
|
25945
|
-
|
|
25946
|
-
|
|
25947
|
-
|
|
25948
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
25949
|
-
});
|
|
26170
|
+
return {
|
|
26171
|
+
success: false,
|
|
26172
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26173
|
+
};
|
|
25950
26174
|
}
|
|
25951
|
-
return results;
|
|
25952
|
-
}
|
|
25953
|
-
async function copyPluginToWorkspace(pluginPath, workspacePath, client, options2 = {}) {
|
|
25954
|
-
const { skillNameMap, syncMode, canonicalSkillsPath, ...baseOptions } = options2;
|
|
25955
|
-
const [commandResults, skillResults, hookResults, agentResults] = await Promise.all([
|
|
25956
|
-
copyCommands(pluginPath, workspacePath, client, baseOptions),
|
|
25957
|
-
copySkills(pluginPath, workspacePath, client, {
|
|
25958
|
-
...baseOptions,
|
|
25959
|
-
...skillNameMap && { skillNameMap },
|
|
25960
|
-
...syncMode && { syncMode },
|
|
25961
|
-
...canonicalSkillsPath && { canonicalSkillsPath }
|
|
25962
|
-
}),
|
|
25963
|
-
copyHooks(pluginPath, workspacePath, client, baseOptions),
|
|
25964
|
-
copyAgents(pluginPath, workspacePath, client, baseOptions)
|
|
25965
|
-
]);
|
|
25966
|
-
const githubResults = await copyGitHubContent(pluginPath, workspacePath, client, {
|
|
25967
|
-
...baseOptions,
|
|
25968
|
-
...skillNameMap && { skillNameMap }
|
|
25969
|
-
});
|
|
25970
|
-
return [...commandResults, ...skillResults, ...hookResults, ...agentResults, ...githubResults];
|
|
25971
26175
|
}
|
|
25972
|
-
function
|
|
25973
|
-
|
|
25974
|
-
|
|
26176
|
+
async function removeDisabledSkill(skillKey, workspacePath = process.cwd()) {
|
|
26177
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
26178
|
+
if (!existsSync5(configPath)) {
|
|
26179
|
+
return {
|
|
26180
|
+
success: false,
|
|
26181
|
+
error: `${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE} not found in ${workspacePath}`
|
|
26182
|
+
};
|
|
25975
26183
|
}
|
|
25976
|
-
|
|
25977
|
-
|
|
25978
|
-
|
|
25979
|
-
|
|
25980
|
-
|
|
25981
|
-
|
|
25982
|
-
}
|
|
25983
|
-
}
|
|
26184
|
+
const parsed = parseSkillKey(skillKey);
|
|
26185
|
+
if (!parsed) {
|
|
26186
|
+
return {
|
|
26187
|
+
success: false,
|
|
26188
|
+
error: `Invalid skill key format: '${skillKey}' (expected pluginName:skillName)`
|
|
26189
|
+
};
|
|
25984
26190
|
}
|
|
25985
|
-
|
|
25986
|
-
|
|
25987
|
-
|
|
25988
|
-
|
|
25989
|
-
|
|
25990
|
-
|
|
26191
|
+
const { pluginName, skillName } = parsed;
|
|
26192
|
+
try {
|
|
26193
|
+
const content = await readFile4(configPath, "utf-8");
|
|
26194
|
+
const config = load(content);
|
|
26195
|
+
const index = findPluginEntryByName(config, pluginName);
|
|
26196
|
+
if (index === -1) {
|
|
26197
|
+
return {
|
|
26198
|
+
success: false,
|
|
26199
|
+
error: `Plugin '${pluginName}' not found in workspace config`
|
|
26200
|
+
};
|
|
25991
26201
|
}
|
|
25992
|
-
|
|
25993
|
-
|
|
26202
|
+
const entry = config.plugins[index];
|
|
26203
|
+
if (!entry) {
|
|
26204
|
+
return { success: false, error: `Plugin '${pluginName}' not found in workspace config` };
|
|
25994
26205
|
}
|
|
25995
|
-
if (
|
|
25996
|
-
return {
|
|
26206
|
+
if (typeof entry === "string" || !entry.skills || Array.isArray(entry.skills)) {
|
|
26207
|
+
return {
|
|
26208
|
+
success: false,
|
|
26209
|
+
error: `Skill '${skillKey}' is already enabled`
|
|
26210
|
+
};
|
|
25997
26211
|
}
|
|
25998
|
-
|
|
25999
|
-
}
|
|
26000
|
-
const parsed = parseFileSource(source);
|
|
26001
|
-
if (parsed.type === "github" && parsed.owner && parsed.repo && parsed.filePath) {
|
|
26002
|
-
const cacheKey = `${parsed.owner}/${parsed.repo}`;
|
|
26003
|
-
const cachePath = githubCache?.get(cacheKey);
|
|
26004
|
-
if (!cachePath) {
|
|
26212
|
+
if (!entry.skills.exclude.includes(skillName)) {
|
|
26005
26213
|
return {
|
|
26006
|
-
|
|
26007
|
-
error: `
|
|
26214
|
+
success: false,
|
|
26215
|
+
error: `Skill '${skillKey}' is already enabled`
|
|
26008
26216
|
};
|
|
26009
26217
|
}
|
|
26010
|
-
|
|
26011
|
-
|
|
26012
|
-
|
|
26218
|
+
const newExclude = entry.skills.exclude.filter((s) => s !== skillName);
|
|
26219
|
+
entry.skills = newExclude.length > 0 ? { exclude: newExclude } : undefined;
|
|
26220
|
+
await writeFile(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
26221
|
+
return { success: true };
|
|
26222
|
+
} catch (error) {
|
|
26013
26223
|
return {
|
|
26014
|
-
|
|
26015
|
-
error:
|
|
26224
|
+
success: false,
|
|
26225
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26016
26226
|
};
|
|
26017
26227
|
}
|
|
26018
|
-
return null;
|
|
26019
26228
|
}
|
|
26020
|
-
async function
|
|
26021
|
-
const
|
|
26022
|
-
|
|
26023
|
-
|
|
26024
|
-
|
|
26025
|
-
|
|
26026
|
-
|
|
26027
|
-
if (typeof file === "string") {
|
|
26028
|
-
stringPatterns.push(file);
|
|
26029
|
-
} else {
|
|
26030
|
-
let dest = file.dest;
|
|
26031
|
-
if (!dest && file.source) {
|
|
26032
|
-
const parts = file.source.split("/");
|
|
26033
|
-
dest = parts[parts.length - 1] || file.source;
|
|
26034
|
-
}
|
|
26035
|
-
if (!dest) {
|
|
26036
|
-
results.push({
|
|
26037
|
-
source: "unknown",
|
|
26038
|
-
destination: join7(workspacePath, "unknown"),
|
|
26039
|
-
action: "failed",
|
|
26040
|
-
error: "File entry must have at least source or dest specified"
|
|
26041
|
-
});
|
|
26042
|
-
continue;
|
|
26043
|
-
}
|
|
26044
|
-
objectEntries.push(file.source ? { source: file.source, dest } : { dest });
|
|
26045
|
-
}
|
|
26229
|
+
async function addEnabledSkill(skillKey, workspacePath = process.cwd()) {
|
|
26230
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
26231
|
+
if (!existsSync5(configPath)) {
|
|
26232
|
+
return {
|
|
26233
|
+
success: false,
|
|
26234
|
+
error: `${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE} not found in ${workspacePath}`
|
|
26235
|
+
};
|
|
26046
26236
|
}
|
|
26047
|
-
|
|
26048
|
-
|
|
26049
|
-
|
|
26050
|
-
|
|
26051
|
-
|
|
26052
|
-
|
|
26053
|
-
destination: join7(workspacePath, pattern),
|
|
26054
|
-
action: "failed",
|
|
26055
|
-
error: `Cannot resolve file '${pattern}' - no workspace.source configured and no explicit source provided`
|
|
26056
|
-
});
|
|
26057
|
-
}
|
|
26058
|
-
}
|
|
26059
|
-
} else {
|
|
26060
|
-
const resolvedFiles = await resolveGlobPatterns(sourcePath, stringPatterns);
|
|
26061
|
-
for (const resolved of resolvedFiles) {
|
|
26062
|
-
const destPath = join7(workspacePath, resolved.relativePath);
|
|
26063
|
-
if (!existsSync4(resolved.sourcePath)) {
|
|
26064
|
-
const wasLiteral = stringPatterns.some((p) => !isGlobPattern(p) && !p.startsWith("!") && p === resolved.relativePath);
|
|
26065
|
-
if (wasLiteral) {
|
|
26066
|
-
results.push({
|
|
26067
|
-
source: resolved.sourcePath,
|
|
26068
|
-
destination: destPath,
|
|
26069
|
-
action: "failed",
|
|
26070
|
-
error: `Source file not found: ${resolved.sourcePath}`
|
|
26071
|
-
});
|
|
26072
|
-
}
|
|
26073
|
-
continue;
|
|
26074
|
-
}
|
|
26075
|
-
if (dryRun) {
|
|
26076
|
-
results.push({ source: resolved.sourcePath, destination: destPath, action: "copied" });
|
|
26077
|
-
if (AGENT_FILES2.includes(resolved.relativePath)) {
|
|
26078
|
-
copiedAgentFiles.push(resolved.relativePath);
|
|
26079
|
-
}
|
|
26080
|
-
continue;
|
|
26081
|
-
}
|
|
26082
|
-
try {
|
|
26083
|
-
await mkdir3(dirname4(destPath), { recursive: true });
|
|
26084
|
-
const content = await readFile3(resolved.sourcePath, "utf-8");
|
|
26085
|
-
await writeFile(destPath, content, "utf-8");
|
|
26086
|
-
results.push({ source: resolved.sourcePath, destination: destPath, action: "copied" });
|
|
26087
|
-
if (AGENT_FILES2.includes(resolved.relativePath)) {
|
|
26088
|
-
copiedAgentFiles.push(resolved.relativePath);
|
|
26089
|
-
}
|
|
26090
|
-
} catch (error) {
|
|
26091
|
-
results.push({
|
|
26092
|
-
source: resolved.sourcePath,
|
|
26093
|
-
destination: destPath,
|
|
26094
|
-
action: "failed",
|
|
26095
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
26096
|
-
});
|
|
26097
|
-
}
|
|
26098
|
-
}
|
|
26099
|
-
}
|
|
26237
|
+
const parsed = parseSkillKey(skillKey);
|
|
26238
|
+
if (!parsed) {
|
|
26239
|
+
return {
|
|
26240
|
+
success: false,
|
|
26241
|
+
error: `Invalid skill key format: '${skillKey}' (expected pluginName:skillName)`
|
|
26242
|
+
};
|
|
26100
26243
|
}
|
|
26101
|
-
|
|
26102
|
-
|
|
26103
|
-
|
|
26104
|
-
|
|
26105
|
-
|
|
26106
|
-
|
|
26107
|
-
|
|
26108
|
-
|
|
26109
|
-
|
|
26110
|
-
|
|
26111
|
-
error: `Failed to resolve source: ${entry.source}`
|
|
26112
|
-
});
|
|
26113
|
-
continue;
|
|
26114
|
-
}
|
|
26115
|
-
if (resolved.error) {
|
|
26116
|
-
results.push({
|
|
26117
|
-
source: entry.source,
|
|
26118
|
-
destination: destPath,
|
|
26119
|
-
action: "failed",
|
|
26120
|
-
error: resolved.error
|
|
26121
|
-
});
|
|
26122
|
-
continue;
|
|
26123
|
-
}
|
|
26124
|
-
srcPath = resolved.path;
|
|
26125
|
-
} else {
|
|
26126
|
-
if (!sourcePath) {
|
|
26127
|
-
results.push({
|
|
26128
|
-
source: entry.dest,
|
|
26129
|
-
destination: destPath,
|
|
26130
|
-
action: "failed",
|
|
26131
|
-
error: `Cannot resolve file '${entry.dest}' - no workspace.source configured and no explicit source provided`
|
|
26132
|
-
});
|
|
26133
|
-
continue;
|
|
26134
|
-
}
|
|
26135
|
-
srcPath = join7(sourcePath, entry.dest);
|
|
26136
|
-
}
|
|
26137
|
-
if (!existsSync4(srcPath)) {
|
|
26138
|
-
results.push({
|
|
26139
|
-
source: srcPath,
|
|
26140
|
-
destination: destPath,
|
|
26141
|
-
action: "failed",
|
|
26142
|
-
error: `Source file not found: ${srcPath}`
|
|
26143
|
-
});
|
|
26144
|
-
continue;
|
|
26145
|
-
}
|
|
26146
|
-
if (dryRun) {
|
|
26147
|
-
results.push({ source: srcPath, destination: destPath, action: "copied" });
|
|
26148
|
-
if (AGENT_FILES2.includes(entry.dest)) {
|
|
26149
|
-
copiedAgentFiles.push(entry.dest);
|
|
26150
|
-
}
|
|
26151
|
-
continue;
|
|
26244
|
+
const { pluginName, skillName } = parsed;
|
|
26245
|
+
try {
|
|
26246
|
+
const content = await readFile4(configPath, "utf-8");
|
|
26247
|
+
const config = load(content);
|
|
26248
|
+
const index = findPluginEntryByName(config, pluginName);
|
|
26249
|
+
if (index === -1) {
|
|
26250
|
+
return {
|
|
26251
|
+
success: false,
|
|
26252
|
+
error: `Plugin '${pluginName}' not found in workspace config`
|
|
26253
|
+
};
|
|
26152
26254
|
}
|
|
26153
|
-
|
|
26154
|
-
|
|
26155
|
-
|
|
26156
|
-
|
|
26157
|
-
|
|
26158
|
-
|
|
26159
|
-
copiedAgentFiles.push(entry.dest);
|
|
26160
|
-
}
|
|
26161
|
-
} catch (error) {
|
|
26162
|
-
results.push({
|
|
26163
|
-
source: srcPath,
|
|
26164
|
-
destination: destPath,
|
|
26165
|
-
action: "failed",
|
|
26166
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
26167
|
-
});
|
|
26255
|
+
const entry = ensureObjectPluginEntry(config, index);
|
|
26256
|
+
if (entry.skills && !Array.isArray(entry.skills)) {
|
|
26257
|
+
return {
|
|
26258
|
+
success: false,
|
|
26259
|
+
error: `Plugin '${pluginName}' is in blocklist mode; use removeDisabledSkill to enable a skill`
|
|
26260
|
+
};
|
|
26168
26261
|
}
|
|
26169
|
-
|
|
26170
|
-
|
|
26171
|
-
|
|
26172
|
-
|
|
26173
|
-
|
|
26174
|
-
|
|
26175
|
-
} catch (error) {
|
|
26176
|
-
results.push({
|
|
26177
|
-
source: "WORKSPACE-RULES",
|
|
26178
|
-
destination: targetPath,
|
|
26179
|
-
action: "failed",
|
|
26180
|
-
error: error instanceof Error ? error.message : "Failed to inject WORKSPACE-RULES"
|
|
26181
|
-
});
|
|
26182
|
-
}
|
|
26262
|
+
const existing = entry.skills ?? [];
|
|
26263
|
+
if (existing.includes(skillName)) {
|
|
26264
|
+
return {
|
|
26265
|
+
success: false,
|
|
26266
|
+
error: `Skill '${skillKey}' is already enabled`
|
|
26267
|
+
};
|
|
26183
26268
|
}
|
|
26269
|
+
entry.skills = [...existing, skillName];
|
|
26270
|
+
await writeFile(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
26271
|
+
return { success: true };
|
|
26272
|
+
} catch (error) {
|
|
26273
|
+
return {
|
|
26274
|
+
success: false,
|
|
26275
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26276
|
+
};
|
|
26184
26277
|
}
|
|
26185
|
-
return results;
|
|
26186
26278
|
}
|
|
26187
|
-
|
|
26188
|
-
|
|
26189
|
-
|
|
26190
|
-
init_client_mapping();
|
|
26191
|
-
init_constants();
|
|
26192
|
-
init_plugin_path();
|
|
26193
|
-
init_symlink();
|
|
26194
|
-
init_link_adjuster();
|
|
26195
|
-
init_skill();
|
|
26196
|
-
import_micromatch = __toESM(require_micromatch(), 1);
|
|
26197
|
-
AGENT_FILES2 = ["AGENTS.md", "CLAUDE.md"];
|
|
26198
|
-
});
|
|
26199
|
-
|
|
26200
|
-
// src/models/marketplace-manifest.ts
|
|
26201
|
-
var UrlSourceSchema, GitHubSourceSchema, PluginSourceRefSchema, ContactSchema, LspServerSchema, MarketplacePluginEntrySchema, MarketplaceManifestSchema, MarketplaceManifestLenientSchema;
|
|
26202
|
-
var init_marketplace_manifest = __esm(() => {
|
|
26203
|
-
init_zod();
|
|
26204
|
-
UrlSourceSchema = exports_external.object({
|
|
26205
|
-
source: exports_external.literal("url"),
|
|
26206
|
-
url: exports_external.string().url()
|
|
26207
|
-
});
|
|
26208
|
-
GitHubSourceSchema = exports_external.object({
|
|
26209
|
-
source: exports_external.literal("github"),
|
|
26210
|
-
repo: exports_external.string().min(1)
|
|
26211
|
-
}).transform((val) => ({
|
|
26212
|
-
source: "url",
|
|
26213
|
-
url: `https://github.com/${val.repo}`
|
|
26214
|
-
}));
|
|
26215
|
-
PluginSourceRefSchema = exports_external.union([exports_external.string(), UrlSourceSchema, GitHubSourceSchema]);
|
|
26216
|
-
ContactSchema = exports_external.object({
|
|
26217
|
-
name: exports_external.string(),
|
|
26218
|
-
email: exports_external.string().optional()
|
|
26219
|
-
});
|
|
26220
|
-
LspServerSchema = exports_external.object({
|
|
26221
|
-
command: exports_external.string(),
|
|
26222
|
-
args: exports_external.array(exports_external.string()).optional(),
|
|
26223
|
-
extensionToLanguage: exports_external.record(exports_external.string()).optional(),
|
|
26224
|
-
startupTimeout: exports_external.number().optional()
|
|
26225
|
-
});
|
|
26226
|
-
MarketplacePluginEntrySchema = exports_external.object({
|
|
26227
|
-
name: exports_external.string().min(1),
|
|
26228
|
-
description: exports_external.string().min(1),
|
|
26229
|
-
source: PluginSourceRefSchema,
|
|
26230
|
-
version: exports_external.string().optional(),
|
|
26231
|
-
author: ContactSchema.optional(),
|
|
26232
|
-
category: exports_external.string().optional(),
|
|
26233
|
-
homepage: exports_external.string().optional(),
|
|
26234
|
-
strict: exports_external.boolean().optional(),
|
|
26235
|
-
tags: exports_external.array(exports_external.string()).optional(),
|
|
26236
|
-
skills: exports_external.array(exports_external.string()).optional(),
|
|
26237
|
-
lspServers: exports_external.record(LspServerSchema).optional()
|
|
26238
|
-
});
|
|
26239
|
-
MarketplaceManifestSchema = exports_external.object({
|
|
26240
|
-
$schema: exports_external.string().optional(),
|
|
26241
|
-
name: exports_external.string().min(1),
|
|
26242
|
-
version: exports_external.string().optional(),
|
|
26243
|
-
description: exports_external.string().min(1),
|
|
26244
|
-
owner: ContactSchema.optional(),
|
|
26245
|
-
plugins: exports_external.array(MarketplacePluginEntrySchema)
|
|
26246
|
-
});
|
|
26247
|
-
MarketplaceManifestLenientSchema = exports_external.object({
|
|
26248
|
-
name: exports_external.string().optional(),
|
|
26249
|
-
plugins: exports_external.array(exports_external.unknown())
|
|
26250
|
-
}).passthrough();
|
|
26251
|
-
});
|
|
26252
|
-
|
|
26253
|
-
// src/utils/marketplace-manifest-parser.ts
|
|
26254
|
-
import { readFile as readFile4 } from "node:fs/promises";
|
|
26255
|
-
import { existsSync as existsSync5 } from "node:fs";
|
|
26256
|
-
import { join as join8, resolve as resolve5 } from "node:path";
|
|
26257
|
-
async function parseMarketplaceManifest(marketplacePath) {
|
|
26258
|
-
const manifestPath = join8(marketplacePath, MANIFEST_PATH);
|
|
26259
|
-
if (!existsSync5(manifestPath)) {
|
|
26279
|
+
async function removeEnabledSkill(skillKey, workspacePath = process.cwd()) {
|
|
26280
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
26281
|
+
if (!existsSync5(configPath)) {
|
|
26260
26282
|
return {
|
|
26261
26283
|
success: false,
|
|
26262
|
-
error:
|
|
26284
|
+
error: `${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE} not found in ${workspacePath}`
|
|
26263
26285
|
};
|
|
26264
26286
|
}
|
|
26265
|
-
|
|
26266
|
-
|
|
26267
|
-
raw = await readFile4(manifestPath, "utf-8");
|
|
26268
|
-
} catch (err) {
|
|
26287
|
+
const parsed = parseSkillKey(skillKey);
|
|
26288
|
+
if (!parsed) {
|
|
26269
26289
|
return {
|
|
26270
26290
|
success: false,
|
|
26271
|
-
error: `
|
|
26291
|
+
error: `Invalid skill key format: '${skillKey}' (expected pluginName:skillName)`
|
|
26272
26292
|
};
|
|
26273
26293
|
}
|
|
26274
|
-
|
|
26294
|
+
const { pluginName, skillName } = parsed;
|
|
26275
26295
|
try {
|
|
26276
|
-
|
|
26277
|
-
|
|
26296
|
+
const content = await readFile4(configPath, "utf-8");
|
|
26297
|
+
const config = load(content);
|
|
26298
|
+
const index = findPluginEntryByName(config, pluginName);
|
|
26299
|
+
if (index === -1) {
|
|
26300
|
+
return {
|
|
26301
|
+
success: false,
|
|
26302
|
+
error: `Plugin '${pluginName}' not found in workspace config`
|
|
26303
|
+
};
|
|
26304
|
+
}
|
|
26305
|
+
const entry = config.plugins[index];
|
|
26306
|
+
if (!entry) {
|
|
26307
|
+
return { success: false, error: `Plugin '${pluginName}' not found in workspace config` };
|
|
26308
|
+
}
|
|
26309
|
+
if (typeof entry === "string" || !entry.skills || !Array.isArray(entry.skills)) {
|
|
26310
|
+
return {
|
|
26311
|
+
success: false,
|
|
26312
|
+
error: `Skill '${skillKey}' is already disabled`
|
|
26313
|
+
};
|
|
26314
|
+
}
|
|
26315
|
+
if (!entry.skills.includes(skillName)) {
|
|
26316
|
+
return {
|
|
26317
|
+
success: false,
|
|
26318
|
+
error: `Skill '${skillKey}' is already disabled`
|
|
26319
|
+
};
|
|
26320
|
+
}
|
|
26321
|
+
const newSkills = entry.skills.filter((s) => s !== skillName);
|
|
26322
|
+
entry.skills = newSkills;
|
|
26323
|
+
await writeFile(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
26324
|
+
return { success: true };
|
|
26325
|
+
} catch (error) {
|
|
26278
26326
|
return {
|
|
26279
26327
|
success: false,
|
|
26280
|
-
error:
|
|
26328
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26281
26329
|
};
|
|
26282
26330
|
}
|
|
26283
|
-
const strictResult = MarketplaceManifestSchema.safeParse(json2);
|
|
26284
|
-
if (strictResult.success) {
|
|
26285
|
-
return { success: true, data: strictResult.data, warnings: [] };
|
|
26286
|
-
}
|
|
26287
|
-
return parseLeniently(json2);
|
|
26288
26331
|
}
|
|
26289
|
-
function
|
|
26290
|
-
const
|
|
26291
|
-
if (!
|
|
26332
|
+
async function setPluginSkillsMode(pluginName, mode, skillNames, workspacePath = process.cwd()) {
|
|
26333
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
26334
|
+
if (!existsSync5(configPath)) {
|
|
26292
26335
|
return {
|
|
26293
26336
|
success: false,
|
|
26294
|
-
error:
|
|
26337
|
+
error: `${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE} not found in ${workspacePath}`
|
|
26295
26338
|
};
|
|
26296
26339
|
}
|
|
26297
|
-
|
|
26298
|
-
|
|
26299
|
-
|
|
26300
|
-
|
|
26301
|
-
|
|
26302
|
-
|
|
26303
|
-
|
|
26304
|
-
|
|
26305
|
-
|
|
26306
|
-
continue;
|
|
26340
|
+
try {
|
|
26341
|
+
const content = await readFile4(configPath, "utf-8");
|
|
26342
|
+
const config = load(content);
|
|
26343
|
+
const index = findPluginEntryByName(config, pluginName);
|
|
26344
|
+
if (index === -1) {
|
|
26345
|
+
return {
|
|
26346
|
+
success: false,
|
|
26347
|
+
error: `Plugin '${pluginName}' not found in workspace config`
|
|
26348
|
+
};
|
|
26307
26349
|
}
|
|
26308
|
-
const
|
|
26309
|
-
if (
|
|
26310
|
-
|
|
26350
|
+
const entry = ensureObjectPluginEntry(config, index);
|
|
26351
|
+
if (mode === "allowlist") {
|
|
26352
|
+
entry.skills = [...skillNames];
|
|
26353
|
+
} else {
|
|
26354
|
+
entry.skills = skillNames.length > 0 ? { exclude: [...skillNames] } : undefined;
|
|
26311
26355
|
}
|
|
26356
|
+
await writeFile(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
26357
|
+
return { success: true };
|
|
26358
|
+
} catch (error) {
|
|
26359
|
+
return {
|
|
26360
|
+
success: false,
|
|
26361
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26362
|
+
};
|
|
26312
26363
|
}
|
|
26313
|
-
const data = {
|
|
26314
|
-
name: typeof raw.name === "string" ? raw.name : "unknown",
|
|
26315
|
-
description: typeof obj.description === "string" ? obj.description : "",
|
|
26316
|
-
plugins: validPlugins
|
|
26317
|
-
};
|
|
26318
|
-
return { success: true, data, warnings };
|
|
26319
26364
|
}
|
|
26320
|
-
function
|
|
26321
|
-
|
|
26322
|
-
|
|
26323
|
-
|
|
26365
|
+
async function upsertGitHubPluginSourceAllowlist(source, skillNames, workspacePath = process.cwd()) {
|
|
26366
|
+
await ensureWorkspace(workspacePath);
|
|
26367
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
26368
|
+
if (!existsSync5(configPath)) {
|
|
26369
|
+
return {
|
|
26370
|
+
success: false,
|
|
26371
|
+
error: `${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE} not found in ${workspacePath}`
|
|
26372
|
+
};
|
|
26324
26373
|
}
|
|
26325
|
-
|
|
26326
|
-
|
|
26327
|
-
|
|
26328
|
-
|
|
26329
|
-
|
|
26374
|
+
try {
|
|
26375
|
+
const content = await readFile4(configPath, "utf-8");
|
|
26376
|
+
const config = load(content);
|
|
26377
|
+
const result = await upsertGitHubPluginSourceAllowlistInConfig(config, source, skillNames);
|
|
26378
|
+
if (!result.success)
|
|
26379
|
+
return result;
|
|
26380
|
+
await writeFile(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
26381
|
+
return result;
|
|
26382
|
+
} catch (error) {
|
|
26383
|
+
return {
|
|
26384
|
+
success: false,
|
|
26385
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26386
|
+
};
|
|
26330
26387
|
}
|
|
26331
|
-
|
|
26332
|
-
|
|
26333
|
-
|
|
26334
|
-
|
|
26335
|
-
|
|
26336
|
-
|
|
26337
|
-
|
|
26338
|
-
|
|
26388
|
+
}
|
|
26389
|
+
function pruneEnabledSkillsForPlugin(config, pluginEntry) {
|
|
26390
|
+
if (!config.enabledSkills?.length)
|
|
26391
|
+
return;
|
|
26392
|
+
const names = extractPluginNames(pluginEntry);
|
|
26393
|
+
if (names.length === 0)
|
|
26394
|
+
return;
|
|
26395
|
+
const prefixes = names.map((n) => `${n}:`);
|
|
26396
|
+
config.enabledSkills = config.enabledSkills.filter((s) => !prefixes.some((p) => s.startsWith(p)));
|
|
26397
|
+
if (config.enabledSkills.length === 0) {
|
|
26398
|
+
config.enabledSkills = undefined;
|
|
26339
26399
|
}
|
|
26340
|
-
|
|
26341
|
-
|
|
26342
|
-
if (
|
|
26343
|
-
|
|
26344
|
-
|
|
26345
|
-
warnings.push(`plugins[${index}] ("${name}"): missing or invalid "source" field`);
|
|
26400
|
+
}
|
|
26401
|
+
async function resolveGitHubIdentity(pluginSource) {
|
|
26402
|
+
if (isGitHubUrl(pluginSource)) {
|
|
26403
|
+
const parsed = parseGitHubUrl(pluginSource);
|
|
26404
|
+
return parsed ? `${parsed.owner}/${parsed.repo}`.toLowerCase() : null;
|
|
26346
26405
|
}
|
|
26347
|
-
|
|
26348
|
-
|
|
26349
|
-
|
|
26350
|
-
|
|
26351
|
-
|
|
26352
|
-
|
|
26353
|
-
|
|
26354
|
-
|
|
26355
|
-
|
|
26406
|
+
if (isPluginSpec(pluginSource)) {
|
|
26407
|
+
const parsed = parsePluginSpec(pluginSource);
|
|
26408
|
+
if (!parsed)
|
|
26409
|
+
return null;
|
|
26410
|
+
const marketplace = await getMarketplace(parsed.marketplaceName);
|
|
26411
|
+
if (!marketplace)
|
|
26412
|
+
return null;
|
|
26413
|
+
const manifestResult = await parseMarketplaceManifest(marketplace.path);
|
|
26414
|
+
if (!manifestResult.success)
|
|
26415
|
+
return null;
|
|
26416
|
+
const entry = manifestResult.data.plugins.find((p) => p.name === parsed.plugin);
|
|
26417
|
+
if (!entry || typeof entry.source === "string")
|
|
26418
|
+
return null;
|
|
26419
|
+
const parsedUrl = parseGitHubUrl(entry.source.url);
|
|
26420
|
+
return parsedUrl ? `${parsedUrl.owner}/${parsedUrl.repo}`.toLowerCase() : null;
|
|
26421
|
+
}
|
|
26422
|
+
return null;
|
|
26356
26423
|
}
|
|
26357
|
-
function
|
|
26358
|
-
|
|
26359
|
-
|
|
26424
|
+
async function migrateWorkspaceSkillsV1toV2(workspacePath) {
|
|
26425
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
26426
|
+
if (!existsSync5(configPath))
|
|
26427
|
+
return;
|
|
26428
|
+
let config;
|
|
26429
|
+
try {
|
|
26430
|
+
const content = await readFile4(configPath, "utf-8");
|
|
26431
|
+
config = load(content);
|
|
26432
|
+
} catch {
|
|
26433
|
+
return;
|
|
26434
|
+
}
|
|
26435
|
+
if (!config || config.version !== undefined && config.version >= 2)
|
|
26436
|
+
return;
|
|
26437
|
+
const enabledSkills = config.enabledSkills ?? [];
|
|
26438
|
+
const disabledSkills = config.disabledSkills ?? [];
|
|
26439
|
+
const enabledByPlugin = new Map;
|
|
26440
|
+
for (const skillKey of enabledSkills) {
|
|
26441
|
+
const parsed = parseSkillKey(skillKey);
|
|
26442
|
+
if (!parsed)
|
|
26443
|
+
continue;
|
|
26444
|
+
const list = enabledByPlugin.get(parsed.pluginName) ?? [];
|
|
26445
|
+
list.push(parsed.skillName);
|
|
26446
|
+
enabledByPlugin.set(parsed.pluginName, list);
|
|
26447
|
+
}
|
|
26448
|
+
const disabledByPlugin = new Map;
|
|
26449
|
+
for (const skillKey of disabledSkills) {
|
|
26450
|
+
const parsed = parseSkillKey(skillKey);
|
|
26451
|
+
if (!parsed)
|
|
26452
|
+
continue;
|
|
26453
|
+
const list = disabledByPlugin.get(parsed.pluginName) ?? [];
|
|
26454
|
+
list.push(parsed.skillName);
|
|
26455
|
+
disabledByPlugin.set(parsed.pluginName, list);
|
|
26456
|
+
}
|
|
26457
|
+
for (const [pluginName, skillNames] of enabledByPlugin) {
|
|
26458
|
+
const index = findPluginEntryByName(config, pluginName);
|
|
26459
|
+
if (index === -1) {
|
|
26460
|
+
console.warn(`[migrate v1→v2] No plugin found for '${pluginName}', skipping`);
|
|
26461
|
+
continue;
|
|
26462
|
+
}
|
|
26463
|
+
const entry = ensureObjectPluginEntry(config, index);
|
|
26464
|
+
entry.skills = skillNames;
|
|
26465
|
+
}
|
|
26466
|
+
for (const [pluginName, skillNames] of disabledByPlugin) {
|
|
26467
|
+
const index = findPluginEntryByName(config, pluginName);
|
|
26468
|
+
if (index === -1) {
|
|
26469
|
+
console.warn(`[migrate v1→v2] No plugin found for '${pluginName}', skipping`);
|
|
26470
|
+
continue;
|
|
26471
|
+
}
|
|
26472
|
+
const entry = ensureObjectPluginEntry(config, index);
|
|
26473
|
+
if (!Array.isArray(entry.skills)) {
|
|
26474
|
+
entry.skills = { exclude: skillNames };
|
|
26475
|
+
}
|
|
26476
|
+
}
|
|
26477
|
+
config.enabledSkills = undefined;
|
|
26478
|
+
config.disabledSkills = undefined;
|
|
26479
|
+
config.version = 2;
|
|
26480
|
+
try {
|
|
26481
|
+
await writeFile(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
26482
|
+
} catch (error) {
|
|
26483
|
+
console.warn(`[migrate v1→v2] Failed to write migrated config: ${error instanceof Error ? error.message : String(error)}`);
|
|
26484
|
+
}
|
|
26485
|
+
}
|
|
26486
|
+
async function updateRepositories(changes, workspacePath = process.cwd()) {
|
|
26487
|
+
if (changes.remove.length === 0 && changes.add.length === 0) {
|
|
26488
|
+
return { success: true };
|
|
26489
|
+
}
|
|
26490
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
26491
|
+
try {
|
|
26492
|
+
const content = await readFile4(configPath, "utf-8");
|
|
26493
|
+
const config = load(content);
|
|
26494
|
+
const removeSet = new Set(changes.remove);
|
|
26495
|
+
config.repositories = config.repositories.filter((repo) => !removeSet.has(repo.path));
|
|
26496
|
+
config.repositories.push(...changes.add);
|
|
26497
|
+
await writeFile(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
26498
|
+
return { success: true };
|
|
26499
|
+
} catch (error) {
|
|
26500
|
+
return {
|
|
26501
|
+
success: false,
|
|
26502
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26503
|
+
};
|
|
26504
|
+
}
|
|
26505
|
+
}
|
|
26506
|
+
async function setRepositories(repositories, workspacePath = process.cwd()) {
|
|
26507
|
+
const configPath = join8(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
26508
|
+
try {
|
|
26509
|
+
const content = await readFile4(configPath, "utf-8");
|
|
26510
|
+
const config = load(content);
|
|
26511
|
+
config.repositories = repositories;
|
|
26512
|
+
await writeFile(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
26513
|
+
return { success: true };
|
|
26514
|
+
} catch (error) {
|
|
26515
|
+
return {
|
|
26516
|
+
success: false,
|
|
26517
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26518
|
+
};
|
|
26360
26519
|
}
|
|
26361
|
-
return resolve5(marketplacePath, source);
|
|
26362
26520
|
}
|
|
26363
|
-
var
|
|
26364
|
-
var
|
|
26365
|
-
|
|
26521
|
+
var DEFAULT_PROJECT_CLIENTS;
|
|
26522
|
+
var init_workspace_modify = __esm(() => {
|
|
26523
|
+
init_js_yaml();
|
|
26524
|
+
init_constants();
|
|
26525
|
+
init_workspace_config();
|
|
26526
|
+
init_marketplace_manifest_parser();
|
|
26527
|
+
init_plugin_path();
|
|
26528
|
+
init_marketplace();
|
|
26529
|
+
DEFAULT_PROJECT_CLIENTS = ["universal"];
|
|
26366
26530
|
});
|
|
26367
26531
|
|
|
26368
26532
|
// src/core/user-workspace.ts
|
|
26369
26533
|
var exports_user_workspace = {};
|
|
26370
26534
|
__export(exports_user_workspace, {
|
|
26535
|
+
upsertUserGitHubPluginSourceAllowlist: () => upsertUserGitHubPluginSourceAllowlist,
|
|
26371
26536
|
setUserPluginSkillsMode: () => setUserPluginSkillsMode,
|
|
26372
26537
|
setUserClients: () => setUserClients,
|
|
26373
26538
|
removeUserPluginsForMarketplace: () => removeUserPluginsForMarketplace,
|
|
@@ -26391,7 +26556,7 @@ __export(exports_user_workspace, {
|
|
|
26391
26556
|
});
|
|
26392
26557
|
import { existsSync as existsSync6 } from "node:fs";
|
|
26393
26558
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile2 } from "node:fs/promises";
|
|
26394
|
-
import { basename as
|
|
26559
|
+
import { basename as basename2, join as join9, resolve as resolve6 } from "node:path";
|
|
26395
26560
|
function getUserWorkspaceConfigPath() {
|
|
26396
26561
|
return join9(getAllagentsDir(), WORKSPACE_CONFIG_FILE);
|
|
26397
26562
|
}
|
|
@@ -26611,7 +26776,7 @@ async function setUserClients(clients) {
|
|
|
26611
26776
|
};
|
|
26612
26777
|
}
|
|
26613
26778
|
}
|
|
26614
|
-
function
|
|
26779
|
+
function parseSkillKey2(skillKey) {
|
|
26615
26780
|
const colonIdx = skillKey.indexOf(":");
|
|
26616
26781
|
if (colonIdx === -1)
|
|
26617
26782
|
return null;
|
|
@@ -26644,7 +26809,7 @@ async function getUserDisabledSkills() {
|
|
|
26644
26809
|
async function addUserDisabledSkill(skillKey) {
|
|
26645
26810
|
await ensureUserWorkspace();
|
|
26646
26811
|
const configPath = getUserWorkspaceConfigPath();
|
|
26647
|
-
const parsed =
|
|
26812
|
+
const parsed = parseSkillKey2(skillKey);
|
|
26648
26813
|
if (!parsed) {
|
|
26649
26814
|
return {
|
|
26650
26815
|
success: false,
|
|
@@ -26689,7 +26854,7 @@ async function addUserDisabledSkill(skillKey) {
|
|
|
26689
26854
|
async function removeUserDisabledSkill(skillKey) {
|
|
26690
26855
|
await ensureUserWorkspace();
|
|
26691
26856
|
const configPath = getUserWorkspaceConfigPath();
|
|
26692
|
-
const parsed =
|
|
26857
|
+
const parsed = parseSkillKey2(skillKey);
|
|
26693
26858
|
if (!parsed) {
|
|
26694
26859
|
return {
|
|
26695
26860
|
success: false,
|
|
@@ -26758,7 +26923,7 @@ async function getUserEnabledSkills() {
|
|
|
26758
26923
|
async function addUserEnabledSkill(skillKey) {
|
|
26759
26924
|
await ensureUserWorkspace();
|
|
26760
26925
|
const configPath = getUserWorkspaceConfigPath();
|
|
26761
|
-
const parsed =
|
|
26926
|
+
const parsed = parseSkillKey2(skillKey);
|
|
26762
26927
|
if (!parsed) {
|
|
26763
26928
|
return {
|
|
26764
26929
|
success: false,
|
|
@@ -26803,7 +26968,7 @@ async function addUserEnabledSkill(skillKey) {
|
|
|
26803
26968
|
async function removeUserEnabledSkill(skillKey) {
|
|
26804
26969
|
await ensureUserWorkspace();
|
|
26805
26970
|
const configPath = getUserWorkspaceConfigPath();
|
|
26806
|
-
const parsed =
|
|
26971
|
+
const parsed = parseSkillKey2(skillKey);
|
|
26807
26972
|
if (!parsed) {
|
|
26808
26973
|
return {
|
|
26809
26974
|
success: false,
|
|
@@ -26876,6 +27041,24 @@ async function setUserPluginSkillsMode(pluginName, mode, skillNames) {
|
|
|
26876
27041
|
};
|
|
26877
27042
|
}
|
|
26878
27043
|
}
|
|
27044
|
+
async function upsertUserGitHubPluginSourceAllowlist(source, skillNames) {
|
|
27045
|
+
await ensureUserWorkspace();
|
|
27046
|
+
const configPath = getUserWorkspaceConfigPath();
|
|
27047
|
+
try {
|
|
27048
|
+
const content = await readFile5(configPath, "utf-8");
|
|
27049
|
+
const config = load(content);
|
|
27050
|
+
const result = await upsertGitHubPluginSourceAllowlistInConfig(config, source, skillNames);
|
|
27051
|
+
if (!result.success)
|
|
27052
|
+
return result;
|
|
27053
|
+
await writeFile2(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
27054
|
+
return result;
|
|
27055
|
+
} catch (error) {
|
|
27056
|
+
return {
|
|
27057
|
+
success: false,
|
|
27058
|
+
error: error instanceof Error ? error.message : String(error)
|
|
27059
|
+
};
|
|
27060
|
+
}
|
|
27061
|
+
}
|
|
26879
27062
|
function pluginSourceToInfo(plugin, scope) {
|
|
26880
27063
|
const parsed = parsePluginSpec(plugin);
|
|
26881
27064
|
if (parsed) {
|
|
@@ -26890,14 +27073,14 @@ function pluginSourceToInfo(plugin, scope) {
|
|
|
26890
27073
|
const ghParsed = parseGitHubUrl(plugin);
|
|
26891
27074
|
return {
|
|
26892
27075
|
spec: plugin,
|
|
26893
|
-
name: ghParsed?.repo ??
|
|
27076
|
+
name: ghParsed?.repo ?? basename2(plugin),
|
|
26894
27077
|
marketplace: "",
|
|
26895
27078
|
scope
|
|
26896
27079
|
};
|
|
26897
27080
|
}
|
|
26898
27081
|
return {
|
|
26899
27082
|
spec: plugin,
|
|
26900
|
-
name:
|
|
27083
|
+
name: basename2(plugin),
|
|
26901
27084
|
marketplace: "",
|
|
26902
27085
|
scope
|
|
26903
27086
|
};
|
|
@@ -27021,8 +27204,8 @@ var init_user_workspace = __esm(() => {
|
|
|
27021
27204
|
|
|
27022
27205
|
// src/core/marketplace.ts
|
|
27023
27206
|
import { existsSync as existsSync7 } from "node:fs";
|
|
27024
|
-
import { mkdir as mkdir5, readFile as readFile6, readdir as
|
|
27025
|
-
import { basename as
|
|
27207
|
+
import { mkdir as mkdir5, readFile as readFile6, readdir as readdir2, rm as rm3, writeFile as writeFile3 } from "node:fs/promises";
|
|
27208
|
+
import { basename as basename3, dirname as dirname4, join as join10, resolve as resolve7 } from "node:path";
|
|
27026
27209
|
function parseLocation(location) {
|
|
27027
27210
|
const [owner = "", repo = "", ...rest] = location.split("/");
|
|
27028
27211
|
const branch = rest.length > 0 ? rest.join("/") : undefined;
|
|
@@ -27052,7 +27235,7 @@ async function loadRegistryFromPath(registryPath) {
|
|
|
27052
27235
|
}
|
|
27053
27236
|
}
|
|
27054
27237
|
async function saveRegistryToPath(registry, registryPath) {
|
|
27055
|
-
const dir =
|
|
27238
|
+
const dir = dirname4(registryPath);
|
|
27056
27239
|
if (!existsSync7(dir)) {
|
|
27057
27240
|
await mkdir5(dir, { recursive: true });
|
|
27058
27241
|
}
|
|
@@ -27108,7 +27291,7 @@ function parseMarketplaceSource(source) {
|
|
|
27108
27291
|
};
|
|
27109
27292
|
}
|
|
27110
27293
|
const absPath = resolve7(source);
|
|
27111
|
-
const name = source.split(/[/\\]/).filter(Boolean).pop() ||
|
|
27294
|
+
const name = source.split(/[/\\]/).filter(Boolean).pop() || basename3(absPath) || "local";
|
|
27112
27295
|
return {
|
|
27113
27296
|
type: "local",
|
|
27114
27297
|
location: absPath,
|
|
@@ -27458,7 +27641,7 @@ async function listMarketplacePlugins(name, workspacePath) {
|
|
|
27458
27641
|
return { plugins: [], warnings: manifestResult.warnings };
|
|
27459
27642
|
}
|
|
27460
27643
|
try {
|
|
27461
|
-
const entries = await
|
|
27644
|
+
const entries = await readdir2(pluginsDir, { withFileTypes: true });
|
|
27462
27645
|
const plugins = entries.filter((e) => e.isDirectory()).map((e) => ({
|
|
27463
27646
|
name: e.name,
|
|
27464
27647
|
path: join10(pluginsDir, e.name)
|
|
@@ -27810,653 +27993,762 @@ var init_marketplace = __esm(() => {
|
|
|
27810
27993
|
updatedMarketplaceCache = new Set;
|
|
27811
27994
|
});
|
|
27812
27995
|
|
|
27813
|
-
// src/core/
|
|
27996
|
+
// src/core/skills.ts
|
|
27814
27997
|
import { existsSync as existsSync8 } from "node:fs";
|
|
27815
|
-
import {
|
|
27816
|
-
import { join as join11 } from "node:path";
|
|
27817
|
-
async function
|
|
27818
|
-
|
|
27819
|
-
await
|
|
27820
|
-
|
|
27821
|
-
|
|
27822
|
-
|
|
27823
|
-
|
|
27824
|
-
|
|
27825
|
-
return { success: true };
|
|
27826
|
-
} catch (error) {
|
|
27998
|
+
import { readFile as readFile7, readdir as readdir3 } from "node:fs/promises";
|
|
27999
|
+
import { join as join11, basename as basename4, resolve as resolve8 } from "node:path";
|
|
28000
|
+
async function resolvePluginPath(pluginSource, workspacePath) {
|
|
28001
|
+
if (isPluginSpec(pluginSource)) {
|
|
28002
|
+
const resolved2 = await resolvePluginSpecWithAutoRegister(pluginSource, {
|
|
28003
|
+
offline: true,
|
|
28004
|
+
workspacePath
|
|
28005
|
+
});
|
|
28006
|
+
if (!resolved2.success || !resolved2.path)
|
|
28007
|
+
return null;
|
|
27827
28008
|
return {
|
|
27828
|
-
|
|
27829
|
-
|
|
28009
|
+
path: resolved2.path,
|
|
28010
|
+
pluginName: resolved2.pluginName
|
|
27830
28011
|
};
|
|
27831
28012
|
}
|
|
27832
|
-
|
|
27833
|
-
|
|
27834
|
-
|
|
27835
|
-
|
|
27836
|
-
|
|
27837
|
-
|
|
27838
|
-
|
|
27839
|
-
|
|
27840
|
-
|
|
27841
|
-
|
|
27842
|
-
};
|
|
27843
|
-
await mkdir6(configDir, { recursive: true });
|
|
27844
|
-
await writeFile4(configPath, dump(defaultConfig, { lineWidth: -1 }), "utf-8");
|
|
27845
|
-
}
|
|
27846
|
-
async function addPlugin(plugin, workspacePath = process.cwd(), force) {
|
|
27847
|
-
const configPath = join11(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
27848
|
-
await ensureWorkspace(workspacePath);
|
|
27849
|
-
if (isPluginSpec(plugin)) {
|
|
27850
|
-
const resolved = await resolvePluginSpecWithAutoRegister(plugin, { workspacePath });
|
|
27851
|
-
if (!resolved.success) {
|
|
27852
|
-
return {
|
|
27853
|
-
success: false,
|
|
27854
|
-
error: resolved.error || "Unknown error"
|
|
27855
|
-
};
|
|
27856
|
-
}
|
|
27857
|
-
return await addPluginToConfig(resolved.registeredAs ? plugin.replace(/@[^@]+$/, `@${resolved.registeredAs}`) : plugin, configPath, resolved.registeredAs, force);
|
|
28013
|
+
if (isGitHubUrl(pluginSource)) {
|
|
28014
|
+
const parsed = parseGitHubUrl(pluginSource);
|
|
28015
|
+
const result = await fetchPlugin(pluginSource, {
|
|
28016
|
+
offline: true,
|
|
28017
|
+
...parsed?.branch && { branch: parsed.branch }
|
|
28018
|
+
});
|
|
28019
|
+
if (!result.success)
|
|
28020
|
+
return null;
|
|
28021
|
+
const path = parsed?.subpath ? join11(result.cachePath, parsed.subpath) : result.cachePath;
|
|
28022
|
+
return existsSync8(path) ? { path } : null;
|
|
27858
28023
|
}
|
|
27859
|
-
|
|
27860
|
-
|
|
27861
|
-
|
|
27862
|
-
|
|
27863
|
-
|
|
27864
|
-
|
|
27865
|
-
|
|
27866
|
-
|
|
27867
|
-
|
|
27868
|
-
|
|
27869
|
-
|
|
27870
|
-
|
|
27871
|
-
|
|
27872
|
-
};
|
|
27873
|
-
}
|
|
27874
|
-
} else {
|
|
27875
|
-
const fullPath = join11(workspacePath, plugin);
|
|
27876
|
-
if (!existsSync8(fullPath) && !existsSync8(plugin)) {
|
|
27877
|
-
return {
|
|
27878
|
-
success: false,
|
|
27879
|
-
error: `Plugin not found at ${plugin}`
|
|
27880
|
-
};
|
|
28024
|
+
const resolved = resolve8(workspacePath, pluginSource);
|
|
28025
|
+
return existsSync8(resolved) ? { path: resolved } : null;
|
|
28026
|
+
}
|
|
28027
|
+
async function discoverNestedSkillEntries(pluginPath) {
|
|
28028
|
+
const entries = await readdir3(pluginPath, { withFileTypes: true });
|
|
28029
|
+
const discovered = [];
|
|
28030
|
+
for (const entry of entries) {
|
|
28031
|
+
if (!entry.isDirectory())
|
|
28032
|
+
continue;
|
|
28033
|
+
const skillPath = join11(pluginPath, entry.name);
|
|
28034
|
+
if (existsSync8(join11(skillPath, "SKILL.md"))) {
|
|
28035
|
+
discovered.push({ name: entry.name, skillPath });
|
|
28036
|
+
continue;
|
|
27881
28037
|
}
|
|
28038
|
+
discovered.push(...await discoverNestedSkillEntries(skillPath));
|
|
27882
28039
|
}
|
|
27883
|
-
return
|
|
28040
|
+
return discovered;
|
|
27884
28041
|
}
|
|
27885
|
-
async function
|
|
27886
|
-
|
|
27887
|
-
|
|
27888
|
-
|
|
27889
|
-
|
|
27890
|
-
|
|
27891
|
-
|
|
27892
|
-
|
|
27893
|
-
|
|
27894
|
-
|
|
27895
|
-
|
|
28042
|
+
async function getAllSkillsFromPlugins(workspacePath = process.cwd()) {
|
|
28043
|
+
const configPath = join11(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
28044
|
+
if (!existsSync8(configPath)) {
|
|
28045
|
+
return [];
|
|
28046
|
+
}
|
|
28047
|
+
const content = await readFile7(configPath, "utf-8");
|
|
28048
|
+
const config = load(content);
|
|
28049
|
+
const isV1Fallback = config.version === undefined || config.version < 2;
|
|
28050
|
+
const disabledSkills = isV1Fallback ? new Set(config.disabledSkills ?? []) : new Set;
|
|
28051
|
+
const enabledSkills = isV1Fallback && config.enabledSkills ? new Set(config.enabledSkills) : null;
|
|
28052
|
+
const skills = [];
|
|
28053
|
+
for (const pluginEntry of config.plugins) {
|
|
28054
|
+
const pluginSource = getPluginSource(pluginEntry);
|
|
28055
|
+
const resolved = await resolvePluginPath(pluginSource, workspacePath);
|
|
28056
|
+
if (!resolved)
|
|
28057
|
+
continue;
|
|
28058
|
+
const pluginPath = resolved.path;
|
|
28059
|
+
const pluginName = resolved.pluginName ?? getPluginName(pluginPath);
|
|
28060
|
+
const skillsDir = join11(pluginPath, "skills");
|
|
28061
|
+
const pluginSkillsConfig = typeof pluginEntry === "string" ? undefined : pluginEntry.skills;
|
|
28062
|
+
const hasEnabledEntries = !pluginSkillsConfig && enabledSkills && [...enabledSkills].some((s) => s.startsWith(`${pluginName}`));
|
|
28063
|
+
let skillEntries;
|
|
28064
|
+
if (existsSync8(skillsDir)) {
|
|
28065
|
+
const entries = await readdir3(skillsDir, { withFileTypes: true });
|
|
28066
|
+
skillEntries = entries.filter((e) => e.isDirectory()).map((e) => ({ name: e.name, skillPath: join11(skillsDir, e.name) }));
|
|
28067
|
+
} else {
|
|
28068
|
+
const nestedSkills = await discoverNestedSkillEntries(pluginPath);
|
|
28069
|
+
if (nestedSkills.length > 0) {
|
|
28070
|
+
skillEntries = nestedSkills;
|
|
28071
|
+
} else {
|
|
28072
|
+
const rootSkillMd = join11(pluginPath, "SKILL.md");
|
|
28073
|
+
if (existsSync8(rootSkillMd)) {
|
|
28074
|
+
const skillContent = await readFile7(rootSkillMd, "utf-8");
|
|
28075
|
+
const metadata = parseSkillMetadata(skillContent);
|
|
28076
|
+
const skillName = metadata?.name ?? basename4(pluginPath);
|
|
28077
|
+
skillEntries = [{ name: skillName, skillPath: pluginPath }];
|
|
28078
|
+
} else {
|
|
28079
|
+
skillEntries = [];
|
|
28080
|
+
}
|
|
27896
28081
|
}
|
|
27897
28082
|
}
|
|
27898
|
-
|
|
27899
|
-
|
|
27900
|
-
|
|
27901
|
-
|
|
27902
|
-
|
|
27903
|
-
|
|
27904
|
-
|
|
27905
|
-
|
|
27906
|
-
|
|
27907
|
-
error: `Plugin duplicates existing entry '${existingSource}': both resolve to ${newIdentity}`
|
|
27908
|
-
};
|
|
27909
|
-
}
|
|
28083
|
+
const pluginSkillsMode = pluginSkillsConfig === undefined ? "none" : Array.isArray(pluginSkillsConfig) ? "allowlist" : "blocklist";
|
|
28084
|
+
for (const { name, skillPath } of skillEntries) {
|
|
28085
|
+
const skillKey = `${pluginName}:${name}`;
|
|
28086
|
+
let isDisabled;
|
|
28087
|
+
if (pluginSkillsConfig !== undefined) {
|
|
28088
|
+
if (Array.isArray(pluginSkillsConfig)) {
|
|
28089
|
+
isDisabled = !pluginSkillsConfig.includes(name);
|
|
28090
|
+
} else {
|
|
28091
|
+
isDisabled = pluginSkillsConfig.exclude.includes(name);
|
|
27910
28092
|
}
|
|
28093
|
+
} else if (isV1Fallback) {
|
|
28094
|
+
isDisabled = hasEnabledEntries ? !enabledSkills?.has(skillKey) : disabledSkills.has(skillKey);
|
|
28095
|
+
} else {
|
|
28096
|
+
isDisabled = false;
|
|
27911
28097
|
}
|
|
28098
|
+
skills.push({
|
|
28099
|
+
name,
|
|
28100
|
+
pluginName,
|
|
28101
|
+
pluginSource,
|
|
28102
|
+
path: skillPath,
|
|
28103
|
+
disabled: isDisabled,
|
|
28104
|
+
pluginSkillsMode
|
|
28105
|
+
});
|
|
27912
28106
|
}
|
|
27913
|
-
|
|
27914
|
-
|
|
27915
|
-
|
|
28107
|
+
}
|
|
28108
|
+
return skills;
|
|
28109
|
+
}
|
|
28110
|
+
async function findSkillByName(skillName, workspacePath = process.cwd()) {
|
|
28111
|
+
const allSkills = await getAllSkillsFromPlugins(workspacePath);
|
|
28112
|
+
return allSkills.filter((s) => s.name === skillName);
|
|
28113
|
+
}
|
|
28114
|
+
async function discoverSkillNames(pluginPath) {
|
|
28115
|
+
if (!existsSync8(pluginPath))
|
|
28116
|
+
return [];
|
|
28117
|
+
const skillsDir = join11(pluginPath, "skills");
|
|
28118
|
+
if (existsSync8(skillsDir)) {
|
|
28119
|
+
const entries = await readdir3(skillsDir, { withFileTypes: true });
|
|
28120
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
28121
|
+
}
|
|
28122
|
+
const nestedSkills = await discoverNestedSkillEntries(pluginPath);
|
|
28123
|
+
if (nestedSkills.length > 0)
|
|
28124
|
+
return nestedSkills.map((entry) => entry.name);
|
|
28125
|
+
const rootSkillMd = join11(pluginPath, "SKILL.md");
|
|
28126
|
+
if (existsSync8(rootSkillMd)) {
|
|
28127
|
+
try {
|
|
28128
|
+
const content = await readFile7(rootSkillMd, "utf-8");
|
|
28129
|
+
const { parseSkillMetadata: parseSkillMetadata2 } = await Promise.resolve().then(() => (init_skill(), exports_skill));
|
|
28130
|
+
const metadata = parseSkillMetadata2(content);
|
|
28131
|
+
return [metadata?.name ?? basename4(pluginPath)];
|
|
28132
|
+
} catch {
|
|
28133
|
+
return [basename4(pluginPath)];
|
|
27916
28134
|
}
|
|
27917
|
-
|
|
27918
|
-
|
|
27919
|
-
|
|
27920
|
-
|
|
27921
|
-
|
|
27922
|
-
|
|
27923
|
-
|
|
27924
|
-
|
|
27925
|
-
|
|
28135
|
+
}
|
|
28136
|
+
return [];
|
|
28137
|
+
}
|
|
28138
|
+
var init_skills = __esm(() => {
|
|
28139
|
+
init_js_yaml();
|
|
28140
|
+
init_constants();
|
|
28141
|
+
init_workspace_config();
|
|
28142
|
+
init_plugin();
|
|
28143
|
+
init_plugin_path();
|
|
28144
|
+
init_marketplace();
|
|
28145
|
+
init_skill();
|
|
28146
|
+
});
|
|
28147
|
+
|
|
28148
|
+
// src/core/transform.ts
|
|
28149
|
+
import { readFile as readFile8, writeFile as writeFile4, mkdir as mkdir6, cp, readdir as readdir4 } from "node:fs/promises";
|
|
28150
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
28151
|
+
import { join as join12, basename as basename5, dirname as dirname5, relative as relative2 } from "node:path";
|
|
28152
|
+
async function ensureWorkspaceRules(filePath, repositories, skillsIndexRefs = []) {
|
|
28153
|
+
const rulesContent = generateWorkspaceRules(repositories, skillsIndexRefs);
|
|
28154
|
+
const startMarker = "<!-- WORKSPACE-RULES:START -->";
|
|
28155
|
+
const endMarker = "<!-- WORKSPACE-RULES:END -->";
|
|
28156
|
+
if (!existsSync9(filePath)) {
|
|
28157
|
+
await writeFile4(filePath, `${rulesContent.trim()}
|
|
28158
|
+
`, "utf-8");
|
|
28159
|
+
return;
|
|
28160
|
+
}
|
|
28161
|
+
const content = await readFile8(filePath, "utf-8");
|
|
28162
|
+
const startIndex = content.indexOf(startMarker);
|
|
28163
|
+
const endIndex = content.indexOf(endMarker);
|
|
28164
|
+
if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
|
|
28165
|
+
const before = content.substring(0, startIndex);
|
|
28166
|
+
const after = content.substring(endIndex + endMarker.length);
|
|
28167
|
+
await writeFile4(filePath, before + rulesContent.trim() + after, "utf-8");
|
|
28168
|
+
} else {
|
|
28169
|
+
await writeFile4(filePath, content + rulesContent, "utf-8");
|
|
28170
|
+
}
|
|
28171
|
+
}
|
|
28172
|
+
function isExcluded(pluginPath, filePath, exclude) {
|
|
28173
|
+
if (!exclude || exclude.length === 0)
|
|
28174
|
+
return false;
|
|
28175
|
+
const relativePath = relative2(pluginPath, filePath).replaceAll("\\", "/");
|
|
28176
|
+
return import_micromatch.default.isMatch(relativePath, exclude);
|
|
28177
|
+
}
|
|
28178
|
+
async function copyDirectoryWithExclusions(sourceDir, destDir, pluginPath, exclude) {
|
|
28179
|
+
await mkdir6(destDir, { recursive: true });
|
|
28180
|
+
const entries = await readdir4(sourceDir, { withFileTypes: true });
|
|
28181
|
+
for (const entry of entries) {
|
|
28182
|
+
const sourcePath = join12(sourceDir, entry.name);
|
|
28183
|
+
const destPath = join12(destDir, entry.name);
|
|
28184
|
+
if (isExcluded(pluginPath, sourcePath, exclude)) {
|
|
28185
|
+
continue;
|
|
27926
28186
|
}
|
|
27927
|
-
if (
|
|
27928
|
-
|
|
28187
|
+
if (entry.isDirectory()) {
|
|
28188
|
+
await copyDirectoryWithExclusions(sourcePath, destPath, pluginPath, exclude);
|
|
28189
|
+
} else {
|
|
28190
|
+
await cp(sourcePath, destPath);
|
|
27929
28191
|
}
|
|
27930
|
-
return result;
|
|
27931
|
-
} catch (error) {
|
|
27932
|
-
return {
|
|
27933
|
-
success: false,
|
|
27934
|
-
error: error instanceof Error ? error.message : String(error)
|
|
27935
|
-
};
|
|
27936
28192
|
}
|
|
27937
28193
|
}
|
|
27938
|
-
|
|
27939
|
-
|
|
27940
|
-
|
|
27941
|
-
|
|
27942
|
-
|
|
27943
|
-
|
|
27944
|
-
|
|
27945
|
-
|
|
27946
|
-
|
|
27947
|
-
|
|
27948
|
-
|
|
27949
|
-
|
|
27950
|
-
|
|
27951
|
-
});
|
|
27952
|
-
}
|
|
27953
|
-
return false;
|
|
27954
|
-
} catch {
|
|
27955
|
-
return false;
|
|
28194
|
+
function getMapping(client, options2) {
|
|
28195
|
+
return options2?.clientMappings?.[client] ?? CLIENT_MAPPINGS[client];
|
|
28196
|
+
}
|
|
28197
|
+
async function copyCommands(pluginPath, workspacePath, client, options2 = {}) {
|
|
28198
|
+
const { dryRun = false } = options2;
|
|
28199
|
+
const mapping = getMapping(client, options2);
|
|
28200
|
+
const results = [];
|
|
28201
|
+
if (!mapping.commandsPath) {
|
|
28202
|
+
return results;
|
|
28203
|
+
}
|
|
28204
|
+
const sourceDir = join12(pluginPath, "commands");
|
|
28205
|
+
if (!existsSync9(sourceDir)) {
|
|
28206
|
+
return results;
|
|
27956
28207
|
}
|
|
28208
|
+
const destDir = join12(workspacePath, mapping.commandsPath);
|
|
28209
|
+
if (!dryRun) {
|
|
28210
|
+
await mkdir6(destDir, { recursive: true });
|
|
28211
|
+
}
|
|
28212
|
+
const files = await readdir4(sourceDir);
|
|
28213
|
+
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
28214
|
+
const copyPromises = mdFiles.filter((file) => !isExcluded(pluginPath, join12(sourceDir, file), options2.exclude)).map(async (file) => {
|
|
28215
|
+
const sourcePath = join12(sourceDir, file);
|
|
28216
|
+
const destPath = join12(destDir, file);
|
|
28217
|
+
if (dryRun) {
|
|
28218
|
+
return { source: sourcePath, destination: destPath, action: "copied" };
|
|
28219
|
+
}
|
|
28220
|
+
try {
|
|
28221
|
+
const content = await readFile8(sourcePath, "utf-8");
|
|
28222
|
+
await writeFile4(destPath, content, "utf-8");
|
|
28223
|
+
return { source: sourcePath, destination: destPath, action: "copied" };
|
|
28224
|
+
} catch (error) {
|
|
28225
|
+
return {
|
|
28226
|
+
source: sourcePath,
|
|
28227
|
+
destination: destPath,
|
|
28228
|
+
action: "failed",
|
|
28229
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
28230
|
+
};
|
|
28231
|
+
}
|
|
28232
|
+
});
|
|
28233
|
+
return Promise.all(copyPromises);
|
|
27957
28234
|
}
|
|
27958
|
-
async function
|
|
27959
|
-
const
|
|
27960
|
-
|
|
27961
|
-
|
|
27962
|
-
|
|
27963
|
-
|
|
27964
|
-
Run 'allagents workspace init <path>' to create a new workspace`
|
|
27965
|
-
};
|
|
28235
|
+
async function copySkills(pluginPath, workspacePath, client, options2 = {}) {
|
|
28236
|
+
const { dryRun = false, skillNameMap, syncMode = "copy", canonicalSkillsPath } = options2;
|
|
28237
|
+
const mapping = getMapping(client, options2);
|
|
28238
|
+
const results = [];
|
|
28239
|
+
if (!mapping.skillsPath) {
|
|
28240
|
+
return results;
|
|
27966
28241
|
}
|
|
27967
|
-
|
|
27968
|
-
|
|
27969
|
-
|
|
27970
|
-
|
|
27971
|
-
|
|
27972
|
-
|
|
27973
|
-
|
|
27974
|
-
|
|
27975
|
-
|
|
28242
|
+
const skillsDir = join12(pluginPath, "skills");
|
|
28243
|
+
let skillSources;
|
|
28244
|
+
if (existsSync9(skillsDir)) {
|
|
28245
|
+
const entries = await readdir4(skillsDir, { withFileTypes: true });
|
|
28246
|
+
skillSources = entries.filter((e) => e.isDirectory()).filter((e) => !isExcluded(pluginPath, join12(skillsDir, e.name), options2.exclude)).map((e) => ({ name: e.name, sourcePath: join12(skillsDir, e.name), isRootLevel: false }));
|
|
28247
|
+
} else {
|
|
28248
|
+
const nestedSkills = (await discoverNestedSkillEntries(pluginPath)).filter((entry) => !isExcluded(pluginPath, entry.skillPath, options2.exclude)).map((entry) => ({ name: entry.name, sourcePath: entry.skillPath, isRootLevel: false }));
|
|
28249
|
+
if (nestedSkills.length > 0) {
|
|
28250
|
+
skillSources = nestedSkills;
|
|
28251
|
+
} else {
|
|
28252
|
+
const rootSkillMd = join12(pluginPath, "SKILL.md");
|
|
28253
|
+
if (existsSync9(rootSkillMd)) {
|
|
28254
|
+
const content = await readFile8(rootSkillMd, "utf-8");
|
|
28255
|
+
const metadata = parseSkillMetadata(content);
|
|
28256
|
+
const skillName = metadata?.name ?? basename5(pluginPath);
|
|
28257
|
+
skillSources = [{ name: skillName, sourcePath: pluginPath, isRootLevel: true }];
|
|
28258
|
+
} else {
|
|
28259
|
+
return results;
|
|
28260
|
+
}
|
|
27976
28261
|
}
|
|
27977
|
-
|
|
27978
|
-
|
|
27979
|
-
|
|
27980
|
-
|
|
27981
|
-
|
|
27982
|
-
|
|
27983
|
-
|
|
27984
|
-
|
|
27985
|
-
|
|
27986
|
-
|
|
27987
|
-
|
|
27988
|
-
|
|
27989
|
-
|
|
28262
|
+
}
|
|
28263
|
+
if (skillNameMap) {
|
|
28264
|
+
skillSources = skillSources.filter((s) => skillNameMap.has(s.name));
|
|
28265
|
+
}
|
|
28266
|
+
if (skillSources.length === 0) {
|
|
28267
|
+
return results;
|
|
28268
|
+
}
|
|
28269
|
+
const destDir = join12(workspacePath, mapping.skillsPath);
|
|
28270
|
+
if (!dryRun) {
|
|
28271
|
+
await mkdir6(destDir, { recursive: true });
|
|
28272
|
+
}
|
|
28273
|
+
const useSymlinks = syncMode === "symlink" && !isUniversalClient(client) && canonicalSkillsPath;
|
|
28274
|
+
const copyPromises = skillSources.map(async (skill) => {
|
|
28275
|
+
const resolvedName = skillNameMap?.get(skill.name) ?? skill.name;
|
|
28276
|
+
const skillDestPath = join12(destDir, resolvedName);
|
|
28277
|
+
if (dryRun) {
|
|
28278
|
+
return {
|
|
28279
|
+
source: skill.sourcePath,
|
|
28280
|
+
destination: skillDestPath,
|
|
28281
|
+
action: "copied"
|
|
28282
|
+
};
|
|
28283
|
+
}
|
|
28284
|
+
if (useSymlinks) {
|
|
28285
|
+
const canonicalSkillPath = join12(workspacePath, canonicalSkillsPath, resolvedName);
|
|
28286
|
+
const symlinkCreated = await createSymlink(canonicalSkillPath, skillDestPath);
|
|
28287
|
+
if (symlinkCreated) {
|
|
28288
|
+
return {
|
|
28289
|
+
source: canonicalSkillPath,
|
|
28290
|
+
destination: skillDestPath,
|
|
28291
|
+
action: "copied"
|
|
28292
|
+
};
|
|
27990
28293
|
}
|
|
27991
28294
|
}
|
|
27992
|
-
|
|
28295
|
+
try {
|
|
28296
|
+
if (skill.isRootLevel) {
|
|
28297
|
+
await mkdir6(skillDestPath, { recursive: true });
|
|
28298
|
+
await cp(join12(skill.sourcePath, "SKILL.md"), join12(skillDestPath, "SKILL.md"));
|
|
28299
|
+
} else if (options2.exclude && options2.exclude.length > 0) {
|
|
28300
|
+
await copyDirectoryWithExclusions(skill.sourcePath, skillDestPath, pluginPath, options2.exclude);
|
|
28301
|
+
} else {
|
|
28302
|
+
await cp(skill.sourcePath, skillDestPath, { recursive: true });
|
|
28303
|
+
}
|
|
27993
28304
|
return {
|
|
27994
|
-
|
|
27995
|
-
|
|
28305
|
+
source: skill.sourcePath,
|
|
28306
|
+
destination: skillDestPath,
|
|
28307
|
+
action: "copied"
|
|
28308
|
+
};
|
|
28309
|
+
} catch (error) {
|
|
28310
|
+
return {
|
|
28311
|
+
source: skill.sourcePath,
|
|
28312
|
+
destination: skillDestPath,
|
|
28313
|
+
action: "failed",
|
|
28314
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
27996
28315
|
};
|
|
27997
28316
|
}
|
|
27998
|
-
|
|
27999
|
-
|
|
28000
|
-
pruneDisabledSkillsForPlugin(config, removedEntry);
|
|
28001
|
-
pruneEnabledSkillsForPlugin(config, removedEntry);
|
|
28002
|
-
const newContent = dump(config, { lineWidth: -1 });
|
|
28003
|
-
await writeFile4(configPath, newContent, "utf-8");
|
|
28004
|
-
return { success: true };
|
|
28005
|
-
} catch (error) {
|
|
28006
|
-
return {
|
|
28007
|
-
success: false,
|
|
28008
|
-
error: error instanceof Error ? error.message : String(error)
|
|
28009
|
-
};
|
|
28010
|
-
}
|
|
28011
|
-
}
|
|
28012
|
-
function pruneDisabledSkillsForPlugin(config, pluginEntry) {
|
|
28013
|
-
if (!config.disabledSkills?.length)
|
|
28014
|
-
return;
|
|
28015
|
-
const names = extractPluginNames(pluginEntry);
|
|
28016
|
-
if (names.length === 0)
|
|
28017
|
-
return;
|
|
28018
|
-
const prefixes = names.map((n) => `${n}:`);
|
|
28019
|
-
config.disabledSkills = config.disabledSkills.filter((s) => !prefixes.some((p) => s.startsWith(p)));
|
|
28020
|
-
if (config.disabledSkills.length === 0) {
|
|
28021
|
-
config.disabledSkills = undefined;
|
|
28022
|
-
}
|
|
28317
|
+
});
|
|
28318
|
+
return Promise.all(copyPromises);
|
|
28023
28319
|
}
|
|
28024
|
-
function
|
|
28025
|
-
|
|
28026
|
-
|
|
28027
|
-
|
|
28028
|
-
|
|
28029
|
-
const
|
|
28030
|
-
|
|
28031
|
-
|
|
28320
|
+
async function collectPluginSkills(pluginPath, pluginSource, disabledSkills, pluginName, enabledSkills, pluginSkillsConfig) {
|
|
28321
|
+
const skillsDir = join12(pluginPath, "skills");
|
|
28322
|
+
const hasEnabledEntries = !pluginSkillsConfig && enabledSkills && pluginName && [...enabledSkills].some((s) => s.startsWith(`${pluginName}:`));
|
|
28323
|
+
let candidateDirs;
|
|
28324
|
+
if (existsSync9(skillsDir)) {
|
|
28325
|
+
const entries = await readdir4(skillsDir, { withFileTypes: true });
|
|
28326
|
+
candidateDirs = entries.filter((e) => e.isDirectory()).map((e) => ({ name: e.name, path: join12(skillsDir, e.name) }));
|
|
28327
|
+
} else {
|
|
28328
|
+
const nestedDirs = await discoverNestedSkillEntries(pluginPath).then((entries) => entries.map((entry) => ({ name: entry.name, path: entry.skillPath })));
|
|
28329
|
+
if (nestedDirs.length > 0) {
|
|
28330
|
+
candidateDirs = nestedDirs;
|
|
28331
|
+
} else {
|
|
28332
|
+
const rootSkillMd = join12(pluginPath, "SKILL.md");
|
|
28333
|
+
if (existsSync9(rootSkillMd)) {
|
|
28334
|
+
const content = await readFile8(rootSkillMd, "utf-8");
|
|
28335
|
+
const metadata = parseSkillMetadata(content);
|
|
28336
|
+
const skillName = metadata?.name ?? basename5(pluginPath);
|
|
28337
|
+
candidateDirs = [{ name: skillName, path: pluginPath }];
|
|
28338
|
+
} else {
|
|
28339
|
+
candidateDirs = [];
|
|
28340
|
+
}
|
|
28032
28341
|
}
|
|
28033
|
-
return names;
|
|
28034
28342
|
}
|
|
28035
|
-
|
|
28036
|
-
|
|
28037
|
-
if (
|
|
28038
|
-
|
|
28039
|
-
|
|
28040
|
-
|
|
28041
|
-
names.push(ownerRepo);
|
|
28042
|
-
return names;
|
|
28343
|
+
let filteredDirs;
|
|
28344
|
+
if (pluginSkillsConfig !== undefined) {
|
|
28345
|
+
if (Array.isArray(pluginSkillsConfig)) {
|
|
28346
|
+
filteredDirs = candidateDirs.filter((e) => pluginSkillsConfig.includes(e.name));
|
|
28347
|
+
} else {
|
|
28348
|
+
filteredDirs = candidateDirs.filter((e) => !pluginSkillsConfig.exclude.includes(e.name));
|
|
28043
28349
|
}
|
|
28350
|
+
} else if (pluginName) {
|
|
28351
|
+
if (hasEnabledEntries) {
|
|
28352
|
+
filteredDirs = candidateDirs.filter((e) => enabledSkills?.has(`${pluginName}:${e.name}`));
|
|
28353
|
+
} else if (disabledSkills) {
|
|
28354
|
+
filteredDirs = candidateDirs.filter((e) => !disabledSkills.has(`${pluginName}:${e.name}`));
|
|
28355
|
+
} else {
|
|
28356
|
+
filteredDirs = candidateDirs;
|
|
28357
|
+
}
|
|
28358
|
+
} else {
|
|
28359
|
+
filteredDirs = candidateDirs;
|
|
28044
28360
|
}
|
|
28045
|
-
|
|
28046
|
-
|
|
28047
|
-
|
|
28048
|
-
|
|
28049
|
-
|
|
28050
|
-
}
|
|
28051
|
-
|
|
28052
|
-
|
|
28053
|
-
}
|
|
28054
|
-
|
|
28055
|
-
const
|
|
28056
|
-
if (
|
|
28057
|
-
|
|
28058
|
-
if (typeof entry === "string") {
|
|
28059
|
-
const objectEntry = { source: entry };
|
|
28060
|
-
config.plugins[index] = objectEntry;
|
|
28061
|
-
return objectEntry;
|
|
28062
|
-
}
|
|
28063
|
-
return entry;
|
|
28064
|
-
}
|
|
28065
|
-
function parseSkillKey2(skillKey) {
|
|
28066
|
-
const colonIdx = skillKey.indexOf(":");
|
|
28067
|
-
if (colonIdx === -1)
|
|
28068
|
-
return null;
|
|
28069
|
-
return {
|
|
28070
|
-
pluginName: skillKey.slice(0, colonIdx),
|
|
28071
|
-
skillName: skillKey.slice(colonIdx + 1)
|
|
28072
|
-
};
|
|
28073
|
-
}
|
|
28074
|
-
async function addDisabledSkill(skillKey, workspacePath = process.cwd()) {
|
|
28075
|
-
const configPath = join11(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
28076
|
-
if (!existsSync8(configPath)) {
|
|
28077
|
-
return {
|
|
28078
|
-
success: false,
|
|
28079
|
-
error: `${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE} not found in ${workspacePath}`
|
|
28080
|
-
};
|
|
28361
|
+
return filteredDirs.map((entry) => ({
|
|
28362
|
+
folderName: entry.name,
|
|
28363
|
+
skillPath: entry.path,
|
|
28364
|
+
pluginPath,
|
|
28365
|
+
pluginSource
|
|
28366
|
+
}));
|
|
28367
|
+
}
|
|
28368
|
+
async function copyHooks(pluginPath, workspacePath, client, options2 = {}) {
|
|
28369
|
+
const { dryRun = false } = options2;
|
|
28370
|
+
const mapping = getMapping(client, options2);
|
|
28371
|
+
const results = [];
|
|
28372
|
+
if (!mapping.hooksPath) {
|
|
28373
|
+
return results;
|
|
28081
28374
|
}
|
|
28082
|
-
const
|
|
28083
|
-
if (!
|
|
28084
|
-
return
|
|
28085
|
-
success: false,
|
|
28086
|
-
error: `Invalid skill key format: '${skillKey}' (expected pluginName:skillName)`
|
|
28087
|
-
};
|
|
28375
|
+
const sourceDir = join12(pluginPath, "hooks");
|
|
28376
|
+
if (!existsSync9(sourceDir)) {
|
|
28377
|
+
return results;
|
|
28088
28378
|
}
|
|
28089
|
-
const
|
|
28379
|
+
const destDir = join12(workspacePath, mapping.hooksPath);
|
|
28380
|
+
if (dryRun) {
|
|
28381
|
+
results.push({ source: sourceDir, destination: destDir, action: "copied" });
|
|
28382
|
+
return results;
|
|
28383
|
+
}
|
|
28384
|
+
await mkdir6(destDir, { recursive: true });
|
|
28090
28385
|
try {
|
|
28091
|
-
|
|
28092
|
-
|
|
28093
|
-
|
|
28094
|
-
|
|
28095
|
-
return {
|
|
28096
|
-
success: false,
|
|
28097
|
-
error: `Plugin '${pluginName}' not found in workspace config`
|
|
28098
|
-
};
|
|
28099
|
-
}
|
|
28100
|
-
const entry = ensureObjectPluginEntry(config, index);
|
|
28101
|
-
if (Array.isArray(entry.skills)) {
|
|
28102
|
-
return {
|
|
28103
|
-
success: false,
|
|
28104
|
-
error: `Plugin '${pluginName}' is in allowlist mode; use removeEnabledSkill to disable a skill`
|
|
28105
|
-
};
|
|
28106
|
-
}
|
|
28107
|
-
const existing = entry.skills?.exclude ?? [];
|
|
28108
|
-
if (existing.includes(skillName)) {
|
|
28109
|
-
return {
|
|
28110
|
-
success: false,
|
|
28111
|
-
error: `Skill '${skillKey}' is already disabled`
|
|
28112
|
-
};
|
|
28386
|
+
if (options2.exclude && options2.exclude.length > 0) {
|
|
28387
|
+
await copyDirectoryWithExclusions(sourceDir, destDir, pluginPath, options2.exclude);
|
|
28388
|
+
} else {
|
|
28389
|
+
await cp(sourceDir, destDir, { recursive: true });
|
|
28113
28390
|
}
|
|
28114
|
-
|
|
28115
|
-
await writeFile4(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
28116
|
-
return { success: true };
|
|
28391
|
+
results.push({ source: sourceDir, destination: destDir, action: "copied" });
|
|
28117
28392
|
} catch (error) {
|
|
28118
|
-
|
|
28119
|
-
|
|
28120
|
-
|
|
28121
|
-
|
|
28393
|
+
results.push({
|
|
28394
|
+
source: sourceDir,
|
|
28395
|
+
destination: destDir,
|
|
28396
|
+
action: "failed",
|
|
28397
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
28398
|
+
});
|
|
28122
28399
|
}
|
|
28400
|
+
return results;
|
|
28123
28401
|
}
|
|
28124
|
-
async function
|
|
28125
|
-
const
|
|
28126
|
-
|
|
28127
|
-
|
|
28128
|
-
|
|
28129
|
-
|
|
28130
|
-
};
|
|
28402
|
+
async function copyAgents(pluginPath, workspacePath, client, options2 = {}) {
|
|
28403
|
+
const { dryRun = false } = options2;
|
|
28404
|
+
const mapping = getMapping(client, options2);
|
|
28405
|
+
const results = [];
|
|
28406
|
+
if (!mapping.agentsPath) {
|
|
28407
|
+
return results;
|
|
28131
28408
|
}
|
|
28132
|
-
const
|
|
28133
|
-
if (!
|
|
28134
|
-
return
|
|
28135
|
-
success: false,
|
|
28136
|
-
error: `Invalid skill key format: '${skillKey}' (expected pluginName:skillName)`
|
|
28137
|
-
};
|
|
28409
|
+
const sourceDir = join12(pluginPath, "agents");
|
|
28410
|
+
if (!existsSync9(sourceDir)) {
|
|
28411
|
+
return results;
|
|
28138
28412
|
}
|
|
28139
|
-
const
|
|
28140
|
-
|
|
28141
|
-
|
|
28142
|
-
|
|
28143
|
-
|
|
28144
|
-
|
|
28145
|
-
|
|
28146
|
-
|
|
28147
|
-
|
|
28148
|
-
|
|
28149
|
-
|
|
28150
|
-
const entry = config.plugins[index];
|
|
28151
|
-
if (!entry) {
|
|
28152
|
-
return { success: false, error: `Plugin '${pluginName}' not found in workspace config` };
|
|
28413
|
+
const destDir = join12(workspacePath, mapping.agentsPath);
|
|
28414
|
+
if (!dryRun) {
|
|
28415
|
+
await mkdir6(destDir, { recursive: true });
|
|
28416
|
+
}
|
|
28417
|
+
const files = await readdir4(sourceDir);
|
|
28418
|
+
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
28419
|
+
const copyPromises = mdFiles.filter((file) => !isExcluded(pluginPath, join12(sourceDir, file), options2.exclude)).map(async (file) => {
|
|
28420
|
+
const sourcePath = join12(sourceDir, file);
|
|
28421
|
+
const destPath = join12(destDir, file);
|
|
28422
|
+
if (dryRun) {
|
|
28423
|
+
return { source: sourcePath, destination: destPath, action: "copied" };
|
|
28153
28424
|
}
|
|
28154
|
-
|
|
28425
|
+
try {
|
|
28426
|
+
const content = await readFile8(sourcePath, "utf-8");
|
|
28427
|
+
await writeFile4(destPath, content, "utf-8");
|
|
28428
|
+
return { source: sourcePath, destination: destPath, action: "copied" };
|
|
28429
|
+
} catch (error) {
|
|
28155
28430
|
return {
|
|
28156
|
-
|
|
28157
|
-
|
|
28431
|
+
source: sourcePath,
|
|
28432
|
+
destination: destPath,
|
|
28433
|
+
action: "failed",
|
|
28434
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
28158
28435
|
};
|
|
28159
28436
|
}
|
|
28160
|
-
|
|
28161
|
-
|
|
28162
|
-
|
|
28163
|
-
|
|
28164
|
-
|
|
28437
|
+
});
|
|
28438
|
+
return Promise.all(copyPromises);
|
|
28439
|
+
}
|
|
28440
|
+
async function copyAndAdjustDirectory(sourceDir, destDir, sourceBase, pluginPath, skillsPath, skillNameMap, exclude) {
|
|
28441
|
+
await mkdir6(destDir, { recursive: true });
|
|
28442
|
+
const entries = await readdir4(sourceDir, { withFileTypes: true });
|
|
28443
|
+
for (const entry of entries) {
|
|
28444
|
+
const sourcePath = join12(sourceDir, entry.name);
|
|
28445
|
+
const destPath = join12(destDir, entry.name);
|
|
28446
|
+
if (isExcluded(pluginPath, sourcePath, exclude)) {
|
|
28447
|
+
continue;
|
|
28448
|
+
}
|
|
28449
|
+
if (entry.isDirectory()) {
|
|
28450
|
+
await copyAndAdjustDirectory(sourcePath, destPath, sourceBase, pluginPath, skillsPath, skillNameMap, exclude);
|
|
28451
|
+
} else {
|
|
28452
|
+
const relativePath = relative2(sourceBase, sourcePath).replaceAll("\\", "/");
|
|
28453
|
+
const isMarkdown = entry.name.endsWith(".md") || entry.name.endsWith(".markdown");
|
|
28454
|
+
if (isMarkdown) {
|
|
28455
|
+
let content = await readFile8(sourcePath, "utf-8");
|
|
28456
|
+
content = adjustLinksInContent(content, relativePath, {
|
|
28457
|
+
...skillNameMap && { skillNameMap },
|
|
28458
|
+
workspaceSkillsPath: skillsPath
|
|
28459
|
+
});
|
|
28460
|
+
await writeFile4(destPath, content, "utf-8");
|
|
28461
|
+
} else {
|
|
28462
|
+
await cp(sourcePath, destPath);
|
|
28463
|
+
}
|
|
28165
28464
|
}
|
|
28166
|
-
const newExclude = entry.skills.exclude.filter((s) => s !== skillName);
|
|
28167
|
-
entry.skills = newExclude.length > 0 ? { exclude: newExclude } : undefined;
|
|
28168
|
-
await writeFile4(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
28169
|
-
return { success: true };
|
|
28170
|
-
} catch (error) {
|
|
28171
|
-
return {
|
|
28172
|
-
success: false,
|
|
28173
|
-
error: error instanceof Error ? error.message : String(error)
|
|
28174
|
-
};
|
|
28175
28465
|
}
|
|
28176
28466
|
}
|
|
28177
|
-
async function
|
|
28178
|
-
const
|
|
28179
|
-
|
|
28180
|
-
|
|
28181
|
-
|
|
28182
|
-
|
|
28183
|
-
};
|
|
28467
|
+
async function copyGitHubContent(pluginPath, workspacePath, client, options2 = {}) {
|
|
28468
|
+
const { dryRun = false, skillNameMap } = options2;
|
|
28469
|
+
const mapping = getMapping(client, options2);
|
|
28470
|
+
const results = [];
|
|
28471
|
+
if (!mapping.githubPath) {
|
|
28472
|
+
return results;
|
|
28184
28473
|
}
|
|
28185
|
-
const
|
|
28186
|
-
if (!
|
|
28187
|
-
return
|
|
28188
|
-
|
|
28189
|
-
|
|
28190
|
-
|
|
28474
|
+
const sourceDir = join12(pluginPath, ".github");
|
|
28475
|
+
if (!existsSync9(sourceDir)) {
|
|
28476
|
+
return results;
|
|
28477
|
+
}
|
|
28478
|
+
const destDir = join12(workspacePath, mapping.githubPath);
|
|
28479
|
+
if (dryRun) {
|
|
28480
|
+
results.push({ source: sourceDir, destination: destDir, action: "copied" });
|
|
28481
|
+
return results;
|
|
28191
28482
|
}
|
|
28192
|
-
const { pluginName, skillName } = parsed;
|
|
28193
28483
|
try {
|
|
28194
|
-
|
|
28195
|
-
|
|
28196
|
-
|
|
28197
|
-
|
|
28198
|
-
return {
|
|
28199
|
-
success: false,
|
|
28200
|
-
error: `Plugin '${pluginName}' not found in workspace config`
|
|
28201
|
-
};
|
|
28202
|
-
}
|
|
28203
|
-
const entry = ensureObjectPluginEntry(config, index);
|
|
28204
|
-
if (entry.skills && !Array.isArray(entry.skills)) {
|
|
28205
|
-
return {
|
|
28206
|
-
success: false,
|
|
28207
|
-
error: `Plugin '${pluginName}' is in blocklist mode; use removeDisabledSkill to enable a skill`
|
|
28208
|
-
};
|
|
28209
|
-
}
|
|
28210
|
-
const existing = entry.skills ?? [];
|
|
28211
|
-
if (existing.includes(skillName)) {
|
|
28212
|
-
return {
|
|
28213
|
-
success: false,
|
|
28214
|
-
error: `Skill '${skillKey}' is already enabled`
|
|
28215
|
-
};
|
|
28484
|
+
if (mapping.skillsPath || options2.exclude && options2.exclude.length > 0) {
|
|
28485
|
+
await copyAndAdjustDirectory(sourceDir, destDir, sourceDir, pluginPath, mapping.skillsPath ?? "", skillNameMap, options2.exclude);
|
|
28486
|
+
} else {
|
|
28487
|
+
await cp(sourceDir, destDir, { recursive: true });
|
|
28216
28488
|
}
|
|
28217
|
-
|
|
28218
|
-
await writeFile4(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
28219
|
-
return { success: true };
|
|
28489
|
+
results.push({ source: sourceDir, destination: destDir, action: "copied" });
|
|
28220
28490
|
} catch (error) {
|
|
28221
|
-
|
|
28222
|
-
|
|
28223
|
-
|
|
28224
|
-
|
|
28491
|
+
results.push({
|
|
28492
|
+
source: sourceDir,
|
|
28493
|
+
destination: destDir,
|
|
28494
|
+
action: "failed",
|
|
28495
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
28496
|
+
});
|
|
28225
28497
|
}
|
|
28498
|
+
return results;
|
|
28226
28499
|
}
|
|
28227
|
-
async function
|
|
28228
|
-
const
|
|
28229
|
-
|
|
28230
|
-
|
|
28231
|
-
|
|
28232
|
-
|
|
28233
|
-
|
|
28234
|
-
|
|
28235
|
-
|
|
28236
|
-
|
|
28237
|
-
|
|
28238
|
-
|
|
28239
|
-
|
|
28240
|
-
|
|
28500
|
+
async function copyPluginToWorkspace(pluginPath, workspacePath, client, options2 = {}) {
|
|
28501
|
+
const { skillNameMap, syncMode, canonicalSkillsPath, ...baseOptions } = options2;
|
|
28502
|
+
const [commandResults, skillResults, hookResults, agentResults] = await Promise.all([
|
|
28503
|
+
copyCommands(pluginPath, workspacePath, client, baseOptions),
|
|
28504
|
+
copySkills(pluginPath, workspacePath, client, {
|
|
28505
|
+
...baseOptions,
|
|
28506
|
+
...skillNameMap && { skillNameMap },
|
|
28507
|
+
...syncMode && { syncMode },
|
|
28508
|
+
...canonicalSkillsPath && { canonicalSkillsPath }
|
|
28509
|
+
}),
|
|
28510
|
+
copyHooks(pluginPath, workspacePath, client, baseOptions),
|
|
28511
|
+
copyAgents(pluginPath, workspacePath, client, baseOptions)
|
|
28512
|
+
]);
|
|
28513
|
+
const githubResults = await copyGitHubContent(pluginPath, workspacePath, client, {
|
|
28514
|
+
...baseOptions,
|
|
28515
|
+
...skillNameMap && { skillNameMap }
|
|
28516
|
+
});
|
|
28517
|
+
return [...commandResults, ...skillResults, ...hookResults, ...agentResults, ...githubResults];
|
|
28518
|
+
}
|
|
28519
|
+
function isExplicitGitHubSource(source) {
|
|
28520
|
+
if (source.startsWith("https://github.com/") || source.startsWith("http://github.com/") || source.startsWith("github.com/") || source.startsWith("gh:")) {
|
|
28521
|
+
return true;
|
|
28241
28522
|
}
|
|
28242
|
-
|
|
28243
|
-
|
|
28244
|
-
|
|
28245
|
-
|
|
28246
|
-
|
|
28247
|
-
|
|
28248
|
-
|
|
28249
|
-
success: false,
|
|
28250
|
-
error: `Plugin '${pluginName}' not found in workspace config`
|
|
28251
|
-
};
|
|
28523
|
+
if (!source.startsWith(".") && !source.startsWith("/") && source.includes("/")) {
|
|
28524
|
+
const parts = source.split("/");
|
|
28525
|
+
if (parts.length >= 3) {
|
|
28526
|
+
const validOwnerRepo = /^[a-zA-Z0-9_.-]+$/;
|
|
28527
|
+
if (parts[0] && parts[1] && validOwnerRepo.test(parts[0]) && validOwnerRepo.test(parts[1])) {
|
|
28528
|
+
return true;
|
|
28529
|
+
}
|
|
28252
28530
|
}
|
|
28253
|
-
|
|
28254
|
-
|
|
28255
|
-
|
|
28531
|
+
}
|
|
28532
|
+
return false;
|
|
28533
|
+
}
|
|
28534
|
+
function resolveFileSourcePath(source, defaultSourcePath, githubCache) {
|
|
28535
|
+
if (!isExplicitGitHubSource(source)) {
|
|
28536
|
+
if (source.startsWith("/")) {
|
|
28537
|
+
return { path: source };
|
|
28256
28538
|
}
|
|
28257
|
-
if (
|
|
28258
|
-
return {
|
|
28259
|
-
success: false,
|
|
28260
|
-
error: `Skill '${skillKey}' is already disabled`
|
|
28261
|
-
};
|
|
28539
|
+
if (source.startsWith("../")) {
|
|
28540
|
+
return { path: join12(process.cwd(), source) };
|
|
28262
28541
|
}
|
|
28263
|
-
if (
|
|
28264
|
-
return {
|
|
28265
|
-
success: false,
|
|
28266
|
-
error: `Skill '${skillKey}' is already disabled`
|
|
28267
|
-
};
|
|
28542
|
+
if (defaultSourcePath) {
|
|
28543
|
+
return { path: join12(defaultSourcePath, source) };
|
|
28268
28544
|
}
|
|
28269
|
-
|
|
28270
|
-
entry.skills = newSkills;
|
|
28271
|
-
await writeFile4(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
28272
|
-
return { success: true };
|
|
28273
|
-
} catch (error) {
|
|
28274
|
-
return {
|
|
28275
|
-
success: false,
|
|
28276
|
-
error: error instanceof Error ? error.message : String(error)
|
|
28277
|
-
};
|
|
28545
|
+
return { path: join12(process.cwd(), source) };
|
|
28278
28546
|
}
|
|
28279
|
-
|
|
28280
|
-
|
|
28281
|
-
|
|
28282
|
-
|
|
28283
|
-
|
|
28284
|
-
success: false,
|
|
28285
|
-
error: `${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE} not found in ${workspacePath}`
|
|
28286
|
-
};
|
|
28287
|
-
}
|
|
28288
|
-
try {
|
|
28289
|
-
const content = await readFile7(configPath, "utf-8");
|
|
28290
|
-
const config = load(content);
|
|
28291
|
-
const index = findPluginEntryByName(config, pluginName);
|
|
28292
|
-
if (index === -1) {
|
|
28547
|
+
const parsed = parseFileSource(source);
|
|
28548
|
+
if (parsed.type === "github" && parsed.owner && parsed.repo && parsed.filePath) {
|
|
28549
|
+
const cacheKey = `${parsed.owner}/${parsed.repo}`;
|
|
28550
|
+
const cachePath = githubCache?.get(cacheKey);
|
|
28551
|
+
if (!cachePath) {
|
|
28293
28552
|
return {
|
|
28294
|
-
|
|
28295
|
-
error: `
|
|
28553
|
+
path: "",
|
|
28554
|
+
error: `GitHub cache not found for ${cacheKey}. Ensure the repo is fetched.`
|
|
28296
28555
|
};
|
|
28297
28556
|
}
|
|
28298
|
-
|
|
28299
|
-
|
|
28300
|
-
|
|
28301
|
-
} else {
|
|
28302
|
-
entry.skills = skillNames.length > 0 ? { exclude: [...skillNames] } : undefined;
|
|
28303
|
-
}
|
|
28304
|
-
await writeFile4(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
28305
|
-
return { success: true };
|
|
28306
|
-
} catch (error) {
|
|
28557
|
+
return { path: join12(cachePath, parsed.filePath) };
|
|
28558
|
+
}
|
|
28559
|
+
if (parsed.type === "github") {
|
|
28307
28560
|
return {
|
|
28308
|
-
|
|
28309
|
-
error:
|
|
28561
|
+
path: "",
|
|
28562
|
+
error: `Invalid GitHub file source: ${source}. Must include path to file (e.g., owner/repo/path/to/file.md)`
|
|
28310
28563
|
};
|
|
28311
28564
|
}
|
|
28312
|
-
}
|
|
28313
|
-
function pruneEnabledSkillsForPlugin(config, pluginEntry) {
|
|
28314
|
-
if (!config.enabledSkills?.length)
|
|
28315
|
-
return;
|
|
28316
|
-
const names = extractPluginNames(pluginEntry);
|
|
28317
|
-
if (names.length === 0)
|
|
28318
|
-
return;
|
|
28319
|
-
const prefixes = names.map((n) => `${n}:`);
|
|
28320
|
-
config.enabledSkills = config.enabledSkills.filter((s) => !prefixes.some((p) => s.startsWith(p)));
|
|
28321
|
-
if (config.enabledSkills.length === 0) {
|
|
28322
|
-
config.enabledSkills = undefined;
|
|
28323
|
-
}
|
|
28324
|
-
}
|
|
28325
|
-
async function resolveGitHubIdentity(pluginSource) {
|
|
28326
|
-
if (isGitHubUrl(pluginSource)) {
|
|
28327
|
-
const parsed = parseGitHubUrl(pluginSource);
|
|
28328
|
-
return parsed ? `${parsed.owner}/${parsed.repo}`.toLowerCase() : null;
|
|
28329
|
-
}
|
|
28330
|
-
if (isPluginSpec(pluginSource)) {
|
|
28331
|
-
const parsed = parsePluginSpec(pluginSource);
|
|
28332
|
-
if (!parsed)
|
|
28333
|
-
return null;
|
|
28334
|
-
const marketplace = await getMarketplace(parsed.marketplaceName);
|
|
28335
|
-
if (!marketplace)
|
|
28336
|
-
return null;
|
|
28337
|
-
const manifestResult = await parseMarketplaceManifest(marketplace.path);
|
|
28338
|
-
if (!manifestResult.success)
|
|
28339
|
-
return null;
|
|
28340
|
-
const entry = manifestResult.data.plugins.find((p) => p.name === parsed.plugin);
|
|
28341
|
-
if (!entry || typeof entry.source === "string")
|
|
28342
|
-
return null;
|
|
28343
|
-
const parsedUrl = parseGitHubUrl(entry.source.url);
|
|
28344
|
-
return parsedUrl ? `${parsedUrl.owner}/${parsedUrl.repo}`.toLowerCase() : null;
|
|
28345
|
-
}
|
|
28346
28565
|
return null;
|
|
28347
28566
|
}
|
|
28348
|
-
async function
|
|
28349
|
-
const
|
|
28350
|
-
|
|
28351
|
-
|
|
28352
|
-
|
|
28353
|
-
|
|
28354
|
-
|
|
28355
|
-
|
|
28356
|
-
|
|
28357
|
-
|
|
28358
|
-
|
|
28359
|
-
|
|
28360
|
-
|
|
28361
|
-
|
|
28362
|
-
|
|
28363
|
-
|
|
28364
|
-
|
|
28365
|
-
|
|
28366
|
-
|
|
28367
|
-
|
|
28368
|
-
|
|
28369
|
-
|
|
28370
|
-
|
|
28567
|
+
async function copyWorkspaceFiles(sourcePath, workspacePath, files, options2 = {}) {
|
|
28568
|
+
const { dryRun = false, githubCache, repositories = [], skillsIndexRefs = [] } = options2;
|
|
28569
|
+
const results = [];
|
|
28570
|
+
const stringPatterns = [];
|
|
28571
|
+
const objectEntries = [];
|
|
28572
|
+
const copiedAgentFiles = [];
|
|
28573
|
+
for (const file of files) {
|
|
28574
|
+
if (typeof file === "string") {
|
|
28575
|
+
stringPatterns.push(file);
|
|
28576
|
+
} else {
|
|
28577
|
+
let dest = file.dest;
|
|
28578
|
+
if (!dest && file.source) {
|
|
28579
|
+
const parts = file.source.split("/");
|
|
28580
|
+
dest = parts[parts.length - 1] || file.source;
|
|
28581
|
+
}
|
|
28582
|
+
if (!dest) {
|
|
28583
|
+
results.push({
|
|
28584
|
+
source: "unknown",
|
|
28585
|
+
destination: join12(workspacePath, "unknown"),
|
|
28586
|
+
action: "failed",
|
|
28587
|
+
error: "File entry must have at least source or dest specified"
|
|
28588
|
+
});
|
|
28589
|
+
continue;
|
|
28590
|
+
}
|
|
28591
|
+
objectEntries.push(file.source ? { source: file.source, dest } : { dest });
|
|
28592
|
+
}
|
|
28371
28593
|
}
|
|
28372
|
-
|
|
28373
|
-
|
|
28374
|
-
|
|
28375
|
-
|
|
28376
|
-
|
|
28377
|
-
|
|
28378
|
-
|
|
28379
|
-
|
|
28594
|
+
if (stringPatterns.length > 0) {
|
|
28595
|
+
if (!sourcePath) {
|
|
28596
|
+
for (const pattern of stringPatterns) {
|
|
28597
|
+
if (!isGlobPattern(pattern) && !pattern.startsWith("!")) {
|
|
28598
|
+
results.push({
|
|
28599
|
+
source: pattern,
|
|
28600
|
+
destination: join12(workspacePath, pattern),
|
|
28601
|
+
action: "failed",
|
|
28602
|
+
error: `Cannot resolve file '${pattern}' - no workspace.source configured and no explicit source provided`
|
|
28603
|
+
});
|
|
28604
|
+
}
|
|
28605
|
+
}
|
|
28606
|
+
} else {
|
|
28607
|
+
const resolvedFiles = await resolveGlobPatterns(sourcePath, stringPatterns);
|
|
28608
|
+
for (const resolved of resolvedFiles) {
|
|
28609
|
+
const destPath = join12(workspacePath, resolved.relativePath);
|
|
28610
|
+
if (!existsSync9(resolved.sourcePath)) {
|
|
28611
|
+
const wasLiteral = stringPatterns.some((p) => !isGlobPattern(p) && !p.startsWith("!") && p === resolved.relativePath);
|
|
28612
|
+
if (wasLiteral) {
|
|
28613
|
+
results.push({
|
|
28614
|
+
source: resolved.sourcePath,
|
|
28615
|
+
destination: destPath,
|
|
28616
|
+
action: "failed",
|
|
28617
|
+
error: `Source file not found: ${resolved.sourcePath}`
|
|
28618
|
+
});
|
|
28619
|
+
}
|
|
28620
|
+
continue;
|
|
28621
|
+
}
|
|
28622
|
+
if (dryRun) {
|
|
28623
|
+
results.push({ source: resolved.sourcePath, destination: destPath, action: "copied" });
|
|
28624
|
+
if (AGENT_FILES2.includes(resolved.relativePath)) {
|
|
28625
|
+
copiedAgentFiles.push(resolved.relativePath);
|
|
28626
|
+
}
|
|
28627
|
+
continue;
|
|
28628
|
+
}
|
|
28629
|
+
try {
|
|
28630
|
+
await mkdir6(dirname5(destPath), { recursive: true });
|
|
28631
|
+
const content = await readFile8(resolved.sourcePath, "utf-8");
|
|
28632
|
+
await writeFile4(destPath, content, "utf-8");
|
|
28633
|
+
results.push({ source: resolved.sourcePath, destination: destPath, action: "copied" });
|
|
28634
|
+
if (AGENT_FILES2.includes(resolved.relativePath)) {
|
|
28635
|
+
copiedAgentFiles.push(resolved.relativePath);
|
|
28636
|
+
}
|
|
28637
|
+
} catch (error) {
|
|
28638
|
+
results.push({
|
|
28639
|
+
source: resolved.sourcePath,
|
|
28640
|
+
destination: destPath,
|
|
28641
|
+
action: "failed",
|
|
28642
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
28643
|
+
});
|
|
28644
|
+
}
|
|
28645
|
+
}
|
|
28646
|
+
}
|
|
28380
28647
|
}
|
|
28381
|
-
for (const
|
|
28382
|
-
const
|
|
28383
|
-
|
|
28384
|
-
|
|
28648
|
+
for (const entry of objectEntries) {
|
|
28649
|
+
const destPath = join12(workspacePath, entry.dest);
|
|
28650
|
+
let srcPath;
|
|
28651
|
+
if (entry.source) {
|
|
28652
|
+
const resolved = resolveFileSourcePath(entry.source, sourcePath, githubCache);
|
|
28653
|
+
if (!resolved) {
|
|
28654
|
+
results.push({
|
|
28655
|
+
source: entry.source,
|
|
28656
|
+
destination: destPath,
|
|
28657
|
+
action: "failed",
|
|
28658
|
+
error: `Failed to resolve source: ${entry.source}`
|
|
28659
|
+
});
|
|
28660
|
+
continue;
|
|
28661
|
+
}
|
|
28662
|
+
if (resolved.error) {
|
|
28663
|
+
results.push({
|
|
28664
|
+
source: entry.source,
|
|
28665
|
+
destination: destPath,
|
|
28666
|
+
action: "failed",
|
|
28667
|
+
error: resolved.error
|
|
28668
|
+
});
|
|
28669
|
+
continue;
|
|
28670
|
+
}
|
|
28671
|
+
srcPath = resolved.path;
|
|
28672
|
+
} else {
|
|
28673
|
+
if (!sourcePath) {
|
|
28674
|
+
results.push({
|
|
28675
|
+
source: entry.dest,
|
|
28676
|
+
destination: destPath,
|
|
28677
|
+
action: "failed",
|
|
28678
|
+
error: `Cannot resolve file '${entry.dest}' - no workspace.source configured and no explicit source provided`
|
|
28679
|
+
});
|
|
28680
|
+
continue;
|
|
28681
|
+
}
|
|
28682
|
+
srcPath = join12(sourcePath, entry.dest);
|
|
28683
|
+
}
|
|
28684
|
+
if (!existsSync9(srcPath)) {
|
|
28685
|
+
results.push({
|
|
28686
|
+
source: srcPath,
|
|
28687
|
+
destination: destPath,
|
|
28688
|
+
action: "failed",
|
|
28689
|
+
error: `Source file not found: ${srcPath}`
|
|
28690
|
+
});
|
|
28385
28691
|
continue;
|
|
28386
28692
|
}
|
|
28387
|
-
|
|
28388
|
-
|
|
28389
|
-
|
|
28390
|
-
|
|
28391
|
-
|
|
28392
|
-
if (index === -1) {
|
|
28393
|
-
console.warn(`[migrate v1→v2] No plugin found for '${pluginName}', skipping`);
|
|
28693
|
+
if (dryRun) {
|
|
28694
|
+
results.push({ source: srcPath, destination: destPath, action: "copied" });
|
|
28695
|
+
if (AGENT_FILES2.includes(entry.dest)) {
|
|
28696
|
+
copiedAgentFiles.push(entry.dest);
|
|
28697
|
+
}
|
|
28394
28698
|
continue;
|
|
28395
28699
|
}
|
|
28396
|
-
|
|
28397
|
-
|
|
28398
|
-
|
|
28700
|
+
try {
|
|
28701
|
+
await mkdir6(dirname5(destPath), { recursive: true });
|
|
28702
|
+
const content = await readFile8(srcPath, "utf-8");
|
|
28703
|
+
await writeFile4(destPath, content, "utf-8");
|
|
28704
|
+
results.push({ source: srcPath, destination: destPath, action: "copied" });
|
|
28705
|
+
if (AGENT_FILES2.includes(entry.dest)) {
|
|
28706
|
+
copiedAgentFiles.push(entry.dest);
|
|
28707
|
+
}
|
|
28708
|
+
} catch (error) {
|
|
28709
|
+
results.push({
|
|
28710
|
+
source: srcPath,
|
|
28711
|
+
destination: destPath,
|
|
28712
|
+
action: "failed",
|
|
28713
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
28714
|
+
});
|
|
28399
28715
|
}
|
|
28400
28716
|
}
|
|
28401
|
-
|
|
28402
|
-
|
|
28403
|
-
|
|
28404
|
-
|
|
28405
|
-
|
|
28406
|
-
|
|
28407
|
-
|
|
28408
|
-
|
|
28409
|
-
|
|
28410
|
-
|
|
28411
|
-
|
|
28412
|
-
|
|
28413
|
-
|
|
28414
|
-
|
|
28415
|
-
try {
|
|
28416
|
-
const content = await readFile7(configPath, "utf-8");
|
|
28417
|
-
const config = load(content);
|
|
28418
|
-
const removeSet = new Set(changes.remove);
|
|
28419
|
-
config.repositories = config.repositories.filter((repo) => !removeSet.has(repo.path));
|
|
28420
|
-
config.repositories.push(...changes.add);
|
|
28421
|
-
await writeFile4(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
28422
|
-
return { success: true };
|
|
28423
|
-
} catch (error) {
|
|
28424
|
-
return {
|
|
28425
|
-
success: false,
|
|
28426
|
-
error: error instanceof Error ? error.message : String(error)
|
|
28427
|
-
};
|
|
28428
|
-
}
|
|
28429
|
-
}
|
|
28430
|
-
async function setRepositories(repositories, workspacePath = process.cwd()) {
|
|
28431
|
-
const configPath = join11(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
28432
|
-
try {
|
|
28433
|
-
const content = await readFile7(configPath, "utf-8");
|
|
28434
|
-
const config = load(content);
|
|
28435
|
-
config.repositories = repositories;
|
|
28436
|
-
await writeFile4(configPath, dump(config, { lineWidth: -1 }), "utf-8");
|
|
28437
|
-
return { success: true };
|
|
28438
|
-
} catch (error) {
|
|
28439
|
-
return {
|
|
28440
|
-
success: false,
|
|
28441
|
-
error: error instanceof Error ? error.message : String(error)
|
|
28442
|
-
};
|
|
28717
|
+
if (!dryRun && repositories.length > 0) {
|
|
28718
|
+
for (const agentFile of copiedAgentFiles) {
|
|
28719
|
+
const targetPath = join12(workspacePath, agentFile);
|
|
28720
|
+
try {
|
|
28721
|
+
await ensureWorkspaceRules(targetPath, repositories, skillsIndexRefs);
|
|
28722
|
+
} catch (error) {
|
|
28723
|
+
results.push({
|
|
28724
|
+
source: "WORKSPACE-RULES",
|
|
28725
|
+
destination: targetPath,
|
|
28726
|
+
action: "failed",
|
|
28727
|
+
error: error instanceof Error ? error.message : "Failed to inject WORKSPACE-RULES"
|
|
28728
|
+
});
|
|
28729
|
+
}
|
|
28730
|
+
}
|
|
28443
28731
|
}
|
|
28732
|
+
return results;
|
|
28444
28733
|
}
|
|
28445
|
-
var
|
|
28446
|
-
var
|
|
28447
|
-
|
|
28734
|
+
var import_micromatch, AGENT_FILES2;
|
|
28735
|
+
var init_transform = __esm(() => {
|
|
28736
|
+
init_glob_patterns();
|
|
28737
|
+
init_client_mapping();
|
|
28448
28738
|
init_constants();
|
|
28449
|
-
init_workspace_config();
|
|
28450
|
-
init_marketplace_manifest_parser();
|
|
28451
28739
|
init_plugin_path();
|
|
28452
|
-
|
|
28453
|
-
|
|
28740
|
+
init_symlink();
|
|
28741
|
+
init_link_adjuster();
|
|
28742
|
+
init_skill();
|
|
28743
|
+
init_skills();
|
|
28744
|
+
import_micromatch = __toESM(require_micromatch(), 1);
|
|
28745
|
+
AGENT_FILES2 = ["AGENTS.md", "CLAUDE.md"];
|
|
28454
28746
|
});
|
|
28455
28747
|
|
|
28456
28748
|
// src/core/repo-skills.ts
|
|
28457
|
-
import { existsSync as
|
|
28458
|
-
import { readdir as
|
|
28459
|
-
import { basename as
|
|
28749
|
+
import { existsSync as existsSync10, lstatSync, mkdirSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
28750
|
+
import { readdir as readdir5, readFile as readFile9 } from "node:fs/promises";
|
|
28751
|
+
import { basename as basename6, join as join13, relative as relative3, resolve as resolve9 } from "node:path";
|
|
28460
28752
|
async function discoverRepoSkills(repoPath, options2) {
|
|
28461
28753
|
if (options2.disabled)
|
|
28462
28754
|
return [];
|
|
@@ -28476,19 +28768,19 @@ async function discoverRepoSkills(repoPath, options2) {
|
|
|
28476
28768
|
const results = [];
|
|
28477
28769
|
const seen = new Set;
|
|
28478
28770
|
for (const skillDir of skillDirs) {
|
|
28479
|
-
const absDir =
|
|
28480
|
-
if (!
|
|
28771
|
+
const absDir = join13(repoPath, skillDir);
|
|
28772
|
+
if (!existsSync10(absDir))
|
|
28481
28773
|
continue;
|
|
28482
28774
|
let entries;
|
|
28483
28775
|
try {
|
|
28484
|
-
entries = await
|
|
28776
|
+
entries = await readdir5(absDir, { withFileTypes: true });
|
|
28485
28777
|
} catch {
|
|
28486
28778
|
continue;
|
|
28487
28779
|
}
|
|
28488
28780
|
for (const entry of entries) {
|
|
28489
28781
|
if (!entry.isDirectory())
|
|
28490
28782
|
continue;
|
|
28491
|
-
const entryPath =
|
|
28783
|
+
const entryPath = join13(absDir, entry.name);
|
|
28492
28784
|
try {
|
|
28493
28785
|
const stat2 = lstatSync(entryPath);
|
|
28494
28786
|
if (stat2.isSymbolicLink())
|
|
@@ -28496,14 +28788,14 @@ async function discoverRepoSkills(repoPath, options2) {
|
|
|
28496
28788
|
} catch {
|
|
28497
28789
|
continue;
|
|
28498
28790
|
}
|
|
28499
|
-
const skillMdPath =
|
|
28500
|
-
if (!
|
|
28791
|
+
const skillMdPath = join13(entryPath, "SKILL.md");
|
|
28792
|
+
if (!existsSync10(skillMdPath))
|
|
28501
28793
|
continue;
|
|
28502
28794
|
const relPath = relative3(repoPath, skillMdPath);
|
|
28503
28795
|
if (seen.has(relPath))
|
|
28504
28796
|
continue;
|
|
28505
28797
|
try {
|
|
28506
|
-
const content = await
|
|
28798
|
+
const content = await readFile9(skillMdPath, "utf-8");
|
|
28507
28799
|
const metadata = parseSkillMetadata(content);
|
|
28508
28800
|
if (!metadata)
|
|
28509
28801
|
continue;
|
|
@@ -28524,7 +28816,7 @@ async function discoverWorkspaceSkills(workspacePath, repositories, clientNames)
|
|
|
28524
28816
|
for (const repo of repositories) {
|
|
28525
28817
|
if (repo.skills === false || repo.skills === undefined)
|
|
28526
28818
|
continue;
|
|
28527
|
-
const repoAbsPath =
|
|
28819
|
+
const repoAbsPath = resolve9(workspacePath, repo.path);
|
|
28528
28820
|
const discoverOpts = Array.isArray(repo.skills) ? { skillPaths: repo.skills } : { clients: clientNames };
|
|
28529
28821
|
const repoSkills = await discoverRepoSkills(repoAbsPath, discoverOpts);
|
|
28530
28822
|
for (const skill of repoSkills) {
|
|
@@ -28556,7 +28848,7 @@ async function discoverWorkspaceSkills(workspacePath, repositories, clientNames)
|
|
|
28556
28848
|
function writeSkillsIndex(workspacePath, skillsByRepo) {
|
|
28557
28849
|
if (skillsByRepo.size === 0)
|
|
28558
28850
|
return { writtenFiles: [], refs: [] };
|
|
28559
|
-
const indexDir =
|
|
28851
|
+
const indexDir = join13(workspacePath, ".allagents", "skills-index");
|
|
28560
28852
|
mkdirSync(indexDir, { recursive: true });
|
|
28561
28853
|
const writtenFiles = [];
|
|
28562
28854
|
const refs = [];
|
|
@@ -28574,15 +28866,15 @@ ${skillEntries}
|
|
|
28574
28866
|
</available_skills>
|
|
28575
28867
|
`;
|
|
28576
28868
|
const filePath = `skills-index/${repoName}.md`;
|
|
28577
|
-
writeFileSync(
|
|
28869
|
+
writeFileSync(join13(indexDir, `${repoName}.md`), content, "utf-8");
|
|
28578
28870
|
writtenFiles.push(filePath);
|
|
28579
28871
|
refs.push({ repoName, indexPath: `.allagents/${filePath}` });
|
|
28580
28872
|
}
|
|
28581
28873
|
return { writtenFiles, refs };
|
|
28582
28874
|
}
|
|
28583
28875
|
function cleanupSkillsIndex(workspacePath, currentFiles) {
|
|
28584
|
-
const indexDir =
|
|
28585
|
-
if (!
|
|
28876
|
+
const indexDir = join13(workspacePath, ".allagents", "skills-index");
|
|
28877
|
+
if (!existsSync10(indexDir))
|
|
28586
28878
|
return;
|
|
28587
28879
|
const currentSet = new Set(currentFiles.map((f) => f.replace("skills-index/", "")));
|
|
28588
28880
|
let entries;
|
|
@@ -28593,7 +28885,7 @@ function cleanupSkillsIndex(workspacePath, currentFiles) {
|
|
|
28593
28885
|
}
|
|
28594
28886
|
for (const entry of entries) {
|
|
28595
28887
|
if (!currentSet.has(entry)) {
|
|
28596
|
-
rmSync(
|
|
28888
|
+
rmSync(join13(indexDir, entry), { force: true });
|
|
28597
28889
|
}
|
|
28598
28890
|
}
|
|
28599
28891
|
try {
|
|
@@ -28606,11 +28898,11 @@ function cleanupSkillsIndex(workspacePath, currentFiles) {
|
|
|
28606
28898
|
function groupSkillsByRepo(skills, repositories) {
|
|
28607
28899
|
const repoNameMap = new Map;
|
|
28608
28900
|
for (const repo of repositories) {
|
|
28609
|
-
repoNameMap.set(repo.path, repo.name ??
|
|
28901
|
+
repoNameMap.set(repo.path, repo.name ?? basename6(repo.path));
|
|
28610
28902
|
}
|
|
28611
28903
|
const grouped = new Map;
|
|
28612
28904
|
for (const skill of skills) {
|
|
28613
|
-
const repoName = repoNameMap.get(skill.repoPath) ??
|
|
28905
|
+
const repoName = repoNameMap.get(skill.repoPath) ?? basename6(skill.repoPath);
|
|
28614
28906
|
const existing = grouped.get(skill.repoPath);
|
|
28615
28907
|
if (existing) {
|
|
28616
28908
|
existing.skills.push(skill);
|
|
@@ -28626,9 +28918,9 @@ var init_repo_skills = __esm(() => {
|
|
|
28626
28918
|
});
|
|
28627
28919
|
|
|
28628
28920
|
// src/core/workspace-repo.ts
|
|
28629
|
-
import { readFile as
|
|
28630
|
-
import { existsSync as
|
|
28631
|
-
import { join as
|
|
28921
|
+
import { readFile as readFile10, writeFile as writeFile5 } from "node:fs/promises";
|
|
28922
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
28923
|
+
import { join as join14 } from "node:path";
|
|
28632
28924
|
async function detectRemote(repoPath) {
|
|
28633
28925
|
try {
|
|
28634
28926
|
const env2 = { ...process.env };
|
|
@@ -28670,10 +28962,10 @@ function normalizePath(p) {
|
|
|
28670
28962
|
}
|
|
28671
28963
|
async function addRepository(path, options2 = {}, workspacePath = process.cwd()) {
|
|
28672
28964
|
const normalizedPath = normalizePath(path);
|
|
28673
|
-
const configPath =
|
|
28965
|
+
const configPath = join14(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
28674
28966
|
await ensureWorkspace(workspacePath);
|
|
28675
28967
|
try {
|
|
28676
|
-
const content = await
|
|
28968
|
+
const content = await readFile10(configPath, "utf-8");
|
|
28677
28969
|
const config = load(content);
|
|
28678
28970
|
if (config.repositories.some((r) => normalizePath(r.path) === normalizedPath)) {
|
|
28679
28971
|
return { success: false, error: `Repository already exists: ${normalizedPath}` };
|
|
@@ -28693,8 +28985,8 @@ async function addRepository(path, options2 = {}, workspacePath = process.cwd())
|
|
|
28693
28985
|
}
|
|
28694
28986
|
}
|
|
28695
28987
|
async function removeRepository(path, workspacePath = process.cwd()) {
|
|
28696
|
-
const configPath =
|
|
28697
|
-
if (!
|
|
28988
|
+
const configPath = join14(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
28989
|
+
if (!existsSync11(configPath)) {
|
|
28698
28990
|
return {
|
|
28699
28991
|
success: false,
|
|
28700
28992
|
error: `${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE} not found in ${workspacePath}
|
|
@@ -28702,7 +28994,7 @@ async function removeRepository(path, workspacePath = process.cwd()) {
|
|
|
28702
28994
|
};
|
|
28703
28995
|
}
|
|
28704
28996
|
try {
|
|
28705
|
-
const content = await
|
|
28997
|
+
const content = await readFile10(configPath, "utf-8");
|
|
28706
28998
|
const config = load(content);
|
|
28707
28999
|
const normalizedPath = normalizePath(path);
|
|
28708
29000
|
const index = config.repositories.findIndex((r) => normalizePath(r.path) === normalizedPath);
|
|
@@ -28717,11 +29009,11 @@ async function removeRepository(path, workspacePath = process.cwd()) {
|
|
|
28717
29009
|
}
|
|
28718
29010
|
}
|
|
28719
29011
|
async function listRepositories(workspacePath = process.cwd()) {
|
|
28720
|
-
const configPath =
|
|
28721
|
-
if (!
|
|
29012
|
+
const configPath = join14(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
29013
|
+
if (!existsSync11(configPath))
|
|
28722
29014
|
return [];
|
|
28723
29015
|
try {
|
|
28724
|
-
const content = await
|
|
29016
|
+
const content = await readFile10(configPath, "utf-8");
|
|
28725
29017
|
const config = load(content);
|
|
28726
29018
|
return config.repositories ?? [];
|
|
28727
29019
|
} catch {
|
|
@@ -28732,10 +29024,10 @@ function resolveClientNames(clients) {
|
|
|
28732
29024
|
return (clients ?? []).map((c) => typeof c === "string" ? c : c.name);
|
|
28733
29025
|
}
|
|
28734
29026
|
async function updateAgentFiles(workspacePath = process.cwd()) {
|
|
28735
|
-
const configPath =
|
|
28736
|
-
if (!
|
|
29027
|
+
const configPath = join14(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
29028
|
+
if (!existsSync11(configPath))
|
|
28737
29029
|
return;
|
|
28738
|
-
const content = await
|
|
29030
|
+
const content = await readFile10(configPath, "utf-8");
|
|
28739
29031
|
const config = load(content);
|
|
28740
29032
|
if (config.repositories.length === 0)
|
|
28741
29033
|
return;
|
|
@@ -28753,7 +29045,7 @@ async function updateAgentFiles(workspacePath = process.cwd()) {
|
|
|
28753
29045
|
}
|
|
28754
29046
|
agentFiles.add("AGENTS.md");
|
|
28755
29047
|
for (const agentFile of agentFiles) {
|
|
28756
|
-
await ensureWorkspaceRules(
|
|
29048
|
+
await ensureWorkspaceRules(join14(workspacePath, agentFile), config.repositories, skillsIndexRefs);
|
|
28757
29049
|
}
|
|
28758
29050
|
}
|
|
28759
29051
|
var init_workspace_repo = __esm(() => {
|
|
@@ -28937,14 +29229,14 @@ var init_sync_state = __esm(() => {
|
|
|
28937
29229
|
});
|
|
28938
29230
|
|
|
28939
29231
|
// src/core/config-gitignore.ts
|
|
28940
|
-
import { writeFile as writeFile6, readFile as
|
|
28941
|
-
import { existsSync as
|
|
28942
|
-
import { join as
|
|
29232
|
+
import { writeFile as writeFile6, readFile as readFile11 } from "node:fs/promises";
|
|
29233
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
29234
|
+
import { join as join15 } from "node:path";
|
|
28943
29235
|
async function ensureConfigGitignore(workspacePath) {
|
|
28944
|
-
const gitignorePath =
|
|
29236
|
+
const gitignorePath = join15(workspacePath, CONFIG_DIR, ".gitignore");
|
|
28945
29237
|
let existing = "";
|
|
28946
|
-
if (
|
|
28947
|
-
existing = await
|
|
29238
|
+
if (existsSync12(gitignorePath)) {
|
|
29239
|
+
existing = await readFile11(gitignorePath, "utf-8");
|
|
28948
29240
|
}
|
|
28949
29241
|
const missing = GITIGNORE_ENTRIES.filter((entry) => !existing.split(`
|
|
28950
29242
|
`).includes(entry));
|
|
@@ -28965,19 +29257,19 @@ var init_config_gitignore = __esm(() => {
|
|
|
28965
29257
|
});
|
|
28966
29258
|
|
|
28967
29259
|
// src/core/sync-state.ts
|
|
28968
|
-
import { readFile as
|
|
28969
|
-
import { existsSync as
|
|
28970
|
-
import { join as
|
|
29260
|
+
import { readFile as readFile12, writeFile as writeFile7, mkdir as mkdir7 } from "node:fs/promises";
|
|
29261
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
29262
|
+
import { join as join16, dirname as dirname6 } from "node:path";
|
|
28971
29263
|
function getSyncStatePath(workspacePath) {
|
|
28972
|
-
return
|
|
29264
|
+
return join16(workspacePath, CONFIG_DIR, SYNC_STATE_FILE);
|
|
28973
29265
|
}
|
|
28974
29266
|
async function loadSyncState(workspacePath) {
|
|
28975
29267
|
const statePath = getSyncStatePath(workspacePath);
|
|
28976
|
-
if (!
|
|
29268
|
+
if (!existsSync13(statePath)) {
|
|
28977
29269
|
return null;
|
|
28978
29270
|
}
|
|
28979
29271
|
try {
|
|
28980
|
-
const content = await
|
|
29272
|
+
const content = await readFile12(statePath, "utf-8");
|
|
28981
29273
|
const parsed = JSON.parse(content);
|
|
28982
29274
|
const result = SyncStateSchema.safeParse(parsed);
|
|
28983
29275
|
if (!result.success) {
|
|
@@ -29052,12 +29344,12 @@ var init_sync_state2 = __esm(() => {
|
|
|
29052
29344
|
|
|
29053
29345
|
// src/core/vscode-workspace.ts
|
|
29054
29346
|
import { createHash as createHash2 } from "node:crypto";
|
|
29055
|
-
import { resolve as
|
|
29347
|
+
import { resolve as resolve10, basename as basename7, isAbsolute as isAbsolute3, relative as relative4 } from "node:path";
|
|
29056
29348
|
function normalizeWorkspacePath(path) {
|
|
29057
29349
|
return path.replace(/\\/g, "/");
|
|
29058
29350
|
}
|
|
29059
29351
|
function resolveFolderAbsolutePath(workspacePath, folderPath) {
|
|
29060
|
-
return (isAbsolute3(folderPath) ? folderPath :
|
|
29352
|
+
return (isAbsolute3(folderPath) ? folderPath : resolve10(workspacePath, folderPath)).replace(/\\/g, "/");
|
|
29061
29353
|
}
|
|
29062
29354
|
function resolveFolderDisplayPath(folderPath) {
|
|
29063
29355
|
return normalizeWorkspacePath(folderPath);
|
|
@@ -29065,7 +29357,7 @@ function resolveFolderDisplayPath(folderPath) {
|
|
|
29065
29357
|
function buildPathPlaceholderMap(repositories, workspacePath) {
|
|
29066
29358
|
const map2 = new Map;
|
|
29067
29359
|
for (const repo of repositories) {
|
|
29068
|
-
const absolutePath =
|
|
29360
|
+
const absolutePath = resolve10(workspacePath, repo.path);
|
|
29069
29361
|
map2.set(repo.path, absolutePath);
|
|
29070
29362
|
}
|
|
29071
29363
|
return map2;
|
|
@@ -29100,7 +29392,7 @@ function generateVscodeWorkspace(input) {
|
|
|
29100
29392
|
const folders = [];
|
|
29101
29393
|
const seenPaths = new Set;
|
|
29102
29394
|
folders.push({ path: "." });
|
|
29103
|
-
seenPaths.add(
|
|
29395
|
+
seenPaths.add(resolve10(workspacePath, "."));
|
|
29104
29396
|
for (const repo of repositories) {
|
|
29105
29397
|
const absolutePath = resolveFolderAbsolutePath(workspacePath, repo.path);
|
|
29106
29398
|
const entry = { path: resolveFolderDisplayPath(repo.path) };
|
|
@@ -29142,22 +29434,22 @@ function getWorkspaceOutputPath(workspacePath, vscodeConfig) {
|
|
|
29142
29434
|
const name = vscodeConfig?.output;
|
|
29143
29435
|
if (name) {
|
|
29144
29436
|
const filename = name.endsWith(".code-workspace") ? name : `${name}.code-workspace`;
|
|
29145
|
-
return
|
|
29437
|
+
return resolve10(workspacePath, filename);
|
|
29146
29438
|
}
|
|
29147
|
-
const dirName =
|
|
29148
|
-
return
|
|
29439
|
+
const dirName = basename7(resolve10(workspacePath));
|
|
29440
|
+
return resolve10(workspacePath, `${dirName}.code-workspace`);
|
|
29149
29441
|
}
|
|
29150
29442
|
function computeWorkspaceHash(content) {
|
|
29151
29443
|
return createHash2("sha256").update(content).digest("hex");
|
|
29152
29444
|
}
|
|
29153
29445
|
function reconcileVscodeWorkspaceFolders(workspacePath, codeWorkspaceFolders, lastSyncedRepos, currentRepos) {
|
|
29154
|
-
const normalizedWorkspacePath =
|
|
29446
|
+
const normalizedWorkspacePath = resolve10(workspacePath).replace(/\\/g, "/");
|
|
29155
29447
|
const codeWorkspaceAbsPaths = new Set;
|
|
29156
29448
|
const codeWorkspaceNames = new Map;
|
|
29157
29449
|
for (const folder of codeWorkspaceFolders) {
|
|
29158
29450
|
if (folder.path === ".")
|
|
29159
29451
|
continue;
|
|
29160
|
-
const absPath = (isAbsolute3(folder.path) ? folder.path :
|
|
29452
|
+
const absPath = (isAbsolute3(folder.path) ? folder.path : resolve10(workspacePath, folder.path)).replace(/\\/g, "/");
|
|
29161
29453
|
codeWorkspaceAbsPaths.add(absPath);
|
|
29162
29454
|
if (folder.name)
|
|
29163
29455
|
codeWorkspaceNames.set(absPath, folder.name);
|
|
@@ -29165,7 +29457,7 @@ function reconcileVscodeWorkspaceFolders(workspacePath, codeWorkspaceFolders, la
|
|
|
29165
29457
|
const lastSyncedSet = new Set(lastSyncedRepos.map((p) => p.replace(/\\/g, "/")));
|
|
29166
29458
|
const currentReposByAbsPath = new Map;
|
|
29167
29459
|
for (const repo of currentRepos) {
|
|
29168
|
-
const absPath =
|
|
29460
|
+
const absPath = resolve10(workspacePath, repo.path).replace(/\\/g, "/");
|
|
29169
29461
|
currentReposByAbsPath.set(absPath, repo);
|
|
29170
29462
|
}
|
|
29171
29463
|
const currentAbsPaths = new Set(currentReposByAbsPath.keys());
|
|
@@ -29216,8 +29508,8 @@ var init_vscode_workspace = __esm(() => {
|
|
|
29216
29508
|
});
|
|
29217
29509
|
|
|
29218
29510
|
// src/core/vscode-mcp.ts
|
|
29219
|
-
import { existsSync as
|
|
29220
|
-
import { join as
|
|
29511
|
+
import { existsSync as existsSync14, readFileSync, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
|
|
29512
|
+
import { join as join17, dirname as dirname7 } from "node:path";
|
|
29221
29513
|
function deepEqual(a, b) {
|
|
29222
29514
|
if (a === b)
|
|
29223
29515
|
return true;
|
|
@@ -29249,17 +29541,17 @@ function getVscodeMcpConfigPath() {
|
|
|
29249
29541
|
if (!appData) {
|
|
29250
29542
|
throw new Error("APPDATA environment variable not set");
|
|
29251
29543
|
}
|
|
29252
|
-
return
|
|
29544
|
+
return join17(appData, "Code", "User", "mcp.json");
|
|
29253
29545
|
}
|
|
29254
29546
|
const home = getHomeDir();
|
|
29255
29547
|
if (platform2 === "darwin") {
|
|
29256
|
-
return
|
|
29548
|
+
return join17(home, "Library", "Application Support", "Code", "User", "mcp.json");
|
|
29257
29549
|
}
|
|
29258
|
-
return
|
|
29550
|
+
return join17(home, ".config", "Code", "User", "mcp.json");
|
|
29259
29551
|
}
|
|
29260
29552
|
function readPluginMcpConfig(pluginPath) {
|
|
29261
|
-
const mcpPath =
|
|
29262
|
-
if (!
|
|
29553
|
+
const mcpPath = join17(pluginPath, ".mcp.json");
|
|
29554
|
+
if (!existsSync14(mcpPath)) {
|
|
29263
29555
|
return null;
|
|
29264
29556
|
}
|
|
29265
29557
|
try {
|
|
@@ -29325,7 +29617,7 @@ function syncVscodeMcpConfig(validatedPlugins, options2) {
|
|
|
29325
29617
|
trackedServers: []
|
|
29326
29618
|
};
|
|
29327
29619
|
let existingConfig = {};
|
|
29328
|
-
if (
|
|
29620
|
+
if (existsSync14(configPath)) {
|
|
29329
29621
|
try {
|
|
29330
29622
|
const content = readFileSync(configPath, "utf-8");
|
|
29331
29623
|
existingConfig = import_json5.default.parse(content);
|
|
@@ -29376,7 +29668,7 @@ function syncVscodeMcpConfig(validatedPlugins, options2) {
|
|
|
29376
29668
|
if (hasChanges && !dryRun) {
|
|
29377
29669
|
existingConfig.servers = existingServers;
|
|
29378
29670
|
const dir = dirname7(configPath);
|
|
29379
|
-
if (!
|
|
29671
|
+
if (!existsSync14(dir)) {
|
|
29380
29672
|
mkdirSync2(dir, { recursive: true });
|
|
29381
29673
|
}
|
|
29382
29674
|
writeFileSync2(configPath, `${JSON.stringify(existingConfig, null, 2)}
|
|
@@ -29394,7 +29686,7 @@ function syncVscodeMcpConfig(validatedPlugins, options2) {
|
|
|
29394
29686
|
if (result.removed > 0 && !dryRun) {
|
|
29395
29687
|
existingConfig.servers = existingServers;
|
|
29396
29688
|
const dir = dirname7(configPath);
|
|
29397
|
-
if (!
|
|
29689
|
+
if (!existsSync14(dir)) {
|
|
29398
29690
|
mkdirSync2(dir, { recursive: true });
|
|
29399
29691
|
}
|
|
29400
29692
|
writeFileSync2(configPath, `${JSON.stringify(existingConfig, null, 2)}
|
|
@@ -29451,7 +29743,7 @@ function applyMcpProxy(servers, client, config) {
|
|
|
29451
29743
|
// src/core/native/types.ts
|
|
29452
29744
|
import { spawn as spawn2 } from "node:child_process";
|
|
29453
29745
|
function executeCommand(binary2, args, options2 = {}) {
|
|
29454
|
-
return new Promise((
|
|
29746
|
+
return new Promise((resolve11) => {
|
|
29455
29747
|
const proc = spawn2(binary2, args, {
|
|
29456
29748
|
cwd: options2.cwd,
|
|
29457
29749
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -29472,7 +29764,7 @@ function executeCommand(binary2, args, options2 = {}) {
|
|
|
29472
29764
|
return;
|
|
29473
29765
|
resolved = true;
|
|
29474
29766
|
const trimmedStderr = stderr.trim();
|
|
29475
|
-
|
|
29767
|
+
resolve11({
|
|
29476
29768
|
success: code === 0,
|
|
29477
29769
|
output: stdout.trim(),
|
|
29478
29770
|
...trimmedStderr && { error: trimmedStderr }
|
|
@@ -29482,7 +29774,7 @@ function executeCommand(binary2, args, options2 = {}) {
|
|
|
29482
29774
|
if (resolved)
|
|
29483
29775
|
return;
|
|
29484
29776
|
resolved = true;
|
|
29485
|
-
|
|
29777
|
+
resolve11({
|
|
29486
29778
|
success: false,
|
|
29487
29779
|
output: "",
|
|
29488
29780
|
error: `Failed to execute ${binary2} CLI: ${err.message}`
|
|
@@ -29501,7 +29793,7 @@ function mergeNativeSyncResults(results) {
|
|
|
29501
29793
|
var init_types2 = () => {};
|
|
29502
29794
|
|
|
29503
29795
|
// src/core/codex-mcp.ts
|
|
29504
|
-
import { existsSync as
|
|
29796
|
+
import { existsSync as existsSync15, readFileSync as readFileSync2, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
|
|
29505
29797
|
import { dirname as dirname8 } from "node:path";
|
|
29506
29798
|
function buildCodexMcpAddArgs(name, config) {
|
|
29507
29799
|
if (typeof config.url === "string") {
|
|
@@ -29712,7 +30004,7 @@ function syncCodexProjectMcpConfig(validatedPlugins, options2) {
|
|
|
29712
30004
|
trackedServers: []
|
|
29713
30005
|
};
|
|
29714
30006
|
let existingContent = "";
|
|
29715
|
-
if (
|
|
30007
|
+
if (existsSync15(configPath)) {
|
|
29716
30008
|
try {
|
|
29717
30009
|
existingContent = readFileSync2(configPath, "utf-8");
|
|
29718
30010
|
} catch {
|
|
@@ -29768,7 +30060,7 @@ function syncCodexProjectMcpConfig(validatedPlugins, options2) {
|
|
|
29768
30060
|
`)}
|
|
29769
30061
|
`;
|
|
29770
30062
|
const dir = dirname8(configPath);
|
|
29771
|
-
if (!
|
|
30063
|
+
if (!existsSync15(dir)) {
|
|
29772
30064
|
mkdirSync3(dir, { recursive: true });
|
|
29773
30065
|
}
|
|
29774
30066
|
writeFileSync3(configPath, output, "utf-8");
|
|
@@ -29782,7 +30074,7 @@ var init_codex_mcp = __esm(() => {
|
|
|
29782
30074
|
});
|
|
29783
30075
|
|
|
29784
30076
|
// src/core/claude-mcp.ts
|
|
29785
|
-
import { existsSync as
|
|
30077
|
+
import { existsSync as existsSync16, readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "node:fs";
|
|
29786
30078
|
import { dirname as dirname9 } from "node:path";
|
|
29787
30079
|
function deepEqual2(a, b) {
|
|
29788
30080
|
if (a === b)
|
|
@@ -29850,7 +30142,7 @@ function syncClaudeMcpConfig(validatedPlugins, options2) {
|
|
|
29850
30142
|
trackedServers: []
|
|
29851
30143
|
};
|
|
29852
30144
|
let existingConfig = {};
|
|
29853
|
-
if (
|
|
30145
|
+
if (existsSync16(configPath)) {
|
|
29854
30146
|
try {
|
|
29855
30147
|
const content = readFileSync3(configPath, "utf-8");
|
|
29856
30148
|
existingConfig = import_json52.default.parse(content);
|
|
@@ -29901,7 +30193,7 @@ function syncClaudeMcpConfig(validatedPlugins, options2) {
|
|
|
29901
30193
|
if (hasChanges && !dryRun) {
|
|
29902
30194
|
existingConfig.mcpServers = existingServers;
|
|
29903
30195
|
const dir = dirname9(configPath);
|
|
29904
|
-
if (!
|
|
30196
|
+
if (!existsSync16(dir)) {
|
|
29905
30197
|
mkdirSync4(dir, { recursive: true });
|
|
29906
30198
|
}
|
|
29907
30199
|
writeFileSync4(configPath, `${JSON.stringify(existingConfig, null, 2)}
|
|
@@ -29919,7 +30211,7 @@ function syncClaudeMcpConfig(validatedPlugins, options2) {
|
|
|
29919
30211
|
if (result.removed > 0 && !dryRun) {
|
|
29920
30212
|
existingConfig.mcpServers = existingServers;
|
|
29921
30213
|
const dir = dirname9(configPath);
|
|
29922
|
-
if (!
|
|
30214
|
+
if (!existsSync16(dir)) {
|
|
29923
30215
|
mkdirSync4(dir, { recursive: true });
|
|
29924
30216
|
}
|
|
29925
30217
|
writeFileSync4(configPath, `${JSON.stringify(existingConfig, null, 2)}
|
|
@@ -30018,41 +30310,41 @@ var init_claude_mcp = __esm(() => {
|
|
|
30018
30310
|
});
|
|
30019
30311
|
|
|
30020
30312
|
// src/core/copilot-mcp.ts
|
|
30021
|
-
import { join as
|
|
30313
|
+
import { join as join18 } from "node:path";
|
|
30022
30314
|
function getCopilotMcpConfigPath() {
|
|
30023
|
-
return
|
|
30315
|
+
return join18(getHomeDir(), ".copilot", "mcp-config.json");
|
|
30024
30316
|
}
|
|
30025
30317
|
var init_copilot_mcp = __esm(() => {
|
|
30026
30318
|
init_constants();
|
|
30027
30319
|
});
|
|
30028
30320
|
|
|
30029
30321
|
// src/core/mcp-sync.ts
|
|
30030
|
-
import { existsSync as
|
|
30031
|
-
import { join as
|
|
30322
|
+
import { existsSync as existsSync17 } from "node:fs";
|
|
30323
|
+
import { join as join19 } from "node:path";
|
|
30032
30324
|
function buildSyncSpecs(workspacePath) {
|
|
30033
30325
|
return [
|
|
30034
30326
|
{
|
|
30035
30327
|
client: "vscode",
|
|
30036
30328
|
scope: "vscode",
|
|
30037
|
-
configPath:
|
|
30329
|
+
configPath: join19(workspacePath, ".vscode", "mcp.json"),
|
|
30038
30330
|
syncFn: syncVscodeMcpConfig
|
|
30039
30331
|
},
|
|
30040
30332
|
{
|
|
30041
30333
|
client: "claude",
|
|
30042
30334
|
scope: "claude",
|
|
30043
|
-
configPath:
|
|
30335
|
+
configPath: join19(workspacePath, ".mcp.json"),
|
|
30044
30336
|
syncFn: syncClaudeMcpConfig
|
|
30045
30337
|
},
|
|
30046
30338
|
{
|
|
30047
30339
|
client: "codex",
|
|
30048
30340
|
scope: "codex",
|
|
30049
|
-
configPath:
|
|
30341
|
+
configPath: join19(workspacePath, ".codex", "config.toml"),
|
|
30050
30342
|
syncFn: syncCodexProjectMcpConfig
|
|
30051
30343
|
},
|
|
30052
30344
|
{
|
|
30053
30345
|
client: "copilot",
|
|
30054
30346
|
scope: "copilot",
|
|
30055
|
-
configPath:
|
|
30347
|
+
configPath: join19(workspacePath, ".copilot", "mcp-config.json"),
|
|
30056
30348
|
syncFn: syncClaudeMcpConfig
|
|
30057
30349
|
}
|
|
30058
30350
|
];
|
|
@@ -30107,8 +30399,8 @@ function syncMcpServers(workspacePath, validPlugins, config, previousState, sync
|
|
|
30107
30399
|
async function syncMcpOnly(workspacePath = process.cwd(), options2 = {}) {
|
|
30108
30400
|
const { offline = false, dryRun = false } = options2;
|
|
30109
30401
|
await migrateWorkspaceSkillsV1toV2(workspacePath);
|
|
30110
|
-
const configPath =
|
|
30111
|
-
if (!
|
|
30402
|
+
const configPath = join19(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
30403
|
+
if (!existsSync17(configPath)) {
|
|
30112
30404
|
return {
|
|
30113
30405
|
success: false,
|
|
30114
30406
|
mcpResults: {},
|
|
@@ -30482,9 +30774,9 @@ function padStart2(str3, len) {
|
|
|
30482
30774
|
}
|
|
30483
30775
|
|
|
30484
30776
|
// src/core/managed-repos.ts
|
|
30485
|
-
import { existsSync as
|
|
30777
|
+
import { existsSync as existsSync18 } from "node:fs";
|
|
30486
30778
|
import { mkdir as mkdir8 } from "node:fs/promises";
|
|
30487
|
-
import { dirname as dirname10, resolve as
|
|
30779
|
+
import { dirname as dirname10, resolve as resolve11 } from "node:path";
|
|
30488
30780
|
function expandHome(p) {
|
|
30489
30781
|
if (p.startsWith("~/") || p === "~") {
|
|
30490
30782
|
return p.replace("~", getHomeDir());
|
|
@@ -30565,8 +30857,8 @@ async function processManagedRepos(repositories, workspacePath, options2 = {}) {
|
|
|
30565
30857
|
continue;
|
|
30566
30858
|
}
|
|
30567
30859
|
const expandedPath = expandHome(repo.path);
|
|
30568
|
-
const absolutePath =
|
|
30569
|
-
if (!
|
|
30860
|
+
const absolutePath = resolve11(workspacePath, expandedPath);
|
|
30861
|
+
if (!existsSync18(absolutePath)) {
|
|
30570
30862
|
if (!shouldClone(repo.managed)) {
|
|
30571
30863
|
results.push({ path: repo.path, repo: repo.repo, action: "skipped" });
|
|
30572
30864
|
continue;
|
|
@@ -30617,9 +30909,9 @@ var init_managed_repos = __esm(() => {
|
|
|
30617
30909
|
});
|
|
30618
30910
|
|
|
30619
30911
|
// src/core/sync.ts
|
|
30620
|
-
import { existsSync as
|
|
30912
|
+
import { existsSync as existsSync19, readFileSync as readFileSync4, writeFileSync as writeFileSync5, lstatSync as lstatSync2 } from "node:fs";
|
|
30621
30913
|
import { rm as rm4, unlink as unlink2, rmdir, copyFile } from "node:fs/promises";
|
|
30622
|
-
import { join as
|
|
30914
|
+
import { join as join20, resolve as resolve12, dirname as dirname11, relative as relative5 } from "node:path";
|
|
30623
30915
|
function deduplicateClientsByPath(clients, clientMappings = CLIENT_MAPPINGS) {
|
|
30624
30916
|
const pathToClients = new Map;
|
|
30625
30917
|
for (const client of clients) {
|
|
@@ -30782,7 +31074,7 @@ async function selectivePurgeWorkspace(workspacePath, state, clients) {
|
|
|
30782
31074
|
const previousFiles = getPreviouslySyncedFiles(state, client);
|
|
30783
31075
|
const purgedPaths = [];
|
|
30784
31076
|
for (const filePath of previousFiles) {
|
|
30785
|
-
const fullPath =
|
|
31077
|
+
const fullPath = join20(workspacePath, filePath);
|
|
30786
31078
|
const cleanPath = fullPath.replace(/\/$/, "");
|
|
30787
31079
|
let stats;
|
|
30788
31080
|
try {
|
|
@@ -30811,8 +31103,8 @@ async function selectivePurgeWorkspace(workspacePath, state, clients) {
|
|
|
30811
31103
|
async function cleanupEmptyParents(workspacePath, filePath) {
|
|
30812
31104
|
let parentPath = dirname11(filePath);
|
|
30813
31105
|
while (parentPath && parentPath !== "." && parentPath !== "/") {
|
|
30814
|
-
const fullParentPath =
|
|
30815
|
-
if (!
|
|
31106
|
+
const fullParentPath = join20(workspacePath, parentPath);
|
|
31107
|
+
if (!existsSync19(fullParentPath)) {
|
|
30816
31108
|
parentPath = dirname11(parentPath);
|
|
30817
31109
|
continue;
|
|
30818
31110
|
}
|
|
@@ -30897,8 +31189,8 @@ function validateFileSources(files, defaultSourcePath, githubCache) {
|
|
|
30897
31189
|
errors2.push(`Cannot resolve file '${file}' - no workspace.source configured`);
|
|
30898
31190
|
continue;
|
|
30899
31191
|
}
|
|
30900
|
-
const fullPath =
|
|
30901
|
-
if (!
|
|
31192
|
+
const fullPath = join20(defaultSourcePath, file);
|
|
31193
|
+
if (!existsSync19(fullPath)) {
|
|
30902
31194
|
errors2.push(`File source not found: ${fullPath}`);
|
|
30903
31195
|
}
|
|
30904
31196
|
continue;
|
|
@@ -30916,8 +31208,8 @@ function validateFileSources(files, defaultSourcePath, githubCache) {
|
|
|
30916
31208
|
errors2.push(`GitHub cache not found for ${cacheKey}`);
|
|
30917
31209
|
continue;
|
|
30918
31210
|
}
|
|
30919
|
-
const fullPath =
|
|
30920
|
-
if (!
|
|
31211
|
+
const fullPath = join20(cachePath, parsed.filePath);
|
|
31212
|
+
if (!existsSync19(fullPath)) {
|
|
30921
31213
|
errors2.push(`Path not found in repository: ${cacheKey}/${parsed.filePath}`);
|
|
30922
31214
|
}
|
|
30923
31215
|
} else {
|
|
@@ -30925,13 +31217,13 @@ function validateFileSources(files, defaultSourcePath, githubCache) {
|
|
|
30925
31217
|
if (file.source.startsWith("/")) {
|
|
30926
31218
|
fullPath = file.source;
|
|
30927
31219
|
} else if (file.source.startsWith("../")) {
|
|
30928
|
-
fullPath =
|
|
31220
|
+
fullPath = resolve12(file.source);
|
|
30929
31221
|
} else if (defaultSourcePath) {
|
|
30930
|
-
fullPath =
|
|
31222
|
+
fullPath = join20(defaultSourcePath, file.source);
|
|
30931
31223
|
} else {
|
|
30932
|
-
fullPath =
|
|
31224
|
+
fullPath = resolve12(file.source);
|
|
30933
31225
|
}
|
|
30934
|
-
if (!
|
|
31226
|
+
if (!existsSync19(fullPath)) {
|
|
30935
31227
|
errors2.push(`File source not found: ${fullPath}`);
|
|
30936
31228
|
}
|
|
30937
31229
|
}
|
|
@@ -30940,8 +31232,8 @@ function validateFileSources(files, defaultSourcePath, githubCache) {
|
|
|
30940
31232
|
errors2.push(`Cannot resolve file '${file.dest}' - no workspace.source configured and no explicit source provided`);
|
|
30941
31233
|
continue;
|
|
30942
31234
|
}
|
|
30943
|
-
const fullPath =
|
|
30944
|
-
if (!
|
|
31235
|
+
const fullPath = join20(defaultSourcePath, file.dest ?? "");
|
|
31236
|
+
if (!existsSync19(fullPath)) {
|
|
30945
31237
|
errors2.push(`File source not found: ${fullPath}`);
|
|
30946
31238
|
}
|
|
30947
31239
|
}
|
|
@@ -31089,7 +31381,7 @@ async function validatePlugin(pluginSource, workspacePath, offline) {
|
|
|
31089
31381
|
...fetchResult.error && { error: fetchResult.error }
|
|
31090
31382
|
};
|
|
31091
31383
|
}
|
|
31092
|
-
const resolvedPath2 = parsed?.subpath ?
|
|
31384
|
+
const resolvedPath2 = parsed?.subpath ? join20(fetchResult.cachePath, parsed.subpath) : fetchResult.cachePath;
|
|
31093
31385
|
return {
|
|
31094
31386
|
plugin: pluginSource,
|
|
31095
31387
|
resolved: resolvedPath2,
|
|
@@ -31098,8 +31390,8 @@ async function validatePlugin(pluginSource, workspacePath, offline) {
|
|
|
31098
31390
|
nativeClients: []
|
|
31099
31391
|
};
|
|
31100
31392
|
}
|
|
31101
|
-
const resolvedPath =
|
|
31102
|
-
if (!
|
|
31393
|
+
const resolvedPath = resolve12(workspacePath, pluginSource);
|
|
31394
|
+
if (!existsSync19(resolvedPath)) {
|
|
31103
31395
|
return {
|
|
31104
31396
|
plugin: pluginSource,
|
|
31105
31397
|
resolved: resolvedPath,
|
|
@@ -31272,10 +31564,10 @@ function buildPluginSkillNameMaps(allSkills) {
|
|
|
31272
31564
|
return pluginMaps;
|
|
31273
31565
|
}
|
|
31274
31566
|
function generateVscodeWorkspaceFile(workspacePath, config) {
|
|
31275
|
-
const configDir =
|
|
31276
|
-
const templatePath =
|
|
31567
|
+
const configDir = join20(workspacePath, CONFIG_DIR);
|
|
31568
|
+
const templatePath = join20(configDir, VSCODE_TEMPLATE_FILE);
|
|
31277
31569
|
let template;
|
|
31278
|
-
if (
|
|
31570
|
+
if (existsSync19(templatePath)) {
|
|
31279
31571
|
try {
|
|
31280
31572
|
template = import_json53.default.parse(readFileSync4(templatePath, "utf-8"));
|
|
31281
31573
|
} catch (error) {
|
|
@@ -31427,7 +31719,7 @@ async function syncVscodeWorkspaceFile(workspacePath, config, configPath, previo
|
|
|
31427
31719
|
let updatedConfig = config;
|
|
31428
31720
|
if (previousState?.vscodeWorkspaceHash && previousState?.vscodeWorkspaceRepos) {
|
|
31429
31721
|
const outputPath = getWorkspaceOutputPath(workspacePath, config.vscode);
|
|
31430
|
-
if (
|
|
31722
|
+
if (existsSync19(outputPath)) {
|
|
31431
31723
|
const existingContent = readFileSync4(outputPath, "utf-8");
|
|
31432
31724
|
const currentHash = computeWorkspaceHash(existingContent);
|
|
31433
31725
|
if (currentHash !== previousState.vscodeWorkspaceHash) {
|
|
@@ -31460,7 +31752,7 @@ async function syncVscodeWorkspaceFile(workspacePath, config, configPath, previo
|
|
|
31460
31752
|
}
|
|
31461
31753
|
const writtenContent = generateVscodeWorkspaceFile(workspacePath, updatedConfig);
|
|
31462
31754
|
const hash = computeWorkspaceHash(writtenContent);
|
|
31463
|
-
const repos = updatedConfig.repositories.map((r) =>
|
|
31755
|
+
const repos = updatedConfig.repositories.map((r) => resolve12(workspacePath, r.path).replace(/\\/g, "/"));
|
|
31464
31756
|
return { config: updatedConfig, hash, repos };
|
|
31465
31757
|
}
|
|
31466
31758
|
async function buildSourcesProvenance(validatedPlugins, pluginEntries) {
|
|
@@ -31542,9 +31834,9 @@ async function syncWorkspace(workspacePath = process.cwd(), options2 = {}) {
|
|
|
31542
31834
|
skipManaged = false
|
|
31543
31835
|
} = options2;
|
|
31544
31836
|
const sw = new Stopwatch;
|
|
31545
|
-
const configDir =
|
|
31546
|
-
const configPath =
|
|
31547
|
-
if (!
|
|
31837
|
+
const configDir = join20(workspacePath, CONFIG_DIR);
|
|
31838
|
+
const configPath = join20(configDir, WORKSPACE_CONFIG_FILE);
|
|
31839
|
+
if (!existsSync19(configPath)) {
|
|
31548
31840
|
return failedSyncResult(`${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE} not found in ${workspacePath}
|
|
31549
31841
|
Run 'allagents workspace init <path>' to create a new workspace`);
|
|
31550
31842
|
}
|
|
@@ -31641,8 +31933,8 @@ ${failedValidations.map((v) => ` - ${v.plugin}: ${v.error}`).join(`
|
|
|
31641
31933
|
const filesToCopy = [...config.workspace.files];
|
|
31642
31934
|
if (hasRepositories && sourcePath) {
|
|
31643
31935
|
for (const agentFile of AGENT_FILES) {
|
|
31644
|
-
const agentPath =
|
|
31645
|
-
if (
|
|
31936
|
+
const agentPath = join20(sourcePath, agentFile);
|
|
31937
|
+
if (existsSync19(agentPath) && !filesToCopy.includes(agentFile)) {
|
|
31646
31938
|
filesToCopy.push(agentFile);
|
|
31647
31939
|
}
|
|
31648
31940
|
}
|
|
@@ -31682,10 +31974,10 @@ ${fileValidationErrors.map((e) => ` - ${e}`).join(`
|
|
|
31682
31974
|
skillsIndexRefs
|
|
31683
31975
|
});
|
|
31684
31976
|
if (hasRepositories && !dryRun && syncClients.includes("claude") && sourcePath) {
|
|
31685
|
-
const claudePath =
|
|
31686
|
-
const agentsPath =
|
|
31687
|
-
const claudeExistsInSource =
|
|
31688
|
-
if (!claudeExistsInSource &&
|
|
31977
|
+
const claudePath = join20(workspacePath, "CLAUDE.md");
|
|
31978
|
+
const agentsPath = join20(workspacePath, "AGENTS.md");
|
|
31979
|
+
const claudeExistsInSource = existsSync19(join20(sourcePath, "CLAUDE.md"));
|
|
31980
|
+
if (!claudeExistsInSource && existsSync19(agentsPath) && !existsSync19(claudePath)) {
|
|
31689
31981
|
await copyFile(agentsPath, claudePath);
|
|
31690
31982
|
}
|
|
31691
31983
|
}
|
|
@@ -31769,7 +32061,7 @@ async function seedFetchCacheFromMarketplaces(results) {
|
|
|
31769
32061
|
}
|
|
31770
32062
|
function readGitBranch(repoPath) {
|
|
31771
32063
|
try {
|
|
31772
|
-
const head = readFileSync4(
|
|
32064
|
+
const head = readFileSync4(join20(repoPath, ".git", "HEAD"), "utf-8").trim();
|
|
31773
32065
|
const prefix = "ref: refs/heads/";
|
|
31774
32066
|
return head.startsWith(prefix) ? head.slice(prefix.length) : null;
|
|
31775
32067
|
} catch {
|
|
@@ -31779,7 +32071,7 @@ function readGitBranch(repoPath) {
|
|
|
31779
32071
|
async function syncUserWorkspace(options2 = {}) {
|
|
31780
32072
|
await migrateUserWorkspaceSkillsV1toV2();
|
|
31781
32073
|
const sw = new Stopwatch;
|
|
31782
|
-
const homeDir =
|
|
32074
|
+
const homeDir = resolve12(getHomeDir());
|
|
31783
32075
|
const config = await getUserWorkspaceConfig();
|
|
31784
32076
|
if (!config) {
|
|
31785
32077
|
return {
|
|
@@ -31977,11 +32269,11 @@ var init_sync = __esm(() => {
|
|
|
31977
32269
|
});
|
|
31978
32270
|
|
|
31979
32271
|
// src/core/github-fetch.ts
|
|
31980
|
-
import { existsSync as
|
|
31981
|
-
import { join as
|
|
32272
|
+
import { existsSync as existsSync20, readFileSync as readFileSync5 } from "node:fs";
|
|
32273
|
+
import { join as join21 } from "node:path";
|
|
31982
32274
|
function readFileFromClone(tempDir, filePath) {
|
|
31983
|
-
const fullPath =
|
|
31984
|
-
if (
|
|
32275
|
+
const fullPath = join21(tempDir, filePath);
|
|
32276
|
+
if (existsSync20(fullPath)) {
|
|
31985
32277
|
return readFileSync5(fullPath, "utf-8");
|
|
31986
32278
|
}
|
|
31987
32279
|
return null;
|
|
@@ -32080,15 +32372,15 @@ var init_github_fetch = __esm(() => {
|
|
|
32080
32372
|
});
|
|
32081
32373
|
|
|
32082
32374
|
// src/core/workspace.ts
|
|
32083
|
-
import { cp as cp2, mkdir as mkdir9, readFile as
|
|
32084
|
-
import { existsSync as
|
|
32085
|
-
import { join as
|
|
32375
|
+
import { cp as cp2, mkdir as mkdir9, readFile as readFile13, writeFile as writeFile8, copyFile as copyFile2, unlink as unlink3 } from "node:fs/promises";
|
|
32376
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
32377
|
+
import { join as join22, resolve as resolve13, dirname as dirname12, relative as relative6, sep as sep2, isAbsolute as isAbsolute4 } from "node:path";
|
|
32086
32378
|
import { fileURLToPath } from "node:url";
|
|
32087
32379
|
async function initWorkspace(targetPath = ".", options2 = {}) {
|
|
32088
|
-
const absoluteTarget =
|
|
32089
|
-
const configDir =
|
|
32090
|
-
const configPath =
|
|
32091
|
-
if (
|
|
32380
|
+
const absoluteTarget = resolve13(targetPath);
|
|
32381
|
+
const configDir = join22(absoluteTarget, CONFIG_DIR);
|
|
32382
|
+
const configPath = join22(configDir, WORKSPACE_CONFIG_FILE);
|
|
32383
|
+
if (existsSync21(configPath)) {
|
|
32092
32384
|
if (options2.force) {
|
|
32093
32385
|
await unlink3(configPath);
|
|
32094
32386
|
} else {
|
|
@@ -32099,7 +32391,7 @@ async function initWorkspace(targetPath = ".", options2 = {}) {
|
|
|
32099
32391
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
32100
32392
|
const currentFileDir = dirname12(currentFilePath);
|
|
32101
32393
|
const isProduction = currentFilePath.includes(`${sep2}dist${sep2}`);
|
|
32102
|
-
const defaultTemplatePath = isProduction ?
|
|
32394
|
+
const defaultTemplatePath = isProduction ? join22(currentFileDir, "templates", "default") : join22(currentFileDir, "..", "templates", "default");
|
|
32103
32395
|
let githubTempDir;
|
|
32104
32396
|
let parsedFromUrl;
|
|
32105
32397
|
let githubBasePath = "";
|
|
@@ -32138,20 +32430,20 @@ async function initWorkspace(targetPath = ".", options2 = {}) {
|
|
|
32138
32430
|
}
|
|
32139
32431
|
console.log(`✓ Using workspace.yaml from: ${options2.from}`);
|
|
32140
32432
|
} else {
|
|
32141
|
-
const fromPath =
|
|
32142
|
-
if (!
|
|
32433
|
+
const fromPath = resolve13(options2.from);
|
|
32434
|
+
if (!existsSync21(fromPath)) {
|
|
32143
32435
|
throw new Error(`Template not found: ${fromPath}`);
|
|
32144
32436
|
}
|
|
32145
32437
|
const { stat: stat2 } = await import("node:fs/promises");
|
|
32146
32438
|
const fromStat = await stat2(fromPath);
|
|
32147
32439
|
let sourceYamlPath;
|
|
32148
32440
|
if (fromStat.isDirectory()) {
|
|
32149
|
-
const nestedPath =
|
|
32150
|
-
const rootPath =
|
|
32151
|
-
if (
|
|
32441
|
+
const nestedPath = join22(fromPath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
32442
|
+
const rootPath = join22(fromPath, WORKSPACE_CONFIG_FILE);
|
|
32443
|
+
if (existsSync21(nestedPath)) {
|
|
32152
32444
|
sourceYamlPath = nestedPath;
|
|
32153
32445
|
sourceDir = fromPath;
|
|
32154
|
-
} else if (
|
|
32446
|
+
} else if (existsSync21(rootPath)) {
|
|
32155
32447
|
sourceYamlPath = rootPath;
|
|
32156
32448
|
sourceDir = fromPath;
|
|
32157
32449
|
} else {
|
|
@@ -32167,14 +32459,14 @@ async function initWorkspace(targetPath = ".", options2 = {}) {
|
|
|
32167
32459
|
sourceDir = parentDir;
|
|
32168
32460
|
}
|
|
32169
32461
|
}
|
|
32170
|
-
workspaceYamlContent = await
|
|
32462
|
+
workspaceYamlContent = await readFile13(sourceYamlPath, "utf-8");
|
|
32171
32463
|
if (sourceDir) {
|
|
32172
32464
|
const parsed2 = load(workspaceYamlContent);
|
|
32173
32465
|
const workspace = parsed2?.workspace;
|
|
32174
32466
|
if (workspace?.source) {
|
|
32175
32467
|
const source = workspace.source;
|
|
32176
32468
|
if (!isGitHubUrl(source) && !isAbsolute4(source)) {
|
|
32177
|
-
workspace.source =
|
|
32469
|
+
workspace.source = resolve13(sourceDir, source);
|
|
32178
32470
|
workspaceYamlContent = dump(parsed2, { lineWidth: -1 });
|
|
32179
32471
|
}
|
|
32180
32472
|
}
|
|
@@ -32182,11 +32474,11 @@ async function initWorkspace(targetPath = ".", options2 = {}) {
|
|
|
32182
32474
|
console.log(`✓ Using workspace.yaml from: ${sourceYamlPath}`);
|
|
32183
32475
|
}
|
|
32184
32476
|
} else {
|
|
32185
|
-
const defaultYamlPath =
|
|
32186
|
-
if (!
|
|
32477
|
+
const defaultYamlPath = join22(defaultTemplatePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
32478
|
+
if (!existsSync21(defaultYamlPath)) {
|
|
32187
32479
|
throw new Error(`Default template not found at: ${defaultTemplatePath}`);
|
|
32188
32480
|
}
|
|
32189
|
-
workspaceYamlContent = await
|
|
32481
|
+
workspaceYamlContent = await readFile13(defaultYamlPath, "utf-8");
|
|
32190
32482
|
}
|
|
32191
32483
|
if (options2.clients && options2.clients.length > 0) {
|
|
32192
32484
|
const configParsed = load(workspaceYamlContent);
|
|
@@ -32199,8 +32491,8 @@ async function initWorkspace(targetPath = ".", options2 = {}) {
|
|
|
32199
32491
|
const clientNames = getClientTypes(clients);
|
|
32200
32492
|
const VSCODE_TEMPLATE_FILE2 = "template.code-workspace";
|
|
32201
32493
|
if (clientNames.includes("vscode") && options2.from) {
|
|
32202
|
-
const targetTemplatePath =
|
|
32203
|
-
if (!
|
|
32494
|
+
const targetTemplatePath = join22(configDir, VSCODE_TEMPLATE_FILE2);
|
|
32495
|
+
if (!existsSync21(targetTemplatePath)) {
|
|
32204
32496
|
if (isGitHubUrl(options2.from) && githubTempDir) {
|
|
32205
32497
|
if (parsedFromUrl) {
|
|
32206
32498
|
const templatePath = githubBasePath ? `${githubBasePath}/${CONFIG_DIR}/${VSCODE_TEMPLATE_FILE2}` : `${CONFIG_DIR}/${VSCODE_TEMPLATE_FILE2}`;
|
|
@@ -32210,8 +32502,8 @@ async function initWorkspace(targetPath = ".", options2 = {}) {
|
|
|
32210
32502
|
}
|
|
32211
32503
|
}
|
|
32212
32504
|
} else if (sourceDir) {
|
|
32213
|
-
const sourceTemplatePath =
|
|
32214
|
-
if (
|
|
32505
|
+
const sourceTemplatePath = join22(sourceDir, CONFIG_DIR, VSCODE_TEMPLATE_FILE2);
|
|
32506
|
+
if (existsSync21(sourceTemplatePath)) {
|
|
32215
32507
|
await copyFile2(sourceTemplatePath, targetTemplatePath);
|
|
32216
32508
|
}
|
|
32217
32509
|
}
|
|
@@ -32224,8 +32516,8 @@ async function initWorkspace(targetPath = ".", options2 = {}) {
|
|
|
32224
32516
|
if (options2.from && isGitHubUrl(options2.from) && githubTempDir) {
|
|
32225
32517
|
if (parsedFromUrl) {
|
|
32226
32518
|
for (const agentFile of AGENT_FILES) {
|
|
32227
|
-
const targetFilePath =
|
|
32228
|
-
if (
|
|
32519
|
+
const targetFilePath = join22(absoluteTarget, agentFile);
|
|
32520
|
+
if (existsSync21(targetFilePath)) {
|
|
32229
32521
|
copiedAgentFiles.push(agentFile);
|
|
32230
32522
|
continue;
|
|
32231
32523
|
}
|
|
@@ -32240,30 +32532,30 @@ async function initWorkspace(targetPath = ".", options2 = {}) {
|
|
|
32240
32532
|
} else {
|
|
32241
32533
|
const effectiveSourceDir = sourceDir ?? defaultTemplatePath;
|
|
32242
32534
|
for (const agentFile of AGENT_FILES) {
|
|
32243
|
-
const targetFilePath =
|
|
32244
|
-
if (
|
|
32535
|
+
const targetFilePath = join22(absoluteTarget, agentFile);
|
|
32536
|
+
if (existsSync21(targetFilePath)) {
|
|
32245
32537
|
copiedAgentFiles.push(agentFile);
|
|
32246
32538
|
continue;
|
|
32247
32539
|
}
|
|
32248
|
-
const sourcePath =
|
|
32249
|
-
if (
|
|
32250
|
-
const content = await
|
|
32540
|
+
const sourcePath = join22(effectiveSourceDir, agentFile);
|
|
32541
|
+
if (existsSync21(sourcePath)) {
|
|
32542
|
+
const content = await readFile13(sourcePath, "utf-8");
|
|
32251
32543
|
await writeFile8(targetFilePath, content, "utf-8");
|
|
32252
32544
|
copiedAgentFiles.push(agentFile);
|
|
32253
32545
|
}
|
|
32254
32546
|
}
|
|
32255
32547
|
}
|
|
32256
32548
|
if (copiedAgentFiles.length === 0) {
|
|
32257
|
-
await ensureWorkspaceRules(
|
|
32549
|
+
await ensureWorkspaceRules(join22(absoluteTarget, "AGENTS.md"), repositories);
|
|
32258
32550
|
copiedAgentFiles.push("AGENTS.md");
|
|
32259
32551
|
} else {
|
|
32260
32552
|
for (const agentFile of copiedAgentFiles) {
|
|
32261
|
-
await ensureWorkspaceRules(
|
|
32553
|
+
await ensureWorkspaceRules(join22(absoluteTarget, agentFile), repositories);
|
|
32262
32554
|
}
|
|
32263
32555
|
}
|
|
32264
32556
|
if (clientNames.includes("claude") && !copiedAgentFiles.includes("CLAUDE.md") && copiedAgentFiles.includes("AGENTS.md")) {
|
|
32265
|
-
const agentsPath =
|
|
32266
|
-
const claudePath =
|
|
32557
|
+
const agentsPath = join22(absoluteTarget, "AGENTS.md");
|
|
32558
|
+
const claudePath = join22(absoluteTarget, "CLAUDE.md");
|
|
32267
32559
|
await copyFile2(agentsPath, claudePath);
|
|
32268
32560
|
}
|
|
32269
32561
|
}
|
|
@@ -32308,14 +32600,14 @@ Next steps:`);
|
|
|
32308
32600
|
async function seedCacheFromClone(tempDir, owner, repo, branch) {
|
|
32309
32601
|
const cachePaths = [
|
|
32310
32602
|
getPluginCachePath(owner, repo, branch),
|
|
32311
|
-
|
|
32603
|
+
join22(getMarketplacesDir(), repo)
|
|
32312
32604
|
];
|
|
32313
32605
|
for (const cachePath of cachePaths) {
|
|
32314
|
-
if (
|
|
32606
|
+
if (existsSync21(cachePath))
|
|
32315
32607
|
continue;
|
|
32316
32608
|
try {
|
|
32317
32609
|
const parentDir = dirname12(cachePath);
|
|
32318
|
-
if (!
|
|
32610
|
+
if (!existsSync21(parentDir)) {
|
|
32319
32611
|
await mkdir9(parentDir, { recursive: true });
|
|
32320
32612
|
}
|
|
32321
32613
|
await cp2(tempDir, cachePath, { recursive: true });
|
|
@@ -32336,11 +32628,11 @@ var init_workspace = __esm(() => {
|
|
|
32336
32628
|
});
|
|
32337
32629
|
|
|
32338
32630
|
// src/core/status.ts
|
|
32339
|
-
import { existsSync as
|
|
32340
|
-
import { join as
|
|
32631
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
32632
|
+
import { join as join23 } from "node:path";
|
|
32341
32633
|
async function getWorkspaceStatus(workspacePath = process.cwd()) {
|
|
32342
|
-
const configPath =
|
|
32343
|
-
if (!
|
|
32634
|
+
const configPath = join23(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
32635
|
+
if (!existsSync22(configPath) || isUserConfigPath(workspacePath)) {
|
|
32344
32636
|
const userPlugins = await getUserPluginStatuses();
|
|
32345
32637
|
return {
|
|
32346
32638
|
success: true,
|
|
@@ -32382,7 +32674,7 @@ async function getWorkspaceStatus(workspacePath = process.cwd()) {
|
|
|
32382
32674
|
function getPluginStatus(parsed) {
|
|
32383
32675
|
if (parsed.type === "github") {
|
|
32384
32676
|
const cachePath = parsed.owner && parsed.repo ? getPluginCachePath(parsed.owner, parsed.repo) : "";
|
|
32385
|
-
const available2 = cachePath ?
|
|
32677
|
+
const available2 = cachePath ? existsSync22(cachePath) : false;
|
|
32386
32678
|
return {
|
|
32387
32679
|
source: parsed.original,
|
|
32388
32680
|
type: "github",
|
|
@@ -32392,7 +32684,7 @@ function getPluginStatus(parsed) {
|
|
|
32392
32684
|
...parsed.repo && { repo: parsed.repo }
|
|
32393
32685
|
};
|
|
32394
32686
|
}
|
|
32395
|
-
const available =
|
|
32687
|
+
const available = existsSync22(parsed.normalized);
|
|
32396
32688
|
return {
|
|
32397
32689
|
source: parsed.original,
|
|
32398
32690
|
type: "local",
|
|
@@ -34553,160 +34845,6 @@ var init_prompt_clients = __esm(() => {
|
|
|
34553
34845
|
({ autocompleteMultiselect } = exports_dist);
|
|
34554
34846
|
});
|
|
34555
34847
|
|
|
34556
|
-
// src/core/skills.ts
|
|
34557
|
-
import { existsSync as existsSync24 } from "node:fs";
|
|
34558
|
-
import { readFile as readFile14, readdir as readdir5 } from "node:fs/promises";
|
|
34559
|
-
import { join as join25, basename as basename7, resolve as resolve14 } from "node:path";
|
|
34560
|
-
async function resolvePluginPath(pluginSource, workspacePath) {
|
|
34561
|
-
if (isPluginSpec(pluginSource)) {
|
|
34562
|
-
const resolved2 = await resolvePluginSpecWithAutoRegister(pluginSource, {
|
|
34563
|
-
offline: true,
|
|
34564
|
-
workspacePath
|
|
34565
|
-
});
|
|
34566
|
-
if (!resolved2.success || !resolved2.path)
|
|
34567
|
-
return null;
|
|
34568
|
-
return {
|
|
34569
|
-
path: resolved2.path,
|
|
34570
|
-
pluginName: resolved2.pluginName
|
|
34571
|
-
};
|
|
34572
|
-
}
|
|
34573
|
-
if (isGitHubUrl(pluginSource)) {
|
|
34574
|
-
const parsed = parseGitHubUrl(pluginSource);
|
|
34575
|
-
const result = await fetchPlugin(pluginSource, {
|
|
34576
|
-
offline: true,
|
|
34577
|
-
...parsed?.branch && { branch: parsed.branch }
|
|
34578
|
-
});
|
|
34579
|
-
if (!result.success)
|
|
34580
|
-
return null;
|
|
34581
|
-
const path = parsed?.subpath ? join25(result.cachePath, parsed.subpath) : result.cachePath;
|
|
34582
|
-
return { path };
|
|
34583
|
-
}
|
|
34584
|
-
const resolved = resolve14(workspacePath, pluginSource);
|
|
34585
|
-
return existsSync24(resolved) ? { path: resolved } : null;
|
|
34586
|
-
}
|
|
34587
|
-
async function getAllSkillsFromPlugins(workspacePath = process.cwd()) {
|
|
34588
|
-
const configPath = join25(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
34589
|
-
if (!existsSync24(configPath)) {
|
|
34590
|
-
return [];
|
|
34591
|
-
}
|
|
34592
|
-
const content = await readFile14(configPath, "utf-8");
|
|
34593
|
-
const config = load(content);
|
|
34594
|
-
const isV1Fallback = config.version === undefined || config.version < 2;
|
|
34595
|
-
const disabledSkills = isV1Fallback ? new Set(config.disabledSkills ?? []) : new Set;
|
|
34596
|
-
const enabledSkills = isV1Fallback && config.enabledSkills ? new Set(config.enabledSkills) : null;
|
|
34597
|
-
const skills = [];
|
|
34598
|
-
for (const pluginEntry of config.plugins) {
|
|
34599
|
-
const pluginSource = getPluginSource(pluginEntry);
|
|
34600
|
-
const resolved = await resolvePluginPath(pluginSource, workspacePath);
|
|
34601
|
-
if (!resolved)
|
|
34602
|
-
continue;
|
|
34603
|
-
const pluginPath = resolved.path;
|
|
34604
|
-
const pluginName = resolved.pluginName ?? getPluginName(pluginPath);
|
|
34605
|
-
const skillsDir = join25(pluginPath, "skills");
|
|
34606
|
-
const pluginSkillsConfig = typeof pluginEntry === "string" ? undefined : pluginEntry.skills;
|
|
34607
|
-
const hasEnabledEntries = !pluginSkillsConfig && enabledSkills && [...enabledSkills].some((s) => s.startsWith(`${pluginName}`));
|
|
34608
|
-
let skillEntries;
|
|
34609
|
-
if (existsSync24(skillsDir)) {
|
|
34610
|
-
const entries = await readdir5(skillsDir, { withFileTypes: true });
|
|
34611
|
-
skillEntries = entries.filter((e) => e.isDirectory()).map((e) => ({ name: e.name, skillPath: join25(skillsDir, e.name) }));
|
|
34612
|
-
} else {
|
|
34613
|
-
const entries = await readdir5(pluginPath, { withFileTypes: true });
|
|
34614
|
-
const flatSkills = [];
|
|
34615
|
-
for (const entry of entries) {
|
|
34616
|
-
if (!entry.isDirectory())
|
|
34617
|
-
continue;
|
|
34618
|
-
const skillMdPath = join25(pluginPath, entry.name, "SKILL.md");
|
|
34619
|
-
if (existsSync24(skillMdPath)) {
|
|
34620
|
-
flatSkills.push({ name: entry.name, skillPath: join25(pluginPath, entry.name) });
|
|
34621
|
-
}
|
|
34622
|
-
}
|
|
34623
|
-
if (flatSkills.length > 0) {
|
|
34624
|
-
skillEntries = flatSkills;
|
|
34625
|
-
} else {
|
|
34626
|
-
const rootSkillMd = join25(pluginPath, "SKILL.md");
|
|
34627
|
-
if (existsSync24(rootSkillMd)) {
|
|
34628
|
-
const skillContent = await readFile14(rootSkillMd, "utf-8");
|
|
34629
|
-
const metadata = parseSkillMetadata(skillContent);
|
|
34630
|
-
const skillName = metadata?.name ?? basename7(pluginPath);
|
|
34631
|
-
skillEntries = [{ name: skillName, skillPath: pluginPath }];
|
|
34632
|
-
} else {
|
|
34633
|
-
skillEntries = [];
|
|
34634
|
-
}
|
|
34635
|
-
}
|
|
34636
|
-
}
|
|
34637
|
-
const pluginSkillsMode = pluginSkillsConfig === undefined ? "none" : Array.isArray(pluginSkillsConfig) ? "allowlist" : "blocklist";
|
|
34638
|
-
for (const { name, skillPath } of skillEntries) {
|
|
34639
|
-
const skillKey = `${pluginName}:${name}`;
|
|
34640
|
-
let isDisabled;
|
|
34641
|
-
if (pluginSkillsConfig !== undefined) {
|
|
34642
|
-
if (Array.isArray(pluginSkillsConfig)) {
|
|
34643
|
-
isDisabled = !pluginSkillsConfig.includes(name);
|
|
34644
|
-
} else {
|
|
34645
|
-
isDisabled = pluginSkillsConfig.exclude.includes(name);
|
|
34646
|
-
}
|
|
34647
|
-
} else if (isV1Fallback) {
|
|
34648
|
-
isDisabled = hasEnabledEntries ? !enabledSkills?.has(skillKey) : disabledSkills.has(skillKey);
|
|
34649
|
-
} else {
|
|
34650
|
-
isDisabled = false;
|
|
34651
|
-
}
|
|
34652
|
-
skills.push({
|
|
34653
|
-
name,
|
|
34654
|
-
pluginName,
|
|
34655
|
-
pluginSource,
|
|
34656
|
-
path: skillPath,
|
|
34657
|
-
disabled: isDisabled,
|
|
34658
|
-
pluginSkillsMode
|
|
34659
|
-
});
|
|
34660
|
-
}
|
|
34661
|
-
}
|
|
34662
|
-
return skills;
|
|
34663
|
-
}
|
|
34664
|
-
async function findSkillByName(skillName, workspacePath = process.cwd()) {
|
|
34665
|
-
const allSkills = await getAllSkillsFromPlugins(workspacePath);
|
|
34666
|
-
return allSkills.filter((s) => s.name === skillName);
|
|
34667
|
-
}
|
|
34668
|
-
async function discoverSkillNames(pluginPath) {
|
|
34669
|
-
if (!existsSync24(pluginPath))
|
|
34670
|
-
return [];
|
|
34671
|
-
const skillsDir = join25(pluginPath, "skills");
|
|
34672
|
-
if (existsSync24(skillsDir)) {
|
|
34673
|
-
const entries2 = await readdir5(skillsDir, { withFileTypes: true });
|
|
34674
|
-
return entries2.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
34675
|
-
}
|
|
34676
|
-
const entries = await readdir5(pluginPath, { withFileTypes: true });
|
|
34677
|
-
const flatSkills = [];
|
|
34678
|
-
for (const entry of entries) {
|
|
34679
|
-
if (!entry.isDirectory())
|
|
34680
|
-
continue;
|
|
34681
|
-
if (existsSync24(join25(pluginPath, entry.name, "SKILL.md"))) {
|
|
34682
|
-
flatSkills.push(entry.name);
|
|
34683
|
-
}
|
|
34684
|
-
}
|
|
34685
|
-
if (flatSkills.length > 0)
|
|
34686
|
-
return flatSkills;
|
|
34687
|
-
const rootSkillMd = join25(pluginPath, "SKILL.md");
|
|
34688
|
-
if (existsSync24(rootSkillMd)) {
|
|
34689
|
-
try {
|
|
34690
|
-
const content = await readFile14(rootSkillMd, "utf-8");
|
|
34691
|
-
const { parseSkillMetadata: parseSkillMetadata2 } = await Promise.resolve().then(() => (init_skill(), exports_skill));
|
|
34692
|
-
const metadata = parseSkillMetadata2(content);
|
|
34693
|
-
return [metadata?.name ?? basename7(pluginPath)];
|
|
34694
|
-
} catch {
|
|
34695
|
-
return [basename7(pluginPath)];
|
|
34696
|
-
}
|
|
34697
|
-
}
|
|
34698
|
-
return [];
|
|
34699
|
-
}
|
|
34700
|
-
var init_skills = __esm(() => {
|
|
34701
|
-
init_js_yaml();
|
|
34702
|
-
init_constants();
|
|
34703
|
-
init_workspace_config();
|
|
34704
|
-
init_plugin();
|
|
34705
|
-
init_plugin_path();
|
|
34706
|
-
init_marketplace();
|
|
34707
|
-
init_skill();
|
|
34708
|
-
});
|
|
34709
|
-
|
|
34710
34848
|
// src/core/skill-search.ts
|
|
34711
34849
|
function validateSkillSearchArgs(query, options2) {
|
|
34712
34850
|
if (query.trim().length < 2) {
|
|
@@ -42055,7 +42193,7 @@ var package_default;
|
|
|
42055
42193
|
var init_package = __esm(() => {
|
|
42056
42194
|
package_default = {
|
|
42057
42195
|
name: "allagents",
|
|
42058
|
-
version: "1.11.
|
|
42196
|
+
version: "1.11.7-next.1",
|
|
42059
42197
|
packageManager: "bun@1.3.12",
|
|
42060
42198
|
description: "CLI tool for managing multi-repo AI agent workspaces with plugin synchronization",
|
|
42061
42199
|
type: "module",
|
|
@@ -43752,8 +43890,8 @@ init_workspace();
|
|
|
43752
43890
|
init_sync();
|
|
43753
43891
|
init_status2();
|
|
43754
43892
|
var import_cmd_ts2 = __toESM(require_cjs(), 1);
|
|
43755
|
-
import { existsSync as
|
|
43756
|
-
import { join as
|
|
43893
|
+
import { existsSync as existsSync24 } from "node:fs";
|
|
43894
|
+
import { join as join25, resolve as resolve14 } from "node:path";
|
|
43757
43895
|
|
|
43758
43896
|
// src/core/prune.ts
|
|
43759
43897
|
init_js_yaml();
|
|
@@ -43761,9 +43899,9 @@ init_constants();
|
|
|
43761
43899
|
init_marketplace();
|
|
43762
43900
|
init_user_workspace();
|
|
43763
43901
|
init_workspace_config();
|
|
43764
|
-
import { readFile as
|
|
43765
|
-
import { existsSync as
|
|
43766
|
-
import { join as
|
|
43902
|
+
import { readFile as readFile14, writeFile as writeFile9 } from "node:fs/promises";
|
|
43903
|
+
import { existsSync as existsSync23 } from "node:fs";
|
|
43904
|
+
import { join as join24 } from "node:path";
|
|
43767
43905
|
async function isOrphanedPlugin(pluginSpec) {
|
|
43768
43906
|
if (!isPluginSpec(pluginSpec))
|
|
43769
43907
|
return false;
|
|
@@ -43790,9 +43928,9 @@ async function prunePlugins(plugins) {
|
|
|
43790
43928
|
}
|
|
43791
43929
|
async function pruneOrphanedPlugins(workspacePath) {
|
|
43792
43930
|
let projectResult = { removed: [], kept: [], keptEntries: [] };
|
|
43793
|
-
const projectConfigPath =
|
|
43794
|
-
if (
|
|
43795
|
-
const content = await
|
|
43931
|
+
const projectConfigPath = join24(workspacePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
|
|
43932
|
+
if (existsSync23(projectConfigPath) && !isUserConfigPath(workspacePath)) {
|
|
43933
|
+
const content = await readFile14(projectConfigPath, "utf-8");
|
|
43796
43934
|
const config = load(content);
|
|
43797
43935
|
projectResult = await prunePlugins(config.plugins);
|
|
43798
43936
|
if (projectResult.removed.length > 0) {
|
|
@@ -44178,8 +44316,8 @@ var syncCmd = import_cmd_ts2.command({
|
|
|
44178
44316
|
`);
|
|
44179
44317
|
}
|
|
44180
44318
|
const userConfigExists = !!await getUserWorkspaceConfig();
|
|
44181
|
-
const projectConfigPath =
|
|
44182
|
-
const projectConfigExists =
|
|
44319
|
+
const projectConfigPath = join25(process.cwd(), ".allagents", "workspace.yaml");
|
|
44320
|
+
const projectConfigExists = existsSync24(projectConfigPath);
|
|
44183
44321
|
if (!userConfigExists && !projectConfigExists) {
|
|
44184
44322
|
await ensureUserWorkspace();
|
|
44185
44323
|
if (isJsonMode()) {
|
|
@@ -44474,7 +44612,7 @@ var repoAddCmd = import_cmd_ts2.command({
|
|
|
44474
44612
|
},
|
|
44475
44613
|
handler: async ({ path: repoPath, description }) => {
|
|
44476
44614
|
try {
|
|
44477
|
-
const resolvedPath =
|
|
44615
|
+
const resolvedPath = resolve14(process.cwd(), repoPath);
|
|
44478
44616
|
const remote = await detectRemote(resolvedPath);
|
|
44479
44617
|
const result = await addRepository(repoPath, {
|
|
44480
44618
|
source: remote?.source,
|
|
@@ -45023,6 +45161,12 @@ async function recordSourceProvenance(opts) {
|
|
|
45023
45161
|
...pinnedRef && { pinnedRef }
|
|
45024
45162
|
});
|
|
45025
45163
|
}
|
|
45164
|
+
function resolveFetchedSourcePath(source, cachePath) {
|
|
45165
|
+
if (!isGitHubUrl(source))
|
|
45166
|
+
return cachePath;
|
|
45167
|
+
const parsed = parseGitHubUrl(source);
|
|
45168
|
+
return parsed?.subpath ? join26(cachePath, parsed.subpath) : cachePath;
|
|
45169
|
+
}
|
|
45026
45170
|
function extractInlineRef(spec) {
|
|
45027
45171
|
const slashIdx = spec.indexOf("/");
|
|
45028
45172
|
if (slashIdx === -1)
|
|
@@ -45284,23 +45428,28 @@ Use --plugin to specify: allagents skill remove ${skill} --plugin <name>`;
|
|
|
45284
45428
|
}
|
|
45285
45429
|
}
|
|
45286
45430
|
});
|
|
45287
|
-
async function installSkillFromSource(opts) {
|
|
45431
|
+
async function installSkillFromSource(opts, deps = {}) {
|
|
45288
45432
|
const { skill, from, isUser, workspacePath } = opts;
|
|
45433
|
+
const fetchPluginFn = deps.fetchPlugin ?? fetchPlugin;
|
|
45434
|
+
const parseMarketplaceManifestFn = deps.parseMarketplaceManifest ?? parseMarketplaceManifest;
|
|
45435
|
+
const installSkillViaMarketplaceFn = deps.installSkillViaMarketplace ?? installSkillViaMarketplace;
|
|
45436
|
+
const installSkillDirectFn = deps.installSkillDirect ?? installSkillDirect;
|
|
45289
45437
|
if (!isJsonMode()) {
|
|
45290
45438
|
console.log(`Installing skill '${skill}' from ${from}...`);
|
|
45291
45439
|
}
|
|
45292
45440
|
const parsed = isGitHubUrl(from) ? parseGitHubUrl(from) : null;
|
|
45293
|
-
const fetchResult = await
|
|
45441
|
+
const fetchResult = await fetchPluginFn(from, {
|
|
45294
45442
|
...parsed?.branch && { branch: parsed.branch }
|
|
45295
45443
|
});
|
|
45296
45444
|
if (!fetchResult.success) {
|
|
45297
45445
|
return { success: false, error: `Failed to fetch '${from}': ${fetchResult.error ?? "Unknown error"}` };
|
|
45298
45446
|
}
|
|
45299
|
-
const
|
|
45447
|
+
const sourcePath = resolveFetchedSourcePath(from, fetchResult.cachePath);
|
|
45448
|
+
const manifestResult = await parseMarketplaceManifestFn(sourcePath);
|
|
45300
45449
|
if (manifestResult.success) {
|
|
45301
|
-
return
|
|
45450
|
+
return installSkillViaMarketplaceFn({ skill, from, isUser, workspacePath });
|
|
45302
45451
|
}
|
|
45303
|
-
return
|
|
45452
|
+
return installSkillDirectFn({ skill, from, isUser, workspacePath, sourcePath });
|
|
45304
45453
|
}
|
|
45305
45454
|
async function installSkillViaMarketplace(opts) {
|
|
45306
45455
|
const { skill, from, isUser, workspacePath } = opts;
|
|
@@ -45352,8 +45501,8 @@ Available skills: ${allAvailableSkills.join(", ") || "none"}`
|
|
|
45352
45501
|
return applySkillAllowlist({ skill, pluginName: targetPluginName, isUser, workspacePath });
|
|
45353
45502
|
}
|
|
45354
45503
|
async function installSkillDirect(opts) {
|
|
45355
|
-
const { skill, from, isUser, workspacePath,
|
|
45356
|
-
const availableSkills = await discoverSkillNames(
|
|
45504
|
+
const { skill, from, isUser, workspacePath, sourcePath } = opts;
|
|
45505
|
+
const availableSkills = await discoverSkillNames(sourcePath);
|
|
45357
45506
|
if (!availableSkills.includes(skill)) {
|
|
45358
45507
|
return {
|
|
45359
45508
|
success: false,
|
|
@@ -45364,6 +45513,25 @@ Available skills: ${availableSkills.join(", ") || "none"}
|
|
|
45364
45513
|
Tip: run \`allagents skill list\` to see all installed skills.`
|
|
45365
45514
|
};
|
|
45366
45515
|
}
|
|
45516
|
+
if (isGitHubUrl(from)) {
|
|
45517
|
+
const existingEnabledSkills = await getEnabledSkillsForGitHubSource(from, workspacePath);
|
|
45518
|
+
const desiredSkills = [...existingEnabledSkills];
|
|
45519
|
+
if (!desiredSkills.includes(skill))
|
|
45520
|
+
desiredSkills.push(skill);
|
|
45521
|
+
const updateResult = isUser ? await upsertUserGitHubPluginSourceAllowlist(from, desiredSkills) : await upsertGitHubPluginSourceAllowlist(from, desiredSkills, workspacePath);
|
|
45522
|
+
if (!updateResult.success) {
|
|
45523
|
+
return {
|
|
45524
|
+
success: false,
|
|
45525
|
+
error: `Failed to update plugin '${from}': ${updateResult.error ?? "Unknown error"}`
|
|
45526
|
+
};
|
|
45527
|
+
}
|
|
45528
|
+
return finishSkillEnable({
|
|
45529
|
+
skill,
|
|
45530
|
+
pluginName: extractPrimaryPluginName(updateResult.normalizedPlugin ?? from),
|
|
45531
|
+
isUser,
|
|
45532
|
+
workspacePath
|
|
45533
|
+
});
|
|
45534
|
+
}
|
|
45367
45535
|
const installResult = isUser ? await addUserPlugin(from) : await addPlugin(from, workspacePath);
|
|
45368
45536
|
if (!installResult.success) {
|
|
45369
45537
|
if (!installResult.error?.includes("already exists") && !installResult.error?.includes("duplicates existing")) {
|
|
@@ -45373,9 +45541,36 @@ Tip: run \`allagents skill list\` to see all installed skills.`
|
|
|
45373
45541
|
console.log("Plugin already installed.");
|
|
45374
45542
|
}
|
|
45375
45543
|
}
|
|
45376
|
-
const pluginName = getPluginName(
|
|
45544
|
+
const pluginName = getPluginName(sourcePath);
|
|
45377
45545
|
return applySkillAllowlist({ skill, pluginName, isUser, workspacePath });
|
|
45378
45546
|
}
|
|
45547
|
+
function extractPrimaryPluginName(source) {
|
|
45548
|
+
const parsed = isGitHubUrl(source) ? parseGitHubUrl(source) : null;
|
|
45549
|
+
if (parsed?.subpath) {
|
|
45550
|
+
const segments = parsed.subpath.split("/").filter(Boolean);
|
|
45551
|
+
const leaf = segments[segments.length - 1];
|
|
45552
|
+
if (leaf)
|
|
45553
|
+
return leaf;
|
|
45554
|
+
}
|
|
45555
|
+
return getPluginName(source);
|
|
45556
|
+
}
|
|
45557
|
+
async function getEnabledSkillsForGitHubSource(source, workspacePath) {
|
|
45558
|
+
const identity = await resolveGitHubIdentity(source);
|
|
45559
|
+
if (!identity)
|
|
45560
|
+
return [];
|
|
45561
|
+
const enabledSkills = [];
|
|
45562
|
+
const allSkills = await getAllSkillsFromPlugins(workspacePath);
|
|
45563
|
+
for (const skill of allSkills) {
|
|
45564
|
+
if (skill.disabled)
|
|
45565
|
+
continue;
|
|
45566
|
+
const skillIdentity = await resolveGitHubIdentity(skill.pluginSource);
|
|
45567
|
+
if (skillIdentity !== identity)
|
|
45568
|
+
continue;
|
|
45569
|
+
if (!enabledSkills.includes(skill.name))
|
|
45570
|
+
enabledSkills.push(skill.name);
|
|
45571
|
+
}
|
|
45572
|
+
return enabledSkills;
|
|
45573
|
+
}
|
|
45379
45574
|
async function applySkillAllowlist(opts) {
|
|
45380
45575
|
const { skill, pluginName, isUser, workspacePath } = opts;
|
|
45381
45576
|
const allSkills = await getAllSkillsFromPlugins(workspacePath);
|
|
@@ -45395,6 +45590,10 @@ async function applySkillAllowlist(opts) {
|
|
|
45395
45590
|
return { success: false, error: `Failed to configure skill allowlist: ${setModeResult.error ?? "Unknown error"}` };
|
|
45396
45591
|
}
|
|
45397
45592
|
}
|
|
45593
|
+
return finishSkillEnable({ skill, pluginName, isUser, workspacePath });
|
|
45594
|
+
}
|
|
45595
|
+
async function finishSkillEnable(opts) {
|
|
45596
|
+
const { skill, pluginName, isUser, workspacePath } = opts;
|
|
45398
45597
|
if (!isJsonMode()) {
|
|
45399
45598
|
console.log(`✓ Enabled skill: ${skill} (${pluginName})`);
|
|
45400
45599
|
}
|
|
@@ -45443,13 +45642,14 @@ async function discoverSkillsFromSource(from) {
|
|
|
45443
45642
|
if (!fetchResult.success) {
|
|
45444
45643
|
return { success: false, error: `Failed to fetch '${from}': ${fetchResult.error ?? "Unknown error"}` };
|
|
45445
45644
|
}
|
|
45446
|
-
const
|
|
45645
|
+
const sourcePath = resolveFetchedSourcePath(from, fetchResult.cachePath);
|
|
45646
|
+
const manifestResult = await parseMarketplaceManifest(sourcePath);
|
|
45447
45647
|
if (manifestResult.success) {
|
|
45448
45648
|
const all = [];
|
|
45449
45649
|
for (const plugin of manifestResult.data.plugins) {
|
|
45450
45650
|
if (typeof plugin.source === "object")
|
|
45451
45651
|
continue;
|
|
45452
|
-
const resolved = resolvePluginSourcePath(plugin.source,
|
|
45652
|
+
const resolved = resolvePluginSourcePath(plugin.source, sourcePath);
|
|
45453
45653
|
if (!existsSync25(resolved))
|
|
45454
45654
|
continue;
|
|
45455
45655
|
const skills2 = await discoverSkillsWithMetadata(resolved, plugin.name);
|
|
@@ -45457,7 +45657,7 @@ async function discoverSkillsFromSource(from) {
|
|
|
45457
45657
|
}
|
|
45458
45658
|
return { success: true, skills: all, isMarketplace: true };
|
|
45459
45659
|
}
|
|
45460
|
-
const skills = await discoverSkillsWithMetadata(
|
|
45660
|
+
const skills = await discoverSkillsWithMetadata(sourcePath);
|
|
45461
45661
|
return { success: true, skills, isMarketplace: false };
|
|
45462
45662
|
}
|
|
45463
45663
|
async function installAllSkillsFromSource(opts) {
|
|
@@ -45472,14 +45672,43 @@ async function installAllSkillsFromSource(opts) {
|
|
|
45472
45672
|
if (!fetchResult.success) {
|
|
45473
45673
|
return { success: false, error: `Failed to fetch '${from}': ${fetchResult.error ?? "Unknown error"}` };
|
|
45474
45674
|
}
|
|
45475
|
-
const
|
|
45675
|
+
const sourcePath = resolveFetchedSourcePath(from, fetchResult.cachePath);
|
|
45676
|
+
const manifestResult = await parseMarketplaceManifest(sourcePath);
|
|
45476
45677
|
if (manifestResult.success) {
|
|
45477
45678
|
return installAllViaMarketplace({ from, isUser, workspacePath, cachedPath: fetchResult.cachePath });
|
|
45478
45679
|
}
|
|
45479
|
-
const skillNames = await discoverSkillNames(
|
|
45680
|
+
const skillNames = await discoverSkillNames(sourcePath);
|
|
45480
45681
|
if (skillNames.length === 0) {
|
|
45481
45682
|
return { success: false, error: `No skills found in '${from}'.` };
|
|
45482
45683
|
}
|
|
45684
|
+
if (isGitHubUrl(from)) {
|
|
45685
|
+
const existingEnabledSkills = await getEnabledSkillsForGitHubSource(from, workspacePath);
|
|
45686
|
+
const desiredSkills = [...existingEnabledSkills];
|
|
45687
|
+
for (const skillName of skillNames) {
|
|
45688
|
+
if (!desiredSkills.includes(skillName))
|
|
45689
|
+
desiredSkills.push(skillName);
|
|
45690
|
+
}
|
|
45691
|
+
const updateResult = isUser ? await upsertUserGitHubPluginSourceAllowlist(from, desiredSkills) : await upsertGitHubPluginSourceAllowlist(from, desiredSkills, workspacePath);
|
|
45692
|
+
if (!updateResult.success) {
|
|
45693
|
+
return {
|
|
45694
|
+
success: false,
|
|
45695
|
+
error: `Failed to configure skill allowlist: ${updateResult.error ?? "Unknown error"}`
|
|
45696
|
+
};
|
|
45697
|
+
}
|
|
45698
|
+
const pluginName2 = extractPrimaryPluginName(updateResult.normalizedPlugin ?? from);
|
|
45699
|
+
if (!isJsonMode()) {
|
|
45700
|
+
console.log(`✓ Enabled ${skillNames.length} skill(s) from ${pluginName2}: ${skillNames.join(", ")}`);
|
|
45701
|
+
}
|
|
45702
|
+
const syncResult2 = isUser ? await syncUserWorkspace() : await syncWorkspace(workspacePath);
|
|
45703
|
+
if (!syncResult2.success) {
|
|
45704
|
+
return { success: false, error: "Sync failed" };
|
|
45705
|
+
}
|
|
45706
|
+
return {
|
|
45707
|
+
success: true,
|
|
45708
|
+
installed: [{ pluginName: pluginName2, skills: desiredSkills }],
|
|
45709
|
+
syncResult: syncResult2
|
|
45710
|
+
};
|
|
45711
|
+
}
|
|
45483
45712
|
const installResult = isUser ? await addUserPlugin(from) : await addPlugin(from, workspacePath);
|
|
45484
45713
|
if (!installResult.success) {
|
|
45485
45714
|
if (!installResult.error?.includes("already exists") && !installResult.error?.includes("duplicates existing")) {
|
|
@@ -45489,7 +45718,7 @@ async function installAllSkillsFromSource(opts) {
|
|
|
45489
45718
|
console.log("Plugin already installed.");
|
|
45490
45719
|
}
|
|
45491
45720
|
}
|
|
45492
|
-
const pluginName = getPluginName(
|
|
45721
|
+
const pluginName = getPluginName(sourcePath);
|
|
45493
45722
|
const setModeResult = isUser ? await setUserPluginSkillsMode(pluginName, "allowlist", skillNames) : await setPluginSkillsMode(pluginName, "allowlist", skillNames, workspacePath);
|
|
45494
45723
|
if (!setModeResult.success) {
|
|
45495
45724
|
return { success: false, error: `Failed to configure skill allowlist: ${setModeResult.error ?? "Unknown error"}` };
|