@dhruvwill/skills-cli 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -72
- package/_config.yml +9 -0
- package/index.ts +1 -1
- package/package.json +1 -1
- package/src/cli.ts +57 -28
- package/src/commands/doctor.ts +4 -4
- package/src/commands/source.ts +41 -36
- package/src/commands/status.ts +5 -5
- package/src/commands/target.ts +72 -5
- package/src/commands/update.ts +12 -12
- package/src/lib/config.ts +67 -6
- package/src/lib/known-targets.ts +77 -0
- package/src/lib/paths.ts +11 -14
- package/src/types.ts +2 -2
- package/tests/cli.test.ts +40 -24
- package/tests/paths.test.ts +11 -11
package/tests/cli.test.ts
CHANGED
|
@@ -15,15 +15,23 @@ describe("CLI Integration Tests", () => {
|
|
|
15
15
|
let testDir: string;
|
|
16
16
|
let testSourceDir: string;
|
|
17
17
|
let testTargetDir: string;
|
|
18
|
+
let uniqueId: string;
|
|
19
|
+
let testSkillName: string;
|
|
20
|
+
let testTargetName: string;
|
|
18
21
|
|
|
19
22
|
beforeAll(async () => {
|
|
23
|
+
// Generate unique IDs for this test run to avoid conflicts
|
|
24
|
+
uniqueId = Date.now().toString(36);
|
|
25
|
+
testSkillName = `test-skill-${uniqueId}`;
|
|
26
|
+
testTargetName = `test-target-${uniqueId}`;
|
|
27
|
+
|
|
20
28
|
// Create a master test directory
|
|
21
|
-
testDir = join(tmpdir(), `skills-integration-${
|
|
29
|
+
testDir = join(tmpdir(), `skills-integration-${uniqueId}`);
|
|
22
30
|
await mkdir(testDir, { recursive: true });
|
|
23
31
|
|
|
24
|
-
// Create test subdirectories
|
|
25
|
-
testSourceDir = join(testDir,
|
|
26
|
-
testTargetDir = join(testDir,
|
|
32
|
+
// Create test subdirectories with unique names
|
|
33
|
+
testSourceDir = join(testDir, testSkillName);
|
|
34
|
+
testTargetDir = join(testDir, testTargetName);
|
|
27
35
|
|
|
28
36
|
await mkdir(testSourceDir, { recursive: true });
|
|
29
37
|
await mkdir(testTargetDir, { recursive: true });
|
|
@@ -36,6 +44,14 @@ describe("CLI Integration Tests", () => {
|
|
|
36
44
|
afterAll(async () => {
|
|
37
45
|
// Clean up test directory
|
|
38
46
|
await rm(testDir, { recursive: true, force: true });
|
|
47
|
+
|
|
48
|
+
// Also clean up any leftover skills/targets from failed tests
|
|
49
|
+
try {
|
|
50
|
+
await $`bun run src/cli.ts source remove ${testSkillName}`.quiet();
|
|
51
|
+
} catch {}
|
|
52
|
+
try {
|
|
53
|
+
await $`bun run src/cli.ts target remove ${testTargetName}`.quiet();
|
|
54
|
+
} catch {}
|
|
39
55
|
});
|
|
40
56
|
|
|
41
57
|
describe("Local Source Management", () => {
|
|
@@ -43,28 +59,28 @@ describe("CLI Integration Tests", () => {
|
|
|
43
59
|
const result = await $`bun run src/cli.ts source add ${testSourceDir} --local`.text();
|
|
44
60
|
|
|
45
61
|
expect(result).toContain("Adding local source");
|
|
46
|
-
expect(result).toContain("Successfully added
|
|
62
|
+
expect(result).toContain("Successfully added skill");
|
|
47
63
|
});
|
|
48
64
|
|
|
49
65
|
test("lists the added source", async () => {
|
|
50
66
|
const result = await $`bun run src/cli.ts source list`.text();
|
|
51
67
|
|
|
52
|
-
expect(result).toContain(
|
|
68
|
+
expect(result).toContain(testSkillName);
|
|
53
69
|
expect(result).toContain("local");
|
|
54
70
|
expect(result).toContain("OK");
|
|
55
71
|
});
|
|
56
72
|
|
|
57
73
|
test("can remove the source", async () => {
|
|
58
|
-
const result = await $`bun run src/cli.ts source remove
|
|
74
|
+
const result = await $`bun run src/cli.ts source remove ${testSkillName}`.text();
|
|
59
75
|
|
|
60
|
-
expect(result).toContain("Removed
|
|
76
|
+
expect(result).toContain("Removed skill");
|
|
61
77
|
});
|
|
62
78
|
|
|
63
79
|
test("source is no longer listed", async () => {
|
|
64
80
|
const result = await $`bun run src/cli.ts source list`.text();
|
|
65
81
|
|
|
66
82
|
// The specific test source should be removed (may have other sources)
|
|
67
|
-
expect(result).not.toContain(
|
|
83
|
+
expect(result).not.toContain(testSkillName);
|
|
68
84
|
});
|
|
69
85
|
});
|
|
70
86
|
|
|
@@ -77,34 +93,34 @@ describe("CLI Integration Tests", () => {
|
|
|
77
93
|
afterEach(async () => {
|
|
78
94
|
// Clean up
|
|
79
95
|
try {
|
|
80
|
-
await $`bun run src/cli.ts target remove
|
|
96
|
+
await $`bun run src/cli.ts target remove ${testTargetName}`.quiet();
|
|
81
97
|
} catch {}
|
|
82
98
|
try {
|
|
83
|
-
await $`bun run src/cli.ts source remove
|
|
99
|
+
await $`bun run src/cli.ts source remove ${testSkillName}`.quiet();
|
|
84
100
|
} catch {}
|
|
85
101
|
});
|
|
86
102
|
|
|
87
103
|
test("can add a target", async () => {
|
|
88
|
-
const result = await $`bun run src/cli.ts target add
|
|
104
|
+
const result = await $`bun run src/cli.ts target add ${testTargetName} ${testTargetDir}`.text();
|
|
89
105
|
|
|
90
|
-
expect(result).toContain(
|
|
106
|
+
expect(result).toContain(`Adding target:`);
|
|
91
107
|
expect(result).toContain("Successfully registered target");
|
|
92
108
|
expect(result).toContain("Performing initial sync");
|
|
93
109
|
});
|
|
94
110
|
|
|
95
111
|
test("lists the added target with sync status", async () => {
|
|
96
|
-
await $`bun run src/cli.ts target add
|
|
112
|
+
await $`bun run src/cli.ts target add ${testTargetName} ${testTargetDir}`.quiet();
|
|
97
113
|
|
|
98
114
|
const result = await $`bun run src/cli.ts target list`.text();
|
|
99
115
|
|
|
100
|
-
expect(result).toContain(
|
|
116
|
+
expect(result).toContain(testTargetName);
|
|
101
117
|
expect(result).toContain("synced");
|
|
102
118
|
});
|
|
103
119
|
|
|
104
120
|
test("can remove the target", async () => {
|
|
105
|
-
await $`bun run src/cli.ts target add
|
|
121
|
+
await $`bun run src/cli.ts target add ${testTargetName} ${testTargetDir}`.quiet();
|
|
106
122
|
|
|
107
|
-
const result = await $`bun run src/cli.ts target remove
|
|
123
|
+
const result = await $`bun run src/cli.ts target remove ${testTargetName}`.text();
|
|
108
124
|
|
|
109
125
|
expect(result).toContain("Removed target");
|
|
110
126
|
});
|
|
@@ -114,15 +130,15 @@ describe("CLI Integration Tests", () => {
|
|
|
114
130
|
beforeEach(async () => {
|
|
115
131
|
// Add source and target
|
|
116
132
|
await $`bun run src/cli.ts source add ${testSourceDir} --local`.quiet();
|
|
117
|
-
await $`bun run src/cli.ts target add
|
|
133
|
+
await $`bun run src/cli.ts target add ${testTargetName} ${testTargetDir}`.quiet();
|
|
118
134
|
});
|
|
119
135
|
|
|
120
136
|
afterEach(async () => {
|
|
121
137
|
try {
|
|
122
|
-
await $`bun run src/cli.ts target remove
|
|
138
|
+
await $`bun run src/cli.ts target remove ${testTargetName}`.quiet();
|
|
123
139
|
} catch {}
|
|
124
140
|
try {
|
|
125
|
-
await $`bun run src/cli.ts source remove
|
|
141
|
+
await $`bun run src/cli.ts source remove ${testSkillName}`.quiet();
|
|
126
142
|
} catch {}
|
|
127
143
|
});
|
|
128
144
|
|
|
@@ -153,7 +169,7 @@ describe("CLI Integration Tests", () => {
|
|
|
153
169
|
|
|
154
170
|
expect(result).toContain("Skills Status");
|
|
155
171
|
expect(result).toContain("Paths");
|
|
156
|
-
expect(result).toContain("
|
|
172
|
+
expect(result).toContain("Skills");
|
|
157
173
|
expect(result).toContain("Targets");
|
|
158
174
|
});
|
|
159
175
|
|
|
@@ -222,12 +238,12 @@ describe("CLI Integration Tests", () => {
|
|
|
222
238
|
}
|
|
223
239
|
});
|
|
224
240
|
|
|
225
|
-
test("target add
|
|
241
|
+
test("target add with unknown name shows helpful error", async () => {
|
|
226
242
|
try {
|
|
227
|
-
await $`bun run src/cli.ts target add
|
|
243
|
+
await $`bun run src/cli.ts target add unknown-tool-xyz`.text();
|
|
228
244
|
expect(true).toBe(false); // Should not reach
|
|
229
245
|
} catch (error: any) {
|
|
230
|
-
expect(error.stderr.toString()).toContain("
|
|
246
|
+
expect(error.stderr.toString()).toContain("Unknown target");
|
|
231
247
|
}
|
|
232
248
|
});
|
|
233
249
|
|
package/tests/paths.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, test, expect } from "bun:test";
|
|
2
|
-
import { parseGitUrl,
|
|
2
|
+
import { parseGitUrl, getDefaultSkillName, getLocalSkillName } from "../src/lib/paths.ts";
|
|
3
3
|
|
|
4
4
|
describe("parseGitUrl", () => {
|
|
5
5
|
describe("GitHub URLs", () => {
|
|
@@ -147,27 +147,27 @@ describe("parseGitUrl", () => {
|
|
|
147
147
|
});
|
|
148
148
|
});
|
|
149
149
|
|
|
150
|
-
describe("
|
|
151
|
-
test("returns
|
|
150
|
+
describe("getDefaultSkillName", () => {
|
|
151
|
+
test("returns repo name for basic URL", () => {
|
|
152
152
|
const parsed = parseGitUrl("https://github.com/owner/repo")!;
|
|
153
|
-
expect(
|
|
153
|
+
expect(getDefaultSkillName(parsed)).toBe("repo");
|
|
154
154
|
});
|
|
155
155
|
|
|
156
|
-
test("returns
|
|
156
|
+
test("returns skill folder name for subdirectory URL", () => {
|
|
157
157
|
const parsed = parseGitUrl("https://github.com/owner/repo/tree/main/skills/my-skill")!;
|
|
158
|
-
expect(
|
|
158
|
+
expect(getDefaultSkillName(parsed)).toBe("my-skill");
|
|
159
159
|
});
|
|
160
160
|
|
|
161
161
|
test("handles nested subdirectories", () => {
|
|
162
162
|
const parsed = parseGitUrl("https://github.com/owner/repo/tree/main/path/to/deep/skill")!;
|
|
163
|
-
expect(
|
|
163
|
+
expect(getDefaultSkillName(parsed)).toBe("skill");
|
|
164
164
|
});
|
|
165
165
|
});
|
|
166
166
|
|
|
167
|
-
describe("
|
|
167
|
+
describe("getLocalSkillName", () => {
|
|
168
168
|
test("extracts folder name from path", () => {
|
|
169
|
-
expect(
|
|
170
|
-
expect(
|
|
171
|
-
expect(
|
|
169
|
+
expect(getLocalSkillName("/home/user/my-skills")).toBe("my-skills");
|
|
170
|
+
expect(getLocalSkillName("C:\\Users\\Admin\\skills")).toBe("skills");
|
|
171
|
+
expect(getLocalSkillName("./relative-path")).toBe("relative-path");
|
|
172
172
|
});
|
|
173
173
|
});
|