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.
Files changed (110) hide show
  1. package/dist/agents/agents-registry.d.ts +48 -37
  2. package/dist/agents/agents-registry.js +206 -261
  3. package/dist/agents/agents-registry.js.map +1 -1
  4. package/dist/agents/agents-registry.test.d.ts +1 -0
  5. package/dist/agents/agents-registry.test.js +203 -0
  6. package/dist/agents/agents-registry.test.js.map +1 -0
  7. package/dist/api/client.test.d.ts +1 -0
  8. package/dist/api/client.test.js +204 -0
  9. package/dist/api/client.test.js.map +1 -0
  10. package/dist/blocklist/blocklist.d.ts +23 -0
  11. package/dist/blocklist/blocklist.js +116 -0
  12. package/dist/blocklist/blocklist.js.map +1 -0
  13. package/dist/blocklist/blocklist.test.d.ts +1 -0
  14. package/dist/blocklist/blocklist.test.js +259 -0
  15. package/dist/blocklist/blocklist.test.js.map +1 -0
  16. package/dist/blocklist/types.d.ts +18 -0
  17. package/dist/blocklist/types.js +5 -0
  18. package/dist/blocklist/types.js.map +1 -0
  19. package/dist/commands/add.d.ts +2 -0
  20. package/dist/commands/add.js +221 -6
  21. package/dist/commands/add.js.map +1 -1
  22. package/dist/commands/add.test.d.ts +1 -0
  23. package/dist/commands/add.test.js +682 -0
  24. package/dist/commands/add.test.js.map +1 -0
  25. package/dist/commands/blocklist.d.ts +1 -0
  26. package/dist/commands/blocklist.js +87 -0
  27. package/dist/commands/blocklist.js.map +1 -0
  28. package/dist/commands/blocklist.test.d.ts +1 -0
  29. package/dist/commands/blocklist.test.js +158 -0
  30. package/dist/commands/blocklist.test.js.map +1 -0
  31. package/dist/commands/remove.d.ts +7 -0
  32. package/dist/commands/remove.js +91 -0
  33. package/dist/commands/remove.js.map +1 -0
  34. package/dist/commands/remove.test.d.ts +1 -0
  35. package/dist/commands/remove.test.js +164 -0
  36. package/dist/commands/remove.test.js.map +1 -0
  37. package/dist/commands/submit.d.ts +1 -1
  38. package/dist/commands/submit.js +26 -16
  39. package/dist/commands/submit.js.map +1 -1
  40. package/dist/commands/submit.test.d.ts +1 -0
  41. package/dist/commands/submit.test.js +74 -0
  42. package/dist/commands/submit.test.js.map +1 -0
  43. package/dist/index.js +21 -2
  44. package/dist/index.js.map +1 -1
  45. package/dist/lockfile/lockfile.test.d.ts +1 -0
  46. package/dist/lockfile/lockfile.test.js +196 -0
  47. package/dist/lockfile/lockfile.test.js.map +1 -0
  48. package/dist/lockfile/types.d.ts +8 -0
  49. package/dist/marketplace/index.d.ts +2 -0
  50. package/dist/marketplace/index.js +2 -0
  51. package/dist/marketplace/index.js.map +1 -0
  52. package/dist/marketplace/marketplace.d.ts +34 -0
  53. package/dist/marketplace/marketplace.js +51 -0
  54. package/dist/marketplace/marketplace.js.map +1 -0
  55. package/dist/marketplace/marketplace.test.d.ts +1 -0
  56. package/dist/marketplace/marketplace.test.js +103 -0
  57. package/dist/marketplace/marketplace.test.js.map +1 -0
  58. package/dist/scanner/index.d.ts +4 -0
  59. package/dist/scanner/index.js +4 -0
  60. package/dist/scanner/index.js.map +1 -1
  61. package/dist/scanner/patterns.test.d.ts +1 -0
  62. package/dist/scanner/patterns.test.js +353 -0
  63. package/dist/scanner/patterns.test.js.map +1 -0
  64. package/dist/scanner/repo-scanner.d.ts +30 -0
  65. package/dist/scanner/repo-scanner.js +190 -0
  66. package/dist/scanner/repo-scanner.js.map +1 -0
  67. package/dist/scanner/tier1.test.d.ts +1 -0
  68. package/dist/scanner/tier1.test.js +182 -0
  69. package/dist/scanner/tier1.test.js.map +1 -0
  70. package/dist/scanner/tier2-llm.d.ts +28 -0
  71. package/dist/scanner/tier2-llm.js +130 -0
  72. package/dist/scanner/tier2-llm.js.map +1 -0
  73. package/dist/scanner/types.d.ts +58 -0
  74. package/dist/scanner/types.js +5 -0
  75. package/dist/scanner/types.js.map +1 -0
  76. package/dist/security/index.d.ts +2 -0
  77. package/dist/security/index.js +2 -0
  78. package/dist/security/index.js.map +1 -0
  79. package/dist/security/platform-security.d.ts +17 -0
  80. package/dist/security/platform-security.js +34 -0
  81. package/dist/security/platform-security.js.map +1 -0
  82. package/dist/security/platform-security.test.d.ts +1 -0
  83. package/dist/security/platform-security.test.js +92 -0
  84. package/dist/security/platform-security.test.js.map +1 -0
  85. package/dist/settings/index.d.ts +2 -0
  86. package/dist/settings/index.js +2 -0
  87. package/dist/settings/index.js.map +1 -0
  88. package/dist/settings/settings.d.ts +16 -0
  89. package/dist/settings/settings.js +73 -0
  90. package/dist/settings/settings.js.map +1 -0
  91. package/dist/settings/settings.test.d.ts +1 -0
  92. package/dist/settings/settings.test.js +103 -0
  93. package/dist/settings/settings.test.js.map +1 -0
  94. package/dist/utils/__tests__/paths.test.d.ts +1 -0
  95. package/dist/utils/__tests__/paths.test.js +22 -0
  96. package/dist/utils/__tests__/paths.test.js.map +1 -0
  97. package/dist/utils/__tests__/validation.test.d.ts +1 -0
  98. package/dist/utils/__tests__/validation.test.js +49 -0
  99. package/dist/utils/__tests__/validation.test.js.map +1 -0
  100. package/dist/utils/browser.d.ts +6 -0
  101. package/dist/utils/browser.js +37 -0
  102. package/dist/utils/browser.js.map +1 -0
  103. package/dist/utils/paths.d.ts +5 -0
  104. package/dist/utils/paths.js +13 -0
  105. package/dist/utils/paths.js.map +1 -0
  106. package/dist/utils/validation.d.ts +14 -0
  107. package/dist/utils/validation.js +34 -0
  108. package/dist/utils/validation.js.map +1 -0
  109. package/package.json +5 -2
  110. package/scripts/preuninstall.cjs +58 -0
@@ -1,8 +1,9 @@
1
1
  // ---------------------------------------------------------------------------
2
- // vskill submit -- submit a skill for verification
2
+ // vskill submit -- open browser for skill submission via GitHub OAuth
3
3
  // ---------------------------------------------------------------------------
4
- import { submitSkill } from "../api/client.js";
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
- const repoUrl = `https://github.com/${owner}/${repo}`;
15
- console.log(dim(`Submitting ${bold(`${owner}/${repo}`)} for verification...\n`));
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
- const result = await submitSkill({
18
- repoUrl,
19
- skillName: repo,
20
- email: opts.email,
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("Submission failed: ") +
38
+ console.error(red("Could not open browser: ") +
30
39
  dim(err.message));
31
- process.exit(1);
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,mDAAmD;AACnD,8EAA8E;AAE9E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAMjE,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;IAC5B,MAAM,OAAO,GAAG,sBAAsB,KAAK,IAAI,IAAI,EAAE,CAAC;IAEtD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAEjF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC;YAC/B,OAAO;YACP,SAAS,EAAE,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CACT,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,0CAA0C,MAAM,CAAC,EAAE,EAAE,CAAC,EAAE,CACjH,CAAC;QACF,OAAO,CAAC,GAAG,CACT,GAAG,CAAC,sDAAsD,CAAC,CAC5D,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CACX,GAAG,CAAC,qBAAqB,CAAC;YACxB,GAAG,CAAE,GAAa,CAAC,OAAO,CAAC,CAC9B,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
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 with security scanning")
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("--email <email>", "Email for submission updates")
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":"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"}
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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"}
@@ -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,2 @@
1
+ export type { MarketplacePlugin, MarketplaceManifest } from "./marketplace.js";
2
+ export { getAvailablePlugins, getPluginSource, getPluginVersion, } from "./marketplace.js";
@@ -0,0 +1,2 @@
1
+ export { getAvailablePlugins, getPluginSource, getPluginVersion, } from "./marketplace.js";
2
+ //# sourceMappingURL=index.js.map
@@ -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 {};