@comet/cli 9.0.0-beta.3 → 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.
@@ -0,0 +1,325 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ /* eslint-disable no-console */
37
+ var fs = __importStar(require("fs"));
38
+ var path = __importStar(require("path"));
39
+ var vitest_1 = require("vitest");
40
+ var install_agent_features_1 = require("./install-agent-features");
41
+ vitest_1.vi.mock("fs");
42
+ /**
43
+ * fs mock for installFeatures.
44
+ *
45
+ * - `listings` maps a directory path to the names of its direct entries.
46
+ * - Entries are assumed to be directories unless the entry name ends in `.md`
47
+ * or appears in `fileContents`.
48
+ * - `existingDests` is the set of destination paths that pathExists/lstatSync
49
+ * should return truthy for (used to assert overwrite behavior).
50
+ * - `fileContents` provides content for fs.readFileSync; any path not in the
51
+ * map throws ENOENT.
52
+ */
53
+ function mockFilesystem(_a) {
54
+ var _b = _a === void 0 ? {} : _a, _c = _b.listings, listings = _c === void 0 ? {} : _c, _d = _b.existingDests, existingDests = _d === void 0 ? [] : _d, _e = _b.fileContents, fileContents = _e === void 0 ? {} : _e;
55
+ var isFile = function (p) {
56
+ if (p in fileContents) {
57
+ return true;
58
+ }
59
+ return path.basename(p).endsWith(".md");
60
+ };
61
+ vitest_1.vi.mocked(fs.existsSync).mockImplementation(function (p) { return String(p) in listings; });
62
+ vitest_1.vi.mocked(fs.readdirSync).mockImplementation(function (p) { var _a; return (_a = listings[String(p)]) !== null && _a !== void 0 ? _a : []; });
63
+ vitest_1.vi.mocked(fs.statSync).mockImplementation(function (p) {
64
+ var fileLike = isFile(String(p));
65
+ return { isDirectory: function () { return !fileLike; }, isFile: function () { return fileLike; } };
66
+ });
67
+ vitest_1.vi.mocked(fs.lstatSync).mockImplementation(function (p) {
68
+ if (existingDests.includes(String(p))) {
69
+ return {};
70
+ }
71
+ throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });
72
+ });
73
+ vitest_1.vi.mocked(fs.readFileSync).mockImplementation(function (p) {
74
+ var content = fileContents[String(p)];
75
+ if (content !== undefined) {
76
+ return content;
77
+ }
78
+ throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });
79
+ });
80
+ }
81
+ (0, vitest_1.beforeEach)(function () {
82
+ vitest_1.vi.mocked(fs.mkdirSync).mockImplementation(function () { return undefined; });
83
+ vitest_1.vi.mocked(fs.symlinkSync).mockImplementation(function () { return undefined; });
84
+ vitest_1.vi.mocked(fs.cpSync).mockImplementation(function () { return undefined; });
85
+ vitest_1.vi.mocked(fs.rmSync).mockImplementation(function () { return undefined; });
86
+ vitest_1.vi.spyOn(console, "log").mockImplementation(function () { return undefined; });
87
+ vitest_1.vi.spyOn(console, "warn").mockImplementation(function () { return undefined; });
88
+ });
89
+ (0, vitest_1.afterEach)(function () {
90
+ vitest_1.vi.clearAllMocks();
91
+ vitest_1.vi.restoreAllMocks();
92
+ });
93
+ (0, vitest_1.describe)("installFeatures – local skills", function () {
94
+ (0, vitest_1.it)("symlinks skill folders into .agents/skills and .claude/skills", function () {
95
+ mockFilesystem({ listings: { "/proj/skills": ["my-skill"] } });
96
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
97
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/skills/my-skill"), path.join("/proj", ".agents", "skills", "my-skill"));
98
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/skills/my-skill"), path.join("/proj", ".claude", "skills", "my-skill"));
99
+ });
100
+ (0, vitest_1.it)("also installs from agentic-plugin/skills/", function () {
101
+ mockFilesystem({ listings: { "/proj/agentic-plugin/skills": ["plugin-skill"] } });
102
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
103
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/agentic-plugin/skills/plugin-skill"), path.join("/proj", ".claude", "skills", "plugin-skill"));
104
+ });
105
+ (0, vitest_1.it)("skills/ takes priority over agentic-plugin/skills/ for same name", function () {
106
+ mockFilesystem({
107
+ listings: {
108
+ "/proj/skills": ["shared"],
109
+ "/proj/agentic-plugin/skills": ["shared"],
110
+ },
111
+ });
112
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
113
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/skills/shared"), vitest_1.expect.any(String));
114
+ (0, vitest_1.expect)(fs.symlinkSync).not.toHaveBeenCalledWith(path.resolve("/proj/agentic-plugin/skills/shared"), vitest_1.expect.any(String));
115
+ (0, vitest_1.expect)(console.warn).toHaveBeenCalledWith(vitest_1.expect.stringContaining('CONFLICT: "shared"'));
116
+ });
117
+ (0, vitest_1.it)("ignores files in skills/ — only subdirectories are skills", function () {
118
+ mockFilesystem({ listings: { "/proj/skills": ["real-skill", "not-a-skill.md"] } });
119
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
120
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/skills/real-skill"), vitest_1.expect.any(String));
121
+ (0, vitest_1.expect)(fs.symlinkSync).not.toHaveBeenCalledWith(path.resolve("/proj/skills/not-a-skill.md"), vitest_1.expect.any(String));
122
+ });
123
+ });
124
+ (0, vitest_1.describe)("installFeatures – local rules", function () {
125
+ (0, vitest_1.it)("symlinks .md files into .agents/rules, .claude/rules, .cursor/rules, and .github/instructions", function () {
126
+ mockFilesystem({ listings: { "/proj/rules": ["my-rule.md"] } });
127
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
128
+ (0, vitest_1.expect)(fs.mkdirSync).toHaveBeenCalledWith(path.join("/proj", ".agents", "rules"), { recursive: true });
129
+ (0, vitest_1.expect)(fs.mkdirSync).toHaveBeenCalledWith(path.join("/proj", ".claude", "rules"), { recursive: true });
130
+ (0, vitest_1.expect)(fs.mkdirSync).toHaveBeenCalledWith(path.join("/proj", ".cursor", "rules"), { recursive: true });
131
+ (0, vitest_1.expect)(fs.mkdirSync).toHaveBeenCalledWith(path.join("/proj", ".github", "instructions"), { recursive: true });
132
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/rules/my-rule.md"), path.join("/proj", ".agents", "rules", "my-rule.md"));
133
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/rules/my-rule.md"), path.join("/proj", ".claude", "rules", "my-rule.md"));
134
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/rules/my-rule.md"), path.join("/proj", ".cursor", "rules", "my-rule.md"));
135
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/rules/my-rule.md"), path.join("/proj", ".github", "instructions", "my-rule.md"));
136
+ });
137
+ (0, vitest_1.it)("walks subdirectories recursively, preserving the layout in each target", function () {
138
+ mockFilesystem({
139
+ listings: {
140
+ "/proj/rules": ["top.md", "backend"],
141
+ "/proj/rules/backend": ["api.md", "deeper"],
142
+ "/proj/rules/backend/deeper": ["nested.md"],
143
+ },
144
+ });
145
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
146
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/rules/backend/api.md"), path.join("/proj", ".claude", "rules", "backend", "api.md"));
147
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/rules/backend/deeper/nested.md"), path.join("/proj", ".claude", "rules", "backend", "deeper", "nested.md"));
148
+ (0, vitest_1.expect)(fs.mkdirSync).toHaveBeenCalledWith(path.join("/proj", ".claude", "rules", "backend"), { recursive: true });
149
+ (0, vitest_1.expect)(fs.mkdirSync).toHaveBeenCalledWith(path.join("/proj", ".claude", "rules", "backend", "deeper"), { recursive: true });
150
+ });
151
+ (0, vitest_1.it)("ignores non-.md entries", function () {
152
+ mockFilesystem({ listings: { "/proj/rules": ["rule.md", "README.txt"] } });
153
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
154
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/rules/rule.md"), vitest_1.expect.any(String));
155
+ (0, vitest_1.expect)(fs.symlinkSync).not.toHaveBeenCalledWith(path.resolve("/proj/rules/README.txt"), vitest_1.expect.any(String));
156
+ });
157
+ });
158
+ (0, vitest_1.describe)("installFeatures – cross-namespace", function () {
159
+ (0, vitest_1.it)("a skill and a rule may share a name without conflicting", function () {
160
+ mockFilesystem({
161
+ listings: {
162
+ "/proj/skills": ["shared"],
163
+ "/proj/rules": ["shared.md"],
164
+ },
165
+ });
166
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
167
+ (0, vitest_1.expect)(console.warn).not.toHaveBeenCalled();
168
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/skills/shared"), vitest_1.expect.any(String));
169
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/rules/shared.md"), vitest_1.expect.any(String));
170
+ });
171
+ });
172
+ (0, vitest_1.describe)("installFeatures – dry-run", function () {
173
+ (0, vitest_1.it)("writes nothing", function () {
174
+ mockFilesystem({
175
+ listings: {
176
+ "/proj/skills": ["my-skill"],
177
+ "/proj/rules": ["my-rule.md"],
178
+ },
179
+ });
180
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: true });
181
+ (0, vitest_1.expect)(fs.symlinkSync).not.toHaveBeenCalled();
182
+ (0, vitest_1.expect)(fs.cpSync).not.toHaveBeenCalled();
183
+ (0, vitest_1.expect)(fs.rmSync).not.toHaveBeenCalled();
184
+ });
185
+ (0, vitest_1.it)("logs would-be operations", function () {
186
+ mockFilesystem({ listings: { "/proj/skills": ["my-skill"] } });
187
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: true });
188
+ (0, vitest_1.expect)(console.log).toHaveBeenCalledWith(vitest_1.expect.stringContaining("[dry-run] Would symlink: ".concat(path.resolve("/proj/skills/my-skill"))));
189
+ });
190
+ });
191
+ (0, vitest_1.describe)("installFeatures – overwrites existing destinations", function () {
192
+ (0, vitest_1.it)("removes the existing destination before re-creating it", function () {
193
+ mockFilesystem({
194
+ listings: { "/proj/skills": ["my-skill"] },
195
+ existingDests: [path.join("/proj", ".agents", "skills", "my-skill"), path.join("/proj", ".claude", "skills", "my-skill")],
196
+ });
197
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
198
+ (0, vitest_1.expect)(fs.rmSync).toHaveBeenCalledWith(path.join("/proj", ".agents", "skills", "my-skill"), { recursive: true, force: true });
199
+ (0, vitest_1.expect)(fs.rmSync).toHaveBeenCalledWith(path.join("/proj", ".claude", "skills", "my-skill"), { recursive: true, force: true });
200
+ });
201
+ });
202
+ (0, vitest_1.describe)("installFeatures – internal filtering", function () {
203
+ (0, vitest_1.it)("local sources install internal skills (filterInternal applies only to external repos)", function () {
204
+ mockFilesystem({
205
+ listings: { "/proj/skills": ["public", "internal"] },
206
+ fileContents: { "/proj/skills/internal/SKILL.md": "---\nmetadata:\n internal: true\n---\n# Internal" },
207
+ });
208
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
209
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/skills/public"), vitest_1.expect.any(String));
210
+ (0, vitest_1.expect)(fs.symlinkSync).toHaveBeenCalledWith(path.resolve("/proj/skills/internal"), vitest_1.expect.any(String));
211
+ });
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
+ });
304
+ (0, vitest_1.describe)("installFeatures – missing local sources", function () {
305
+ (0, vitest_1.it)("runs cleanly when there are no local skills or rules", function () {
306
+ mockFilesystem({});
307
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
308
+ (0, vitest_1.expect)(fs.symlinkSync).not.toHaveBeenCalled();
309
+ (0, vitest_1.expect)(fs.cpSync).not.toHaveBeenCalled();
310
+ (0, vitest_1.expect)(console.log).toHaveBeenCalledWith(vitest_1.expect.stringContaining("No skills found"));
311
+ (0, vitest_1.expect)(console.log).toHaveBeenCalledWith(vitest_1.expect.stringContaining("No rules found"));
312
+ });
313
+ });
314
+ (0, vitest_1.describe)("installFeatures – EPERM symlink fallback", function () {
315
+ (0, vitest_1.it)("falls back to copy when symlinkSync throws EPERM (e.g. Windows without privileges)", function () {
316
+ mockFilesystem({ listings: { "/proj/skills": ["my-skill"] } });
317
+ vitest_1.vi.mocked(fs.symlinkSync).mockImplementationOnce(function () {
318
+ throw Object.assign(new Error("permission denied"), { code: "EPERM" });
319
+ });
320
+ (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
321
+ (0, vitest_1.expect)(fs.cpSync).toHaveBeenCalledWith(path.resolve("/proj/skills/my-skill"), path.join("/proj", ".agents", "skills", "my-skill"), {
322
+ recursive: true,
323
+ });
324
+ });
325
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comet/cli",
3
- "version": "9.0.0-beta.3",
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",
@@ -14,6 +14,7 @@
14
14
  "bin": {
15
15
  "comet": "bin/comet.js"
16
16
  },
17
+ "sideEffects": false,
17
18
  "files": [
18
19
  "bin/**/*.js",
19
20
  "lib/*"
@@ -26,13 +27,13 @@
26
27
  },
27
28
  "devDependencies": {
28
29
  "@types/js-yaml": "^4.0.9",
29
- "@types/node": "^24.12.2",
30
- "eslint": "^9.39.2",
30
+ "@types/node": "^24.12.4",
31
+ "eslint": "^9.39.4",
31
32
  "npm-run-all2": "^8.0.4",
32
33
  "rimraf": "^6.1.2",
33
34
  "typescript": "^5.9.3",
34
35
  "vitest": "^4.0.16",
35
- "@comet/eslint-config": "9.0.0-beta.3"
36
+ "@comet/eslint-config": "9.0.0-beta.5"
36
37
  },
37
38
  "engines": {
38
39
  "node": ">=22.0.0"
@@ -1,15 +0,0 @@
1
- import { Command } from "commander";
2
- export interface SkillSource {
3
- label: string;
4
- directory: string;
5
- /** If true, create symlinks; if false, copy files (used for tmp clone dirs) */
6
- symlink: boolean;
7
- /** If true, skills with metadata.internal: true in their SKILL.md are excluded */
8
- filterInternal?: boolean;
9
- }
10
- export interface InstallOptions {
11
- dryRun: boolean;
12
- }
13
- export declare function isInternalSkill(skillFolderPath: string): boolean;
14
- export declare function installSkills(sources: SkillSource[], targetDirs: string[], { dryRun }: InstallOptions): void;
15
- export declare const installAgentSkillsCommand: Command;
@@ -1,255 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
- return new (P || (P = Promise))(function (resolve, reject) {
38
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
- step((generator = generator.apply(thisArg, _arguments || [])).next());
42
- });
43
- };
44
- var __generator = (this && this.__generator) || function (thisArg, body) {
45
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
46
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
47
- function verb(n) { return function (v) { return step([n, v]); }; }
48
- function step(op) {
49
- if (f) throw new TypeError("Generator is already executing.");
50
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
51
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
52
- if (y = 0, t) op = [op[0] & 2, t.value];
53
- switch (op[0]) {
54
- case 0: case 1: t = op; break;
55
- case 4: _.label++; return { value: op[1], done: false };
56
- case 5: _.label++; y = op[1]; op = [0]; continue;
57
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
58
- default:
59
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
60
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
61
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
62
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
63
- if (t[2]) _.ops.pop();
64
- _.trys.pop(); continue;
65
- }
66
- op = body.call(thisArg, _);
67
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
68
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
69
- }
70
- };
71
- Object.defineProperty(exports, "__esModule", { value: true });
72
- exports.installAgentSkillsCommand = void 0;
73
- exports.isInternalSkill = isInternalSkill;
74
- exports.installSkills = installSkills;
75
- /* eslint-disable no-console */
76
- var child_process_1 = require("child_process");
77
- var commander_1 = require("commander");
78
- var fs = __importStar(require("fs"));
79
- var yaml = __importStar(require("js-yaml"));
80
- var os = __importStar(require("os"));
81
- var path = __importStar(require("path"));
82
- function parseRepoUrl(rawUrl) {
83
- var hashIndex = rawUrl.lastIndexOf("#");
84
- if (hashIndex === -1) {
85
- return { repoUrl: rawUrl, ref: undefined };
86
- }
87
- return { repoUrl: rawUrl.slice(0, hashIndex), ref: rawUrl.slice(hashIndex + 1) || undefined };
88
- }
89
- var SKILL_SOURCE_PATHS = ["skills", "agentic-plugin/skills"];
90
- function cloneRepo(rawUrl) {
91
- var _a = parseRepoUrl(rawUrl), repoUrl = _a.repoUrl, ref = _a.ref;
92
- var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "comet-agent-skills-"));
93
- // Use sparse checkout to fetch only the skill source folders
94
- (0, child_process_1.execFileSync)("git", ["init", tmpDir], { stdio: "pipe" });
95
- (0, child_process_1.execFileSync)("git", ["-C", tmpDir, "remote", "add", "origin", "--", repoUrl], { stdio: "pipe" });
96
- (0, child_process_1.execFileSync)("git", ["-C", tmpDir, "config", "core.sparseCheckout", "true"], { stdio: "pipe" });
97
- fs.writeFileSync(path.join(tmpDir, ".git", "info", "sparse-checkout"), SKILL_SOURCE_PATHS.map(function (p) { return "".concat(p, "/\n"); }).join(""));
98
- var fetchRef = ref !== null && ref !== void 0 ? ref : "HEAD";
99
- try {
100
- console.log("Fetching ".concat(repoUrl, " ref \"").concat(fetchRef, "\" (sparse, ").concat(SKILL_SOURCE_PATHS.map(function (p) { return "".concat(p, "/"); }).join(", "), " only)..."));
101
- (0, child_process_1.execFileSync)("git", ["-C", tmpDir, "fetch", "--depth", "1", "origin", fetchRef], { stdio: "pipe" });
102
- (0, child_process_1.execFileSync)("git", ["-C", tmpDir, "checkout", "FETCH_HEAD"], { stdio: "pipe" });
103
- }
104
- catch (_b) {
105
- console.log("Shallow fetch failed for ref \"".concat(fetchRef, "\"; falling back to full fetch..."));
106
- (0, child_process_1.execFileSync)("git", ["-C", tmpDir, "fetch", "origin", fetchRef], { stdio: "pipe" });
107
- (0, child_process_1.execFileSync)("git", ["-C", tmpDir, "checkout", "FETCH_HEAD"], { stdio: "pipe" });
108
- }
109
- return tmpDir;
110
- }
111
- function pathExists(p) {
112
- try {
113
- fs.lstatSync(p);
114
- return true;
115
- }
116
- catch (_a) {
117
- return false;
118
- }
119
- }
120
- function isInternalSkill(skillFolderPath) {
121
- var _a;
122
- var skillMdPath = path.join(skillFolderPath, "SKILL.md");
123
- var skillMdContent;
124
- try {
125
- skillMdContent = fs.readFileSync(skillMdPath, "utf-8");
126
- }
127
- catch (_b) {
128
- return false;
129
- }
130
- var frontmatterMatch = skillMdContent.match(/^---\n([\s\S]*?)\n---/);
131
- if (!frontmatterMatch) {
132
- return false;
133
- }
134
- try {
135
- var parsed = yaml.load(frontmatterMatch[1]);
136
- return ((_a = parsed === null || parsed === void 0 ? void 0 : parsed.metadata) === null || _a === void 0 ? void 0 : _a.internal) === true;
137
- }
138
- catch (_c) {
139
- return false;
140
- }
141
- }
142
- function listSkillFolders(directory, filterInternal) {
143
- if (filterInternal === void 0) { filterInternal = false; }
144
- if (!fs.existsSync(directory)) {
145
- return [];
146
- }
147
- return fs
148
- .readdirSync(directory)
149
- .filter(function (f) { return fs.statSync(path.join(directory, f)).isDirectory(); })
150
- .filter(function (folder) { return !filterInternal || !isInternalSkill(path.join(directory, folder)); })
151
- .sort();
152
- }
153
- function installSkills(sources, targetDirs, _a) {
154
- var dryRun = _a.dryRun;
155
- var installed = new Set();
156
- for (var _i = 0, sources_1 = sources; _i < sources_1.length; _i++) {
157
- var _b = sources_1[_i], label = _b.label, directory = _b.directory, symlink = _b.symlink, filterInternal = _b.filterInternal;
158
- var folders = listSkillFolders(directory, filterInternal);
159
- if (folders.length === 0) {
160
- console.log("No skills found in ".concat(label));
161
- continue;
162
- }
163
- console.log("Installing ".concat(folders.length, " skill(s) from ").concat(label, "..."));
164
- for (var _c = 0, folders_1 = folders; _c < folders_1.length; _c++) {
165
- var folder = folders_1[_c];
166
- if (installed.has(folder)) {
167
- console.warn(" CONFLICT: \"".concat(folder, "\" from ").concat(label, " skipped (already installed from a higher-priority source)"));
168
- continue;
169
- }
170
- var srcPath = path.resolve(path.join(directory, folder));
171
- for (var _d = 0, targetDirs_1 = targetDirs; _d < targetDirs_1.length; _d++) {
172
- var targetDir = targetDirs_1[_d];
173
- var destPath = path.join(targetDir, folder);
174
- var exists = pathExists(destPath);
175
- if (dryRun) {
176
- console.log(" [dry-run] Would ".concat(symlink ? "symlink" : "copy", ": ").concat(srcPath, " -> ").concat(destPath));
177
- }
178
- else {
179
- if (exists) {
180
- fs.rmSync(destPath, { recursive: true, force: true });
181
- }
182
- if (symlink) {
183
- fs.symlinkSync(srcPath, destPath);
184
- }
185
- else {
186
- fs.cpSync(srcPath, destPath, { recursive: true });
187
- }
188
- console.log(" ".concat(symlink ? "Symlinked" : "Copied", ": ").concat(folder));
189
- }
190
- }
191
- installed.add(folder);
192
- }
193
- }
194
- console.log("\nTotal skills installed: ".concat(installed.size));
195
- }
196
- function loadConfig(configPath) {
197
- var resolved = path.resolve(configPath);
198
- if (!fs.existsSync(resolved)) {
199
- throw new Error("Config file not found: ".concat(resolved));
200
- }
201
- var raw = fs.readFileSync(resolved, "utf-8");
202
- return JSON.parse(raw);
203
- }
204
- exports.installAgentSkillsCommand = new commander_1.Command("install-agent-skills")
205
- .description("Install agent skills from local directories and optional external git repos")
206
- .option("--config <path>", "Path to a JSON config file specifying repos to install skills from", "agent-skills.json")
207
- .option("--dry-run", "Show which symlinks/copies would be created without making changes", false)
208
- .action(function (options) { return __awaiter(void 0, void 0, void 0, function () {
209
- var configPath, dryRun, resolvedConfig, repos, cwd, targetDirs, _i, targetDirs_2, dir, sources, tempDirs, _a, repos_1, rawUrl, cloneDir, _b, SKILL_SOURCE_PATHS_1, p, _c, tempDirs_1, tmpDir;
210
- var _d;
211
- return __generator(this, function (_e) {
212
- configPath = options.config, dryRun = options.dryRun;
213
- resolvedConfig = path.resolve(configPath);
214
- repos = fs.existsSync(resolvedConfig) ? ((_d = loadConfig(configPath).repos) !== null && _d !== void 0 ? _d : []) : [];
215
- console.log("=== Installing agent skills".concat(dryRun ? " (dry run)" : "", " ==="));
216
- cwd = process.cwd();
217
- targetDirs = [path.join(cwd, ".agents", "skills"), path.join(cwd, ".claude", "skills")];
218
- // Ensure target directories exist (without clearing existing contents)
219
- for (_i = 0, targetDirs_2 = targetDirs; _i < targetDirs_2.length; _i++) {
220
- dir = targetDirs_2[_i];
221
- fs.mkdirSync(dir, { recursive: true });
222
- }
223
- sources = SKILL_SOURCE_PATHS.map(function (p) { return ({
224
- label: "local ".concat(p, "/"),
225
- directory: path.join(cwd, p),
226
- symlink: true,
227
- }); });
228
- tempDirs = [];
229
- try {
230
- for (_a = 0, repos_1 = repos; _a < repos_1.length; _a++) {
231
- rawUrl = repos_1[_a];
232
- cloneDir = cloneRepo(rawUrl);
233
- tempDirs.push(cloneDir);
234
- for (_b = 0, SKILL_SOURCE_PATHS_1 = SKILL_SOURCE_PATHS; _b < SKILL_SOURCE_PATHS_1.length; _b++) {
235
- p = SKILL_SOURCE_PATHS_1[_b];
236
- sources.push({
237
- label: "external ".concat(rawUrl, " (").concat(p, "/)"),
238
- directory: path.join(cloneDir, p),
239
- symlink: false,
240
- filterInternal: true,
241
- });
242
- }
243
- }
244
- installSkills(sources, targetDirs, { dryRun: dryRun });
245
- }
246
- finally {
247
- for (_c = 0, tempDirs_1 = tempDirs; _c < tempDirs_1.length; _c++) {
248
- tmpDir = tempDirs_1[_c];
249
- fs.rmSync(tmpDir, { recursive: true, force: true });
250
- }
251
- }
252
- console.log("=== Finished ===");
253
- return [2 /*return*/];
254
- });
255
- }); });