@comet/cli 9.0.0-beta.4 → 9.0.0-beta.5
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.
|
@@ -89,6 +89,63 @@ var os = __importStar(require("os"));
|
|
|
89
89
|
var path = __importStar(require("path"));
|
|
90
90
|
var SKILL_SOURCE_PATHS = ["skills", "agentic-plugin/skills"];
|
|
91
91
|
var RULE_SOURCE_PATHS = ["rules"];
|
|
92
|
+
function discoverNodeModulesPackages(cwd) {
|
|
93
|
+
var nodeModulesDir = path.join(cwd, "node_modules");
|
|
94
|
+
if (!fs.existsSync(nodeModulesDir)) {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
var packageDirs = [];
|
|
98
|
+
var entries;
|
|
99
|
+
try {
|
|
100
|
+
entries = fs.readdirSync(nodeModulesDir);
|
|
101
|
+
}
|
|
102
|
+
catch (_a) {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
|
|
106
|
+
var entry = entries_1[_i];
|
|
107
|
+
if (entry.startsWith(".")) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
var fullPath = path.join(nodeModulesDir, entry);
|
|
111
|
+
if (entry.startsWith("@")) {
|
|
112
|
+
// Scoped package: read one level deeper
|
|
113
|
+
var scopedEntries = void 0;
|
|
114
|
+
try {
|
|
115
|
+
scopedEntries = fs.readdirSync(fullPath);
|
|
116
|
+
}
|
|
117
|
+
catch (_b) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
for (var _c = 0, scopedEntries_1 = scopedEntries; _c < scopedEntries_1.length; _c++) {
|
|
121
|
+
var scopedEntry = scopedEntries_1[_c];
|
|
122
|
+
if (scopedEntry.startsWith(".")) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
var scopedPath = path.join(fullPath, scopedEntry);
|
|
126
|
+
try {
|
|
127
|
+
if (fs.statSync(scopedPath).isDirectory()) {
|
|
128
|
+
packageDirs.push(scopedPath);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (_d) {
|
|
132
|
+
// skip unreadable entries
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
try {
|
|
138
|
+
if (fs.statSync(fullPath).isDirectory()) {
|
|
139
|
+
packageDirs.push(fullPath);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (_e) {
|
|
143
|
+
// skip unreadable entries
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return packageDirs;
|
|
148
|
+
}
|
|
92
149
|
function parseRepoUrl(rawUrl) {
|
|
93
150
|
var hashIndex = rawUrl.lastIndexOf("#");
|
|
94
151
|
if (hashIndex === -1) {
|
|
@@ -274,15 +331,53 @@ function installFeatures(cwd, repos, options) {
|
|
|
274
331
|
itemLabelSingular: "rule",
|
|
275
332
|
itemLabelPlural: "rules",
|
|
276
333
|
}); });
|
|
334
|
+
// Discover skills/rules from node_modules (direct dependencies only, including @scoped packages)
|
|
335
|
+
var nodeModulesPackages = discoverNodeModulesPackages(cwd);
|
|
336
|
+
for (var _b = 0, nodeModulesPackages_1 = nodeModulesPackages; _b < nodeModulesPackages_1.length; _b++) {
|
|
337
|
+
var pkgDir = nodeModulesPackages_1[_b];
|
|
338
|
+
var pkgName = pkgDir.includes("".concat(path.sep, "@")) ? pkgDir.split(path.sep).slice(-2).join("/") : path.basename(pkgDir);
|
|
339
|
+
for (var _c = 0, SKILL_SOURCE_PATHS_1 = SKILL_SOURCE_PATHS; _c < SKILL_SOURCE_PATHS_1.length; _c++) {
|
|
340
|
+
var p = SKILL_SOURCE_PATHS_1[_c];
|
|
341
|
+
var dir = path.join(pkgDir, p);
|
|
342
|
+
if (fs.existsSync(dir)) {
|
|
343
|
+
skillSources.push({
|
|
344
|
+
label: "node_modules ".concat(pkgName, " (").concat(p, "/)"),
|
|
345
|
+
directory: dir,
|
|
346
|
+
discover: "folders",
|
|
347
|
+
symlink: true,
|
|
348
|
+
filterInternal: true,
|
|
349
|
+
installed: installedSkills,
|
|
350
|
+
itemLabelSingular: "skill",
|
|
351
|
+
itemLabelPlural: "skills",
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
for (var _d = 0, RULE_SOURCE_PATHS_1 = RULE_SOURCE_PATHS; _d < RULE_SOURCE_PATHS_1.length; _d++) {
|
|
356
|
+
var p = RULE_SOURCE_PATHS_1[_d];
|
|
357
|
+
var dir = path.join(pkgDir, p);
|
|
358
|
+
if (fs.existsSync(dir)) {
|
|
359
|
+
ruleSources.push({
|
|
360
|
+
label: "node_modules ".concat(pkgName, " (").concat(p, "/)"),
|
|
361
|
+
directory: dir,
|
|
362
|
+
discover: "files",
|
|
363
|
+
symlink: true,
|
|
364
|
+
filterInternal: true,
|
|
365
|
+
installed: installedRules,
|
|
366
|
+
itemLabelSingular: "rule",
|
|
367
|
+
itemLabelPlural: "rules",
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
277
372
|
var sparsePatterns = __spreadArray(__spreadArray([], SKILL_SOURCE_PATHS, true), RULE_SOURCE_PATHS, true).map(function (p) { return "".concat(p, "/"); });
|
|
278
373
|
var tempDirs = [];
|
|
279
374
|
try {
|
|
280
|
-
for (var
|
|
281
|
-
var rawUrl = repos_1[
|
|
375
|
+
for (var _e = 0, repos_1 = repos; _e < repos_1.length; _e++) {
|
|
376
|
+
var rawUrl = repos_1[_e];
|
|
282
377
|
var cloneDir = cloneRepo(rawUrl, sparsePatterns);
|
|
283
378
|
tempDirs.push(cloneDir);
|
|
284
|
-
for (var
|
|
285
|
-
var p =
|
|
379
|
+
for (var _f = 0, SKILL_SOURCE_PATHS_2 = SKILL_SOURCE_PATHS; _f < SKILL_SOURCE_PATHS_2.length; _f++) {
|
|
380
|
+
var p = SKILL_SOURCE_PATHS_2[_f];
|
|
286
381
|
skillSources.push({
|
|
287
382
|
label: "external ".concat(rawUrl, " (").concat(p, "/)"),
|
|
288
383
|
directory: path.join(cloneDir, p),
|
|
@@ -294,8 +389,8 @@ function installFeatures(cwd, repos, options) {
|
|
|
294
389
|
itemLabelPlural: "skills",
|
|
295
390
|
});
|
|
296
391
|
}
|
|
297
|
-
for (var
|
|
298
|
-
var p =
|
|
392
|
+
for (var _g = 0, RULE_SOURCE_PATHS_2 = RULE_SOURCE_PATHS; _g < RULE_SOURCE_PATHS_2.length; _g++) {
|
|
393
|
+
var p = RULE_SOURCE_PATHS_2[_g];
|
|
299
394
|
ruleSources.push({
|
|
300
395
|
label: "external ".concat(rawUrl, " (").concat(p, "/)"),
|
|
301
396
|
directory: path.join(cloneDir, p),
|
|
@@ -314,8 +409,8 @@ function installFeatures(cwd, repos, options) {
|
|
|
314
409
|
console.log("Total rules installed: ".concat(ruleCount));
|
|
315
410
|
}
|
|
316
411
|
finally {
|
|
317
|
-
for (var
|
|
318
|
-
var tmpDir = tempDirs_1[
|
|
412
|
+
for (var _h = 0, tempDirs_1 = tempDirs; _h < tempDirs_1.length; _h++) {
|
|
413
|
+
var tmpDir = tempDirs_1[_h];
|
|
319
414
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
320
415
|
}
|
|
321
416
|
}
|
|
@@ -210,6 +210,97 @@ function mockFilesystem(_a) {
|
|
|
210
210
|
(0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/skills/internal"), vitest_1.expect.any(String));
|
|
211
211
|
});
|
|
212
212
|
});
|
|
213
|
+
(0, vitest_1.describe)("installFeatures – node_modules skills and rules", function () {
|
|
214
|
+
(0, vitest_1.it)("symlinks skills from node_modules packages", function () {
|
|
215
|
+
mockFilesystem({
|
|
216
|
+
listings: {
|
|
217
|
+
"/proj/node_modules": ["some-tool"],
|
|
218
|
+
"/proj/node_modules/some-tool": ["skills", "package.json"],
|
|
219
|
+
"/proj/node_modules/some-tool/skills": ["tool-docs"],
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
(0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
|
|
223
|
+
(0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/node_modules/some-tool/skills/tool-docs"), path.join("/proj", ".agents", "skills", "tool-docs"));
|
|
224
|
+
(0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/node_modules/some-tool/skills/tool-docs"), path.join("/proj", ".claude", "skills", "tool-docs"));
|
|
225
|
+
});
|
|
226
|
+
(0, vitest_1.it)("symlinks rules from node_modules packages", function () {
|
|
227
|
+
mockFilesystem({
|
|
228
|
+
listings: {
|
|
229
|
+
"/proj/node_modules": ["some-tool"],
|
|
230
|
+
"/proj/node_modules/some-tool": ["rules", "package.json"],
|
|
231
|
+
"/proj/node_modules/some-tool/rules": ["best-practices.md"],
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
(0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
|
|
235
|
+
(0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/node_modules/some-tool/rules/best-practices.md"), path.join("/proj", ".agents", "rules", "best-practices.md"));
|
|
236
|
+
(0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/node_modules/some-tool/rules/best-practices.md"), path.join("/proj", ".claude", "rules", "best-practices.md"));
|
|
237
|
+
});
|
|
238
|
+
(0, vitest_1.it)("discovers skills from @scoped packages", function () {
|
|
239
|
+
mockFilesystem({
|
|
240
|
+
listings: {
|
|
241
|
+
"/proj/node_modules": ["@my-scope"],
|
|
242
|
+
"/proj/node_modules/@my-scope": ["my-tool"],
|
|
243
|
+
"/proj/node_modules/@my-scope/my-tool": ["skills", "package.json"],
|
|
244
|
+
"/proj/node_modules/@my-scope/my-tool/skills": ["scoped-skill"],
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
(0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
|
|
248
|
+
(0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/node_modules/@my-scope/my-tool/skills/scoped-skill"), path.join("/proj", ".agents", "skills", "scoped-skill"));
|
|
249
|
+
});
|
|
250
|
+
(0, vitest_1.it)("local skills take priority over node_modules skills", function () {
|
|
251
|
+
mockFilesystem({
|
|
252
|
+
listings: {
|
|
253
|
+
"/proj/skills": ["shared"],
|
|
254
|
+
"/proj/node_modules": ["some-tool"],
|
|
255
|
+
"/proj/node_modules/some-tool": ["skills", "package.json"],
|
|
256
|
+
"/proj/node_modules/some-tool/skills": ["shared"],
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
(0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
|
|
260
|
+
(0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/skills/shared"), vitest_1.expect.any(String));
|
|
261
|
+
(0, vitest_1.expect)(fs.symlinkSync).not.toHaveBeenCalledWith(path.resolve("/proj/node_modules/some-tool/skills/shared"), vitest_1.expect.any(String));
|
|
262
|
+
(0, vitest_1.expect)(console.warn).toHaveBeenCalledWith(vitest_1.expect.stringContaining('CONFLICT: "shared"'));
|
|
263
|
+
});
|
|
264
|
+
(0, vitest_1.it)("filters internal skills from node_modules", function () {
|
|
265
|
+
mockFilesystem({
|
|
266
|
+
listings: {
|
|
267
|
+
"/proj/node_modules": ["some-tool"],
|
|
268
|
+
"/proj/node_modules/some-tool": ["skills", "package.json"],
|
|
269
|
+
"/proj/node_modules/some-tool/skills": ["public-skill", "internal-skill"],
|
|
270
|
+
},
|
|
271
|
+
fileContents: {
|
|
272
|
+
"/proj/node_modules/some-tool/skills/internal-skill/SKILL.md": "---\nmetadata:\n internal: true\n---\n# Internal",
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
(0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
|
|
276
|
+
(0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/node_modules/some-tool/skills/public-skill"), vitest_1.expect.any(String));
|
|
277
|
+
(0, vitest_1.expect)(fs.symlinkSync).not.toHaveBeenCalledWith(path.resolve("/proj/node_modules/some-tool/skills/internal-skill"), vitest_1.expect.any(String));
|
|
278
|
+
});
|
|
279
|
+
(0, vitest_1.it)("skips dotfiles and dotfolders in node_modules", function () {
|
|
280
|
+
mockFilesystem({
|
|
281
|
+
listings: {
|
|
282
|
+
"/proj/node_modules": [".bin", ".package-lock.json", "some-tool"],
|
|
283
|
+
"/proj/node_modules/some-tool": ["skills", "package.json"],
|
|
284
|
+
"/proj/node_modules/some-tool/skills": ["my-skill"],
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
(0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
|
|
288
|
+
(0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/node_modules/some-tool/skills/my-skill"), vitest_1.expect.any(String));
|
|
289
|
+
});
|
|
290
|
+
(0, vitest_1.it)("does not add a source entry for packages without a skills/ or rules/ directory", function () {
|
|
291
|
+
mockFilesystem({
|
|
292
|
+
listings: {
|
|
293
|
+
"/proj/node_modules": ["no-skills-tool"],
|
|
294
|
+
"/proj/node_modules/no-skills-tool": ["dist", "package.json"],
|
|
295
|
+
// no skills/ or rules/ entry
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
(0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
|
|
299
|
+
// No symlinks and no "No skills found in node_modules" log noise
|
|
300
|
+
(0, vitest_1.expect)(fs.symlinkSync).not.toHaveBeenCalled();
|
|
301
|
+
(0, vitest_1.expect)(console.log).not.toHaveBeenCalledWith(vitest_1.expect.stringContaining("node_modules no-skills-tool"));
|
|
302
|
+
});
|
|
303
|
+
});
|
|
213
304
|
(0, vitest_1.describe)("installFeatures – missing local sources", function () {
|
|
214
305
|
(0, vitest_1.it)("runs cleanly when there are no local skills or rules", function () {
|
|
215
306
|
mockFilesystem({});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@comet/cli",
|
|
3
|
-
"version": "9.0.0-beta.
|
|
3
|
+
"version": "9.0.0-beta.5",
|
|
4
4
|
"description": "A collection of CLI tools for Comet projects",
|
|
5
5
|
"repository": {
|
|
6
6
|
"directory": "packages/cli",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"rimraf": "^6.1.2",
|
|
34
34
|
"typescript": "^5.9.3",
|
|
35
35
|
"vitest": "^4.0.16",
|
|
36
|
-
"@comet/eslint-config": "9.0.0-beta.
|
|
36
|
+
"@comet/eslint-config": "9.0.0-beta.5"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|
|
39
39
|
"node": ">=22.0.0"
|