vskill 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/agents-registry.d.ts +48 -37
- package/dist/agents/agents-registry.js +206 -261
- package/dist/agents/agents-registry.js.map +1 -1
- package/dist/agents/agents-registry.test.d.ts +1 -0
- package/dist/agents/agents-registry.test.js +203 -0
- package/dist/agents/agents-registry.test.js.map +1 -0
- package/dist/api/client.test.d.ts +1 -0
- package/dist/api/client.test.js +204 -0
- package/dist/api/client.test.js.map +1 -0
- package/dist/blocklist/blocklist.d.ts +23 -0
- package/dist/blocklist/blocklist.js +116 -0
- package/dist/blocklist/blocklist.js.map +1 -0
- package/dist/blocklist/blocklist.test.d.ts +1 -0
- package/dist/blocklist/blocklist.test.js +259 -0
- package/dist/blocklist/blocklist.test.js.map +1 -0
- package/dist/blocklist/types.d.ts +18 -0
- package/dist/blocklist/types.js +5 -0
- package/dist/blocklist/types.js.map +1 -0
- package/dist/commands/add.d.ts +2 -0
- package/dist/commands/add.js +221 -6
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/add.test.d.ts +1 -0
- package/dist/commands/add.test.js +682 -0
- package/dist/commands/add.test.js.map +1 -0
- package/dist/commands/blocklist.d.ts +1 -0
- package/dist/commands/blocklist.js +87 -0
- package/dist/commands/blocklist.js.map +1 -0
- package/dist/commands/blocklist.test.d.ts +1 -0
- package/dist/commands/blocklist.test.js +158 -0
- package/dist/commands/blocklist.test.js.map +1 -0
- package/dist/commands/remove.d.ts +7 -0
- package/dist/commands/remove.js +91 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/remove.test.d.ts +1 -0
- package/dist/commands/remove.test.js +164 -0
- package/dist/commands/remove.test.js.map +1 -0
- package/dist/commands/submit.d.ts +1 -1
- package/dist/commands/submit.js +26 -16
- package/dist/commands/submit.js.map +1 -1
- package/dist/commands/submit.test.d.ts +1 -0
- package/dist/commands/submit.test.js +74 -0
- package/dist/commands/submit.test.js.map +1 -0
- package/dist/index.js +21 -2
- package/dist/index.js.map +1 -1
- package/dist/lockfile/lockfile.test.d.ts +1 -0
- package/dist/lockfile/lockfile.test.js +196 -0
- package/dist/lockfile/lockfile.test.js.map +1 -0
- package/dist/lockfile/types.d.ts +8 -0
- package/dist/marketplace/index.d.ts +2 -0
- package/dist/marketplace/index.js +2 -0
- package/dist/marketplace/index.js.map +1 -0
- package/dist/marketplace/marketplace.d.ts +34 -0
- package/dist/marketplace/marketplace.js +51 -0
- package/dist/marketplace/marketplace.js.map +1 -0
- package/dist/marketplace/marketplace.test.d.ts +1 -0
- package/dist/marketplace/marketplace.test.js +103 -0
- package/dist/marketplace/marketplace.test.js.map +1 -0
- package/dist/scanner/index.d.ts +4 -0
- package/dist/scanner/index.js +4 -0
- package/dist/scanner/index.js.map +1 -1
- package/dist/scanner/patterns.test.d.ts +1 -0
- package/dist/scanner/patterns.test.js +353 -0
- package/dist/scanner/patterns.test.js.map +1 -0
- package/dist/scanner/repo-scanner.d.ts +30 -0
- package/dist/scanner/repo-scanner.js +190 -0
- package/dist/scanner/repo-scanner.js.map +1 -0
- package/dist/scanner/tier1.test.d.ts +1 -0
- package/dist/scanner/tier1.test.js +182 -0
- package/dist/scanner/tier1.test.js.map +1 -0
- package/dist/scanner/tier2-llm.d.ts +28 -0
- package/dist/scanner/tier2-llm.js +130 -0
- package/dist/scanner/tier2-llm.js.map +1 -0
- package/dist/scanner/types.d.ts +58 -0
- package/dist/scanner/types.js +5 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/security/index.d.ts +2 -0
- package/dist/security/index.js +2 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/platform-security.d.ts +17 -0
- package/dist/security/platform-security.js +34 -0
- package/dist/security/platform-security.js.map +1 -0
- package/dist/security/platform-security.test.d.ts +1 -0
- package/dist/security/platform-security.test.js +92 -0
- package/dist/security/platform-security.test.js.map +1 -0
- package/dist/settings/index.d.ts +2 -0
- package/dist/settings/index.js +2 -0
- package/dist/settings/index.js.map +1 -0
- package/dist/settings/settings.d.ts +16 -0
- package/dist/settings/settings.js +73 -0
- package/dist/settings/settings.js.map +1 -0
- package/dist/settings/settings.test.d.ts +1 -0
- package/dist/settings/settings.test.js +103 -0
- package/dist/settings/settings.test.js.map +1 -0
- package/dist/utils/__tests__/paths.test.d.ts +1 -0
- package/dist/utils/__tests__/paths.test.js +22 -0
- package/dist/utils/__tests__/paths.test.js.map +1 -0
- package/dist/utils/__tests__/validation.test.d.ts +1 -0
- package/dist/utils/__tests__/validation.test.js +49 -0
- package/dist/utils/__tests__/validation.test.js.map +1 -0
- package/dist/utils/browser.d.ts +6 -0
- package/dist/utils/browser.js +37 -0
- package/dist/utils/browser.js.map +1 -0
- package/dist/utils/paths.d.ts +5 -0
- package/dist/utils/paths.js +13 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/validation.d.ts +14 -0
- package/dist/utils/validation.js +34 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +5 -2
- package/scripts/preuninstall.cjs +58 -0
package/dist/commands/submit.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// vskill submit --
|
|
2
|
+
// vskill submit -- open browser for skill submission via GitHub OAuth
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
|
-
import {
|
|
4
|
+
import { openBrowser } from "../utils/browser.js";
|
|
5
5
|
import { bold, green, red, dim, cyan } from "../utils/output.js";
|
|
6
|
+
import { validateRepoSegment, validateSkillName } from "../utils/validation.js";
|
|
6
7
|
export async function submitCommand(source, opts) {
|
|
7
8
|
// Parse owner/repo
|
|
8
9
|
const parts = source.split("/");
|
|
@@ -11,24 +12,33 @@ export async function submitCommand(source, opts) {
|
|
|
11
12
|
process.exit(1);
|
|
12
13
|
}
|
|
13
14
|
const [owner, repo] = parts;
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
if (!validateRepoSegment(owner) || !validateRepoSegment(repo)) {
|
|
16
|
+
console.error(red("Invalid owner/repo name. ") + dim("Only letters, numbers, dots, hyphens, and underscores are allowed."));
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
if (opts.skill && !validateSkillName(opts.skill)) {
|
|
20
|
+
console.error(red("Invalid skill name. ") + dim("Path traversal patterns are not allowed."));
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
const submitUrl = new URL("https://verified-skill.com/submit");
|
|
24
|
+
submitUrl.searchParams.set("repo", `${owner}/${repo}`);
|
|
25
|
+
if (opts.skill) {
|
|
26
|
+
submitUrl.searchParams.set("skill", opts.skill);
|
|
27
|
+
}
|
|
28
|
+
const url = submitUrl.toString();
|
|
29
|
+
console.log(dim(`Opening browser to submit ${bold(`${owner}/${repo}`)} for verification...\n`));
|
|
16
30
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
console.log(green("Submission received!\n"));
|
|
23
|
-
console.log(`${bold("Submission ID:")} ${result.id}`);
|
|
24
|
-
console.log(`${bold("Status:")} ${result.status}`);
|
|
25
|
-
console.log(`${bold("Track at:")} ${cyan(result.trackingUrl || `https://verified-skill.com/submissions/${result.id}`)}`);
|
|
26
|
-
console.log(dim("\nYou will receive updates as the review progresses."));
|
|
31
|
+
await openBrowser(url);
|
|
32
|
+
console.log(green("Browser opened!\n"));
|
|
33
|
+
console.log(`Complete your submission in the browser at:`);
|
|
34
|
+
console.log(cyan(url));
|
|
35
|
+
console.log(dim("\nYou will authenticate with GitHub and complete the submission there."));
|
|
27
36
|
}
|
|
28
37
|
catch (err) {
|
|
29
|
-
console.error(red("
|
|
38
|
+
console.error(red("Could not open browser: ") +
|
|
30
39
|
dim(err.message));
|
|
31
|
-
|
|
40
|
+
console.log(`\nOpen this URL manually in your browser:`);
|
|
41
|
+
console.log(cyan(url));
|
|
32
42
|
}
|
|
33
43
|
}
|
|
34
44
|
//# sourceMappingURL=submit.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submit.js","sourceRoot":"","sources":["../../src/commands/submit.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,
|
|
1
|
+
{"version":3,"file":"submit.js","sourceRoot":"","sources":["../../src/commands/submit.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,sEAAsE;AACtE,8EAA8E;AAE9E,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAMhF,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,IAAmB;IAEnB,mBAAmB;IACnB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CACX,GAAG,CAAC,8BAA8B,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CACzD,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;IAE5B,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9D,OAAO,CAAC,KAAK,CACX,GAAG,CAAC,2BAA2B,CAAC,GAAG,GAAG,CAAC,oEAAoE,CAAC,CAC7G,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,OAAO,CAAC,KAAK,CACX,GAAG,CAAC,sBAAsB,CAAC,GAAG,GAAG,CAAC,0CAA0C,CAAC,CAC9E,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,mCAAmC,CAAC,CAAC;IAC/D,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC;IACvD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;IAEjC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,6BAA6B,IAAI,CAAC,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAEhG,IAAI,CAAC;QACH,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,wEAAwE,CAAC,CAAC,CAAC;IAC7F,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CACX,GAAG,CAAC,0BAA0B,CAAC;YAC7B,GAAG,CAAE,GAAa,CAAC,OAAO,CAAC,CAC9B,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Mock the browser opener module (will be created in submit.ts)
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
const mockOpenBrowser = vi.fn().mockResolvedValue(undefined);
|
|
6
|
+
vi.mock("../utils/browser.js", () => ({
|
|
7
|
+
openBrowser: (...args) => mockOpenBrowser(...args),
|
|
8
|
+
}));
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Mock utils/output (suppress console output in tests)
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
vi.mock("../utils/output.js", () => ({
|
|
13
|
+
bold: (s) => s,
|
|
14
|
+
green: (s) => s,
|
|
15
|
+
red: (s) => s,
|
|
16
|
+
yellow: (s) => s,
|
|
17
|
+
dim: (s) => s,
|
|
18
|
+
cyan: (s) => s,
|
|
19
|
+
}));
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Import module under test AFTER mocks
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const { submitCommand } = await import("./submit.js");
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Tests
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
vi.clearAllMocks();
|
|
29
|
+
vi.spyOn(console, "log").mockImplementation(() => { });
|
|
30
|
+
vi.spyOn(console, "error").mockImplementation(() => { });
|
|
31
|
+
});
|
|
32
|
+
describe("submitCommand", () => {
|
|
33
|
+
// TC-001: Given owner/repo arg, constructs correct URL with repo query param
|
|
34
|
+
describe("TC-001: constructs URL with repo query param", () => {
|
|
35
|
+
it("opens browser with https://verified-skill.com/submit?repo=owner/repo", async () => {
|
|
36
|
+
await submitCommand("myorg/myskill", {});
|
|
37
|
+
expect(mockOpenBrowser).toHaveBeenCalledOnce();
|
|
38
|
+
const url = mockOpenBrowser.mock.calls[0][0];
|
|
39
|
+
expect(url).toBe("https://verified-skill.com/submit?repo=myorg%2Fmyskill");
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
// TC-002: Given --skill flag, URL includes skill query param
|
|
43
|
+
describe("TC-002: URL includes skill query param when --skill provided", () => {
|
|
44
|
+
it("appends &skill=skillName to the URL", async () => {
|
|
45
|
+
await submitCommand("myorg/myskill", { skill: "my-awesome-skill" });
|
|
46
|
+
expect(mockOpenBrowser).toHaveBeenCalledOnce();
|
|
47
|
+
const url = mockOpenBrowser.mock.calls[0][0];
|
|
48
|
+
expect(url).toBe("https://verified-skill.com/submit?repo=myorg%2Fmyskill&skill=my-awesome-skill");
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
// TC-003: Invalid source format still rejected
|
|
52
|
+
describe("TC-003: rejects invalid source format", () => {
|
|
53
|
+
it("exits with error for source without slash", async () => {
|
|
54
|
+
const exitError = new Error("process.exit");
|
|
55
|
+
const mockExit = vi
|
|
56
|
+
.spyOn(process, "exit")
|
|
57
|
+
.mockImplementation(() => { throw exitError; });
|
|
58
|
+
await expect(submitCommand("invalid-source", {})).rejects.toThrow("process.exit");
|
|
59
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
60
|
+
expect(mockOpenBrowser).not.toHaveBeenCalled();
|
|
61
|
+
mockExit.mockRestore();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
// TC-004: Prints message telling user to complete in browser
|
|
65
|
+
describe("TC-004: prints browser instructions", () => {
|
|
66
|
+
it("logs a message about completing submission in browser", async () => {
|
|
67
|
+
const consoleSpy = vi.spyOn(console, "log");
|
|
68
|
+
await submitCommand("myorg/myskill", {});
|
|
69
|
+
const allOutput = consoleSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
70
|
+
expect(allOutput).toContain("browser");
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=submit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit.test.js","sourceRoot":"","sources":["../../src/commands/submit.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE9D,8EAA8E;AAC9E,gEAAgE;AAChE,8EAA8E;AAC9E,MAAM,eAAe,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAE7D,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,CAAC;IACpC,WAAW,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC;CAC9D,CAAC,CAAC,CAAC;AAEJ,8EAA8E;AAC9E,uDAAuD;AACvD,8EAA8E;AAC9E,EAAE,CAAC,IAAI,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC;IACnC,IAAI,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC;IACtB,KAAK,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC;IACvB,GAAG,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC;IACrB,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC;IACxB,GAAG,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC;IACrB,IAAI,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC;CACvB,CAAC,CAAC,CAAC;AAEJ,8EAA8E;AAC9E,uCAAuC;AACvC,8EAA8E;AAC9E,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;AAEtD,8EAA8E;AAC9E,QAAQ;AACR,8EAA8E;AAE9E,UAAU,CAAC,GAAG,EAAE;IACd,EAAE,CAAC,aAAa,EAAE,CAAC;IACnB,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACtD,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAC1D,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,6EAA6E;IAC7E,QAAQ,CAAC,8CAA8C,EAAE,GAAG,EAAE;QAC5D,EAAE,CAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;YACpF,MAAM,aAAa,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;YAEzC,MAAM,CAAC,eAAe,CAAC,CAAC,oBAAoB,EAAE,CAAC;YAC/C,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC;YACvD,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;QAC7E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,6DAA6D;IAC7D,QAAQ,CAAC,8DAA8D,EAAE,GAAG,EAAE;QAC5E,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;YACnD,MAAM,aAAa,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAEpE,MAAM,CAAC,eAAe,CAAC,CAAC,oBAAoB,EAAE,CAAC;YAC/C,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC;YACvD,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CACd,+EAA+E,CAChF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,+CAA+C;IAC/C,QAAQ,CAAC,uCAAuC,EAAE,GAAG,EAAE;QACrD,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;YAC5C,MAAM,QAAQ,GAAG,EAAE;iBAChB,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC;iBACtB,kBAAkB,CAAC,GAAG,EAAE,GAAG,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YAElD,MAAM,MAAM,CAAC,aAAa,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;YAElF,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;YACzC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YAE/C,QAAQ,CAAC,WAAW,EAAE,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,6DAA6D;IAC7D,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;QACnD,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;YACrE,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAE5C,MAAM,aAAa,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;YAEzC,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3E,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -17,8 +17,10 @@ program
|
|
|
17
17
|
});
|
|
18
18
|
program
|
|
19
19
|
.command("add <source>")
|
|
20
|
-
.description("Install a skill from GitHub
|
|
20
|
+
.description("Install a skill from GitHub or local plugin directory")
|
|
21
21
|
.option("--skill <name>", "Skill name within a multi-skill repo")
|
|
22
|
+
.option("--plugin <name>", "Plugin name from marketplace.json")
|
|
23
|
+
.option("--plugin-dir <path>", "Local plugin directory path")
|
|
22
24
|
.option("--global", "Install to global agent directories")
|
|
23
25
|
.option("--force", "Install even if scan finds issues")
|
|
24
26
|
.action(async (source, opts) => {
|
|
@@ -41,6 +43,16 @@ program
|
|
|
41
43
|
const { listCommand } = await import("./commands/list.js");
|
|
42
44
|
await listCommand(opts);
|
|
43
45
|
});
|
|
46
|
+
program
|
|
47
|
+
.command("remove <skill-name>")
|
|
48
|
+
.description("Remove an installed skill from all agents")
|
|
49
|
+
.option("--global", "Only remove from global agent directories")
|
|
50
|
+
.option("--local", "Only remove from local agent directories")
|
|
51
|
+
.option("--force", "Skip confirmation and proceed even if not in lockfile")
|
|
52
|
+
.action(async (skillName, opts) => {
|
|
53
|
+
const { removeCommand } = await import("./commands/remove.js");
|
|
54
|
+
await removeCommand(skillName, opts);
|
|
55
|
+
});
|
|
44
56
|
program
|
|
45
57
|
.command("find <query>")
|
|
46
58
|
.description("Search the verified-skill.com registry")
|
|
@@ -59,10 +71,17 @@ program
|
|
|
59
71
|
program
|
|
60
72
|
.command("submit <source>")
|
|
61
73
|
.description("Submit a skill for verification on verified-skill.com")
|
|
62
|
-
.option("--
|
|
74
|
+
.option("--skill <name>", "Skill name within a multi-skill repo")
|
|
63
75
|
.action(async (source, opts) => {
|
|
64
76
|
const { submitCommand } = await import("./commands/submit.js");
|
|
65
77
|
await submitCommand(source, opts);
|
|
66
78
|
});
|
|
79
|
+
program
|
|
80
|
+
.command("blocklist [subcommand] [name]")
|
|
81
|
+
.description("Manage the malicious skills blocklist")
|
|
82
|
+
.action(async (subcommand, name) => {
|
|
83
|
+
const { blocklistCommand } = await import("./commands/blocklist.js");
|
|
84
|
+
await blocklistCommand(subcommand || "list", name);
|
|
85
|
+
});
|
|
67
86
|
program.parse();
|
|
68
87
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAEvC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,qEAAqE,CAAC;KAClF,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AAEzC,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,kDAAkD,CAAC;KAC/D,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAC3D,MAAM,WAAW,EAAE,CAAC;AACtB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,cAAc,CAAC;KACvB,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Mock node:fs
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
const mockReadFileSync = vi.fn();
|
|
6
|
+
const mockWriteFileSync = vi.fn();
|
|
7
|
+
const mockExistsSync = vi.fn();
|
|
8
|
+
vi.mock("node:fs", () => ({
|
|
9
|
+
readFileSync: (...args) => mockReadFileSync(...args),
|
|
10
|
+
writeFileSync: (...args) => mockWriteFileSync(...args),
|
|
11
|
+
existsSync: (...args) => mockExistsSync(...args),
|
|
12
|
+
}));
|
|
13
|
+
// Import after mock is set up
|
|
14
|
+
const { readLockfile, writeLockfile, ensureLockfile, addSkillToLock, removeSkillFromLock, } = await import("./lockfile.js");
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Helpers
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
const TEST_DIR = "/tmp/test-project";
|
|
19
|
+
const LOCK_PATH = `${TEST_DIR}/vskill.lock`;
|
|
20
|
+
function makeLock(overrides = {}) {
|
|
21
|
+
return {
|
|
22
|
+
version: 1,
|
|
23
|
+
agents: [],
|
|
24
|
+
skills: {},
|
|
25
|
+
createdAt: "2026-01-01T00:00:00.000Z",
|
|
26
|
+
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
27
|
+
...overrides,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function makeEntry(overrides = {}) {
|
|
31
|
+
return {
|
|
32
|
+
version: "1.0.0",
|
|
33
|
+
sha: "abc123",
|
|
34
|
+
tier: "SCANNED",
|
|
35
|
+
installedAt: "2026-01-01T00:00:00.000Z",
|
|
36
|
+
source: "registry",
|
|
37
|
+
...overrides,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Tests
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
vi.clearAllMocks();
|
|
45
|
+
vi.useFakeTimers();
|
|
46
|
+
vi.setSystemTime(new Date("2026-02-17T12:00:00.000Z"));
|
|
47
|
+
});
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
vi.useRealTimers();
|
|
50
|
+
});
|
|
51
|
+
describe("readLockfile", () => {
|
|
52
|
+
it("returns null when file does not exist", () => {
|
|
53
|
+
mockExistsSync.mockReturnValue(false);
|
|
54
|
+
const result = readLockfile(TEST_DIR);
|
|
55
|
+
expect(result).toBeNull();
|
|
56
|
+
expect(mockExistsSync).toHaveBeenCalledWith(LOCK_PATH);
|
|
57
|
+
expect(mockReadFileSync).not.toHaveBeenCalled();
|
|
58
|
+
});
|
|
59
|
+
it("returns null on invalid JSON", () => {
|
|
60
|
+
mockExistsSync.mockReturnValue(true);
|
|
61
|
+
mockReadFileSync.mockReturnValue("not valid json {{{");
|
|
62
|
+
const result = readLockfile(TEST_DIR);
|
|
63
|
+
expect(result).toBeNull();
|
|
64
|
+
});
|
|
65
|
+
it("parses a valid lockfile", () => {
|
|
66
|
+
const lock = makeLock({ agents: ["claude"] });
|
|
67
|
+
mockExistsSync.mockReturnValue(true);
|
|
68
|
+
mockReadFileSync.mockReturnValue(JSON.stringify(lock));
|
|
69
|
+
const result = readLockfile(TEST_DIR);
|
|
70
|
+
expect(result).toEqual(lock);
|
|
71
|
+
expect(mockReadFileSync).toHaveBeenCalledWith(LOCK_PATH, "utf-8");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe("writeLockfile", () => {
|
|
75
|
+
it("writes JSON with updated timestamp", () => {
|
|
76
|
+
const lock = makeLock();
|
|
77
|
+
writeLockfile(lock, TEST_DIR);
|
|
78
|
+
expect(lock.updatedAt).toBe("2026-02-17T12:00:00.000Z");
|
|
79
|
+
expect(mockWriteFileSync).toHaveBeenCalledWith(LOCK_PATH, JSON.stringify(lock, null, 2) + "\n", "utf-8");
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe("ensureLockfile", () => {
|
|
83
|
+
it("creates a new lockfile when none exists", () => {
|
|
84
|
+
mockExistsSync.mockReturnValue(false);
|
|
85
|
+
const result = ensureLockfile(TEST_DIR);
|
|
86
|
+
expect(result.version).toBe(1);
|
|
87
|
+
expect(result.agents).toEqual([]);
|
|
88
|
+
expect(result.skills).toEqual({});
|
|
89
|
+
expect(result.createdAt).toBe("2026-02-17T12:00:00.000Z");
|
|
90
|
+
expect(mockWriteFileSync).toHaveBeenCalled();
|
|
91
|
+
});
|
|
92
|
+
it("returns existing lockfile without writing", () => {
|
|
93
|
+
const existing = makeLock({ agents: ["cursor"] });
|
|
94
|
+
mockExistsSync.mockReturnValue(true);
|
|
95
|
+
mockReadFileSync.mockReturnValue(JSON.stringify(existing));
|
|
96
|
+
const result = ensureLockfile(TEST_DIR);
|
|
97
|
+
expect(result).toEqual(existing);
|
|
98
|
+
expect(mockWriteFileSync).not.toHaveBeenCalled();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
describe("addSkillToLock", () => {
|
|
102
|
+
it("adds a skill entry to the lockfile", () => {
|
|
103
|
+
const existing = makeLock();
|
|
104
|
+
mockExistsSync.mockReturnValue(true);
|
|
105
|
+
mockReadFileSync.mockReturnValue(JSON.stringify(existing));
|
|
106
|
+
const entry = makeEntry({ version: "2.0.0", tier: "VERIFIED" });
|
|
107
|
+
addSkillToLock("my-skill", entry, TEST_DIR);
|
|
108
|
+
// writeLockfile should have been called with the skill added
|
|
109
|
+
expect(mockWriteFileSync).toHaveBeenCalledTimes(1);
|
|
110
|
+
const writtenJson = JSON.parse(mockWriteFileSync.mock.calls[0][1].trimEnd());
|
|
111
|
+
expect(writtenJson.skills["my-skill"]).toEqual(entry);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
describe("removeSkillFromLock", () => {
|
|
115
|
+
it("removes a skill entry from the lockfile", () => {
|
|
116
|
+
const existing = makeLock({
|
|
117
|
+
skills: {
|
|
118
|
+
"skill-a": makeEntry(),
|
|
119
|
+
"skill-b": makeEntry({ version: "3.0.0" }),
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
mockExistsSync.mockReturnValue(true);
|
|
123
|
+
mockReadFileSync.mockReturnValue(JSON.stringify(existing));
|
|
124
|
+
removeSkillFromLock("skill-a", TEST_DIR);
|
|
125
|
+
expect(mockWriteFileSync).toHaveBeenCalledTimes(1);
|
|
126
|
+
const writtenJson = JSON.parse(mockWriteFileSync.mock.calls[0][1].trimEnd());
|
|
127
|
+
expect(writtenJson.skills).not.toHaveProperty("skill-a");
|
|
128
|
+
expect(writtenJson.skills).toHaveProperty("skill-b");
|
|
129
|
+
});
|
|
130
|
+
it("is a no-op when no lockfile exists", () => {
|
|
131
|
+
mockExistsSync.mockReturnValue(false);
|
|
132
|
+
removeSkillFromLock("nonexistent", TEST_DIR);
|
|
133
|
+
expect(mockWriteFileSync).not.toHaveBeenCalled();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
// TC-008: Extended entry with marketplace field round-trips
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
describe("lockfile extended fields", () => {
|
|
140
|
+
it("TC-008: extended entry with marketplace field round-trips", () => {
|
|
141
|
+
const extendedEntry = makeEntry({
|
|
142
|
+
marketplace: "specweave",
|
|
143
|
+
pluginDir: true,
|
|
144
|
+
scope: "user",
|
|
145
|
+
installedPath: "~/.claude/plugins/cache/specweave/sw/1.0.0",
|
|
146
|
+
});
|
|
147
|
+
const lock = makeLock({ skills: { "sw-frontend": extendedEntry } });
|
|
148
|
+
mockExistsSync.mockReturnValue(true);
|
|
149
|
+
// Write the lockfile
|
|
150
|
+
writeLockfile(lock, TEST_DIR);
|
|
151
|
+
// Capture what was written
|
|
152
|
+
const writtenJson = JSON.parse(mockWriteFileSync.mock.calls[0][1].trimEnd());
|
|
153
|
+
// Simulate reading it back
|
|
154
|
+
mockReadFileSync.mockReturnValue(JSON.stringify(writtenJson));
|
|
155
|
+
const readBack = readLockfile(TEST_DIR);
|
|
156
|
+
expect(readBack).not.toBeNull();
|
|
157
|
+
const entry = readBack.skills["sw-frontend"];
|
|
158
|
+
expect(entry.marketplace).toBe("specweave");
|
|
159
|
+
expect(entry.pluginDir).toBe(true);
|
|
160
|
+
expect(entry.scope).toBe("user");
|
|
161
|
+
expect(entry.installedPath).toBe("~/.claude/plugins/cache/specweave/sw/1.0.0");
|
|
162
|
+
// Original fields still present
|
|
163
|
+
expect(entry.version).toBe("1.0.0");
|
|
164
|
+
expect(entry.sha).toBe("abc123");
|
|
165
|
+
expect(entry.tier).toBe("SCANNED");
|
|
166
|
+
expect(entry.source).toBe("registry");
|
|
167
|
+
});
|
|
168
|
+
// TC-009: Backward-compatible with existing entries
|
|
169
|
+
it("TC-009: backward-compatible with existing entries", () => {
|
|
170
|
+
// Old-format entry with only the original fields
|
|
171
|
+
const oldEntry = {
|
|
172
|
+
version: "1.0.0",
|
|
173
|
+
sha: "abc123",
|
|
174
|
+
tier: "SCANNED",
|
|
175
|
+
installedAt: "2026-01-01T00:00:00.000Z",
|
|
176
|
+
source: "registry",
|
|
177
|
+
};
|
|
178
|
+
const lock = makeLock({ skills: { "old-skill": oldEntry } });
|
|
179
|
+
mockExistsSync.mockReturnValue(true);
|
|
180
|
+
mockReadFileSync.mockReturnValue(JSON.stringify(lock));
|
|
181
|
+
const result = readLockfile(TEST_DIR);
|
|
182
|
+
expect(result).not.toBeNull();
|
|
183
|
+
const entry = result.skills["old-skill"];
|
|
184
|
+
expect(entry.version).toBe("1.0.0");
|
|
185
|
+
expect(entry.sha).toBe("abc123");
|
|
186
|
+
expect(entry.tier).toBe("SCANNED");
|
|
187
|
+
expect(entry.installedAt).toBe("2026-01-01T00:00:00.000Z");
|
|
188
|
+
expect(entry.source).toBe("registry");
|
|
189
|
+
// New fields should be undefined
|
|
190
|
+
expect(entry.marketplace).toBeUndefined();
|
|
191
|
+
expect(entry.pluginDir).toBeUndefined();
|
|
192
|
+
expect(entry.scope).toBeUndefined();
|
|
193
|
+
expect(entry.installedPath).toBeUndefined();
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
//# sourceMappingURL=lockfile.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockfile.test.js","sourceRoot":"","sources":["../../src/lockfile/lockfile.test.ts"],"names":[],"mappings":"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"}
|
package/dist/lockfile/types.d.ts
CHANGED
|
@@ -4,6 +4,14 @@ export interface SkillLockEntry {
|
|
|
4
4
|
tier: string;
|
|
5
5
|
installedAt: string;
|
|
6
6
|
source: string;
|
|
7
|
+
/** Marketplace origin (e.g. "specweave") */
|
|
8
|
+
marketplace?: string;
|
|
9
|
+
/** Whether this entry is a plugin directory (not a single SKILL.md) */
|
|
10
|
+
pluginDir?: boolean;
|
|
11
|
+
/** Installation scope: user-global or project-local */
|
|
12
|
+
scope?: "user" | "project";
|
|
13
|
+
/** Absolute path where the plugin was installed */
|
|
14
|
+
installedPath?: string;
|
|
7
15
|
}
|
|
8
16
|
export interface VskillLock {
|
|
9
17
|
version: 1;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/marketplace/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,gBAAgB,GACjB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface MarketplacePlugin {
|
|
2
|
+
name: string;
|
|
3
|
+
source: string;
|
|
4
|
+
version: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface MarketplaceManifest {
|
|
8
|
+
name: string;
|
|
9
|
+
version: string;
|
|
10
|
+
plugins: MarketplacePlugin[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parse marketplace.json content and extract available plugins.
|
|
14
|
+
*
|
|
15
|
+
* @param content - Raw JSON string from marketplace.json
|
|
16
|
+
* @returns Array of plugin entries, or empty array on parse failure
|
|
17
|
+
*/
|
|
18
|
+
export declare function getAvailablePlugins(content: string): MarketplacePlugin[];
|
|
19
|
+
/**
|
|
20
|
+
* Get the source path for a named plugin from marketplace.json.
|
|
21
|
+
*
|
|
22
|
+
* @param name - Plugin name to look up (e.g. "sw-frontend")
|
|
23
|
+
* @param content - Raw JSON string from marketplace.json
|
|
24
|
+
* @returns Source path (e.g. "./plugins/specweave-frontend") or null
|
|
25
|
+
*/
|
|
26
|
+
export declare function getPluginSource(name: string, content: string): string | null;
|
|
27
|
+
/**
|
|
28
|
+
* Get the version for a named plugin from marketplace.json.
|
|
29
|
+
*
|
|
30
|
+
* @param name - Plugin name to look up
|
|
31
|
+
* @param content - Raw JSON string from marketplace.json
|
|
32
|
+
* @returns Version string or null if not found
|
|
33
|
+
*/
|
|
34
|
+
export declare function getPluginVersion(name: string, content: string): string | null;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Marketplace.json parser -- parse .claude-plugin/marketplace.json
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// ---- Parser ---------------------------------------------------------------
|
|
5
|
+
/**
|
|
6
|
+
* Parse marketplace.json content and extract available plugins.
|
|
7
|
+
*
|
|
8
|
+
* @param content - Raw JSON string from marketplace.json
|
|
9
|
+
* @returns Array of plugin entries, or empty array on parse failure
|
|
10
|
+
*/
|
|
11
|
+
export function getAvailablePlugins(content) {
|
|
12
|
+
try {
|
|
13
|
+
const manifest = JSON.parse(content);
|
|
14
|
+
if (!Array.isArray(manifest.plugins))
|
|
15
|
+
return [];
|
|
16
|
+
return manifest.plugins.map((p) => ({
|
|
17
|
+
name: p.name,
|
|
18
|
+
source: p.source,
|
|
19
|
+
version: p.version,
|
|
20
|
+
...(p.description ? { description: p.description } : {}),
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get the source path for a named plugin from marketplace.json.
|
|
29
|
+
*
|
|
30
|
+
* @param name - Plugin name to look up (e.g. "sw-frontend")
|
|
31
|
+
* @param content - Raw JSON string from marketplace.json
|
|
32
|
+
* @returns Source path (e.g. "./plugins/specweave-frontend") or null
|
|
33
|
+
*/
|
|
34
|
+
export function getPluginSource(name, content) {
|
|
35
|
+
const plugins = getAvailablePlugins(content);
|
|
36
|
+
const found = plugins.find((p) => p.name === name);
|
|
37
|
+
return found?.source ?? null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the version for a named plugin from marketplace.json.
|
|
41
|
+
*
|
|
42
|
+
* @param name - Plugin name to look up
|
|
43
|
+
* @param content - Raw JSON string from marketplace.json
|
|
44
|
+
* @returns Version string or null if not found
|
|
45
|
+
*/
|
|
46
|
+
export function getPluginVersion(name, content) {
|
|
47
|
+
const plugins = getAvailablePlugins(content);
|
|
48
|
+
const found = plugins.find((p) => p.name === name);
|
|
49
|
+
return found?.version ?? null;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=marketplace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketplace.js","sourceRoot":"","sources":["../../src/marketplace/marketplace.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,mEAAmE;AACnE,8EAA8E;AAiB9E,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAwB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,CAAC;QAChD,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAClC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzD,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,OAAe;IAEf,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACnD,OAAO,KAAK,EAAE,MAAM,IAAI,IAAI,CAAC;AAC/B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,OAAe;IAEf,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACnD,OAAO,KAAK,EAAE,OAAO,IAAI,IAAI,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|