@polyskill/cli 0.1.0
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/__tests__/build.test.d.ts +2 -0
- package/dist/__tests__/build.test.d.ts.map +1 -0
- package/dist/__tests__/build.test.js +58 -0
- package/dist/__tests__/build.test.js.map +1 -0
- package/dist/__tests__/fixtures.d.ts +5 -0
- package/dist/__tests__/fixtures.d.ts.map +1 -0
- package/dist/__tests__/fixtures.js +51 -0
- package/dist/__tests__/fixtures.js.map +1 -0
- package/dist/__tests__/init.test.d.ts +2 -0
- package/dist/__tests__/init.test.d.ts.map +1 -0
- package/dist/__tests__/init.test.js +94 -0
- package/dist/__tests__/init.test.js.map +1 -0
- package/dist/__tests__/install.test.d.ts +2 -0
- package/dist/__tests__/install.test.d.ts.map +1 -0
- package/dist/__tests__/install.test.js +107 -0
- package/dist/__tests__/install.test.js.map +1 -0
- package/dist/__tests__/publish.test.d.ts +2 -0
- package/dist/__tests__/publish.test.d.ts.map +1 -0
- package/dist/__tests__/publish.test.js +102 -0
- package/dist/__tests__/publish.test.js.map +1 -0
- package/dist/__tests__/validate.test.d.ts +2 -0
- package/dist/__tests__/validate.test.d.ts.map +1 -0
- package/dist/__tests__/validate.test.js +45 -0
- package/dist/__tests__/validate.test.js.map +1 -0
- package/dist/commands/build.d.ts +3 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +44 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +55 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install.d.ts +3 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +96 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/publish.d.ts +3 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +80 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/validate.d.ts +3 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +19 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/templates/instructions.md.template +1 -0
- package/dist/templates/skill.json.template +17 -0
- package/dist/templates/templates/instructions.md.template +1 -0
- package/dist/templates/templates/skill.json.template +17 -0
- package/dist/templates/templates/tools.json.template +18 -0
- package/dist/templates/tools.json.template +18 -0
- package/package.json +33 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/build.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
vi.mock("@skillstore/core", () => ({
|
|
3
|
+
loadSkill: vi.fn(),
|
|
4
|
+
getAdapter: vi.fn(),
|
|
5
|
+
}));
|
|
6
|
+
vi.mock("node:fs/promises", () => ({
|
|
7
|
+
writeFile: vi.fn(),
|
|
8
|
+
mkdir: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
import { buildCommand } from "../commands/build.js";
|
|
11
|
+
import { loadSkill, getAdapter } from "@skillstore/core";
|
|
12
|
+
import { writeFile, mkdir } from "node:fs/promises";
|
|
13
|
+
import { mockSkill, mockTranspileResult } from "./fixtures.js";
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
vi.clearAllMocks();
|
|
16
|
+
vi.spyOn(console, "log").mockImplementation(() => { });
|
|
17
|
+
});
|
|
18
|
+
describe("build command", () => {
|
|
19
|
+
it("builds adapter outputs for each platform", async () => {
|
|
20
|
+
vi.mocked(loadSkill).mockResolvedValue(mockSkill);
|
|
21
|
+
vi.mocked(getAdapter).mockReturnValue({
|
|
22
|
+
name: "openai",
|
|
23
|
+
transpile: vi.fn().mockReturnValue(mockTranspileResult),
|
|
24
|
+
});
|
|
25
|
+
await buildCommand.parseAsync(["/tmp/test-skill"], { from: "user" });
|
|
26
|
+
expect(mkdir).toHaveBeenCalledWith("/tmp/test-skill/dist", { recursive: true });
|
|
27
|
+
// 2 adapters in mockSkill.manifest: openai, anthropic
|
|
28
|
+
expect(writeFile).toHaveBeenCalledTimes(2);
|
|
29
|
+
expect(writeFile).toHaveBeenCalledWith("/tmp/test-skill/dist/openai.json", expect.any(String));
|
|
30
|
+
expect(writeFile).toHaveBeenCalledWith("/tmp/test-skill/dist/anthropic.json", expect.any(String));
|
|
31
|
+
});
|
|
32
|
+
it("skips unknown adapters with a warning", async () => {
|
|
33
|
+
vi.mocked(loadSkill).mockResolvedValue(mockSkill);
|
|
34
|
+
vi.mocked(getAdapter)
|
|
35
|
+
.mockReturnValueOnce(null) // openai → unknown
|
|
36
|
+
.mockReturnValueOnce({
|
|
37
|
+
name: "anthropic",
|
|
38
|
+
transpile: vi.fn().mockReturnValue(mockTranspileResult),
|
|
39
|
+
});
|
|
40
|
+
await buildCommand.parseAsync(["/tmp/test-skill"], { from: "user" });
|
|
41
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("Skipping unknown adapter"));
|
|
42
|
+
expect(writeFile).toHaveBeenCalledTimes(1);
|
|
43
|
+
});
|
|
44
|
+
it("creates dist directory with recursive flag", async () => {
|
|
45
|
+
vi.mocked(loadSkill).mockResolvedValue(mockSkill);
|
|
46
|
+
vi.mocked(getAdapter).mockReturnValue({
|
|
47
|
+
name: "openai",
|
|
48
|
+
transpile: vi.fn().mockReturnValue(mockTranspileResult),
|
|
49
|
+
});
|
|
50
|
+
await buildCommand.parseAsync(["/tmp/test-skill"], { from: "user" });
|
|
51
|
+
expect(mkdir).toHaveBeenCalledWith(expect.stringContaining("dist"), { recursive: true });
|
|
52
|
+
});
|
|
53
|
+
it("propagates loadSkill errors", async () => {
|
|
54
|
+
vi.mocked(loadSkill).mockRejectedValue(new Error("Missing skill.json"));
|
|
55
|
+
await expect(buildCommand.parseAsync(["/tmp/bad-skill"], { from: "user" })).rejects.toThrow("Missing skill.json");
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=build.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.test.js","sourceRoot":"","sources":["../../src/__tests__/build.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { SkillManifest, SkillDefinition, TranspileResult } from "@skillstore/core";
|
|
2
|
+
export declare const mockManifest: SkillManifest;
|
|
3
|
+
export declare const mockSkill: SkillDefinition;
|
|
4
|
+
export declare const mockTranspileResult: TranspileResult;
|
|
5
|
+
//# sourceMappingURL=fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../src/__tests__/fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExF,eAAO,MAAM,YAAY,EAAE,aAY1B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,eAgBvB,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,eAmBjC,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export const mockManifest = {
|
|
2
|
+
name: "@test/my-skill",
|
|
3
|
+
version: "1.0.0",
|
|
4
|
+
description: "A test skill",
|
|
5
|
+
type: "tool",
|
|
6
|
+
license: "MIT",
|
|
7
|
+
author: { name: "Test Author" },
|
|
8
|
+
skill: {
|
|
9
|
+
instructions: "./instructions.md",
|
|
10
|
+
tools: "./tools.json",
|
|
11
|
+
},
|
|
12
|
+
adapters: ["openai", "anthropic"],
|
|
13
|
+
};
|
|
14
|
+
export const mockSkill = {
|
|
15
|
+
manifest: mockManifest,
|
|
16
|
+
tools: [
|
|
17
|
+
{
|
|
18
|
+
name: "test_tool",
|
|
19
|
+
description: "A test tool",
|
|
20
|
+
parameters: {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {
|
|
23
|
+
input: { type: "string", description: "Test input" },
|
|
24
|
+
},
|
|
25
|
+
required: ["input"],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
instructions: "You are a test assistant.",
|
|
30
|
+
};
|
|
31
|
+
export const mockTranspileResult = {
|
|
32
|
+
platform: "openai",
|
|
33
|
+
systemPrompt: "You are a test assistant.",
|
|
34
|
+
tools: [
|
|
35
|
+
{
|
|
36
|
+
type: "function",
|
|
37
|
+
function: {
|
|
38
|
+
name: "test_tool",
|
|
39
|
+
description: "A test tool",
|
|
40
|
+
parameters: {
|
|
41
|
+
type: "object",
|
|
42
|
+
properties: {
|
|
43
|
+
input: { type: "string", description: "Test input" },
|
|
44
|
+
},
|
|
45
|
+
required: ["input"],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=fixtures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../../src/__tests__/fixtures.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAkB;IACzC,IAAI,EAAE,gBAAgB;IACtB,OAAO,EAAE,OAAO;IAChB,WAAW,EAAE,cAAc;IAC3B,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE;IAC/B,KAAK,EAAE;QACL,YAAY,EAAE,mBAAmB;QACjC,KAAK,EAAE,cAAc;KACtB;IACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC;CAClC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAoB;IACxC,QAAQ,EAAE,YAAY;IACtB,KAAK,EAAE;QACL;YACE,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,aAAa;YAC1B,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE;iBACrD;gBACD,QAAQ,EAAE,CAAC,OAAO,CAAC;aACpB;SACF;KACF;IACD,YAAY,EAAE,2BAA2B;CAC1C,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAoB;IAClD,QAAQ,EAAE,QAAQ;IAClB,YAAY,EAAE,2BAA2B;IACzC,KAAK,EAAE;QACL;YACE,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE;gBACR,IAAI,EAAE,WAAW;gBACjB,WAAW,EAAE,aAAa;gBAC1B,UAAU,EAAE;oBACV,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE;qBACrD;oBACD,QAAQ,EAAE,CAAC,OAAO,CAAC;iBACpB;aACF;SACF;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/init.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
vi.mock("@inquirer/prompts", () => ({
|
|
3
|
+
input: vi.fn(),
|
|
4
|
+
}));
|
|
5
|
+
vi.mock("node:fs/promises", () => ({
|
|
6
|
+
readFile: vi.fn(),
|
|
7
|
+
writeFile: vi.fn(),
|
|
8
|
+
mkdir: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
import { initCommand } from "../commands/init.js";
|
|
11
|
+
import { input } from "@inquirer/prompts";
|
|
12
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
vi.clearAllMocks();
|
|
15
|
+
vi.spyOn(console, "log").mockImplementation(() => { });
|
|
16
|
+
});
|
|
17
|
+
describe("init command", () => {
|
|
18
|
+
it("scaffolds a skill with all template files", async () => {
|
|
19
|
+
vi.mocked(input)
|
|
20
|
+
.mockResolvedValueOnce("@test/my-skill") // name
|
|
21
|
+
.mockResolvedValueOnce("A test skill") // description
|
|
22
|
+
.mockResolvedValueOnce("Test Author"); // author
|
|
23
|
+
vi.mocked(readFile)
|
|
24
|
+
.mockResolvedValueOnce('{"name":"{{name}}","description":"{{description}}","author":{"name":"{{authorName}}"}}')
|
|
25
|
+
.mockResolvedValueOnce('{"tools":[]}')
|
|
26
|
+
.mockResolvedValueOnce("# Instructions");
|
|
27
|
+
await initCommand.parseAsync(["/tmp/new-skill"], { from: "user" });
|
|
28
|
+
expect(mkdir).toHaveBeenCalledWith("/tmp/new-skill", { recursive: true });
|
|
29
|
+
expect(writeFile).toHaveBeenCalledTimes(3);
|
|
30
|
+
// skill.json should have variables substituted
|
|
31
|
+
const skillJsonCall = vi.mocked(writeFile).mock.calls.find((c) => c[0].endsWith("skill.json"));
|
|
32
|
+
expect(skillJsonCall).toBeDefined();
|
|
33
|
+
expect(skillJsonCall[1]).toContain("@test/my-skill");
|
|
34
|
+
expect(skillJsonCall[1]).toContain("A test skill");
|
|
35
|
+
expect(skillJsonCall[1]).toContain("Test Author");
|
|
36
|
+
});
|
|
37
|
+
it("creates target directory with recursive flag", async () => {
|
|
38
|
+
vi.mocked(input)
|
|
39
|
+
.mockResolvedValueOnce("@test/my-skill")
|
|
40
|
+
.mockResolvedValueOnce("A test skill")
|
|
41
|
+
.mockResolvedValueOnce("Test Author");
|
|
42
|
+
vi.mocked(readFile)
|
|
43
|
+
.mockResolvedValueOnce("{}")
|
|
44
|
+
.mockResolvedValueOnce("{}")
|
|
45
|
+
.mockResolvedValueOnce("");
|
|
46
|
+
await initCommand.parseAsync(["/tmp/nested/dir"], { from: "user" });
|
|
47
|
+
expect(mkdir).toHaveBeenCalledWith("/tmp/nested/dir", { recursive: true });
|
|
48
|
+
});
|
|
49
|
+
it("validates skill name must be scoped format", async () => {
|
|
50
|
+
// Extract the validate function from the first input() call
|
|
51
|
+
vi.mocked(input).mockImplementation(async (opts) => {
|
|
52
|
+
if (opts.message.includes("Skill name")) {
|
|
53
|
+
// Test the validate function
|
|
54
|
+
const validate = opts.validate;
|
|
55
|
+
expect(validate("@scope/name")).toBe(true);
|
|
56
|
+
expect(validate("bad-name")).toBe("Must be scoped: @scope/name (lowercase, hyphens)");
|
|
57
|
+
expect(validate("@UPPER/case")).toBe("Must be scoped: @scope/name (lowercase, hyphens)");
|
|
58
|
+
return "@test/my-skill";
|
|
59
|
+
}
|
|
60
|
+
return "placeholder";
|
|
61
|
+
});
|
|
62
|
+
vi.mocked(readFile).mockResolvedValue("{}");
|
|
63
|
+
await initCommand.parseAsync(["/tmp/test"], { from: "user" });
|
|
64
|
+
});
|
|
65
|
+
it("validates description is not empty", async () => {
|
|
66
|
+
vi.mocked(input).mockImplementation(async (opts) => {
|
|
67
|
+
if (opts.message.includes("Description")) {
|
|
68
|
+
const validate = opts.validate;
|
|
69
|
+
expect(validate("")).toBe("Description is required");
|
|
70
|
+
expect(validate("Valid description")).toBe(true);
|
|
71
|
+
return "A description";
|
|
72
|
+
}
|
|
73
|
+
return "@test/my-skill";
|
|
74
|
+
});
|
|
75
|
+
vi.mocked(readFile).mockResolvedValue("{}");
|
|
76
|
+
await initCommand.parseAsync(["/tmp/test"], { from: "user" });
|
|
77
|
+
});
|
|
78
|
+
it("writes tools.json and instructions.md without variable substitution", async () => {
|
|
79
|
+
vi.mocked(input)
|
|
80
|
+
.mockResolvedValueOnce("@test/my-skill")
|
|
81
|
+
.mockResolvedValueOnce("A test skill")
|
|
82
|
+
.mockResolvedValueOnce("Test Author");
|
|
83
|
+
vi.mocked(readFile)
|
|
84
|
+
.mockResolvedValueOnce('{"name":"{{name}}"}') // skill.json template
|
|
85
|
+
.mockResolvedValueOnce('{"tools":[]}') // tools.json template
|
|
86
|
+
.mockResolvedValueOnce("# Instructions template"); // instructions.md template
|
|
87
|
+
await initCommand.parseAsync(["/tmp/test"], { from: "user" });
|
|
88
|
+
const toolsCall = vi.mocked(writeFile).mock.calls.find((c) => c[0].endsWith("tools.json"));
|
|
89
|
+
expect(toolsCall[1]).toBe('{"tools":[]}');
|
|
90
|
+
const instructionsCall = vi.mocked(writeFile).mock.calls.find((c) => c[0].endsWith("instructions.md"));
|
|
91
|
+
expect(instructionsCall[1]).toBe("# Instructions template");
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=init.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.test.js","sourceRoot":"","sources":["../../src/__tests__/init.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE9D,EAAE,CAAC,IAAI,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC;IAClC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;CACf,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE;IACjB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE;IAClB,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;CACf,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9D,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;AACxD,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;aACb,qBAAqB,CAAC,gBAAgB,CAAC,CAAG,OAAO;aACjD,qBAAqB,CAAC,cAAc,CAAC,CAAM,cAAc;aACzD,qBAAqB,CAAC,aAAa,CAAC,CAAC,CAAM,SAAS;QAEvD,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;aAChB,qBAAqB,CAAC,wFAAwF,CAAC;aAC/G,qBAAqB,CAAC,cAAc,CAAC;aACrC,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;QAE3C,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC,gBAAgB,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAEnE,MAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,gBAAgB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1E,MAAM,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAE3C,+CAA+C;QAC/C,MAAM,aAAa,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CACxD,CAAC,CAAC,EAAE,EAAE,CAAE,CAAC,CAAC,CAAC,CAAY,CAAC,QAAQ,CAAC,YAAY,CAAC,CAC/C,CAAC;QACF,MAAM,CAAC,aAAa,CAAC,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,CAAC,aAAc,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QACtD,MAAM,CAAC,aAAc,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACpD,MAAM,CAAC,aAAc,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;aACb,qBAAqB,CAAC,gBAAgB,CAAC;aACvC,qBAAqB,CAAC,cAAc,CAAC;aACrC,qBAAqB,CAAC,aAAa,CAAC,CAAC;QAExC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;aAChB,qBAAqB,CAAC,IAAI,CAAC;aAC3B,qBAAqB,CAAC,IAAI,CAAC;aAC3B,qBAAqB,CAAC,EAAE,CAAC,CAAC;QAE7B,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAEpE,MAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,iBAAiB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,4DAA4D;QAC5D,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,IAAS,EAAE,EAAE;YACtD,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;gBACxC,6BAA6B;gBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC/B,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC3C,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;gBACtF,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;gBACzF,OAAO,gBAAgB,CAAC;YAC1B,CAAC;YACD,OAAO,aAAa,CAAC;QACvB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAE5C,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,IAAS,EAAE,EAAE;YACtD,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;gBACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC/B,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;gBACrD,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACjD,OAAO,eAAe,CAAC;YACzB,CAAC;YACD,OAAO,gBAAgB,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAE5C,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;aACb,qBAAqB,CAAC,gBAAgB,CAAC;aACvC,qBAAqB,CAAC,cAAc,CAAC;aACrC,qBAAqB,CAAC,aAAa,CAAC,CAAC;QAExC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;aAChB,qBAAqB,CAAC,qBAAqB,CAAC,CAAI,sBAAsB;aACtE,qBAAqB,CAAC,cAAc,CAAC,CAAY,sBAAsB;aACvE,qBAAqB,CAAC,yBAAyB,CAAC,CAAC,CAAC,2BAA2B;QAEhF,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAE9D,MAAM,SAAS,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CACpD,CAAC,CAAC,EAAE,EAAE,CAAE,CAAC,CAAC,CAAC,CAAY,CAAC,QAAQ,CAAC,YAAY,CAAC,CAC/C,CAAC;QACF,MAAM,CAAC,SAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAE3C,MAAM,gBAAgB,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAC3D,CAAC,CAAC,EAAE,EAAE,CAAE,CAAC,CAAC,CAAC,CAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CACpD,CAAC;QACF,MAAM,CAAC,gBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/install.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
vi.mock("node:fs/promises", () => ({
|
|
3
|
+
writeFile: vi.fn(),
|
|
4
|
+
mkdir: vi.fn(),
|
|
5
|
+
}));
|
|
6
|
+
vi.mock("../config.js", () => ({
|
|
7
|
+
REGISTRY_URL: "http://localhost:3000",
|
|
8
|
+
}));
|
|
9
|
+
import { installCommand } from "../commands/install.js";
|
|
10
|
+
import { writeFile, mkdir } from "node:fs/promises";
|
|
11
|
+
class ExitError extends Error {
|
|
12
|
+
code;
|
|
13
|
+
constructor(code) {
|
|
14
|
+
super(`process.exit(${code})`);
|
|
15
|
+
this.code = code;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
vi.clearAllMocks();
|
|
20
|
+
vi.spyOn(console, "log").mockImplementation(() => { });
|
|
21
|
+
vi.spyOn(process, "exit").mockImplementation((code) => {
|
|
22
|
+
throw new ExitError(code);
|
|
23
|
+
});
|
|
24
|
+
vi.stubGlobal("fetch", vi.fn());
|
|
25
|
+
});
|
|
26
|
+
const fullSkillResponse = {
|
|
27
|
+
name: "@test/my-skill",
|
|
28
|
+
version: "1.0.0",
|
|
29
|
+
manifest: { name: "@test/my-skill", version: "1.0.0" },
|
|
30
|
+
tools: { tools: [{ name: "test_tool" }] },
|
|
31
|
+
instructions: "You are a test assistant.",
|
|
32
|
+
adapters: { openai: { platform: "openai" } },
|
|
33
|
+
verified: true,
|
|
34
|
+
};
|
|
35
|
+
function mockFetchResponse(status, body) {
|
|
36
|
+
vi.mocked(fetch).mockResolvedValue({
|
|
37
|
+
ok: status >= 200 && status < 300,
|
|
38
|
+
status,
|
|
39
|
+
statusText: status === 404 ? "Not Found" : "Internal Server Error",
|
|
40
|
+
json: () => Promise.resolve(body),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
describe("install command", () => {
|
|
44
|
+
it("writes all files when skill has tools, instructions, and adapters", async () => {
|
|
45
|
+
mockFetchResponse(200, fullSkillResponse);
|
|
46
|
+
await installCommand.parseAsync(["@test/my-skill", "--output", "/tmp/output"], { from: "user" });
|
|
47
|
+
// skill.json
|
|
48
|
+
expect(writeFile).toHaveBeenCalledWith(expect.stringContaining("skill.json"), expect.any(String));
|
|
49
|
+
// tools.json
|
|
50
|
+
expect(writeFile).toHaveBeenCalledWith(expect.stringContaining("tools.json"), expect.any(String));
|
|
51
|
+
// instructions.md
|
|
52
|
+
expect(writeFile).toHaveBeenCalledWith(expect.stringContaining("instructions.md"), "You are a test assistant.");
|
|
53
|
+
// adapter output in dist/
|
|
54
|
+
expect(writeFile).toHaveBeenCalledWith(expect.stringContaining("dist/openai.json"), expect.any(String));
|
|
55
|
+
// dist directory created
|
|
56
|
+
expect(mkdir).toHaveBeenCalledWith(expect.stringContaining("dist"), { recursive: true });
|
|
57
|
+
});
|
|
58
|
+
it("writes only skill.json when skill has no tools/instructions/adapters", async () => {
|
|
59
|
+
mockFetchResponse(200, {
|
|
60
|
+
name: "@test/minimal",
|
|
61
|
+
version: "1.0.0",
|
|
62
|
+
manifest: { name: "@test/minimal" },
|
|
63
|
+
tools: null,
|
|
64
|
+
instructions: null,
|
|
65
|
+
adapters: null,
|
|
66
|
+
verified: true,
|
|
67
|
+
});
|
|
68
|
+
await installCommand.parseAsync(["@test/minimal", "--output", "/tmp/output"], { from: "user" });
|
|
69
|
+
// Only skill.json should be written
|
|
70
|
+
expect(writeFile).toHaveBeenCalledTimes(1);
|
|
71
|
+
expect(writeFile).toHaveBeenCalledWith(expect.stringContaining("skill.json"), expect.any(String));
|
|
72
|
+
});
|
|
73
|
+
it("shows green badge for verified skills", async () => {
|
|
74
|
+
mockFetchResponse(200, { ...fullSkillResponse, verified: true });
|
|
75
|
+
await installCommand.parseAsync(["@test/my-skill", "--output", "/tmp/output"], { from: "user" });
|
|
76
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("verified"));
|
|
77
|
+
// Should NOT print the unverified warning
|
|
78
|
+
const calls = vi.mocked(console.log).mock.calls.map((c) => String(c[0]));
|
|
79
|
+
const warningCall = calls.find((c) => c.includes("Warning"));
|
|
80
|
+
expect(warningCall).toBeUndefined();
|
|
81
|
+
});
|
|
82
|
+
it("shows yellow badge and warning for unverified skills", async () => {
|
|
83
|
+
mockFetchResponse(200, { ...fullSkillResponse, verified: false });
|
|
84
|
+
await installCommand.parseAsync(["@test/my-skill", "--output", "/tmp/output"], { from: "user" });
|
|
85
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("unverified"));
|
|
86
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("Warning"));
|
|
87
|
+
});
|
|
88
|
+
it("prints error and exits on 404", async () => {
|
|
89
|
+
mockFetchResponse(404, {});
|
|
90
|
+
await expect(installCommand.parseAsync(["@test/nonexistent", "--output", "/tmp/output"], { from: "user" })).rejects.toThrow(ExitError);
|
|
91
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("Skill not found"));
|
|
92
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
93
|
+
});
|
|
94
|
+
it("prints error and exits on 500", async () => {
|
|
95
|
+
mockFetchResponse(500, {});
|
|
96
|
+
await expect(installCommand.parseAsync(["@test/my-skill", "--output", "/tmp/output"], { from: "user" })).rejects.toThrow(ExitError);
|
|
97
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("Failed to fetch"));
|
|
98
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
99
|
+
});
|
|
100
|
+
it("creates directory with scoped name replacing / with __", async () => {
|
|
101
|
+
mockFetchResponse(200, fullSkillResponse);
|
|
102
|
+
await installCommand.parseAsync(["@test/my-skill", "--output", "/tmp/output"], { from: "user" });
|
|
103
|
+
// Should create skills/@test__my-skill directory
|
|
104
|
+
expect(mkdir).toHaveBeenCalledWith(expect.stringContaining("@test__my-skill"), { recursive: true });
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
//# sourceMappingURL=install.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.test.js","sourceRoot":"","sources":["../../src/__tests__/install.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/publish.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
vi.mock("@skillstore/core", () => ({
|
|
3
|
+
loadSkill: vi.fn(),
|
|
4
|
+
getAdapter: vi.fn(),
|
|
5
|
+
}));
|
|
6
|
+
vi.mock("../config.js", () => ({
|
|
7
|
+
REGISTRY_URL: "http://localhost:3000",
|
|
8
|
+
}));
|
|
9
|
+
import { publishCommand } from "../commands/publish.js";
|
|
10
|
+
import { loadSkill, getAdapter } from "@skillstore/core";
|
|
11
|
+
import { mockSkill, mockTranspileResult } from "./fixtures.js";
|
|
12
|
+
class ExitError extends Error {
|
|
13
|
+
code;
|
|
14
|
+
constructor(code) {
|
|
15
|
+
super(`process.exit(${code})`);
|
|
16
|
+
this.code = code;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
vi.clearAllMocks();
|
|
21
|
+
vi.spyOn(console, "log").mockImplementation(() => { });
|
|
22
|
+
vi.spyOn(process, "exit").mockImplementation((code) => {
|
|
23
|
+
throw new ExitError(code);
|
|
24
|
+
});
|
|
25
|
+
vi.stubGlobal("fetch", vi.fn());
|
|
26
|
+
});
|
|
27
|
+
function mockFetchResponse(status, body) {
|
|
28
|
+
vi.mocked(fetch).mockResolvedValue({
|
|
29
|
+
ok: status >= 200 && status < 300,
|
|
30
|
+
status,
|
|
31
|
+
statusText: status === 500 ? "Internal Server Error" : "Error",
|
|
32
|
+
json: () => Promise.resolve(body),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
describe("publish command", () => {
|
|
36
|
+
it("prints success on 201 response", async () => {
|
|
37
|
+
vi.mocked(loadSkill).mockResolvedValue(mockSkill);
|
|
38
|
+
vi.mocked(getAdapter).mockReturnValue({
|
|
39
|
+
name: "openai",
|
|
40
|
+
transpile: vi.fn().mockReturnValue(mockTranspileResult),
|
|
41
|
+
});
|
|
42
|
+
mockFetchResponse(201, { id: "test-uuid" });
|
|
43
|
+
await publishCommand.parseAsync(["/tmp/test-skill"], { from: "user" });
|
|
44
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("Published @test/my-skill@1.0.0"));
|
|
45
|
+
expect(process.exit).not.toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
it("prints error and exits on 409 conflict", async () => {
|
|
48
|
+
vi.mocked(loadSkill).mockResolvedValue(mockSkill);
|
|
49
|
+
vi.mocked(getAdapter).mockReturnValue(null);
|
|
50
|
+
mockFetchResponse(409, { error: "Conflict", message: "Version already exists" });
|
|
51
|
+
await expect(publishCommand.parseAsync(["/tmp/test-skill"], { from: "user" })).rejects.toThrow(ExitError);
|
|
52
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("Publish failed"));
|
|
53
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
54
|
+
});
|
|
55
|
+
it("prints details array on 400 response", async () => {
|
|
56
|
+
vi.mocked(loadSkill).mockResolvedValue(mockSkill);
|
|
57
|
+
vi.mocked(getAdapter).mockReturnValue(null);
|
|
58
|
+
mockFetchResponse(400, {
|
|
59
|
+
error: "Bad Request",
|
|
60
|
+
message: "Invalid manifest",
|
|
61
|
+
details: ["missing name", "missing version"],
|
|
62
|
+
});
|
|
63
|
+
await expect(publishCommand.parseAsync(["/tmp/test-skill"], { from: "user" })).rejects.toThrow(ExitError);
|
|
64
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("missing name"));
|
|
65
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("missing version"));
|
|
66
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
67
|
+
});
|
|
68
|
+
it("prints error and exits on 500 response", async () => {
|
|
69
|
+
vi.mocked(loadSkill).mockResolvedValue(mockSkill);
|
|
70
|
+
vi.mocked(getAdapter).mockReturnValue(null);
|
|
71
|
+
mockFetchResponse(500, { message: "Internal Server Error" });
|
|
72
|
+
await expect(publishCommand.parseAsync(["/tmp/test-skill"], { from: "user" })).rejects.toThrow(ExitError);
|
|
73
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("Publish failed"));
|
|
74
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
75
|
+
});
|
|
76
|
+
it("sends correct request body to registry", async () => {
|
|
77
|
+
vi.mocked(loadSkill).mockResolvedValue(mockSkill);
|
|
78
|
+
vi.mocked(getAdapter).mockReturnValue({
|
|
79
|
+
name: "openai",
|
|
80
|
+
transpile: vi.fn().mockReturnValue(mockTranspileResult),
|
|
81
|
+
});
|
|
82
|
+
mockFetchResponse(201, { id: "test-uuid" });
|
|
83
|
+
await publishCommand.parseAsync(["/tmp/test-skill"], { from: "user" });
|
|
84
|
+
expect(fetch).toHaveBeenCalledWith("http://localhost:3000/api/skills", expect.objectContaining({
|
|
85
|
+
method: "POST",
|
|
86
|
+
headers: { "Content-Type": "application/json" },
|
|
87
|
+
}));
|
|
88
|
+
const callBody = JSON.parse(vi.mocked(fetch).mock.calls[0][1].body);
|
|
89
|
+
expect(callBody.manifest).toEqual(mockSkill.manifest);
|
|
90
|
+
expect(callBody.tools).toEqual({ tools: mockSkill.tools });
|
|
91
|
+
expect(callBody.instructions).toBe("You are a test assistant.");
|
|
92
|
+
expect(callBody.adapters).toBeDefined();
|
|
93
|
+
});
|
|
94
|
+
it("prints error and exits when loadSkill fails", async () => {
|
|
95
|
+
vi.mocked(loadSkill).mockRejectedValue(new Error("File not found"));
|
|
96
|
+
await expect(publishCommand.parseAsync(["/tmp/bad-skill"], { from: "user" })).rejects.toThrow(ExitError);
|
|
97
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("File not found"));
|
|
98
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
99
|
+
expect(fetch).not.toHaveBeenCalled();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=publish.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.test.js","sourceRoot":"","sources":["../../src/__tests__/publish.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/validate.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
vi.mock("@skillstore/core", () => ({
|
|
3
|
+
loadSkill: vi.fn(),
|
|
4
|
+
}));
|
|
5
|
+
import { validateCommand } from "../commands/validate.js";
|
|
6
|
+
import { loadSkill } from "@skillstore/core";
|
|
7
|
+
import { mockSkill } from "./fixtures.js";
|
|
8
|
+
class ExitError extends Error {
|
|
9
|
+
code;
|
|
10
|
+
constructor(code) {
|
|
11
|
+
super(`process.exit(${code})`);
|
|
12
|
+
this.code = code;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
vi.clearAllMocks();
|
|
17
|
+
vi.spyOn(console, "log").mockImplementation(() => { });
|
|
18
|
+
vi.spyOn(process, "exit").mockImplementation((code) => {
|
|
19
|
+
throw new ExitError(code);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe("validate command", () => {
|
|
23
|
+
it("prints success when loadSkill resolves", async () => {
|
|
24
|
+
vi.mocked(loadSkill).mockResolvedValue(mockSkill);
|
|
25
|
+
await validateCommand.parseAsync(["/tmp/test-skill"], { from: "user" });
|
|
26
|
+
expect(loadSkill).toHaveBeenCalledWith("/tmp/test-skill");
|
|
27
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("All checks passed"));
|
|
28
|
+
expect(process.exit).not.toHaveBeenCalled();
|
|
29
|
+
});
|
|
30
|
+
it("prints error and exits when loadSkill throws", async () => {
|
|
31
|
+
vi.mocked(loadSkill).mockRejectedValue(new Error("Invalid manifest"));
|
|
32
|
+
await expect(validateCommand.parseAsync(["/tmp/bad-skill"], { from: "user" })).rejects.toThrow(ExitError);
|
|
33
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("Invalid manifest"));
|
|
34
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
35
|
+
});
|
|
36
|
+
it("resolves relative directory to absolute path", async () => {
|
|
37
|
+
vi.mocked(loadSkill).mockResolvedValue(mockSkill);
|
|
38
|
+
await validateCommand.parseAsync(["my-skill"], { from: "user" });
|
|
39
|
+
const calledWith = vi.mocked(loadSkill).mock.calls[0][0];
|
|
40
|
+
// Should be an absolute path, not "my-skill"
|
|
41
|
+
expect(calledWith).toMatch(/^\//);
|
|
42
|
+
expect(calledWith).toContain("my-skill");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=validate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.test.js","sourceRoot":"","sources":["../../src/__tests__/validate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,YAAY,SAmCrB,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Build flow state machine:
|
|
3
|
+
*
|
|
4
|
+
* LOAD_SKILL ──→ CREATE_DIST ──→ TRANSPILE_EACH ──→ SUCCESS
|
|
5
|
+
* │ │ │
|
|
6
|
+
* ▼ ▼ ▼
|
|
7
|
+
* LOAD_ERR DIR_ERR WRITE_ERR
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from "commander";
|
|
10
|
+
import { writeFile, mkdir } from "node:fs/promises";
|
|
11
|
+
import { join, resolve } from "node:path";
|
|
12
|
+
import chalk from "chalk";
|
|
13
|
+
import { loadSkill, getAdapter } from "@polyskill/core";
|
|
14
|
+
export const buildCommand = new Command("build")
|
|
15
|
+
.description("Build platform-specific adapter outputs")
|
|
16
|
+
.argument("[directory]", "Skill directory to build", ".")
|
|
17
|
+
.action(async (directory) => {
|
|
18
|
+
const skillDir = resolve(process.cwd(), directory);
|
|
19
|
+
console.log(chalk.bold("\nBuilding skill..."));
|
|
20
|
+
try {
|
|
21
|
+
// Load and validate skill
|
|
22
|
+
const skill = await loadSkill(skillDir);
|
|
23
|
+
const distDir = join(skillDir, "dist");
|
|
24
|
+
await mkdir(distDir, { recursive: true });
|
|
25
|
+
const adapters = skill.manifest.adapters;
|
|
26
|
+
for (const platform of adapters) {
|
|
27
|
+
const adapter = getAdapter(platform);
|
|
28
|
+
if (!adapter) {
|
|
29
|
+
console.log(chalk.yellow(` Skipping unknown adapter: ${platform}`));
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const result = adapter.transpile(skill);
|
|
33
|
+
const outputPath = join(distDir, `${platform}.json`);
|
|
34
|
+
await writeFile(outputPath, JSON.stringify(result, null, 2));
|
|
35
|
+
console.log(chalk.green(` Built ${platform} → ${outputPath}`));
|
|
36
|
+
}
|
|
37
|
+
console.log(chalk.green("\nBuild complete.\n"));
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
console.log(chalk.red(`\n${err.message}\n`));
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,yCAAyC,CAAC;KACtD,QAAQ,CAAC,aAAa,EAAE,0BAA0B,EAAE,GAAG,CAAC;KACxD,MAAM,CAAC,KAAK,EAAE,SAAiB,EAAE,EAAE;IAClC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;IAEnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAE/C,IAAI,CAAC;QACH,0BAA0B;QAC1B,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACzC,KAAK,MAAM,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;YACrC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CAAC,+BAA+B,QAAQ,EAAE,CAAC,CACxD,CAAC;gBACF,SAAS;YACX,CAAC;YAED,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACxC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,QAAQ,OAAO,CAAC,CAAC;YACrD,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,QAAQ,MAAM,UAAU,EAAE,CAAC,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyBpC,eAAO,MAAM,WAAW,SAkDpB,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { input } from "@inquirer/prompts";
|
|
3
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
4
|
+
import { join, dirname, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const templatesDir = join(__dirname, "..", "templates");
|
|
9
|
+
async function loadTemplate(name) {
|
|
10
|
+
return readFile(join(templatesDir, `${name}.template`), "utf-8");
|
|
11
|
+
}
|
|
12
|
+
function fillTemplate(template, vars) {
|
|
13
|
+
let result = template;
|
|
14
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
15
|
+
result = result.replaceAll(`{{${key}}}`, value);
|
|
16
|
+
}
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
export const initCommand = new Command("init")
|
|
20
|
+
.description("Scaffold a new Skill project")
|
|
21
|
+
.argument("[directory]", "Directory to create the skill in", ".")
|
|
22
|
+
.action(async (directory) => {
|
|
23
|
+
console.log(chalk.bold("\nSkillStore — Create a new Skill\n"));
|
|
24
|
+
const skillName = await input({
|
|
25
|
+
message: "Skill name (e.g. @yourname/my-skill):",
|
|
26
|
+
validate: (val) => /^@[a-z0-9-]+\/[a-z0-9-]+$/.test(val) ||
|
|
27
|
+
"Must be scoped: @scope/name (lowercase, hyphens)",
|
|
28
|
+
});
|
|
29
|
+
const description = await input({
|
|
30
|
+
message: "Description:",
|
|
31
|
+
validate: (val) => val.length > 0 || "Description is required",
|
|
32
|
+
});
|
|
33
|
+
const authorName = await input({
|
|
34
|
+
message: "Author name:",
|
|
35
|
+
validate: (val) => val.length > 0 || "Author name is required",
|
|
36
|
+
});
|
|
37
|
+
const targetDir = resolve(process.cwd(), directory);
|
|
38
|
+
await mkdir(targetDir, { recursive: true });
|
|
39
|
+
const vars = { name: skillName, description, authorName };
|
|
40
|
+
// Write skill.json
|
|
41
|
+
const manifestTemplate = await loadTemplate("skill.json");
|
|
42
|
+
await writeFile(join(targetDir, "skill.json"), fillTemplate(manifestTemplate, vars));
|
|
43
|
+
// Write tools.json
|
|
44
|
+
const toolsTemplate = await loadTemplate("tools.json");
|
|
45
|
+
await writeFile(join(targetDir, "tools.json"), toolsTemplate);
|
|
46
|
+
// Write instructions.md
|
|
47
|
+
const instructionsTemplate = await loadTemplate("instructions.md");
|
|
48
|
+
await writeFile(join(targetDir, "instructions.md"), instructionsTemplate);
|
|
49
|
+
console.log(chalk.green("\nSkill scaffolded successfully!"));
|
|
50
|
+
console.log(` ${chalk.dim(join(targetDir, "skill.json"))}`);
|
|
51
|
+
console.log(` ${chalk.dim(join(targetDir, "tools.json"))}`);
|
|
52
|
+
console.log(` ${chalk.dim(join(targetDir, "instructions.md"))}`);
|
|
53
|
+
console.log(`\nNext steps:\n 1. Edit tools.json with your tool definitions\n 2. Edit instructions.md with your system prompt\n 3. Run ${chalk.cyan("skillstore validate")} to check\n 4. Run ${chalk.cyan("skillstore build")} to generate adapters\n`);
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,cAAc,SA2GxB,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Install flow state machine:
|
|
3
|
+
*
|
|
4
|
+
* FETCH_REGISTRY ──→ CREATE_DIRS ──→ WRITE_FILES ──→ SUCCESS
|
|
5
|
+
* │
|
|
6
|
+
* ├──→ NOT_FOUND / HTTP_ERR
|
|
7
|
+
* │
|
|
8
|
+
* ▼
|
|
9
|
+
* NETWORK_ERR (DNS / timeout / refused)
|
|
10
|
+
*/
|
|
11
|
+
import { Command } from "commander";
|
|
12
|
+
import { writeFile, mkdir } from "node:fs/promises";
|
|
13
|
+
import { join, resolve } from "node:path";
|
|
14
|
+
import chalk from "chalk";
|
|
15
|
+
import { REGISTRY_URL } from "../config.js";
|
|
16
|
+
export const installCommand = new Command("install")
|
|
17
|
+
.description("Install a Skill from the SkillStore registry")
|
|
18
|
+
.argument("<name>", "Skill name (e.g. @author/skill-name)")
|
|
19
|
+
.argument("[version]", "Specific version (defaults to latest)")
|
|
20
|
+
.option("--registry <url>", "Registry URL", REGISTRY_URL)
|
|
21
|
+
.option("-o, --output <dir>", "Output directory", ".")
|
|
22
|
+
.action(async (name, version, options) => {
|
|
23
|
+
const registryUrl = options.registry;
|
|
24
|
+
const outputDir = resolve(process.cwd(), options.output);
|
|
25
|
+
console.log(chalk.bold(`\nInstalling ${name}${version ? `@${version}` : ""}...`));
|
|
26
|
+
// Fetch from registry
|
|
27
|
+
const encodedName = encodeURIComponent(name);
|
|
28
|
+
const url = version
|
|
29
|
+
? `${registryUrl}/api/skills/${encodedName}/${version}`
|
|
30
|
+
: `${registryUrl}/api/skills/${encodedName}`;
|
|
31
|
+
let res;
|
|
32
|
+
try {
|
|
33
|
+
res = await fetch(url, { signal: AbortSignal.timeout(30_000) });
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
const msg = err.name === "TimeoutError"
|
|
37
|
+
? "Request timed out — is the registry running?"
|
|
38
|
+
: `Network error: ${err.message}`;
|
|
39
|
+
console.log(chalk.red(`\n${msg}\n`));
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
if (!res.ok) {
|
|
43
|
+
if (res.status === 404) {
|
|
44
|
+
console.log(chalk.red(`\nSkill not found: ${name}`));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log(chalk.red(`\nFailed to fetch skill: ${res.statusText}`));
|
|
48
|
+
}
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
const skill = (await res.json());
|
|
52
|
+
// Track download (fire-and-forget for the user, but await for correctness)
|
|
53
|
+
try {
|
|
54
|
+
await fetch(`${registryUrl}/api/skills/${encodedName}/download`, {
|
|
55
|
+
method: "POST",
|
|
56
|
+
signal: AbortSignal.timeout(5_000),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch (_) {
|
|
60
|
+
// Non-critical — don't block the install
|
|
61
|
+
}
|
|
62
|
+
// Create skill directory
|
|
63
|
+
const skillDir = join(outputDir, "skills", skill.name.replaceAll("/", "__"));
|
|
64
|
+
await mkdir(skillDir, { recursive: true });
|
|
65
|
+
// Write manifest
|
|
66
|
+
await writeFile(join(skillDir, "skill.json"), JSON.stringify(skill.manifest, null, 2));
|
|
67
|
+
// Write tools if present
|
|
68
|
+
if (skill.tools) {
|
|
69
|
+
await writeFile(join(skillDir, "tools.json"), JSON.stringify(skill.tools, null, 2));
|
|
70
|
+
}
|
|
71
|
+
// Write instructions if present
|
|
72
|
+
if (skill.instructions) {
|
|
73
|
+
await writeFile(join(skillDir, "instructions.md"), skill.instructions);
|
|
74
|
+
}
|
|
75
|
+
// Write adapter outputs
|
|
76
|
+
const adapterEntries = skill.adapters && typeof skill.adapters === "object"
|
|
77
|
+
? Object.entries(skill.adapters)
|
|
78
|
+
: [];
|
|
79
|
+
if (adapterEntries.length > 0) {
|
|
80
|
+
const distDir = join(skillDir, "dist");
|
|
81
|
+
await mkdir(distDir, { recursive: true });
|
|
82
|
+
for (const [platform, output] of adapterEntries) {
|
|
83
|
+
await writeFile(join(distDir, `${platform}.json`), JSON.stringify(output, null, 2));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const badge = skill.verified
|
|
87
|
+
? chalk.green("[verified]")
|
|
88
|
+
: chalk.yellow("[unverified]");
|
|
89
|
+
console.log(chalk.green(`\nInstalled ${skill.name}@${skill.version}`) + ` ${badge}`);
|
|
90
|
+
if (!skill.verified) {
|
|
91
|
+
console.log(chalk.yellow(" Warning: This skill has not been verified"));
|
|
92
|
+
}
|
|
93
|
+
console.log(chalk.dim(` Location: ${skillDir}`));
|
|
94
|
+
console.log();
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,eAAO,MAAM,cAAc,SA8EvB,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Publish flow state machine:
|
|
3
|
+
*
|
|
4
|
+
* LOAD_SKILL ──→ BUILD_ADAPTERS ──→ POST_REGISTRY ──→ SUCCESS
|
|
5
|
+
* │ │
|
|
6
|
+
* ▼ ├──→ HTTP_ERR (409 / 400 / 5xx)
|
|
7
|
+
* LOAD_ERR │
|
|
8
|
+
* ▼
|
|
9
|
+
* NETWORK_ERR (DNS / timeout / refused)
|
|
10
|
+
*/
|
|
11
|
+
import { Command } from "commander";
|
|
12
|
+
import { resolve } from "node:path";
|
|
13
|
+
import chalk from "chalk";
|
|
14
|
+
import { loadSkill, getAdapter } from "@polyskill/core";
|
|
15
|
+
import { REGISTRY_URL } from "../config.js";
|
|
16
|
+
export const publishCommand = new Command("publish")
|
|
17
|
+
.description("Publish a Skill to the SkillStore registry")
|
|
18
|
+
.argument("[directory]", "Skill directory to publish", ".")
|
|
19
|
+
.option("--registry <url>", "Registry URL", REGISTRY_URL)
|
|
20
|
+
.action(async (directory, options) => {
|
|
21
|
+
const skillDir = resolve(process.cwd(), directory);
|
|
22
|
+
const registryUrl = options.registry;
|
|
23
|
+
console.log(chalk.bold("\nPublishing skill..."));
|
|
24
|
+
// Load and validate skill
|
|
25
|
+
let skill;
|
|
26
|
+
try {
|
|
27
|
+
skill = await loadSkill(skillDir);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
console.log(chalk.red(`\n${err.message}\n`));
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
// Build adapter outputs
|
|
34
|
+
const adapters = {};
|
|
35
|
+
for (const platform of skill.manifest.adapters) {
|
|
36
|
+
const adapter = getAdapter(platform);
|
|
37
|
+
if (adapter) {
|
|
38
|
+
adapters[platform] = adapter.transpile(skill);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Publish to registry
|
|
42
|
+
const body = {
|
|
43
|
+
manifest: skill.manifest,
|
|
44
|
+
tools: skill.tools.length > 0 ? { tools: skill.tools } : null,
|
|
45
|
+
instructions: skill.instructions,
|
|
46
|
+
adapters,
|
|
47
|
+
};
|
|
48
|
+
let res;
|
|
49
|
+
try {
|
|
50
|
+
res = await fetch(`${registryUrl}/api/skills`, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: { "Content-Type": "application/json" },
|
|
53
|
+
body: JSON.stringify(body),
|
|
54
|
+
signal: AbortSignal.timeout(30_000),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
const msg = err.name === "TimeoutError"
|
|
59
|
+
? "Request timed out — is the registry running?"
|
|
60
|
+
: `Network error: ${err.message}`;
|
|
61
|
+
console.log(chalk.red(`\n${msg}\n`));
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
if (!res.ok) {
|
|
65
|
+
const error = await res.json().catch(() => ({ message: res.statusText }));
|
|
66
|
+
console.log(chalk.red(`\nPublish failed: ${error.error || error.message}`));
|
|
67
|
+
if (error.details) {
|
|
68
|
+
for (const detail of error.details) {
|
|
69
|
+
console.log(chalk.red(` - ${detail}`));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
const result = await res.json();
|
|
75
|
+
console.log(chalk.green(`\nPublished ${skill.manifest.name}@${skill.manifest.version}`));
|
|
76
|
+
console.log(chalk.dim(` ID: ${result.id}`));
|
|
77
|
+
console.log(chalk.dim(` Registry: ${registryUrl}`));
|
|
78
|
+
console.log(`\nInstall with: ${chalk.cyan(`skillstore install ${skill.manifest.name}`)}\n`);
|
|
79
|
+
});
|
|
80
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,eAAe,SAaxB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { loadSkill } from "@polyskill/core";
|
|
5
|
+
export const validateCommand = new Command("validate")
|
|
6
|
+
.description("Validate a Skill project")
|
|
7
|
+
.argument("[directory]", "Skill directory to validate", ".")
|
|
8
|
+
.action(async (directory) => {
|
|
9
|
+
const skillDir = resolve(process.cwd(), directory);
|
|
10
|
+
try {
|
|
11
|
+
await loadSkill(skillDir);
|
|
12
|
+
console.log(chalk.green("\nAll checks passed.\n"));
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
console.log(chalk.red(`\n${err.message}\n`));
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC;KACnD,WAAW,CAAC,0BAA0B,CAAC;KACvC,QAAQ,CAAC,aAAa,EAAE,6BAA6B,EAAE,GAAG,CAAC;KAC3D,MAAM,CAAC,KAAK,EAAE,SAAiB,EAAE,EAAE;IAClC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;IAEnD,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,eAAO,MAAM,YAAY,QACgE,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,MAAM,CAAC,MAAM,YAAY,GACvB,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,oDAAoD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { initCommand } from "./commands/init.js";
|
|
4
|
+
import { validateCommand } from "./commands/validate.js";
|
|
5
|
+
import { buildCommand } from "./commands/build.js";
|
|
6
|
+
import { publishCommand } from "./commands/publish.js";
|
|
7
|
+
import { installCommand } from "./commands/install.js";
|
|
8
|
+
const program = new Command();
|
|
9
|
+
program
|
|
10
|
+
.name("skillstore")
|
|
11
|
+
.description("CLI for the SkillStore marketplace")
|
|
12
|
+
.version("0.1.0");
|
|
13
|
+
program.addCommand(initCommand);
|
|
14
|
+
program.addCommand(validateCommand);
|
|
15
|
+
program.addCommand(buildCommand);
|
|
16
|
+
program.addCommand(publishCommand);
|
|
17
|
+
program.addCommand(installCommand);
|
|
18
|
+
program.parse();
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,oCAAoC,CAAC;KACjD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AAEnC,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
You are a helpful assistant with access to the tools defined in this skill. Use them when appropriate to fulfill user requests.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "{{description}}",
|
|
5
|
+
"type": "tool",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": {
|
|
8
|
+
"name": "{{authorName}}"
|
|
9
|
+
},
|
|
10
|
+
"main": "./src/index.ts",
|
|
11
|
+
"skill": {
|
|
12
|
+
"instructions": "./instructions.md",
|
|
13
|
+
"tools": "./tools.json"
|
|
14
|
+
},
|
|
15
|
+
"adapters": ["openai", "anthropic"],
|
|
16
|
+
"keywords": []
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
You are a helpful assistant with access to the tools defined in this skill. Use them when appropriate to fulfill user requests.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "{{description}}",
|
|
5
|
+
"type": "tool",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": {
|
|
8
|
+
"name": "{{authorName}}"
|
|
9
|
+
},
|
|
10
|
+
"main": "./src/index.ts",
|
|
11
|
+
"skill": {
|
|
12
|
+
"instructions": "./instructions.md",
|
|
13
|
+
"tools": "./tools.json"
|
|
14
|
+
},
|
|
15
|
+
"adapters": ["openai", "anthropic"],
|
|
16
|
+
"keywords": []
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tools": [
|
|
3
|
+
{
|
|
4
|
+
"name": "example_tool",
|
|
5
|
+
"description": "An example tool — replace with your own",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"input": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Example input parameter"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"required": ["input"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tools": [
|
|
3
|
+
{
|
|
4
|
+
"name": "example_tool",
|
|
5
|
+
"description": "An example tool — replace with your own",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"input": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Example input parameter"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"required": ["input"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@polyskill/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for creating, validating, and publishing SkillStore skills",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"skillstore": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc && cp -r src/templates dist/templates",
|
|
13
|
+
"dev": "tsx src/index.ts",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@polyskill/core": "workspace:*",
|
|
19
|
+
"commander": "^13.0.0",
|
|
20
|
+
"chalk": "^5.4.0",
|
|
21
|
+
"@inquirer/prompts": "^7.0.0"
|
|
22
|
+
},
|
|
23
|
+
"files": ["dist"],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"typescript": "^5.7.0",
|
|
29
|
+
"tsx": "^4.19.0",
|
|
30
|
+
"@types/node": "^22.0.0",
|
|
31
|
+
"vitest": "^3.0.0"
|
|
32
|
+
}
|
|
33
|
+
}
|