claudekit-cli 1.1.0 → 1.2.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/.github/workflows/release.yml +44 -0
- package/CHANGELOG.md +23 -0
- package/CLAUDE.md +3 -9
- package/LICENSE +21 -0
- package/README.md +53 -1
- package/biome.json +1 -1
- package/dist/index.js +14438 -13905
- package/package.json +1 -1
- package/src/commands/new.ts +43 -11
- package/src/commands/update.ts +61 -15
- package/src/index.ts +42 -1
- package/src/lib/download.ts +238 -6
- package/src/lib/github.ts +73 -0
- package/src/lib/prompts.ts +4 -3
- package/src/types.ts +6 -3
- package/src/utils/file-scanner.ts +134 -0
- package/src/utils/logger.ts +108 -21
- package/src/utils/safe-prompts.ts +44 -0
- package/src/utils/safe-spinner.ts +38 -0
- package/tests/commands/version.test.ts +2 -2
- package/tests/lib/github-download-priority.test.ts +432 -0
- package/tests/lib/github.test.ts +2 -2
- package/tests/lib/merge.test.ts +77 -0
- package/tests/types.test.ts +7 -0
- package/tests/utils/file-scanner.test.ts +202 -0
- package/tests/utils/logger.test.ts +115 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { GitHubClient } from "../../src/lib/github.js";
|
|
3
|
+
import type { GitHubRelease } from "../../src/types.js";
|
|
4
|
+
|
|
5
|
+
describe("GitHubClient - Asset Download Priority", () => {
|
|
6
|
+
describe("getDownloadableAsset", () => {
|
|
7
|
+
test("should prioritize ClaudeKit Engineer Package zip file", () => {
|
|
8
|
+
const release: GitHubRelease = {
|
|
9
|
+
id: 1,
|
|
10
|
+
tag_name: "v1.0.0",
|
|
11
|
+
name: "Release 1.0.0",
|
|
12
|
+
draft: false,
|
|
13
|
+
prerelease: false,
|
|
14
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.0.0",
|
|
15
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.0.0",
|
|
16
|
+
assets: [
|
|
17
|
+
{
|
|
18
|
+
id: 1,
|
|
19
|
+
name: "other-file.tar.gz",
|
|
20
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/1",
|
|
21
|
+
browser_download_url: "https://github.com/test/other-file.tar.gz",
|
|
22
|
+
size: 1024,
|
|
23
|
+
content_type: "application/gzip",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: 2,
|
|
27
|
+
name: "ClaudeKit-Engineer-Package.zip",
|
|
28
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/2",
|
|
29
|
+
browser_download_url: "https://github.com/test/claudekit-package.zip",
|
|
30
|
+
size: 2048,
|
|
31
|
+
content_type: "application/zip",
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
37
|
+
|
|
38
|
+
expect(result.type).toBe("asset");
|
|
39
|
+
expect(result.name).toBe("ClaudeKit-Engineer-Package.zip");
|
|
40
|
+
expect(result.url).toBe("https://api.github.com/repos/test/repo/releases/assets/2");
|
|
41
|
+
expect(result.size).toBe(2048);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("should prioritize ClaudeKit Marketing Package zip file", () => {
|
|
45
|
+
const release: GitHubRelease = {
|
|
46
|
+
id: 1,
|
|
47
|
+
tag_name: "v1.0.0",
|
|
48
|
+
name: "Release 1.0.0",
|
|
49
|
+
draft: false,
|
|
50
|
+
prerelease: false,
|
|
51
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.0.0",
|
|
52
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.0.0",
|
|
53
|
+
assets: [
|
|
54
|
+
{
|
|
55
|
+
id: 1,
|
|
56
|
+
name: "random.zip",
|
|
57
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/1",
|
|
58
|
+
browser_download_url: "https://github.com/test/random.zip",
|
|
59
|
+
size: 512,
|
|
60
|
+
content_type: "application/zip",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 2,
|
|
64
|
+
name: "ClaudeKit-Marketing-Package.zip",
|
|
65
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/2",
|
|
66
|
+
browser_download_url: "https://github.com/test/marketing-package.zip",
|
|
67
|
+
size: 2048,
|
|
68
|
+
content_type: "application/zip",
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
74
|
+
|
|
75
|
+
expect(result.type).toBe("asset");
|
|
76
|
+
expect(result.name).toBe("ClaudeKit-Marketing-Package.zip");
|
|
77
|
+
expect(result.url).toBe("https://api.github.com/repos/test/repo/releases/assets/2");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("should match ClaudeKit package case-insensitively", () => {
|
|
81
|
+
const release: GitHubRelease = {
|
|
82
|
+
id: 1,
|
|
83
|
+
tag_name: "v1.0.0",
|
|
84
|
+
name: "Release 1.0.0",
|
|
85
|
+
draft: false,
|
|
86
|
+
prerelease: false,
|
|
87
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.0.0",
|
|
88
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.0.0",
|
|
89
|
+
assets: [
|
|
90
|
+
{
|
|
91
|
+
id: 1,
|
|
92
|
+
name: "claudekit-engineer-package.zip",
|
|
93
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/1",
|
|
94
|
+
browser_download_url: "https://github.com/test/package.zip",
|
|
95
|
+
size: 2048,
|
|
96
|
+
content_type: "application/zip",
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
102
|
+
|
|
103
|
+
expect(result.type).toBe("asset");
|
|
104
|
+
expect(result.name).toBe("claudekit-engineer-package.zip");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("should fallback to other zip files if no ClaudeKit package found", () => {
|
|
108
|
+
const release: GitHubRelease = {
|
|
109
|
+
id: 1,
|
|
110
|
+
tag_name: "v1.0.0",
|
|
111
|
+
name: "Release 1.0.0",
|
|
112
|
+
draft: false,
|
|
113
|
+
prerelease: false,
|
|
114
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.0.0",
|
|
115
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.0.0",
|
|
116
|
+
assets: [
|
|
117
|
+
{
|
|
118
|
+
id: 1,
|
|
119
|
+
name: "release-package.zip",
|
|
120
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/1",
|
|
121
|
+
browser_download_url: "https://github.com/test/release.zip",
|
|
122
|
+
size: 1024,
|
|
123
|
+
content_type: "application/zip",
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
129
|
+
|
|
130
|
+
expect(result.type).toBe("asset");
|
|
131
|
+
expect(result.name).toBe("release-package.zip");
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("should fallback to tar.gz files if no zip found", () => {
|
|
135
|
+
const release: GitHubRelease = {
|
|
136
|
+
id: 1,
|
|
137
|
+
tag_name: "v1.0.0",
|
|
138
|
+
name: "Release 1.0.0",
|
|
139
|
+
draft: false,
|
|
140
|
+
prerelease: false,
|
|
141
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.0.0",
|
|
142
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.0.0",
|
|
143
|
+
assets: [
|
|
144
|
+
{
|
|
145
|
+
id: 1,
|
|
146
|
+
name: "release.tar.gz",
|
|
147
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/1",
|
|
148
|
+
browser_download_url: "https://github.com/test/release.tar.gz",
|
|
149
|
+
size: 1024,
|
|
150
|
+
content_type: "application/gzip",
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
156
|
+
|
|
157
|
+
expect(result.type).toBe("asset");
|
|
158
|
+
expect(result.name).toBe("release.tar.gz");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("should fallback to tgz files", () => {
|
|
162
|
+
const release: GitHubRelease = {
|
|
163
|
+
id: 1,
|
|
164
|
+
tag_name: "v1.0.0",
|
|
165
|
+
name: "Release 1.0.0",
|
|
166
|
+
draft: false,
|
|
167
|
+
prerelease: false,
|
|
168
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.0.0",
|
|
169
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.0.0",
|
|
170
|
+
assets: [
|
|
171
|
+
{
|
|
172
|
+
id: 1,
|
|
173
|
+
name: "release.tgz",
|
|
174
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/1",
|
|
175
|
+
browser_download_url: "https://github.com/test/release.tgz",
|
|
176
|
+
size: 1024,
|
|
177
|
+
content_type: "application/gzip",
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
183
|
+
|
|
184
|
+
expect(result.type).toBe("asset");
|
|
185
|
+
expect(result.name).toBe("release.tgz");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("should fallback to GitHub automatic tarball if no assets", () => {
|
|
189
|
+
const release: GitHubRelease = {
|
|
190
|
+
id: 1,
|
|
191
|
+
tag_name: "v1.0.0",
|
|
192
|
+
name: "Release 1.0.0",
|
|
193
|
+
draft: false,
|
|
194
|
+
prerelease: false,
|
|
195
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.0.0",
|
|
196
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.0.0",
|
|
197
|
+
assets: [],
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
201
|
+
|
|
202
|
+
expect(result.type).toBe("tarball");
|
|
203
|
+
expect(result.url).toBe("https://api.github.com/repos/test/repo/tarball/v1.0.0");
|
|
204
|
+
expect(result.name).toBe("v1.0.0.tar.gz");
|
|
205
|
+
expect(result.size).toBeUndefined();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("should fallback to tarball if assets have no archive files", () => {
|
|
209
|
+
const release: GitHubRelease = {
|
|
210
|
+
id: 1,
|
|
211
|
+
tag_name: "v1.0.0",
|
|
212
|
+
name: "Release 1.0.0",
|
|
213
|
+
draft: false,
|
|
214
|
+
prerelease: false,
|
|
215
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.0.0",
|
|
216
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.0.0",
|
|
217
|
+
assets: [
|
|
218
|
+
{
|
|
219
|
+
id: 1,
|
|
220
|
+
name: "README.md",
|
|
221
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/1",
|
|
222
|
+
browser_download_url: "https://github.com/test/README.md",
|
|
223
|
+
size: 128,
|
|
224
|
+
content_type: "text/markdown",
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
id: 2,
|
|
228
|
+
name: "checksums.txt",
|
|
229
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/2",
|
|
230
|
+
browser_download_url: "https://github.com/test/checksums.txt",
|
|
231
|
+
size: 64,
|
|
232
|
+
content_type: "text/plain",
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
238
|
+
|
|
239
|
+
expect(result.type).toBe("tarball");
|
|
240
|
+
expect(result.url).toBe("https://api.github.com/repos/test/repo/tarball/v1.0.0");
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("should prioritize ClaudeKit package over other archives", () => {
|
|
244
|
+
const release: GitHubRelease = {
|
|
245
|
+
id: 1,
|
|
246
|
+
tag_name: "v1.0.0",
|
|
247
|
+
name: "Release 1.0.0",
|
|
248
|
+
draft: false,
|
|
249
|
+
prerelease: false,
|
|
250
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.0.0",
|
|
251
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.0.0",
|
|
252
|
+
assets: [
|
|
253
|
+
{
|
|
254
|
+
id: 1,
|
|
255
|
+
name: "source.tar.gz",
|
|
256
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/1",
|
|
257
|
+
browser_download_url: "https://github.com/test/source.tar.gz",
|
|
258
|
+
size: 5000,
|
|
259
|
+
content_type: "application/gzip",
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
id: 2,
|
|
263
|
+
name: "docs.zip",
|
|
264
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/2",
|
|
265
|
+
browser_download_url: "https://github.com/test/docs.zip",
|
|
266
|
+
size: 3000,
|
|
267
|
+
content_type: "application/zip",
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
id: 3,
|
|
271
|
+
name: "ClaudeKit-Engineer-Package.zip",
|
|
272
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/3",
|
|
273
|
+
browser_download_url: "https://github.com/test/package.zip",
|
|
274
|
+
size: 2000,
|
|
275
|
+
content_type: "application/zip",
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
281
|
+
|
|
282
|
+
// Should pick the ClaudeKit package even though it's listed last
|
|
283
|
+
expect(result.type).toBe("asset");
|
|
284
|
+
expect(result.name).toBe("ClaudeKit-Engineer-Package.zip");
|
|
285
|
+
expect(result.size).toBe(2000);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test("should handle assets with variations in naming", () => {
|
|
289
|
+
const release: GitHubRelease = {
|
|
290
|
+
id: 1,
|
|
291
|
+
tag_name: "v1.0.0",
|
|
292
|
+
name: "Release 1.0.0",
|
|
293
|
+
draft: false,
|
|
294
|
+
prerelease: false,
|
|
295
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.0.0",
|
|
296
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.0.0",
|
|
297
|
+
assets: [
|
|
298
|
+
{
|
|
299
|
+
id: 1,
|
|
300
|
+
name: "claudekit_marketing_package.zip",
|
|
301
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/1",
|
|
302
|
+
browser_download_url: "https://github.com/test/package.zip",
|
|
303
|
+
size: 2000,
|
|
304
|
+
content_type: "application/zip",
|
|
305
|
+
},
|
|
306
|
+
],
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
310
|
+
|
|
311
|
+
expect(result.type).toBe("asset");
|
|
312
|
+
expect(result.name).toBe("claudekit_marketing_package.zip");
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
test("should handle assets with spaces in name", () => {
|
|
316
|
+
const release: GitHubRelease = {
|
|
317
|
+
id: 1,
|
|
318
|
+
tag_name: "v1.4.0",
|
|
319
|
+
name: "Release 1.4.0",
|
|
320
|
+
draft: false,
|
|
321
|
+
prerelease: false,
|
|
322
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.4.0",
|
|
323
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.4.0",
|
|
324
|
+
assets: [
|
|
325
|
+
{
|
|
326
|
+
id: 1,
|
|
327
|
+
name: "Changelog",
|
|
328
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/1",
|
|
329
|
+
browser_download_url: "https://github.com/test/changelog",
|
|
330
|
+
size: 7979,
|
|
331
|
+
content_type: "text/plain",
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
id: 2,
|
|
335
|
+
name: "ClaudeKit Engineer Package.zip",
|
|
336
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/2",
|
|
337
|
+
browser_download_url: "https://github.com/test/package.zip",
|
|
338
|
+
size: 3334963,
|
|
339
|
+
content_type: "application/zip",
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
345
|
+
|
|
346
|
+
expect(result.type).toBe("asset");
|
|
347
|
+
expect(result.name).toBe("ClaudeKit Engineer Package.zip");
|
|
348
|
+
expect(result.size).toBe(3334963);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
test("should exclude assets named 'Source code' or starting with 'source'", () => {
|
|
352
|
+
const release: GitHubRelease = {
|
|
353
|
+
id: 1,
|
|
354
|
+
tag_name: "v1.0.0",
|
|
355
|
+
name: "Release 1.0.0",
|
|
356
|
+
draft: false,
|
|
357
|
+
prerelease: false,
|
|
358
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.0.0",
|
|
359
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.0.0",
|
|
360
|
+
assets: [
|
|
361
|
+
{
|
|
362
|
+
id: 1,
|
|
363
|
+
name: "Source code.zip",
|
|
364
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/1",
|
|
365
|
+
browser_download_url: "https://github.com/test/source.zip",
|
|
366
|
+
size: 5000,
|
|
367
|
+
content_type: "application/zip",
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
id: 2,
|
|
371
|
+
name: "source-archive.tar.gz",
|
|
372
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/2",
|
|
373
|
+
browser_download_url: "https://github.com/test/source.tar.gz",
|
|
374
|
+
size: 4500,
|
|
375
|
+
content_type: "application/gzip",
|
|
376
|
+
},
|
|
377
|
+
],
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
381
|
+
|
|
382
|
+
// Should fall back to tarball instead of using "Source code" assets
|
|
383
|
+
expect(result.type).toBe("tarball");
|
|
384
|
+
expect(result.url).toBe("https://api.github.com/repos/test/repo/tarball/v1.0.0");
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
test("should prioritize ClaudeKit package over source code archives", () => {
|
|
388
|
+
const release: GitHubRelease = {
|
|
389
|
+
id: 1,
|
|
390
|
+
tag_name: "v1.4.0",
|
|
391
|
+
name: "Release 1.4.0",
|
|
392
|
+
draft: false,
|
|
393
|
+
prerelease: false,
|
|
394
|
+
tarball_url: "https://api.github.com/repos/test/repo/tarball/v1.4.0",
|
|
395
|
+
zipball_url: "https://api.github.com/repos/test/repo/zipball/v1.4.0",
|
|
396
|
+
assets: [
|
|
397
|
+
{
|
|
398
|
+
id: 1,
|
|
399
|
+
name: "Source code.zip",
|
|
400
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/1",
|
|
401
|
+
browser_download_url: "https://github.com/test/source.zip",
|
|
402
|
+
size: 5000,
|
|
403
|
+
content_type: "application/zip",
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
id: 2,
|
|
407
|
+
name: "ClaudeKit Engineer Package.zip",
|
|
408
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/2",
|
|
409
|
+
browser_download_url: "https://github.com/test/package.zip",
|
|
410
|
+
size: 3334963,
|
|
411
|
+
content_type: "application/zip",
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
id: 3,
|
|
415
|
+
name: "Source code.tar.gz",
|
|
416
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/3",
|
|
417
|
+
browser_download_url: "https://github.com/test/source.tar.gz",
|
|
418
|
+
size: 4500,
|
|
419
|
+
content_type: "application/gzip",
|
|
420
|
+
},
|
|
421
|
+
],
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
const result = GitHubClient.getDownloadableAsset(release);
|
|
425
|
+
|
|
426
|
+
// Should pick the ClaudeKit package and ignore source code archives
|
|
427
|
+
expect(result.type).toBe("asset");
|
|
428
|
+
expect(result.name).toBe("ClaudeKit Engineer Package.zip");
|
|
429
|
+
expect(result.size).toBe(3334963);
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
});
|
package/tests/lib/github.test.ts
CHANGED
|
@@ -36,13 +36,13 @@ describe("GitHubClient", () => {
|
|
|
36
36
|
describe("integration scenarios", () => {
|
|
37
37
|
test("should handle kit configuration correctly", () => {
|
|
38
38
|
const engineerKit = AVAILABLE_KITS.engineer;
|
|
39
|
-
expect(engineerKit.owner).toBe("
|
|
39
|
+
expect(engineerKit.owner).toBe("claudekit");
|
|
40
40
|
expect(engineerKit.repo).toBe("claudekit-engineer");
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
test("should handle marketing kit configuration", () => {
|
|
44
44
|
const marketingKit = AVAILABLE_KITS.marketing;
|
|
45
|
-
expect(marketingKit.owner).toBe("
|
|
45
|
+
expect(marketingKit.owner).toBe("claudekit");
|
|
46
46
|
expect(marketingKit.repo).toBe("claudekit-marketing");
|
|
47
47
|
});
|
|
48
48
|
});
|
package/tests/lib/merge.test.ts
CHANGED
|
@@ -135,4 +135,81 @@ describe("FileMerger", () => {
|
|
|
135
135
|
expect(existsSync(join(testDestDir, "custom-ignore.txt"))).toBe(false);
|
|
136
136
|
});
|
|
137
137
|
});
|
|
138
|
+
|
|
139
|
+
describe("custom .claude file preservation", () => {
|
|
140
|
+
test("should preserve custom .claude files when patterns are added", async () => {
|
|
141
|
+
// Create .claude directories
|
|
142
|
+
const sourceClaudeDir = join(testSourceDir, ".claude");
|
|
143
|
+
const destClaudeDir = join(testDestDir, ".claude");
|
|
144
|
+
await mkdir(sourceClaudeDir, { recursive: true });
|
|
145
|
+
await mkdir(destClaudeDir, { recursive: true });
|
|
146
|
+
|
|
147
|
+
// Create files in source (from release package)
|
|
148
|
+
await writeFile(join(sourceClaudeDir, "standard.md"), "standard content");
|
|
149
|
+
|
|
150
|
+
// Create files in destination (existing + custom)
|
|
151
|
+
await writeFile(join(destClaudeDir, "standard.md"), "old standard content");
|
|
152
|
+
await writeFile(join(destClaudeDir, "custom.md"), "custom content");
|
|
153
|
+
|
|
154
|
+
// Add custom file to ignore patterns (this would be done by update.ts)
|
|
155
|
+
merger.addIgnorePatterns([".claude/custom.md"]);
|
|
156
|
+
|
|
157
|
+
await merger.merge(testSourceDir, testDestDir, true);
|
|
158
|
+
|
|
159
|
+
// Standard file should be overwritten
|
|
160
|
+
const standardContent = await Bun.file(join(destClaudeDir, "standard.md")).text();
|
|
161
|
+
expect(standardContent).toBe("standard content");
|
|
162
|
+
|
|
163
|
+
// Custom file should be preserved
|
|
164
|
+
expect(existsSync(join(destClaudeDir, "custom.md"))).toBe(true);
|
|
165
|
+
const customContent = await Bun.file(join(destClaudeDir, "custom.md")).text();
|
|
166
|
+
expect(customContent).toBe("custom content");
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("should preserve nested custom .claude files", async () => {
|
|
170
|
+
// Create nested .claude structure
|
|
171
|
+
const sourceCommandsDir = join(testSourceDir, ".claude", "commands");
|
|
172
|
+
const destCommandsDir = join(testDestDir, ".claude", "commands");
|
|
173
|
+
await mkdir(sourceCommandsDir, { recursive: true });
|
|
174
|
+
await mkdir(destCommandsDir, { recursive: true });
|
|
175
|
+
|
|
176
|
+
// Create standard file in source
|
|
177
|
+
await writeFile(join(sourceCommandsDir, "standard-cmd.md"), "standard command");
|
|
178
|
+
|
|
179
|
+
// Create custom file in destination
|
|
180
|
+
await writeFile(join(destCommandsDir, "custom-cmd.md"), "custom command");
|
|
181
|
+
|
|
182
|
+
// Add custom file to ignore patterns
|
|
183
|
+
merger.addIgnorePatterns([".claude/commands/custom-cmd.md"]);
|
|
184
|
+
|
|
185
|
+
await merger.merge(testSourceDir, testDestDir, true);
|
|
186
|
+
|
|
187
|
+
// Custom file should be preserved
|
|
188
|
+
expect(existsSync(join(destCommandsDir, "custom-cmd.md"))).toBe(true);
|
|
189
|
+
const customContent = await Bun.file(join(destCommandsDir, "custom-cmd.md")).text();
|
|
190
|
+
expect(customContent).toBe("custom command");
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test("should preserve multiple custom .claude files", async () => {
|
|
194
|
+
const sourceClaudeDir = join(testSourceDir, ".claude");
|
|
195
|
+
const destClaudeDir = join(testDestDir, ".claude");
|
|
196
|
+
await mkdir(sourceClaudeDir, { recursive: true });
|
|
197
|
+
await mkdir(destClaudeDir, { recursive: true });
|
|
198
|
+
|
|
199
|
+
// Create multiple custom files in destination
|
|
200
|
+
await writeFile(join(destClaudeDir, "custom1.md"), "custom1");
|
|
201
|
+
await writeFile(join(destClaudeDir, "custom2.md"), "custom2");
|
|
202
|
+
await writeFile(join(destClaudeDir, "custom3.md"), "custom3");
|
|
203
|
+
|
|
204
|
+
// Add all custom files to ignore patterns
|
|
205
|
+
merger.addIgnorePatterns([".claude/custom1.md", ".claude/custom2.md", ".claude/custom3.md"]);
|
|
206
|
+
|
|
207
|
+
await merger.merge(testSourceDir, testDestDir, true);
|
|
208
|
+
|
|
209
|
+
// All custom files should be preserved
|
|
210
|
+
expect(existsSync(join(destClaudeDir, "custom1.md"))).toBe(true);
|
|
211
|
+
expect(existsSync(join(destClaudeDir, "custom2.md"))).toBe(true);
|
|
212
|
+
expect(existsSync(join(destClaudeDir, "custom3.md"))).toBe(true);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
138
215
|
});
|
package/tests/types.test.ts
CHANGED
|
@@ -108,6 +108,7 @@ describe("Types and Schemas", () => {
|
|
|
108
108
|
const asset = {
|
|
109
109
|
id: 123,
|
|
110
110
|
name: "release.tar.gz",
|
|
111
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/123",
|
|
111
112
|
browser_download_url: "https://github.com/test/release.tar.gz",
|
|
112
113
|
size: 1024,
|
|
113
114
|
content_type: "application/gzip",
|
|
@@ -122,6 +123,7 @@ describe("Types and Schemas", () => {
|
|
|
122
123
|
const asset = {
|
|
123
124
|
id: 123,
|
|
124
125
|
name: "release.tar.gz",
|
|
126
|
+
url: "not-a-url",
|
|
125
127
|
browser_download_url: "not-a-url",
|
|
126
128
|
size: 1024,
|
|
127
129
|
content_type: "application/gzip",
|
|
@@ -150,12 +152,15 @@ describe("Types and Schemas", () => {
|
|
|
150
152
|
{
|
|
151
153
|
id: 123,
|
|
152
154
|
name: "release.tar.gz",
|
|
155
|
+
url: "https://api.github.com/repos/test/repo/releases/assets/123",
|
|
153
156
|
browser_download_url: "https://github.com/test/release.tar.gz",
|
|
154
157
|
size: 1024,
|
|
155
158
|
content_type: "application/gzip",
|
|
156
159
|
},
|
|
157
160
|
],
|
|
158
161
|
published_at: "2024-01-01T00:00:00Z",
|
|
162
|
+
tarball_url: "https://api.github.com/repos/test/test-repo/tarball/v1.0.0",
|
|
163
|
+
zipball_url: "https://api.github.com/repos/test/test-repo/zipball/v1.0.0",
|
|
159
164
|
};
|
|
160
165
|
const result = GitHubReleaseSchema.parse(release);
|
|
161
166
|
expect(result.id).toBe(1);
|
|
@@ -171,6 +176,8 @@ describe("Types and Schemas", () => {
|
|
|
171
176
|
draft: false,
|
|
172
177
|
prerelease: false,
|
|
173
178
|
assets: [],
|
|
179
|
+
tarball_url: "https://api.github.com/repos/test/test-repo/tarball/v1.0.0",
|
|
180
|
+
zipball_url: "https://api.github.com/repos/test/test-repo/zipball/v1.0.0",
|
|
174
181
|
};
|
|
175
182
|
const result = GitHubReleaseSchema.parse(release);
|
|
176
183
|
expect(result.published_at).toBeUndefined();
|