@comet/cli 9.0.0-beta.4 → 9.0.0-beta.6

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 _b = 0, repos_1 = repos; _b < repos_1.length; _b++) {
281
- var rawUrl = repos_1[_b];
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 _c = 0, SKILL_SOURCE_PATHS_1 = SKILL_SOURCE_PATHS; _c < SKILL_SOURCE_PATHS_1.length; _c++) {
285
- var p = SKILL_SOURCE_PATHS_1[_c];
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 _d = 0, RULE_SOURCE_PATHS_1 = RULE_SOURCE_PATHS; _d < RULE_SOURCE_PATHS_1.length; _d++) {
298
- var p = RULE_SOURCE_PATHS_1[_d];
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 _e = 0, tempDirs_1 = tempDirs; _e < tempDirs_1.length; _e++) {
318
- var tmpDir = tempDirs_1[_e];
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comet/cli",
3
- "version": "9.0.0-beta.4",
3
+ "version": "9.0.0-beta.6",
4
4
  "description": "A collection of CLI tools for Comet projects",
5
5
  "repository": {
6
6
  "directory": "packages/cli",
@@ -32,8 +32,8 @@
32
32
  "npm-run-all2": "^8.0.4",
33
33
  "rimraf": "^6.1.2",
34
34
  "typescript": "^5.9.3",
35
- "vitest": "^4.0.16",
36
- "@comet/eslint-config": "9.0.0-beta.4"
35
+ "vitest": "^4.1.8",
36
+ "@comet/eslint-config": "9.0.0-beta.6"
37
37
  },
38
38
  "engines": {
39
39
  "node": ">=22.0.0"
@@ -43,7 +43,7 @@
43
43
  "registry": "https://registry.npmjs.org"
44
44
  },
45
45
  "scripts": {
46
- "build": "pnpm run clean && tsc",
46
+ "build": "pnpm run clean && tsc -p tsconfig.build.json",
47
47
  "clean": "rimraf lib",
48
48
  "dev": "tsc --watch",
49
49
  "lint": "run-p lint:prettier lint:eslint lint:tsc",
@@ -54,7 +54,8 @@
54
54
  "lint:fix:prettier": "pnpm run lint:prettier --write",
55
55
  "lint:prettier": "pnpm exec prettier --check '*.{ts,js,json,md,yml,yaml}'",
56
56
  "lint:tsc": "tsc",
57
- "test": "vitest --run",
57
+ "test": "pnpm run test:unit",
58
+ "test:unit": "vitest --run",
58
59
  "test:watch": "vitest --watch"
59
60
  }
60
61
  }
@@ -1 +0,0 @@
1
- export {};
@@ -1,234 +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
- 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 – missing local sources", function () {
214
- (0, vitest_1.it)("runs cleanly when there are no local skills or rules", function () {
215
- mockFilesystem({});
216
- (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
217
- (0, vitest_1.expect)(fs.symlinkSync).not.toHaveBeenCalled();
218
- (0, vitest_1.expect)(fs.cpSync).not.toHaveBeenCalled();
219
- (0, vitest_1.expect)(console.log).toHaveBeenCalledWith(vitest_1.expect.stringContaining("No skills found"));
220
- (0, vitest_1.expect)(console.log).toHaveBeenCalledWith(vitest_1.expect.stringContaining("No rules found"));
221
- });
222
- });
223
- (0, vitest_1.describe)("installFeatures – EPERM symlink fallback", function () {
224
- (0, vitest_1.it)("falls back to copy when symlinkSync throws EPERM (e.g. Windows without privileges)", function () {
225
- mockFilesystem({ listings: { "/proj/skills": ["my-skill"] } });
226
- vitest_1.vi.mocked(fs.symlinkSync).mockImplementationOnce(function () {
227
- throw Object.assign(new Error("permission denied"), { code: "EPERM" });
228
- });
229
- (0, install_agent_features_1.installFeatures)("/proj", [], { dryRun: false });
230
- (0, vitest_1.expect)(fs.cpSync).toHaveBeenCalledWith(path.resolve("/proj/skills/my-skill"), path.join("/proj", ".agents", "skills", "my-skill"), {
231
- recursive: true,
232
- });
233
- });
234
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,70 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- var child_process_1 = require("child_process");
4
- var vitest_1 = require("vitest");
5
- var site_configs_1 = require("./site-configs");
6
- vitest_1.vi.mock("child_process", function () { return ({
7
- execSync: vitest_1.vi.fn(),
8
- }); });
9
- var mockedExecSync = vitest_1.vi.mocked(child_process_1.execSync);
10
- (0, vitest_1.afterEach)(function () {
11
- vitest_1.vi.clearAllMocks();
12
- vitest_1.vi.restoreAllMocks();
13
- });
14
- (0, vitest_1.describe)("resolveOpReferences", function () {
15
- (0, vitest_1.it)("should resolve op:// references", function () {
16
- mockedExecSync.mockImplementation(function (cmd) {
17
- if (cmd === "op --version") {
18
- return Buffer.from("2.0.0");
19
- }
20
- if (cmd === 'op read "op://vault/item/password"') {
21
- return "resolved-secret\n";
22
- }
23
- return "";
24
- });
25
- var result = (0, site_configs_1.resolveOpReferences)('{"key":"{{ op://vault/item/password }}"}');
26
- (0, vitest_1.expect)(result).toBe('{"key":"resolved-secret"}');
27
- });
28
- (0, vitest_1.it)("should throw an error when op CLI is not installed", function () {
29
- mockedExecSync.mockImplementation(function () {
30
- throw new Error("command not found: op");
31
- });
32
- (0, vitest_1.expect)(function () { return (0, site_configs_1.resolveOpReferences)('{"key":"{{ op://vault/item/password }}"}'); }).toThrow("inject-site-configs: Config contains 1Password references (op://) but the 1Password CLI (op) is not installed");
33
- });
34
- (0, vitest_1.it)("should throw an error when op reference resolution fails", function () {
35
- mockedExecSync.mockImplementation(function (cmd) {
36
- if (cmd === "op --version") {
37
- return Buffer.from("2.0.0");
38
- }
39
- if (cmd === 'op read "op://vault/item/password"') {
40
- throw new Error("Item not found");
41
- }
42
- return "";
43
- });
44
- (0, vitest_1.expect)(function () { return (0, site_configs_1.resolveOpReferences)('{"key":"{{ op://vault/item/password }}"}'); }).toThrow("inject-site-configs: Failed to resolve 1Password reference {{ op://vault/item/password }}");
45
- });
46
- (0, vitest_1.it)("should resolve multiple op:// references", function () {
47
- mockedExecSync.mockImplementation(function (cmd) {
48
- if (cmd === "op --version") {
49
- return Buffer.from("2.0.0");
50
- }
51
- if (cmd === 'op read "op://vault/item/api-key"') {
52
- return "resolved-api-key\n";
53
- }
54
- if (cmd === 'op read "op://vault/item/api-secret"') {
55
- return "resolved-api-secret\n";
56
- }
57
- if (cmd === 'op read "op://vault/database/password"') {
58
- return "resolved-db-password\n";
59
- }
60
- return "";
61
- });
62
- var result = (0, site_configs_1.resolveOpReferences)('{"apiKey":"{{ op://vault/item/api-key }}","apiSecret":"{{ op://vault/item/api-secret }}","dbPassword":"{{ op://vault/database/password }}"}');
63
- (0, vitest_1.expect)(result).toBe('{"apiKey":"resolved-api-key","apiSecret":"resolved-api-secret","dbPassword":"resolved-db-password"}');
64
- });
65
- (0, vitest_1.it)("should not call op CLI when no op:// references are present", function () {
66
- var result = (0, site_configs_1.resolveOpReferences)('{"key":"plain-value"}');
67
- (0, vitest_1.expect)(result).toBe('{"key":"plain-value"}');
68
- (0, vitest_1.expect)(mockedExecSync).not.toHaveBeenCalled();
69
- });
70
- });