cursor-kit-cli 1.1.1 → 1.2.0-beta.2

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.
Files changed (94) hide show
  1. package/README.md +36 -0
  2. package/bin/cursor-new-instance +74 -0
  3. package/bin/cursor-remove-instance +69 -0
  4. package/dist/cli.cjs +601 -62
  5. package/dist/cli.cjs.map +1 -1
  6. package/dist/cli.js +601 -62
  7. package/dist/cli.js.map +1 -1
  8. package/dist/index.cjs +39 -1
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +9 -1
  11. package/dist/index.d.ts +9 -1
  12. package/dist/index.js +33 -2
  13. package/dist/index.js.map +1 -1
  14. package/package.json +3 -2
  15. package/templates/commands/docs.md +5 -3
  16. package/templates/commands/explain.md +5 -3
  17. package/templates/commands/fix.md +5 -3
  18. package/templates/commands/implement.md +5 -3
  19. package/templates/commands/refactor.md +5 -3
  20. package/templates/commands/review.md +5 -3
  21. package/templates/commands/test.md +5 -3
  22. package/templates/manifest.json +11 -8
  23. package/templates/rules/git.mdc +0 -2
  24. package/templates/rules/toc.mdc +17 -9
  25. package/templates/skills/aesthetic/SKILL.md +121 -0
  26. package/templates/skills/aesthetic/assets/design-guideline-template.md +163 -0
  27. package/templates/skills/aesthetic/assets/design-story-template.md +135 -0
  28. package/templates/skills/aesthetic/references/design-principles.md +62 -0
  29. package/templates/skills/aesthetic/references/design-resources.md +75 -0
  30. package/templates/skills/aesthetic/references/micro-interactions.md +53 -0
  31. package/templates/skills/aesthetic/references/storytelling-design.md +50 -0
  32. package/templates/skills/backend-development/SKILL.mdc +95 -0
  33. package/templates/skills/backend-development/references/backend-api-design.md +495 -0
  34. package/templates/skills/backend-development/references/backend-architecture.md +454 -0
  35. package/templates/skills/backend-development/references/backend-authentication.md +338 -0
  36. package/templates/skills/backend-development/references/backend-code-quality.md +659 -0
  37. package/templates/skills/backend-development/references/backend-debugging.md +904 -0
  38. package/templates/skills/backend-development/references/backend-devops.md +494 -0
  39. package/templates/skills/backend-development/references/backend-mindset.md +387 -0
  40. package/templates/skills/backend-development/references/backend-performance.md +397 -0
  41. package/templates/skills/backend-development/references/backend-security.md +290 -0
  42. package/templates/skills/backend-development/references/backend-technologies.md +256 -0
  43. package/templates/skills/backend-development/references/backend-testing.md +429 -0
  44. package/templates/skills/frontend-design/SKILL.mdc +41 -0
  45. package/templates/skills/frontend-design/references/animejs.md +396 -0
  46. package/templates/skills/frontend-development/SKILL.mdc +399 -0
  47. package/templates/skills/frontend-development/resources/common-patterns.md +331 -0
  48. package/templates/skills/frontend-development/resources/complete-examples.md +872 -0
  49. package/templates/skills/frontend-development/resources/component-patterns.md +502 -0
  50. package/templates/skills/frontend-development/resources/data-fetching.md +767 -0
  51. package/templates/skills/frontend-development/resources/file-organization.md +502 -0
  52. package/templates/skills/frontend-development/resources/loading-and-error-states.md +501 -0
  53. package/templates/skills/frontend-development/resources/performance.md +406 -0
  54. package/templates/skills/frontend-development/resources/routing-guide.md +364 -0
  55. package/templates/skills/frontend-development/resources/styling-guide.md +428 -0
  56. package/templates/skills/frontend-development/resources/typescript-standards.md +418 -0
  57. package/templates/skills/problem-solving/SKILL.mdc +96 -0
  58. package/templates/skills/problem-solving/references/attribution.md +69 -0
  59. package/templates/skills/problem-solving/references/collision-zone-thinking.md +79 -0
  60. package/templates/skills/problem-solving/references/inversion-exercise.md +91 -0
  61. package/templates/skills/problem-solving/references/meta-pattern-recognition.md +87 -0
  62. package/templates/skills/problem-solving/references/scale-game.md +95 -0
  63. package/templates/skills/problem-solving/references/simplification-cascades.md +80 -0
  64. package/templates/skills/problem-solving/references/when-stuck.md +72 -0
  65. package/templates/skills/research/SKILL.mdc +168 -0
  66. package/templates/skills/sequential-thinking/.env.example +8 -0
  67. package/templates/skills/sequential-thinking/README.md +183 -0
  68. package/templates/skills/sequential-thinking/SKILL.mdc +94 -0
  69. package/templates/skills/sequential-thinking/package.json +31 -0
  70. package/templates/skills/sequential-thinking/references/advanced-strategies.md +79 -0
  71. package/templates/skills/sequential-thinking/references/advanced-techniques.md +76 -0
  72. package/templates/skills/sequential-thinking/references/core-patterns.md +95 -0
  73. package/templates/skills/sequential-thinking/references/examples-api.md +88 -0
  74. package/templates/skills/sequential-thinking/references/examples-architecture.md +94 -0
  75. package/templates/skills/sequential-thinking/references/examples-debug.md +90 -0
  76. package/templates/skills/sequential-thinking/scripts/format-thought.js +159 -0
  77. package/templates/skills/sequential-thinking/scripts/process-thought.js +236 -0
  78. package/templates/skills/sequential-thinking/tests/format-thought.test.js +133 -0
  79. package/templates/skills/sequential-thinking/tests/process-thought.test.js +215 -0
  80. package/templates/skills/ui-styling/LICENSE.txt +202 -0
  81. package/templates/skills/ui-styling/SKILL.mdc +321 -0
  82. package/templates/skills/ui-styling/references/canvas-design-system.md +320 -0
  83. package/templates/skills/ui-styling/references/shadcn-accessibility.md +471 -0
  84. package/templates/skills/ui-styling/references/shadcn-components.md +424 -0
  85. package/templates/skills/ui-styling/references/shadcn-theming.md +373 -0
  86. package/templates/skills/ui-styling/references/tailwind-customization.md +483 -0
  87. package/templates/skills/ui-styling/references/tailwind-responsive.md +382 -0
  88. package/templates/skills/ui-styling/references/tailwind-utilities.md +455 -0
  89. package/templates/rules/frontend-design.mdc +0 -48
  90. package/templates/rules/performance.mdc +0 -54
  91. package/templates/rules/react.mdc +0 -58
  92. package/templates/rules/security.mdc +0 -50
  93. package/templates/rules/testing.mdc +0 -54
  94. package/templates/rules/typescript.mdc +0 -36
package/dist/cli.cjs CHANGED
@@ -28,7 +28,7 @@ var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${_
28
28
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
29
29
 
30
30
  // src/cli.ts
31
- var import_citty6 = require("citty");
31
+ var import_citty7 = require("citty");
32
32
  var import_node_module = require("module");
33
33
 
34
34
  // src/utils/branding.ts
@@ -54,6 +54,9 @@ function printSuccess(message) {
54
54
  function printInfo(message) {
55
55
  console.log(import_picocolors.default.cyan("\u2139") + import_picocolors.default.dim(" ") + message);
56
56
  }
57
+ function printWarning(message) {
58
+ console.log(import_picocolors.default.yellow("\u26A0") + import_picocolors.default.dim(" ") + message);
59
+ }
57
60
  function printDivider() {
58
61
  console.log(import_picocolors.default.dim("\u2500".repeat(50)));
59
62
  }
@@ -63,8 +66,8 @@ function printVersion(version) {
63
66
  );
64
67
  console.log();
65
68
  }
66
- function highlight(text2) {
67
- return import_picocolors.default.cyan(text2);
69
+ function highlight(text3) {
70
+ return import_picocolors.default.cyan(text3);
68
71
  }
69
72
 
70
73
  // src/commands/init.ts
@@ -99,6 +102,9 @@ function removeFile(path) {
99
102
  (0, import_node_fs.rmSync)(path, { recursive: true });
100
103
  }
101
104
  }
105
+ function copyDir(src, dest) {
106
+ (0, import_node_fs.cpSync)(src, dest, { recursive: true });
107
+ }
102
108
  function listFiles(dir, extension) {
103
109
  if (!dirExists(dir)) return [];
104
110
  const files = (0, import_node_fs.readdirSync)(dir);
@@ -107,6 +113,13 @@ function listFiles(dir, extension) {
107
113
  }
108
114
  return files;
109
115
  }
116
+ function listDirs(dir) {
117
+ if (!dirExists(dir)) return [];
118
+ return (0, import_node_fs.readdirSync)(dir).filter((item) => {
119
+ const itemPath = (0, import_node_path.join)(dir, item);
120
+ return (0, import_node_fs.statSync)(itemPath).isDirectory();
121
+ });
122
+ }
110
123
  function getCursorDir(cwd = process.cwd()) {
111
124
  return (0, import_node_path.join)(cwd, ".cursor");
112
125
  }
@@ -116,10 +129,17 @@ function getCommandsDir(cwd = process.cwd()) {
116
129
  function getRulesDir(cwd = process.cwd()) {
117
130
  return (0, import_node_path.join)(getCursorDir(cwd), "rules");
118
131
  }
132
+ function getSkillsDir(cwd = process.cwd()) {
133
+ return (0, import_node_path.join)(getCursorDir(cwd), "skills");
134
+ }
119
135
  function getConflictingFiles(dir, files) {
120
136
  if (!dirExists(dir)) return [];
121
137
  return files.filter((file) => fileExists((0, import_node_path.join)(dir, file)));
122
138
  }
139
+ function getConflictingDirs(dir, dirs) {
140
+ if (!dirExists(dir)) return [];
141
+ return dirs.filter((d) => dirExists((0, import_node_path.join)(dir, d)));
142
+ }
123
143
 
124
144
  // src/utils/templates.ts
125
145
  var import_node_path2 = require("path");
@@ -131,7 +151,8 @@ var REPO_REF = "master";
131
151
  var REPO_RAW_URL = "https://raw.githubusercontent.com/duongductrong/cursor-kit/master";
132
152
  var TEMPLATE_PATHS = {
133
153
  commands: "templates/commands",
134
- rules: "templates/rules"
154
+ rules: "templates/rules",
155
+ skills: "templates/skills"
135
156
  };
136
157
 
137
158
  // src/utils/templates.ts
@@ -151,12 +172,14 @@ function getLocalManifest() {
151
172
  }
152
173
  const commandsDir = (0, import_node_path2.join)(templatesDir, "commands");
153
174
  const rulesDir = (0, import_node_path2.join)(templatesDir, "rules");
154
- if (!dirExists(commandsDir) && !dirExists(rulesDir)) {
175
+ const skillsDir = (0, import_node_path2.join)(templatesDir, "skills");
176
+ if (!dirExists(commandsDir) && !dirExists(rulesDir) && !dirExists(skillsDir)) {
155
177
  return null;
156
178
  }
157
179
  return {
158
180
  commands: dirExists(commandsDir) ? listFiles(commandsDir, ".md") : [],
159
- rules: dirExists(rulesDir) ? listFiles(rulesDir, ".mdc") : []
181
+ rules: dirExists(rulesDir) ? listFiles(rulesDir, ".mdc") : [],
182
+ skills: dirExists(skillsDir) ? listDirs(skillsDir) : []
160
183
  };
161
184
  }
162
185
  function getLocalTemplateContent(type, filename) {
@@ -167,6 +190,22 @@ function getLocalTemplateContent(type, filename) {
167
190
  }
168
191
  return null;
169
192
  }
193
+ function getLocalSkillDir(skillName) {
194
+ const templatesDir = getLocalTemplatesDir();
195
+ const skillPath = (0, import_node_path2.join)(templatesDir, "skills", skillName);
196
+ if (dirExists(skillPath)) {
197
+ return skillPath;
198
+ }
199
+ return null;
200
+ }
201
+ function copyLocalSkill(skillName, targetDir) {
202
+ const sourcePath = getLocalSkillDir(skillName);
203
+ if (!sourcePath) return false;
204
+ const destPath = (0, import_node_path2.join)(targetDir, skillName);
205
+ ensureDir(destPath);
206
+ copyDir(sourcePath, destPath);
207
+ return true;
208
+ }
170
209
  async function fetchTemplateManifest() {
171
210
  const localManifest = getLocalManifest();
172
211
  if (localManifest) {
@@ -210,9 +249,13 @@ function getTemplateLabel(filename) {
210
249
  const nameWithoutExt = filename.replace(/\.(md|mdc)$/, "");
211
250
  return nameWithoutExt.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
212
251
  }
252
+ function getSkillLabel(skillName) {
253
+ return skillName.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
254
+ }
213
255
 
214
256
  // src/commands/init.ts
215
257
  async function selectTemplates(type, availableTemplates) {
258
+ const labelFn = type === "skills" ? getSkillLabel : getTemplateLabel;
216
259
  const selectionMode = await p.select({
217
260
  message: `How would you like to add ${type}?`,
218
261
  options: [
@@ -236,7 +279,7 @@ async function selectTemplates(type, availableTemplates) {
236
279
  message: `Select ${type} to add:`,
237
280
  options: availableTemplates.map((template) => ({
238
281
  value: template,
239
- label: getTemplateLabel(template),
282
+ label: labelFn(template),
240
283
  hint: template
241
284
  })),
242
285
  required: true
@@ -300,10 +343,36 @@ async function installTemplates(type, targetDir, selectedTemplates, conflictStra
300
343
  }
301
344
  return result;
302
345
  }
346
+ async function installSkills(targetDir, selectedSkills, conflictStrategy) {
347
+ const result = { added: [], skipped: [] };
348
+ const conflictingDirs = getConflictingDirs(targetDir, selectedSkills);
349
+ let skillsToInstall;
350
+ if (conflictStrategy === "merge") {
351
+ skillsToInstall = selectedSkills.filter(
352
+ (s) => !conflictingDirs.includes(s)
353
+ );
354
+ result.skipped = conflictingDirs.filter(
355
+ (d) => selectedSkills.includes(d)
356
+ );
357
+ } else {
358
+ skillsToInstall = selectedSkills;
359
+ }
360
+ if (skillsToInstall.length === 0) {
361
+ return result;
362
+ }
363
+ ensureDir(targetDir);
364
+ for (const skillName of skillsToInstall) {
365
+ const success = copyLocalSkill(skillName, targetDir);
366
+ if (success) {
367
+ result.added.push(skillName);
368
+ }
369
+ }
370
+ return result;
371
+ }
303
372
  var initCommand = (0, import_citty.defineCommand)({
304
373
  meta: {
305
374
  name: "init",
306
- description: "Initialize .cursor/commands and .cursor/rules in your project"
375
+ description: "Initialize .cursor/commands, .cursor/rules, and .cursor/skills in your project"
307
376
  },
308
377
  args: {
309
378
  force: {
@@ -324,6 +393,12 @@ var initCommand = (0, import_citty.defineCommand)({
324
393
  description: "Only initialize rules",
325
394
  default: false
326
395
  },
396
+ skills: {
397
+ type: "boolean",
398
+ alias: "s",
399
+ description: "Only initialize skills",
400
+ default: false
401
+ },
327
402
  all: {
328
403
  type: "boolean",
329
404
  alias: "a",
@@ -336,9 +411,11 @@ var initCommand = (0, import_citty.defineCommand)({
336
411
  const cursorDir = getCursorDir(cwd);
337
412
  const commandsDir = getCommandsDir(cwd);
338
413
  const rulesDir = getRulesDir(cwd);
339
- const initBoth = !args.commands && !args.rules;
340
- const shouldInitCommands = initBoth || args.commands;
341
- const shouldInitRules = initBoth || args.rules;
414
+ const skillsDir = getSkillsDir(cwd);
415
+ const initAll = !args.commands && !args.rules && !args.skills;
416
+ const shouldInitCommands = initAll || args.commands;
417
+ const shouldInitRules = initAll || args.rules;
418
+ const shouldInitSkills = initAll || args.skills;
342
419
  p.intro(import_picocolors2.default.bgCyan(import_picocolors2.default.black(" cursor-kit init ")));
343
420
  const s = p.spinner();
344
421
  let manifest;
@@ -421,6 +498,36 @@ var initCommand = (0, import_citty.defineCommand)({
421
498
  );
422
499
  s.stop("Rules installed");
423
500
  }
501
+ if (shouldInitSkills) {
502
+ let selectedSkills;
503
+ if (args.all) {
504
+ selectedSkills = manifest.skills;
505
+ } else {
506
+ const selection = await selectTemplates("skills", manifest.skills);
507
+ if (p.isCancel(selection)) {
508
+ p.cancel("Operation cancelled");
509
+ process.exit(0);
510
+ }
511
+ selectedSkills = selection;
512
+ }
513
+ const conflictingSkills = getConflictingDirs(skillsDir, selectedSkills);
514
+ let skillStrategy = "overwrite";
515
+ if (conflictingSkills.length > 0 && !args.force) {
516
+ const strategy = await handleConflicts("skills", conflictingSkills);
517
+ if (p.isCancel(strategy) || strategy === "cancel") {
518
+ p.cancel("Operation cancelled");
519
+ process.exit(0);
520
+ }
521
+ skillStrategy = strategy;
522
+ }
523
+ s.start("Installing skills...");
524
+ results.skills = await installSkills(
525
+ skillsDir,
526
+ selectedSkills,
527
+ skillStrategy
528
+ );
529
+ s.stop("Skills installed");
530
+ }
424
531
  printDivider();
425
532
  console.log();
426
533
  if (results.commands) {
@@ -451,8 +558,22 @@ var initCommand = (0, import_citty.defineCommand)({
451
558
  }
452
559
  }
453
560
  }
454
- const totalAdded = (results.commands?.added.length ?? 0) + (results.rules?.added.length ?? 0);
455
- const totalSkipped = (results.commands?.skipped.length ?? 0) + (results.rules?.skipped.length ?? 0);
561
+ if (results.skills) {
562
+ const { added, skipped } = results.skills;
563
+ if (added.length > 0 || skipped.length > 0) {
564
+ printSuccess(
565
+ `Skills: ${highlight(added.length.toString())} added${skipped.length > 0 ? `, ${import_picocolors2.default.yellow(skipped.length.toString())} skipped` : ""}`
566
+ );
567
+ for (const f of added) {
568
+ console.log(import_picocolors2.default.dim(` \u2514\u2500 ${import_picocolors2.default.green("+")} ${f}`));
569
+ }
570
+ for (const f of skipped) {
571
+ console.log(import_picocolors2.default.dim(` \u2514\u2500 ${import_picocolors2.default.yellow("\u25CB")} ${f} (kept existing)`));
572
+ }
573
+ }
574
+ }
575
+ const totalAdded = (results.commands?.added.length ?? 0) + (results.rules?.added.length ?? 0) + (results.skills?.added.length ?? 0);
576
+ const totalSkipped = (results.commands?.skipped.length ?? 0) + (results.rules?.skipped.length ?? 0) + (results.skills?.skipped.length ?? 0);
456
577
  if (totalAdded === 0 && totalSkipped > 0) {
457
578
  console.log();
458
579
  p.outro(import_picocolors2.default.yellow("No new templates added (all selected files already exist)"));
@@ -471,10 +592,10 @@ var initCommand = (0, import_citty.defineCommand)({
471
592
  });
472
593
 
473
594
  // src/commands/add.ts
474
- var import_citty2 = require("citty");
475
595
  var p2 = __toESM(require("@clack/prompts"), 1);
476
- var import_picocolors3 = __toESM(require("picocolors"), 1);
596
+ var import_citty2 = require("citty");
477
597
  var import_node_path4 = require("path");
598
+ var import_picocolors3 = __toESM(require("picocolors"), 1);
478
599
  var COMMAND_TEMPLATE = `You are a helpful assistant. Describe what this command does.
479
600
 
480
601
  ## Instructions
@@ -501,31 +622,69 @@ Describe the rule behavior here.
501
622
  - Guideline 1
502
623
  - Guideline 2
503
624
  `;
625
+ var SKILL_TEMPLATE = `---
626
+ description: Describe when this skill should be activated
627
+ globs:
628
+ alwaysApply: false
629
+ ---
630
+
631
+ # Skill Name
632
+
633
+ Brief description of what this skill enables.
634
+
635
+ ## Core Capabilities
636
+
637
+ - Capability 1
638
+ - Capability 2
639
+
640
+ ## When to Use
641
+
642
+ Use this skill when:
643
+ - Condition 1
644
+ - Condition 2
645
+
646
+ ## References
647
+
648
+ For detailed guidance, see the references folder:
649
+ - [Reference 1](./references/example.md) - Description
650
+ `;
651
+ var SKILL_REFERENCE_TEMPLATE = `# Reference Title
652
+
653
+ Detailed reference content goes here.
654
+
655
+ ## Section 1
656
+
657
+ Content...
658
+
659
+ ## Section 2
660
+
661
+ Content...
662
+ `;
504
663
  function generateSlug(name) {
505
664
  return name.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
506
665
  }
507
666
  var addCommand = (0, import_citty2.defineCommand)({
508
667
  meta: {
509
668
  name: "add",
510
- description: "Add a new command or rule"
669
+ description: "Add a new command, rule, or skill"
511
670
  },
512
671
  args: {
513
672
  type: {
514
673
  type: "string",
515
674
  alias: "t",
516
- description: "Type: 'command' or 'rule'"
675
+ description: "Type: 'command', 'rule', or 'skill'"
517
676
  },
518
677
  name: {
519
678
  type: "string",
520
679
  alias: "n",
521
- description: "Name of the command or rule"
680
+ description: "Name of the command, rule, or skill"
522
681
  }
523
682
  },
524
683
  async run({ args }) {
525
684
  p2.intro(import_picocolors3.default.bgCyan(import_picocolors3.default.black(" cursor-kit add ")));
526
685
  let itemType;
527
686
  let itemName;
528
- if (args.type && ["command", "rule"].includes(args.type)) {
687
+ if (args.type && ["command", "rule", "skill"].includes(args.type)) {
529
688
  itemType = args.type;
530
689
  } else {
531
690
  const typeResult = await p2.select({
@@ -540,6 +699,11 @@ var addCommand = (0, import_citty2.defineCommand)({
540
699
  value: "rule",
541
700
  label: "Rule",
542
701
  hint: "Project-specific AI behavior rules"
702
+ },
703
+ {
704
+ value: "skill",
705
+ label: "Skill",
706
+ hint: "Comprehensive guide with references"
543
707
  }
544
708
  ]
545
709
  });
@@ -554,7 +718,7 @@ var addCommand = (0, import_citty2.defineCommand)({
554
718
  } else {
555
719
  const nameResult = await p2.text({
556
720
  message: `Enter ${itemType} name:`,
557
- placeholder: itemType === "command" ? "my-command" : "my-rule",
721
+ placeholder: itemType === "command" ? "my-command" : itemType === "rule" ? "my-rule" : "my-skill",
558
722
  validate: (value) => {
559
723
  if (!value.trim()) return "Name is required";
560
724
  if (value.length < 2) return "Name must be at least 2 characters";
@@ -569,12 +733,22 @@ var addCommand = (0, import_citty2.defineCommand)({
569
733
  }
570
734
  const slug = generateSlug(itemName);
571
735
  const isCommand = itemType === "command";
572
- const targetDir = isCommand ? getCommandsDir() : getRulesDir();
573
- const extension = isCommand ? ".md" : ".mdc";
574
- const filePath = (0, import_node_path4.join)(targetDir, `${slug}${extension}`);
575
- if (fileExists(filePath)) {
736
+ const isSkill = itemType === "skill";
737
+ let targetPath;
738
+ let displayPath;
739
+ if (isSkill) {
740
+ const skillsDir = getSkillsDir();
741
+ targetPath = (0, import_node_path4.join)(skillsDir, slug);
742
+ displayPath = targetPath;
743
+ } else {
744
+ const targetDir = isCommand ? getCommandsDir() : getRulesDir();
745
+ const extension = isCommand ? ".md" : ".mdc";
746
+ targetPath = (0, import_node_path4.join)(targetDir, `${slug}${extension}`);
747
+ displayPath = targetPath;
748
+ }
749
+ if (isSkill ? dirExists(targetPath) : fileExists(targetPath)) {
576
750
  const shouldOverwrite = await p2.confirm({
577
- message: `${highlight(slug + extension)} already exists. Overwrite?`,
751
+ message: `${highlight(isSkill ? slug : slug + (isCommand ? ".md" : ".mdc"))} already exists. Overwrite?`,
578
752
  initialValue: false
579
753
  });
580
754
  if (p2.isCancel(shouldOverwrite) || !shouldOverwrite) {
@@ -585,12 +759,25 @@ var addCommand = (0, import_citty2.defineCommand)({
585
759
  const s = p2.spinner();
586
760
  s.start(`Creating ${itemType}...`);
587
761
  try {
588
- ensureDir(targetDir);
589
- const template = isCommand ? COMMAND_TEMPLATE : RULE_TEMPLATE;
590
- writeFile(filePath, template);
762
+ if (isSkill) {
763
+ ensureDir(targetPath);
764
+ ensureDir((0, import_node_path4.join)(targetPath, "references"));
765
+ writeFile((0, import_node_path4.join)(targetPath, "SKILL.mdc"), SKILL_TEMPLATE);
766
+ writeFile((0, import_node_path4.join)(targetPath, "references", "example.md"), SKILL_REFERENCE_TEMPLATE);
767
+ } else {
768
+ const targetDir = isCommand ? getCommandsDir() : getRulesDir();
769
+ ensureDir(targetDir);
770
+ const template = isCommand ? COMMAND_TEMPLATE : RULE_TEMPLATE;
771
+ writeFile(targetPath, template);
772
+ }
591
773
  s.stop(`${itemType.charAt(0).toUpperCase() + itemType.slice(1)} created`);
592
774
  console.log();
593
- console.log(import_picocolors3.default.dim(" File: ") + highlight(filePath));
775
+ if (isSkill) {
776
+ console.log(import_picocolors3.default.dim(" Directory: ") + highlight(displayPath));
777
+ console.log(import_picocolors3.default.dim(" Main file: ") + highlight((0, import_node_path4.join)(displayPath, "SKILL.mdc")));
778
+ } else {
779
+ console.log(import_picocolors3.default.dim(" File: ") + highlight(displayPath));
780
+ }
594
781
  console.log();
595
782
  p2.outro(
596
783
  import_picocolors3.default.green(`\u2728 ${itemType.charAt(0).toUpperCase() + itemType.slice(1)} created! Edit the file to customize it.`)
@@ -626,6 +813,12 @@ var pullCommand = (0, import_citty3.defineCommand)({
626
813
  description: "Only pull rules",
627
814
  default: false
628
815
  },
816
+ skills: {
817
+ type: "boolean",
818
+ alias: "s",
819
+ description: "Only pull skills",
820
+ default: false
821
+ },
629
822
  force: {
630
823
  type: "boolean",
631
824
  alias: "f",
@@ -634,15 +827,18 @@ var pullCommand = (0, import_citty3.defineCommand)({
634
827
  }
635
828
  },
636
829
  async run({ args }) {
637
- const pullBoth = !args.commands && !args.rules;
638
- const shouldPullCommands = pullBoth || args.commands;
639
- const shouldPullRules = pullBoth || args.rules;
830
+ const pullAll = !args.commands && !args.rules && !args.skills;
831
+ const shouldPullCommands = pullAll || args.commands;
832
+ const shouldPullRules = pullAll || args.rules;
833
+ const shouldPullSkills = pullAll || args.skills;
640
834
  p3.intro(import_picocolors4.default.bgCyan(import_picocolors4.default.black(" cursor-kit pull ")));
641
835
  const commandsDir = getCommandsDir();
642
836
  const rulesDir = getRulesDir();
837
+ const skillsDir = getSkillsDir();
643
838
  const existingCommands = listFiles(commandsDir, ".md");
644
839
  const existingRules = listFiles(rulesDir, ".mdc");
645
- const hasExisting = existingCommands.length > 0 || existingRules.length > 0;
840
+ const existingSkills = listDirs(skillsDir);
841
+ const hasExisting = existingCommands.length > 0 || existingRules.length > 0 || existingSkills.length > 0;
646
842
  if (hasExisting && !args.force) {
647
843
  printInfo("Current status:");
648
844
  if (existingCommands.length > 0) {
@@ -651,6 +847,9 @@ var pullCommand = (0, import_citty3.defineCommand)({
651
847
  if (existingRules.length > 0) {
652
848
  console.log(import_picocolors4.default.dim(` Rules: ${existingRules.length} files`));
653
849
  }
850
+ if (existingSkills.length > 0) {
851
+ console.log(import_picocolors4.default.dim(` Skills: ${existingSkills.length} directories`));
852
+ }
654
853
  console.log();
655
854
  const shouldContinue = await p3.confirm({
656
855
  message: "This will merge with existing files. Continue?",
@@ -680,10 +879,19 @@ var pullCommand = (0, import_citty3.defineCommand)({
680
879
  });
681
880
  s.stop("Rules updated");
682
881
  }
882
+ if (shouldPullSkills) {
883
+ s.start("Pulling skills...");
884
+ await (0, import_giget.downloadTemplate)(`${REPO_URL}/templates/skills#${REPO_REF}`, {
885
+ dir: skillsDir,
886
+ force: true
887
+ });
888
+ s.stop("Skills updated");
889
+ }
683
890
  printDivider();
684
891
  console.log();
685
892
  const newCommands = listFiles(commandsDir, ".md");
686
893
  const newRules = listFiles(rulesDir, ".mdc");
894
+ const newSkills = listDirs(skillsDir);
687
895
  if (shouldPullCommands) {
688
896
  const added = newCommands.length - existingCommands.length;
689
897
  printSuccess(
@@ -696,6 +904,12 @@ var pullCommand = (0, import_citty3.defineCommand)({
696
904
  `Rules: ${highlight(newRules.length.toString())} total` + (added > 0 ? import_picocolors4.default.green(` (+${added} new)`) : "")
697
905
  );
698
906
  }
907
+ if (shouldPullSkills) {
908
+ const added = newSkills.length - existingSkills.length;
909
+ printSuccess(
910
+ `Skills: ${highlight(newSkills.length.toString())} total` + (added > 0 ? import_picocolors4.default.green(` (+${added} new)`) : "")
911
+ );
912
+ }
699
913
  console.log();
700
914
  p3.outro(import_picocolors4.default.green("\u2728 Successfully pulled latest updates!"));
701
915
  } catch (error) {
@@ -707,10 +921,10 @@ var pullCommand = (0, import_citty3.defineCommand)({
707
921
  });
708
922
 
709
923
  // src/commands/list.ts
710
- var import_citty4 = require("citty");
711
924
  var p4 = __toESM(require("@clack/prompts"), 1);
712
- var import_picocolors5 = __toESM(require("picocolors"), 1);
925
+ var import_citty4 = require("citty");
713
926
  var import_node_path5 = require("path");
927
+ var import_picocolors5 = __toESM(require("picocolors"), 1);
714
928
  function extractDescription(content, isCommand) {
715
929
  if (isCommand) {
716
930
  const firstLine = content.trim().split("\n")[0];
@@ -737,10 +951,31 @@ function getItems(dir, extension, isCommand) {
737
951
  };
738
952
  });
739
953
  }
954
+ function getSkills(dir) {
955
+ const skillDirs = listDirs(dir);
956
+ return skillDirs.map((skillName) => {
957
+ const skillPath = (0, import_node_path5.join)(dir, skillName);
958
+ const skillFile = (0, import_node_path5.join)(skillPath, "SKILL.mdc");
959
+ const altSkillFile = (0, import_node_path5.join)(skillPath, "SKILL.md");
960
+ let description;
961
+ if (fileExists(skillFile)) {
962
+ const content = readFile(skillFile);
963
+ description = extractDescription(content, false);
964
+ } else if (fileExists(altSkillFile)) {
965
+ const content = readFile(altSkillFile);
966
+ description = extractDescription(content, false);
967
+ }
968
+ return {
969
+ name: skillName,
970
+ path: skillPath,
971
+ description
972
+ };
973
+ });
974
+ }
740
975
  var listCommand = (0, import_citty4.defineCommand)({
741
976
  meta: {
742
977
  name: "list",
743
- description: "List all commands and rules"
978
+ description: "List all commands, rules, and skills"
744
979
  },
745
980
  args: {
746
981
  commands: {
@@ -755,6 +990,12 @@ var listCommand = (0, import_citty4.defineCommand)({
755
990
  description: "Only list rules",
756
991
  default: false
757
992
  },
993
+ skills: {
994
+ type: "boolean",
995
+ alias: "s",
996
+ description: "Only list skills",
997
+ default: false
998
+ },
758
999
  verbose: {
759
1000
  type: "boolean",
760
1001
  alias: "v",
@@ -763,18 +1004,23 @@ var listCommand = (0, import_citty4.defineCommand)({
763
1004
  }
764
1005
  },
765
1006
  async run({ args }) {
766
- const listBoth = !args.commands && !args.rules;
767
- const shouldListCommands = listBoth || args.commands;
768
- const shouldListRules = listBoth || args.rules;
1007
+ const listAll = !args.commands && !args.rules && !args.skills;
1008
+ const shouldListCommands = listAll || args.commands;
1009
+ const shouldListRules = listAll || args.rules;
1010
+ const shouldListSkills = listAll || args.skills;
769
1011
  p4.intro(import_picocolors5.default.bgCyan(import_picocolors5.default.black(" cursor-kit list ")));
770
1012
  const commandsDir = getCommandsDir();
771
1013
  const rulesDir = getRulesDir();
1014
+ const skillsDir = getSkillsDir();
772
1015
  const commands = shouldListCommands ? getItems(commandsDir, ".md", true) : [];
773
1016
  const rules = shouldListRules ? getItems(rulesDir, ".mdc", false) : [];
774
- if (commands.length === 0 && rules.length === 0) {
1017
+ const skills = shouldListSkills ? getSkills(skillsDir) : [];
1018
+ if (commands.length === 0 && rules.length === 0 && skills.length === 0) {
775
1019
  console.log();
776
- console.log(import_picocolors5.default.yellow(" No commands or rules found."));
777
- console.log(import_picocolors5.default.dim(" Run ") + highlight("cursor-kit init") + import_picocolors5.default.dim(" to get started."));
1020
+ console.log(import_picocolors5.default.yellow(" No commands, rules, or skills found."));
1021
+ console.log(
1022
+ import_picocolors5.default.dim(" Run ") + highlight("cursor-kit init") + import_picocolors5.default.dim(" to get started.")
1023
+ );
778
1024
  console.log();
779
1025
  p4.outro(import_picocolors5.default.dim("Nothing to show"));
780
1026
  return;
@@ -782,7 +1028,9 @@ var listCommand = (0, import_citty4.defineCommand)({
782
1028
  printDivider();
783
1029
  if (shouldListCommands && commands.length > 0) {
784
1030
  console.log();
785
- console.log(import_picocolors5.default.bold(import_picocolors5.default.cyan(" \u{1F4DC} Commands")) + import_picocolors5.default.dim(` (${commands.length})`));
1031
+ console.log(
1032
+ import_picocolors5.default.bold(import_picocolors5.default.cyan(" \u{1F4DC} Commands")) + import_picocolors5.default.dim(` (${commands.length})`)
1033
+ );
786
1034
  console.log();
787
1035
  commands.forEach((cmd) => {
788
1036
  console.log(` ${import_picocolors5.default.green("\u25CF")} ${highlight(cmd.name)}`);
@@ -796,7 +1044,9 @@ var listCommand = (0, import_citty4.defineCommand)({
796
1044
  }
797
1045
  if (shouldListRules && rules.length > 0) {
798
1046
  console.log();
799
- console.log(import_picocolors5.default.bold(import_picocolors5.default.cyan(" \u{1F4CB} Rules")) + import_picocolors5.default.dim(` (${rules.length})`));
1047
+ console.log(
1048
+ import_picocolors5.default.bold(import_picocolors5.default.cyan(" \u{1F4CB} Rules")) + import_picocolors5.default.dim(` (${rules.length})`)
1049
+ );
800
1050
  console.log();
801
1051
  rules.forEach((rule) => {
802
1052
  console.log(` ${import_picocolors5.default.green("\u25CF")} ${highlight(rule.name)}`);
@@ -808,9 +1058,25 @@ var listCommand = (0, import_citty4.defineCommand)({
808
1058
  }
809
1059
  });
810
1060
  }
1061
+ if (shouldListSkills && skills.length > 0) {
1062
+ console.log();
1063
+ console.log(
1064
+ import_picocolors5.default.bold(import_picocolors5.default.cyan(" \u{1F3AF} Skills")) + import_picocolors5.default.dim(` (${skills.length})`)
1065
+ );
1066
+ console.log();
1067
+ skills.forEach((skill) => {
1068
+ console.log(` ${import_picocolors5.default.green("\u25CF")} ${highlight(skill.name)}`);
1069
+ if (skill.description) {
1070
+ console.log(import_picocolors5.default.dim(` ${skill.description}`));
1071
+ }
1072
+ if (args.verbose) {
1073
+ console.log(import_picocolors5.default.dim(` ${skill.path}`));
1074
+ }
1075
+ });
1076
+ }
811
1077
  console.log();
812
1078
  printDivider();
813
- const total = commands.length + rules.length;
1079
+ const total = commands.length + rules.length + skills.length;
814
1080
  p4.outro(import_picocolors5.default.dim(`Total: ${total} item${total !== 1 ? "s" : ""}`));
815
1081
  }
816
1082
  });
@@ -823,18 +1089,18 @@ var import_node_path6 = require("path");
823
1089
  var removeCommand = (0, import_citty5.defineCommand)({
824
1090
  meta: {
825
1091
  name: "remove",
826
- description: "Remove a command or rule"
1092
+ description: "Remove a command, rule, or skill"
827
1093
  },
828
1094
  args: {
829
1095
  type: {
830
1096
  type: "string",
831
1097
  alias: "t",
832
- description: "Type: 'command' or 'rule'"
1098
+ description: "Type: 'command', 'rule', or 'skill'"
833
1099
  },
834
1100
  name: {
835
1101
  type: "string",
836
1102
  alias: "n",
837
- description: "Name of the command or rule to remove"
1103
+ description: "Name of the command, rule, or skill to remove"
838
1104
  },
839
1105
  force: {
840
1106
  type: "boolean",
@@ -847,18 +1113,20 @@ var removeCommand = (0, import_citty5.defineCommand)({
847
1113
  p5.intro(import_picocolors6.default.bgCyan(import_picocolors6.default.black(" cursor-kit remove ")));
848
1114
  const commandsDir = getCommandsDir();
849
1115
  const rulesDir = getRulesDir();
1116
+ const skillsDir = getSkillsDir();
850
1117
  const commands = listFiles(commandsDir, ".md").map((f) => f.replace(".md", ""));
851
1118
  const rules = listFiles(rulesDir, ".mdc").map((f) => f.replace(".mdc", ""));
852
- if (commands.length === 0 && rules.length === 0) {
1119
+ const skills = listDirs(skillsDir);
1120
+ if (commands.length === 0 && rules.length === 0 && skills.length === 0) {
853
1121
  console.log();
854
- console.log(import_picocolors6.default.yellow(" No commands or rules to remove."));
1122
+ console.log(import_picocolors6.default.yellow(" No commands, rules, or skills to remove."));
855
1123
  console.log();
856
1124
  p5.outro(import_picocolors6.default.dim("Nothing to do"));
857
1125
  return;
858
1126
  }
859
1127
  let itemType;
860
1128
  let itemName;
861
- if (args.type && ["command", "rule"].includes(args.type)) {
1129
+ if (args.type && ["command", "rule", "skill"].includes(args.type)) {
862
1130
  itemType = args.type;
863
1131
  } else {
864
1132
  const typeOptions = [];
@@ -876,6 +1144,13 @@ var removeCommand = (0, import_citty5.defineCommand)({
876
1144
  hint: `${rules.length} available`
877
1145
  });
878
1146
  }
1147
+ if (skills.length > 0) {
1148
+ typeOptions.push({
1149
+ value: "skill",
1150
+ label: "Skill",
1151
+ hint: `${skills.length} available`
1152
+ });
1153
+ }
879
1154
  const typeResult = await p5.select({
880
1155
  message: "What do you want to remove?",
881
1156
  options: typeOptions
@@ -887,9 +1162,11 @@ var removeCommand = (0, import_citty5.defineCommand)({
887
1162
  itemType = typeResult;
888
1163
  }
889
1164
  const isCommand = itemType === "command";
890
- const items = isCommand ? commands : rules;
891
- const dir = isCommand ? commandsDir : rulesDir;
892
- const extension = isCommand ? ".md" : ".mdc";
1165
+ const isRule = itemType === "rule";
1166
+ const isSkill = itemType === "skill";
1167
+ const items = isCommand ? commands : isRule ? rules : skills;
1168
+ const dir = isCommand ? commandsDir : isRule ? rulesDir : skillsDir;
1169
+ const extension = isCommand ? ".md" : isRule ? ".mdc" : "";
893
1170
  if (items.length === 0) {
894
1171
  p5.cancel(`No ${itemType}s found`);
895
1172
  process.exit(0);
@@ -911,14 +1188,16 @@ var removeCommand = (0, import_citty5.defineCommand)({
911
1188
  }
912
1189
  itemName = nameResult;
913
1190
  }
914
- const filePath = (0, import_node_path6.join)(dir, `${itemName}${extension}`);
915
- if (!fileExists(filePath)) {
1191
+ const targetPath = isSkill ? (0, import_node_path6.join)(dir, itemName) : (0, import_node_path6.join)(dir, `${itemName}${extension}`);
1192
+ const exists = isSkill ? dirExists(targetPath) : fileExists(targetPath);
1193
+ if (!exists) {
916
1194
  p5.cancel(`${itemType} '${itemName}' not found`);
917
1195
  process.exit(1);
918
1196
  }
919
1197
  if (!args.force) {
1198
+ const displayName = isSkill ? itemName : itemName + extension;
920
1199
  const shouldDelete = await p5.confirm({
921
- message: `Are you sure you want to delete ${highlight(itemName + extension)}?`,
1200
+ message: `Are you sure you want to delete ${highlight(displayName)}?${isSkill ? " (This will remove the entire skill directory)" : ""}`,
922
1201
  initialValue: false
923
1202
  });
924
1203
  if (p5.isCancel(shouldDelete) || !shouldDelete) {
@@ -927,9 +1206,10 @@ var removeCommand = (0, import_citty5.defineCommand)({
927
1206
  }
928
1207
  }
929
1208
  try {
930
- removeFile(filePath);
1209
+ removeFile(targetPath);
1210
+ const displayName = isSkill ? itemName : itemName + extension;
931
1211
  console.log();
932
- printSuccess(`Removed ${highlight(itemName + extension)}`);
1212
+ printSuccess(`Removed ${highlight(displayName)}`);
933
1213
  console.log();
934
1214
  p5.outro(import_picocolors6.default.green("\u2728 Done!"));
935
1215
  } catch (error) {
@@ -939,10 +1219,268 @@ var removeCommand = (0, import_citty5.defineCommand)({
939
1219
  }
940
1220
  });
941
1221
 
1222
+ // src/commands/instance.ts
1223
+ var import_citty6 = require("citty");
1224
+ var p6 = __toESM(require("@clack/prompts"), 1);
1225
+ var import_picocolors7 = __toESM(require("picocolors"), 1);
1226
+ var import_node_child_process = require("child_process");
1227
+ var import_node_path7 = require("path");
1228
+ var import_node_url2 = require("url");
1229
+ var import_node_fs2 = require("fs");
1230
+ function getBinPath() {
1231
+ const currentDir = (0, import_node_path7.dirname)((0, import_node_url2.fileURLToPath)(importMetaUrl));
1232
+ const possiblePaths = [
1233
+ (0, import_node_path7.join)(currentDir, "..", "..", "bin"),
1234
+ (0, import_node_path7.join)(currentDir, "..", "bin")
1235
+ ];
1236
+ for (const binPath of possiblePaths) {
1237
+ if ((0, import_node_fs2.existsSync)(binPath)) {
1238
+ return binPath;
1239
+ }
1240
+ }
1241
+ return possiblePaths[0];
1242
+ }
1243
+ function ensureExecutable(scriptPath) {
1244
+ try {
1245
+ (0, import_node_fs2.chmodSync)(scriptPath, 493);
1246
+ } catch {
1247
+ }
1248
+ }
1249
+ function getExistingInstances() {
1250
+ const userAppsDir = (0, import_node_path7.join)(process.env.HOME ?? "", "Applications");
1251
+ if (!(0, import_node_fs2.existsSync)(userAppsDir)) return [];
1252
+ try {
1253
+ const apps = (0, import_node_fs2.readdirSync)(userAppsDir);
1254
+ return apps.filter((app) => app.startsWith("Cursor") && app.endsWith(".app") && app !== "Cursor.app").map((app) => ({
1255
+ name: app.replace(".app", ""),
1256
+ path: (0, import_node_path7.join)(userAppsDir, app)
1257
+ }));
1258
+ } catch {
1259
+ return [];
1260
+ }
1261
+ }
1262
+ function runScript(scriptPath, args) {
1263
+ return new Promise((resolve2) => {
1264
+ ensureExecutable(scriptPath);
1265
+ const child = (0, import_node_child_process.spawn)(scriptPath, args, {
1266
+ stdio: "inherit"
1267
+ });
1268
+ child.on("close", (code) => {
1269
+ resolve2(code ?? 1);
1270
+ });
1271
+ child.on("error", () => {
1272
+ resolve2(1);
1273
+ });
1274
+ });
1275
+ }
1276
+ var instanceCommand = (0, import_citty6.defineCommand)({
1277
+ meta: {
1278
+ name: "instance",
1279
+ description: "Manage Cursor IDE instances for multi-account login (macOS only)"
1280
+ },
1281
+ args: {
1282
+ action: {
1283
+ type: "string",
1284
+ alias: "a",
1285
+ description: "Action: 'create' or 'remove'"
1286
+ },
1287
+ name: {
1288
+ type: "string",
1289
+ alias: "n",
1290
+ description: "Name of the instance (e.g. 'Cursor Enterprise')"
1291
+ },
1292
+ list: {
1293
+ type: "boolean",
1294
+ alias: "l",
1295
+ description: "List existing Cursor instances",
1296
+ default: false
1297
+ }
1298
+ },
1299
+ async run({ args }) {
1300
+ p6.intro(import_picocolors7.default.bgCyan(import_picocolors7.default.black(" cursor-kit instance ")));
1301
+ if (process.platform !== "darwin") {
1302
+ console.log();
1303
+ printWarning("This command only works on macOS.");
1304
+ console.log(import_picocolors7.default.dim(" Cursor instance management requires macOS-specific features."));
1305
+ console.log();
1306
+ p6.outro(import_picocolors7.default.dim("Exiting"));
1307
+ process.exit(1);
1308
+ }
1309
+ if (args.list) {
1310
+ const instances = getExistingInstances();
1311
+ printDivider();
1312
+ console.log();
1313
+ if (instances.length === 0) {
1314
+ printInfo("No custom Cursor instances found.");
1315
+ console.log(import_picocolors7.default.dim(" Run ") + highlight("cursor-kit instance") + import_picocolors7.default.dim(" to create one."));
1316
+ } else {
1317
+ console.log(import_picocolors7.default.bold(import_picocolors7.default.cyan(" \u{1F5A5} Cursor Instances")) + import_picocolors7.default.dim(` (${instances.length})`));
1318
+ console.log();
1319
+ for (const instance of instances) {
1320
+ console.log(` ${import_picocolors7.default.green("\u25CF")} ${highlight(instance.name)}`);
1321
+ console.log(import_picocolors7.default.dim(` \u2514\u2500 ${instance.path}`));
1322
+ }
1323
+ }
1324
+ console.log();
1325
+ printDivider();
1326
+ p6.outro(import_picocolors7.default.dim(`Total: ${instances.length} instance${instances.length !== 1 ? "s" : ""}`));
1327
+ return;
1328
+ }
1329
+ const s = p6.spinner();
1330
+ s.start("Checking prerequisites...");
1331
+ const binPath = getBinPath();
1332
+ const createScript = (0, import_node_path7.join)(binPath, "cursor-new-instance");
1333
+ const removeScript = (0, import_node_path7.join)(binPath, "cursor-remove-instance");
1334
+ const scriptsExist = (0, import_node_fs2.existsSync)(createScript) && (0, import_node_fs2.existsSync)(removeScript);
1335
+ if (!scriptsExist) {
1336
+ s.stop("Prerequisites check failed");
1337
+ console.log();
1338
+ printWarning("Required scripts not found.");
1339
+ console.log(import_picocolors7.default.dim(` Expected at: ${binPath}`));
1340
+ console.log();
1341
+ p6.outro(import_picocolors7.default.red("Installation may be corrupted"));
1342
+ process.exit(1);
1343
+ }
1344
+ const originalCursor = "/Applications/Cursor.app";
1345
+ if (!(0, import_node_fs2.existsSync)(originalCursor)) {
1346
+ s.stop("Prerequisites check failed");
1347
+ console.log();
1348
+ printWarning("Cursor.app not found in /Applications");
1349
+ console.log(import_picocolors7.default.dim(" Please install Cursor IDE first."));
1350
+ console.log();
1351
+ p6.outro(import_picocolors7.default.red("Cursor IDE required"));
1352
+ process.exit(1);
1353
+ }
1354
+ s.stop("Prerequisites verified");
1355
+ const existingInstances = getExistingInstances();
1356
+ let action;
1357
+ let instanceName;
1358
+ if (args.action && ["create", "remove"].includes(args.action)) {
1359
+ action = args.action;
1360
+ } else {
1361
+ const actionResult = await p6.select({
1362
+ message: "What would you like to do?",
1363
+ options: [
1364
+ {
1365
+ value: "create",
1366
+ label: "Create new instance",
1367
+ hint: "Clone Cursor with separate identity"
1368
+ },
1369
+ {
1370
+ value: "remove",
1371
+ label: "Remove instance",
1372
+ hint: existingInstances.length > 0 ? `${existingInstances.length} instance${existingInstances.length !== 1 ? "s" : ""} available` : "No instances to remove"
1373
+ }
1374
+ ]
1375
+ });
1376
+ if (p6.isCancel(actionResult)) {
1377
+ p6.cancel("Operation cancelled");
1378
+ process.exit(0);
1379
+ }
1380
+ action = actionResult;
1381
+ }
1382
+ if (args.name) {
1383
+ instanceName = args.name;
1384
+ } else if (action === "remove" && existingInstances.length > 0) {
1385
+ const instanceResult = await p6.select({
1386
+ message: "Select instance to remove:",
1387
+ options: existingInstances.map((inst) => ({
1388
+ value: inst.name,
1389
+ label: inst.name,
1390
+ hint: inst.path
1391
+ }))
1392
+ });
1393
+ if (p6.isCancel(instanceResult)) {
1394
+ p6.cancel("Operation cancelled");
1395
+ process.exit(0);
1396
+ }
1397
+ instanceName = instanceResult;
1398
+ } else if (action === "remove" && existingInstances.length === 0) {
1399
+ console.log();
1400
+ printInfo("No custom Cursor instances found to remove.");
1401
+ console.log();
1402
+ p6.outro(import_picocolors7.default.dim("Nothing to do"));
1403
+ return;
1404
+ } else {
1405
+ const nameResult = await p6.text({
1406
+ message: "Enter a name for the new instance:",
1407
+ placeholder: "Cursor Enterprise",
1408
+ validate: (value) => {
1409
+ if (!value.trim()) return "Instance name is required";
1410
+ if (value.length < 2) return "Name must be at least 2 characters";
1411
+ const existing = existingInstances.find(
1412
+ (i) => i.name.toLowerCase() === value.toLowerCase()
1413
+ );
1414
+ if (existing) return `Instance "${value}" already exists`;
1415
+ return void 0;
1416
+ }
1417
+ });
1418
+ if (p6.isCancel(nameResult)) {
1419
+ p6.cancel("Operation cancelled");
1420
+ process.exit(0);
1421
+ }
1422
+ instanceName = nameResult;
1423
+ }
1424
+ printDivider();
1425
+ console.log();
1426
+ console.log(import_picocolors7.default.bold(import_picocolors7.default.cyan(" \u{1F4CB} Summary")));
1427
+ console.log();
1428
+ console.log(` ${import_picocolors7.default.dim("Action:")} ${action === "create" ? import_picocolors7.default.green("Create") : import_picocolors7.default.yellow("Remove")}`);
1429
+ console.log(` ${import_picocolors7.default.dim("Instance:")} ${highlight(instanceName)}`);
1430
+ if (action === "create") {
1431
+ const slug = instanceName.toLowerCase().replace(/[^a-z0-9]/g, "");
1432
+ console.log(` ${import_picocolors7.default.dim("Bundle ID:")} ${import_picocolors7.default.dim("com.cursor.")}${highlight(slug)}`);
1433
+ console.log(` ${import_picocolors7.default.dim("Location:")} ${import_picocolors7.default.dim("~/Applications/")}${highlight(instanceName + ".app")}`);
1434
+ } else {
1435
+ const targetPath = (0, import_node_path7.join)(process.env.HOME ?? "", "Applications", `${instanceName}.app`);
1436
+ console.log(` ${import_picocolors7.default.dim("Path:")} ${import_picocolors7.default.dim(targetPath)}`);
1437
+ }
1438
+ console.log();
1439
+ printDivider();
1440
+ console.log();
1441
+ const shouldContinue = await p6.confirm({
1442
+ message: action === "create" ? "Create this Cursor instance?" : "Remove this Cursor instance? This cannot be undone.",
1443
+ initialValue: action === "create"
1444
+ });
1445
+ if (p6.isCancel(shouldContinue) || !shouldContinue) {
1446
+ p6.cancel("Operation cancelled");
1447
+ process.exit(0);
1448
+ }
1449
+ console.log();
1450
+ printDivider();
1451
+ console.log();
1452
+ const scriptPath = action === "create" ? createScript : removeScript;
1453
+ const scriptArgs = action === "remove" ? ["--yes", instanceName] : [instanceName];
1454
+ const exitCode = await runScript(scriptPath, scriptArgs);
1455
+ console.log();
1456
+ printDivider();
1457
+ console.log();
1458
+ if (exitCode === 0) {
1459
+ if (action === "create") {
1460
+ printSuccess(`Instance ${highlight(instanceName)} created successfully!`);
1461
+ console.log();
1462
+ console.log(import_picocolors7.default.dim(" Next steps:"));
1463
+ console.log(import_picocolors7.default.dim(" \u2022 The new instance should launch automatically"));
1464
+ console.log(import_picocolors7.default.dim(" \u2022 Sign in with a different Cursor account"));
1465
+ console.log(import_picocolors7.default.dim(" \u2022 Find it in ~/Applications/"));
1466
+ } else {
1467
+ printSuccess(`Instance ${highlight(instanceName)} removed successfully!`);
1468
+ }
1469
+ console.log();
1470
+ p6.outro(import_picocolors7.default.green("\u2728 Done!"));
1471
+ } else {
1472
+ printWarning(`Operation completed with exit code ${exitCode}`);
1473
+ console.log();
1474
+ p6.outro(import_picocolors7.default.yellow("Check the output above for details"));
1475
+ process.exit(exitCode);
1476
+ }
1477
+ }
1478
+ });
1479
+
942
1480
  // src/cli.ts
943
1481
  var require2 = (0, import_node_module.createRequire)(importMetaUrl);
944
1482
  var pkg = require2("../package.json");
945
- var main = (0, import_citty6.defineCommand)({
1483
+ var main = (0, import_citty7.defineCommand)({
946
1484
  meta: {
947
1485
  name: "cursor-kit",
948
1486
  version: pkg.version,
@@ -957,8 +1495,9 @@ var main = (0, import_citty6.defineCommand)({
957
1495
  add: addCommand,
958
1496
  pull: pullCommand,
959
1497
  list: listCommand,
960
- remove: removeCommand
1498
+ remove: removeCommand,
1499
+ instance: instanceCommand
961
1500
  }
962
1501
  });
963
- (0, import_citty6.runMain)(main);
1502
+ (0, import_citty7.runMain)(main);
964
1503
  //# sourceMappingURL=cli.cjs.map