cursor-kit-cli 1.2.0-beta → 1.2.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cursor-reinstall-instance.sh +102 -0
- package/dist/cli.cjs +366 -69
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +367 -70
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +39 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +33 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/commands/docs.md +5 -3
- package/templates/commands/explain.md +5 -3
- package/templates/commands/fix.md +5 -3
- package/templates/commands/implement.md +5 -3
- package/templates/commands/refactor.md +5 -3
- package/templates/commands/review.md +5 -3
- package/templates/commands/test.md +5 -3
- package/templates/manifest.json +11 -8
- package/templates/rules/git.mdc +0 -2
- package/templates/rules/toc.mdc +17 -9
- package/templates/skills/aesthetic/SKILL.md +121 -0
- package/templates/skills/aesthetic/assets/design-guideline-template.md +163 -0
- package/templates/skills/aesthetic/assets/design-story-template.md +135 -0
- package/templates/skills/aesthetic/references/design-principles.md +62 -0
- package/templates/skills/aesthetic/references/design-resources.md +75 -0
- package/templates/skills/aesthetic/references/micro-interactions.md +53 -0
- package/templates/skills/aesthetic/references/storytelling-design.md +50 -0
- package/templates/skills/backend-development/SKILL.mdc +95 -0
- package/templates/skills/backend-development/references/backend-api-design.md +495 -0
- package/templates/skills/backend-development/references/backend-architecture.md +454 -0
- package/templates/skills/backend-development/references/backend-authentication.md +338 -0
- package/templates/skills/backend-development/references/backend-code-quality.md +659 -0
- package/templates/skills/backend-development/references/backend-debugging.md +904 -0
- package/templates/skills/backend-development/references/backend-devops.md +494 -0
- package/templates/skills/backend-development/references/backend-mindset.md +387 -0
- package/templates/skills/backend-development/references/backend-performance.md +397 -0
- package/templates/skills/backend-development/references/backend-security.md +290 -0
- package/templates/skills/backend-development/references/backend-technologies.md +256 -0
- package/templates/skills/backend-development/references/backend-testing.md +429 -0
- package/templates/skills/frontend-design/SKILL.mdc +41 -0
- package/templates/skills/frontend-design/references/animejs.md +396 -0
- package/templates/skills/frontend-development/SKILL.mdc +399 -0
- package/templates/skills/frontend-development/resources/common-patterns.md +331 -0
- package/templates/skills/frontend-development/resources/complete-examples.md +872 -0
- package/templates/skills/frontend-development/resources/component-patterns.md +502 -0
- package/templates/skills/frontend-development/resources/data-fetching.md +767 -0
- package/templates/skills/frontend-development/resources/file-organization.md +502 -0
- package/templates/skills/frontend-development/resources/loading-and-error-states.md +501 -0
- package/templates/skills/frontend-development/resources/performance.md +406 -0
- package/templates/skills/frontend-development/resources/routing-guide.md +364 -0
- package/templates/skills/frontend-development/resources/styling-guide.md +428 -0
- package/templates/skills/frontend-development/resources/typescript-standards.md +418 -0
- package/templates/skills/problem-solving/SKILL.mdc +96 -0
- package/templates/skills/problem-solving/references/attribution.md +69 -0
- package/templates/skills/problem-solving/references/collision-zone-thinking.md +79 -0
- package/templates/skills/problem-solving/references/inversion-exercise.md +91 -0
- package/templates/skills/problem-solving/references/meta-pattern-recognition.md +87 -0
- package/templates/skills/problem-solving/references/scale-game.md +95 -0
- package/templates/skills/problem-solving/references/simplification-cascades.md +80 -0
- package/templates/skills/problem-solving/references/when-stuck.md +72 -0
- package/templates/skills/research/SKILL.mdc +168 -0
- package/templates/skills/sequential-thinking/.env.example +8 -0
- package/templates/skills/sequential-thinking/README.md +183 -0
- package/templates/skills/sequential-thinking/SKILL.mdc +94 -0
- package/templates/skills/sequential-thinking/package.json +31 -0
- package/templates/skills/sequential-thinking/references/advanced-strategies.md +79 -0
- package/templates/skills/sequential-thinking/references/advanced-techniques.md +76 -0
- package/templates/skills/sequential-thinking/references/core-patterns.md +95 -0
- package/templates/skills/sequential-thinking/references/examples-api.md +88 -0
- package/templates/skills/sequential-thinking/references/examples-architecture.md +94 -0
- package/templates/skills/sequential-thinking/references/examples-debug.md +90 -0
- package/templates/skills/sequential-thinking/scripts/format-thought.js +159 -0
- package/templates/skills/sequential-thinking/scripts/process-thought.js +236 -0
- package/templates/skills/sequential-thinking/tests/format-thought.test.js +133 -0
- package/templates/skills/sequential-thinking/tests/process-thought.test.js +215 -0
- package/templates/skills/ui-styling/LICENSE.txt +202 -0
- package/templates/skills/ui-styling/SKILL.mdc +321 -0
- package/templates/skills/ui-styling/references/canvas-design-system.md +320 -0
- package/templates/skills/ui-styling/references/shadcn-accessibility.md +471 -0
- package/templates/skills/ui-styling/references/shadcn-components.md +424 -0
- package/templates/skills/ui-styling/references/shadcn-theming.md +373 -0
- package/templates/skills/ui-styling/references/tailwind-customization.md +483 -0
- package/templates/skills/ui-styling/references/tailwind-responsive.md +382 -0
- package/templates/skills/ui-styling/references/tailwind-utilities.md +455 -0
- package/templates/rules/frontend-design.mdc +0 -48
- package/templates/rules/performance.mdc +0 -54
- package/templates/rules/react.mdc +0 -58
- package/templates/rules/security.mdc +0 -50
- package/templates/rules/testing.mdc +0 -54
- package/templates/rules/typescript.mdc +0 -36
package/dist/cli.js
CHANGED
|
@@ -50,7 +50,7 @@ import pc2 from "picocolors";
|
|
|
50
50
|
import { join as join3 } from "path";
|
|
51
51
|
|
|
52
52
|
// src/utils/fs.ts
|
|
53
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, rmSync, statSync } from "fs";
|
|
53
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, rmSync, statSync, cpSync } from "fs";
|
|
54
54
|
import { dirname, join, resolve } from "path";
|
|
55
55
|
function ensureDir(path) {
|
|
56
56
|
if (!existsSync(path)) {
|
|
@@ -75,6 +75,9 @@ function removeFile(path) {
|
|
|
75
75
|
rmSync(path, { recursive: true });
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
+
function copyDir(src, dest) {
|
|
79
|
+
cpSync(src, dest, { recursive: true });
|
|
80
|
+
}
|
|
78
81
|
function listFiles(dir, extension) {
|
|
79
82
|
if (!dirExists(dir)) return [];
|
|
80
83
|
const files = readdirSync(dir);
|
|
@@ -83,6 +86,13 @@ function listFiles(dir, extension) {
|
|
|
83
86
|
}
|
|
84
87
|
return files;
|
|
85
88
|
}
|
|
89
|
+
function listDirs(dir) {
|
|
90
|
+
if (!dirExists(dir)) return [];
|
|
91
|
+
return readdirSync(dir).filter((item) => {
|
|
92
|
+
const itemPath = join(dir, item);
|
|
93
|
+
return statSync(itemPath).isDirectory();
|
|
94
|
+
});
|
|
95
|
+
}
|
|
86
96
|
function getCursorDir(cwd = process.cwd()) {
|
|
87
97
|
return join(cwd, ".cursor");
|
|
88
98
|
}
|
|
@@ -92,10 +102,17 @@ function getCommandsDir(cwd = process.cwd()) {
|
|
|
92
102
|
function getRulesDir(cwd = process.cwd()) {
|
|
93
103
|
return join(getCursorDir(cwd), "rules");
|
|
94
104
|
}
|
|
105
|
+
function getSkillsDir(cwd = process.cwd()) {
|
|
106
|
+
return join(getCursorDir(cwd), "skills");
|
|
107
|
+
}
|
|
95
108
|
function getConflictingFiles(dir, files) {
|
|
96
109
|
if (!dirExists(dir)) return [];
|
|
97
110
|
return files.filter((file) => fileExists(join(dir, file)));
|
|
98
111
|
}
|
|
112
|
+
function getConflictingDirs(dir, dirs) {
|
|
113
|
+
if (!dirExists(dir)) return [];
|
|
114
|
+
return dirs.filter((d) => dirExists(join(dir, d)));
|
|
115
|
+
}
|
|
99
116
|
|
|
100
117
|
// src/utils/templates.ts
|
|
101
118
|
import { join as join2, dirname as dirname2 } from "path";
|
|
@@ -107,7 +124,8 @@ var REPO_REF = "master";
|
|
|
107
124
|
var REPO_RAW_URL = "https://raw.githubusercontent.com/duongductrong/cursor-kit/master";
|
|
108
125
|
var TEMPLATE_PATHS = {
|
|
109
126
|
commands: "templates/commands",
|
|
110
|
-
rules: "templates/rules"
|
|
127
|
+
rules: "templates/rules",
|
|
128
|
+
skills: "templates/skills"
|
|
111
129
|
};
|
|
112
130
|
|
|
113
131
|
// src/utils/templates.ts
|
|
@@ -127,12 +145,14 @@ function getLocalManifest() {
|
|
|
127
145
|
}
|
|
128
146
|
const commandsDir = join2(templatesDir, "commands");
|
|
129
147
|
const rulesDir = join2(templatesDir, "rules");
|
|
130
|
-
|
|
148
|
+
const skillsDir = join2(templatesDir, "skills");
|
|
149
|
+
if (!dirExists(commandsDir) && !dirExists(rulesDir) && !dirExists(skillsDir)) {
|
|
131
150
|
return null;
|
|
132
151
|
}
|
|
133
152
|
return {
|
|
134
153
|
commands: dirExists(commandsDir) ? listFiles(commandsDir, ".md") : [],
|
|
135
|
-
rules: dirExists(rulesDir) ? listFiles(rulesDir, ".mdc") : []
|
|
154
|
+
rules: dirExists(rulesDir) ? listFiles(rulesDir, ".mdc") : [],
|
|
155
|
+
skills: dirExists(skillsDir) ? listDirs(skillsDir) : []
|
|
136
156
|
};
|
|
137
157
|
}
|
|
138
158
|
function getLocalTemplateContent(type, filename) {
|
|
@@ -143,6 +163,22 @@ function getLocalTemplateContent(type, filename) {
|
|
|
143
163
|
}
|
|
144
164
|
return null;
|
|
145
165
|
}
|
|
166
|
+
function getLocalSkillDir(skillName) {
|
|
167
|
+
const templatesDir = getLocalTemplatesDir();
|
|
168
|
+
const skillPath = join2(templatesDir, "skills", skillName);
|
|
169
|
+
if (dirExists(skillPath)) {
|
|
170
|
+
return skillPath;
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
function copyLocalSkill(skillName, targetDir) {
|
|
175
|
+
const sourcePath = getLocalSkillDir(skillName);
|
|
176
|
+
if (!sourcePath) return false;
|
|
177
|
+
const destPath = join2(targetDir, skillName);
|
|
178
|
+
ensureDir(destPath);
|
|
179
|
+
copyDir(sourcePath, destPath);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
146
182
|
async function fetchTemplateManifest() {
|
|
147
183
|
const localManifest = getLocalManifest();
|
|
148
184
|
if (localManifest) {
|
|
@@ -186,9 +222,13 @@ function getTemplateLabel(filename) {
|
|
|
186
222
|
const nameWithoutExt = filename.replace(/\.(md|mdc)$/, "");
|
|
187
223
|
return nameWithoutExt.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
188
224
|
}
|
|
225
|
+
function getSkillLabel(skillName) {
|
|
226
|
+
return skillName.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
227
|
+
}
|
|
189
228
|
|
|
190
229
|
// src/commands/init.ts
|
|
191
230
|
async function selectTemplates(type, availableTemplates) {
|
|
231
|
+
const labelFn = type === "skills" ? getSkillLabel : getTemplateLabel;
|
|
192
232
|
const selectionMode = await p.select({
|
|
193
233
|
message: `How would you like to add ${type}?`,
|
|
194
234
|
options: [
|
|
@@ -212,7 +252,7 @@ async function selectTemplates(type, availableTemplates) {
|
|
|
212
252
|
message: `Select ${type} to add:`,
|
|
213
253
|
options: availableTemplates.map((template) => ({
|
|
214
254
|
value: template,
|
|
215
|
-
label:
|
|
255
|
+
label: labelFn(template),
|
|
216
256
|
hint: template
|
|
217
257
|
})),
|
|
218
258
|
required: true
|
|
@@ -276,10 +316,36 @@ async function installTemplates(type, targetDir, selectedTemplates, conflictStra
|
|
|
276
316
|
}
|
|
277
317
|
return result;
|
|
278
318
|
}
|
|
319
|
+
async function installSkills(targetDir, selectedSkills, conflictStrategy) {
|
|
320
|
+
const result = { added: [], skipped: [] };
|
|
321
|
+
const conflictingDirs = getConflictingDirs(targetDir, selectedSkills);
|
|
322
|
+
let skillsToInstall;
|
|
323
|
+
if (conflictStrategy === "merge") {
|
|
324
|
+
skillsToInstall = selectedSkills.filter(
|
|
325
|
+
(s) => !conflictingDirs.includes(s)
|
|
326
|
+
);
|
|
327
|
+
result.skipped = conflictingDirs.filter(
|
|
328
|
+
(d) => selectedSkills.includes(d)
|
|
329
|
+
);
|
|
330
|
+
} else {
|
|
331
|
+
skillsToInstall = selectedSkills;
|
|
332
|
+
}
|
|
333
|
+
if (skillsToInstall.length === 0) {
|
|
334
|
+
return result;
|
|
335
|
+
}
|
|
336
|
+
ensureDir(targetDir);
|
|
337
|
+
for (const skillName of skillsToInstall) {
|
|
338
|
+
const success = copyLocalSkill(skillName, targetDir);
|
|
339
|
+
if (success) {
|
|
340
|
+
result.added.push(skillName);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return result;
|
|
344
|
+
}
|
|
279
345
|
var initCommand = defineCommand({
|
|
280
346
|
meta: {
|
|
281
347
|
name: "init",
|
|
282
|
-
description: "Initialize .cursor/commands and .cursor/
|
|
348
|
+
description: "Initialize .cursor/commands, .cursor/rules, and .cursor/skills in your project"
|
|
283
349
|
},
|
|
284
350
|
args: {
|
|
285
351
|
force: {
|
|
@@ -300,6 +366,12 @@ var initCommand = defineCommand({
|
|
|
300
366
|
description: "Only initialize rules",
|
|
301
367
|
default: false
|
|
302
368
|
},
|
|
369
|
+
skills: {
|
|
370
|
+
type: "boolean",
|
|
371
|
+
alias: "s",
|
|
372
|
+
description: "Only initialize skills",
|
|
373
|
+
default: false
|
|
374
|
+
},
|
|
303
375
|
all: {
|
|
304
376
|
type: "boolean",
|
|
305
377
|
alias: "a",
|
|
@@ -312,9 +384,11 @@ var initCommand = defineCommand({
|
|
|
312
384
|
const cursorDir = getCursorDir(cwd);
|
|
313
385
|
const commandsDir = getCommandsDir(cwd);
|
|
314
386
|
const rulesDir = getRulesDir(cwd);
|
|
315
|
-
const
|
|
316
|
-
const
|
|
317
|
-
const
|
|
387
|
+
const skillsDir = getSkillsDir(cwd);
|
|
388
|
+
const initAll = !args.commands && !args.rules && !args.skills;
|
|
389
|
+
const shouldInitCommands = initAll || args.commands;
|
|
390
|
+
const shouldInitRules = initAll || args.rules;
|
|
391
|
+
const shouldInitSkills = initAll || args.skills;
|
|
318
392
|
p.intro(pc2.bgCyan(pc2.black(" cursor-kit init ")));
|
|
319
393
|
const s = p.spinner();
|
|
320
394
|
let manifest;
|
|
@@ -397,6 +471,36 @@ var initCommand = defineCommand({
|
|
|
397
471
|
);
|
|
398
472
|
s.stop("Rules installed");
|
|
399
473
|
}
|
|
474
|
+
if (shouldInitSkills) {
|
|
475
|
+
let selectedSkills;
|
|
476
|
+
if (args.all) {
|
|
477
|
+
selectedSkills = manifest.skills;
|
|
478
|
+
} else {
|
|
479
|
+
const selection = await selectTemplates("skills", manifest.skills);
|
|
480
|
+
if (p.isCancel(selection)) {
|
|
481
|
+
p.cancel("Operation cancelled");
|
|
482
|
+
process.exit(0);
|
|
483
|
+
}
|
|
484
|
+
selectedSkills = selection;
|
|
485
|
+
}
|
|
486
|
+
const conflictingSkills = getConflictingDirs(skillsDir, selectedSkills);
|
|
487
|
+
let skillStrategy = "overwrite";
|
|
488
|
+
if (conflictingSkills.length > 0 && !args.force) {
|
|
489
|
+
const strategy = await handleConflicts("skills", conflictingSkills);
|
|
490
|
+
if (p.isCancel(strategy) || strategy === "cancel") {
|
|
491
|
+
p.cancel("Operation cancelled");
|
|
492
|
+
process.exit(0);
|
|
493
|
+
}
|
|
494
|
+
skillStrategy = strategy;
|
|
495
|
+
}
|
|
496
|
+
s.start("Installing skills...");
|
|
497
|
+
results.skills = await installSkills(
|
|
498
|
+
skillsDir,
|
|
499
|
+
selectedSkills,
|
|
500
|
+
skillStrategy
|
|
501
|
+
);
|
|
502
|
+
s.stop("Skills installed");
|
|
503
|
+
}
|
|
400
504
|
printDivider();
|
|
401
505
|
console.log();
|
|
402
506
|
if (results.commands) {
|
|
@@ -427,8 +531,22 @@ var initCommand = defineCommand({
|
|
|
427
531
|
}
|
|
428
532
|
}
|
|
429
533
|
}
|
|
430
|
-
|
|
431
|
-
|
|
534
|
+
if (results.skills) {
|
|
535
|
+
const { added, skipped } = results.skills;
|
|
536
|
+
if (added.length > 0 || skipped.length > 0) {
|
|
537
|
+
printSuccess(
|
|
538
|
+
`Skills: ${highlight(added.length.toString())} added${skipped.length > 0 ? `, ${pc2.yellow(skipped.length.toString())} skipped` : ""}`
|
|
539
|
+
);
|
|
540
|
+
for (const f of added) {
|
|
541
|
+
console.log(pc2.dim(` \u2514\u2500 ${pc2.green("+")} ${f}`));
|
|
542
|
+
}
|
|
543
|
+
for (const f of skipped) {
|
|
544
|
+
console.log(pc2.dim(` \u2514\u2500 ${pc2.yellow("\u25CB")} ${f} (kept existing)`));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
const totalAdded = (results.commands?.added.length ?? 0) + (results.rules?.added.length ?? 0) + (results.skills?.added.length ?? 0);
|
|
549
|
+
const totalSkipped = (results.commands?.skipped.length ?? 0) + (results.rules?.skipped.length ?? 0) + (results.skills?.skipped.length ?? 0);
|
|
432
550
|
if (totalAdded === 0 && totalSkipped > 0) {
|
|
433
551
|
console.log();
|
|
434
552
|
p.outro(pc2.yellow("No new templates added (all selected files already exist)"));
|
|
@@ -447,10 +565,10 @@ var initCommand = defineCommand({
|
|
|
447
565
|
});
|
|
448
566
|
|
|
449
567
|
// src/commands/add.ts
|
|
450
|
-
import { defineCommand as defineCommand2 } from "citty";
|
|
451
568
|
import * as p2 from "@clack/prompts";
|
|
452
|
-
import
|
|
569
|
+
import { defineCommand as defineCommand2 } from "citty";
|
|
453
570
|
import { join as join4 } from "path";
|
|
571
|
+
import pc3 from "picocolors";
|
|
454
572
|
var COMMAND_TEMPLATE = `You are a helpful assistant. Describe what this command does.
|
|
455
573
|
|
|
456
574
|
## Instructions
|
|
@@ -477,31 +595,69 @@ Describe the rule behavior here.
|
|
|
477
595
|
- Guideline 1
|
|
478
596
|
- Guideline 2
|
|
479
597
|
`;
|
|
598
|
+
var SKILL_TEMPLATE = `---
|
|
599
|
+
description: Describe when this skill should be activated
|
|
600
|
+
globs:
|
|
601
|
+
alwaysApply: false
|
|
602
|
+
---
|
|
603
|
+
|
|
604
|
+
# Skill Name
|
|
605
|
+
|
|
606
|
+
Brief description of what this skill enables.
|
|
607
|
+
|
|
608
|
+
## Core Capabilities
|
|
609
|
+
|
|
610
|
+
- Capability 1
|
|
611
|
+
- Capability 2
|
|
612
|
+
|
|
613
|
+
## When to Use
|
|
614
|
+
|
|
615
|
+
Use this skill when:
|
|
616
|
+
- Condition 1
|
|
617
|
+
- Condition 2
|
|
618
|
+
|
|
619
|
+
## References
|
|
620
|
+
|
|
621
|
+
For detailed guidance, see the references folder:
|
|
622
|
+
- [Reference 1](./references/example.md) - Description
|
|
623
|
+
`;
|
|
624
|
+
var SKILL_REFERENCE_TEMPLATE = `# Reference Title
|
|
625
|
+
|
|
626
|
+
Detailed reference content goes here.
|
|
627
|
+
|
|
628
|
+
## Section 1
|
|
629
|
+
|
|
630
|
+
Content...
|
|
631
|
+
|
|
632
|
+
## Section 2
|
|
633
|
+
|
|
634
|
+
Content...
|
|
635
|
+
`;
|
|
480
636
|
function generateSlug(name) {
|
|
481
637
|
return name.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
|
|
482
638
|
}
|
|
483
639
|
var addCommand = defineCommand2({
|
|
484
640
|
meta: {
|
|
485
641
|
name: "add",
|
|
486
|
-
description: "Add a new command or
|
|
642
|
+
description: "Add a new command, rule, or skill"
|
|
487
643
|
},
|
|
488
644
|
args: {
|
|
489
645
|
type: {
|
|
490
646
|
type: "string",
|
|
491
647
|
alias: "t",
|
|
492
|
-
description: "Type: 'command' or '
|
|
648
|
+
description: "Type: 'command', 'rule', or 'skill'"
|
|
493
649
|
},
|
|
494
650
|
name: {
|
|
495
651
|
type: "string",
|
|
496
652
|
alias: "n",
|
|
497
|
-
description: "Name of the command or
|
|
653
|
+
description: "Name of the command, rule, or skill"
|
|
498
654
|
}
|
|
499
655
|
},
|
|
500
656
|
async run({ args }) {
|
|
501
657
|
p2.intro(pc3.bgCyan(pc3.black(" cursor-kit add ")));
|
|
502
658
|
let itemType;
|
|
503
659
|
let itemName;
|
|
504
|
-
if (args.type && ["command", "rule"].includes(args.type)) {
|
|
660
|
+
if (args.type && ["command", "rule", "skill"].includes(args.type)) {
|
|
505
661
|
itemType = args.type;
|
|
506
662
|
} else {
|
|
507
663
|
const typeResult = await p2.select({
|
|
@@ -516,6 +672,11 @@ var addCommand = defineCommand2({
|
|
|
516
672
|
value: "rule",
|
|
517
673
|
label: "Rule",
|
|
518
674
|
hint: "Project-specific AI behavior rules"
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
value: "skill",
|
|
678
|
+
label: "Skill",
|
|
679
|
+
hint: "Comprehensive guide with references"
|
|
519
680
|
}
|
|
520
681
|
]
|
|
521
682
|
});
|
|
@@ -530,7 +691,7 @@ var addCommand = defineCommand2({
|
|
|
530
691
|
} else {
|
|
531
692
|
const nameResult = await p2.text({
|
|
532
693
|
message: `Enter ${itemType} name:`,
|
|
533
|
-
placeholder: itemType === "command" ? "my-command" : "my-rule",
|
|
694
|
+
placeholder: itemType === "command" ? "my-command" : itemType === "rule" ? "my-rule" : "my-skill",
|
|
534
695
|
validate: (value) => {
|
|
535
696
|
if (!value.trim()) return "Name is required";
|
|
536
697
|
if (value.length < 2) return "Name must be at least 2 characters";
|
|
@@ -545,12 +706,22 @@ var addCommand = defineCommand2({
|
|
|
545
706
|
}
|
|
546
707
|
const slug = generateSlug(itemName);
|
|
547
708
|
const isCommand = itemType === "command";
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
if (
|
|
709
|
+
const isSkill = itemType === "skill";
|
|
710
|
+
let targetPath;
|
|
711
|
+
let displayPath;
|
|
712
|
+
if (isSkill) {
|
|
713
|
+
const skillsDir = getSkillsDir();
|
|
714
|
+
targetPath = join4(skillsDir, slug);
|
|
715
|
+
displayPath = targetPath;
|
|
716
|
+
} else {
|
|
717
|
+
const targetDir = isCommand ? getCommandsDir() : getRulesDir();
|
|
718
|
+
const extension = isCommand ? ".md" : ".mdc";
|
|
719
|
+
targetPath = join4(targetDir, `${slug}${extension}`);
|
|
720
|
+
displayPath = targetPath;
|
|
721
|
+
}
|
|
722
|
+
if (isSkill ? dirExists(targetPath) : fileExists(targetPath)) {
|
|
552
723
|
const shouldOverwrite = await p2.confirm({
|
|
553
|
-
message: `${highlight(slug +
|
|
724
|
+
message: `${highlight(isSkill ? slug : slug + (isCommand ? ".md" : ".mdc"))} already exists. Overwrite?`,
|
|
554
725
|
initialValue: false
|
|
555
726
|
});
|
|
556
727
|
if (p2.isCancel(shouldOverwrite) || !shouldOverwrite) {
|
|
@@ -561,12 +732,25 @@ var addCommand = defineCommand2({
|
|
|
561
732
|
const s = p2.spinner();
|
|
562
733
|
s.start(`Creating ${itemType}...`);
|
|
563
734
|
try {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
735
|
+
if (isSkill) {
|
|
736
|
+
ensureDir(targetPath);
|
|
737
|
+
ensureDir(join4(targetPath, "references"));
|
|
738
|
+
writeFile(join4(targetPath, "SKILL.mdc"), SKILL_TEMPLATE);
|
|
739
|
+
writeFile(join4(targetPath, "references", "example.md"), SKILL_REFERENCE_TEMPLATE);
|
|
740
|
+
} else {
|
|
741
|
+
const targetDir = isCommand ? getCommandsDir() : getRulesDir();
|
|
742
|
+
ensureDir(targetDir);
|
|
743
|
+
const template = isCommand ? COMMAND_TEMPLATE : RULE_TEMPLATE;
|
|
744
|
+
writeFile(targetPath, template);
|
|
745
|
+
}
|
|
567
746
|
s.stop(`${itemType.charAt(0).toUpperCase() + itemType.slice(1)} created`);
|
|
568
747
|
console.log();
|
|
569
|
-
|
|
748
|
+
if (isSkill) {
|
|
749
|
+
console.log(pc3.dim(" Directory: ") + highlight(displayPath));
|
|
750
|
+
console.log(pc3.dim(" Main file: ") + highlight(join4(displayPath, "SKILL.mdc")));
|
|
751
|
+
} else {
|
|
752
|
+
console.log(pc3.dim(" File: ") + highlight(displayPath));
|
|
753
|
+
}
|
|
570
754
|
console.log();
|
|
571
755
|
p2.outro(
|
|
572
756
|
pc3.green(`\u2728 ${itemType.charAt(0).toUpperCase() + itemType.slice(1)} created! Edit the file to customize it.`)
|
|
@@ -602,6 +786,12 @@ var pullCommand = defineCommand3({
|
|
|
602
786
|
description: "Only pull rules",
|
|
603
787
|
default: false
|
|
604
788
|
},
|
|
789
|
+
skills: {
|
|
790
|
+
type: "boolean",
|
|
791
|
+
alias: "s",
|
|
792
|
+
description: "Only pull skills",
|
|
793
|
+
default: false
|
|
794
|
+
},
|
|
605
795
|
force: {
|
|
606
796
|
type: "boolean",
|
|
607
797
|
alias: "f",
|
|
@@ -610,15 +800,18 @@ var pullCommand = defineCommand3({
|
|
|
610
800
|
}
|
|
611
801
|
},
|
|
612
802
|
async run({ args }) {
|
|
613
|
-
const
|
|
614
|
-
const shouldPullCommands =
|
|
615
|
-
const shouldPullRules =
|
|
803
|
+
const pullAll = !args.commands && !args.rules && !args.skills;
|
|
804
|
+
const shouldPullCommands = pullAll || args.commands;
|
|
805
|
+
const shouldPullRules = pullAll || args.rules;
|
|
806
|
+
const shouldPullSkills = pullAll || args.skills;
|
|
616
807
|
p3.intro(pc4.bgCyan(pc4.black(" cursor-kit pull ")));
|
|
617
808
|
const commandsDir = getCommandsDir();
|
|
618
809
|
const rulesDir = getRulesDir();
|
|
810
|
+
const skillsDir = getSkillsDir();
|
|
619
811
|
const existingCommands = listFiles(commandsDir, ".md");
|
|
620
812
|
const existingRules = listFiles(rulesDir, ".mdc");
|
|
621
|
-
const
|
|
813
|
+
const existingSkills = listDirs(skillsDir);
|
|
814
|
+
const hasExisting = existingCommands.length > 0 || existingRules.length > 0 || existingSkills.length > 0;
|
|
622
815
|
if (hasExisting && !args.force) {
|
|
623
816
|
printInfo("Current status:");
|
|
624
817
|
if (existingCommands.length > 0) {
|
|
@@ -627,6 +820,9 @@ var pullCommand = defineCommand3({
|
|
|
627
820
|
if (existingRules.length > 0) {
|
|
628
821
|
console.log(pc4.dim(` Rules: ${existingRules.length} files`));
|
|
629
822
|
}
|
|
823
|
+
if (existingSkills.length > 0) {
|
|
824
|
+
console.log(pc4.dim(` Skills: ${existingSkills.length} directories`));
|
|
825
|
+
}
|
|
630
826
|
console.log();
|
|
631
827
|
const shouldContinue = await p3.confirm({
|
|
632
828
|
message: "This will merge with existing files. Continue?",
|
|
@@ -656,10 +852,19 @@ var pullCommand = defineCommand3({
|
|
|
656
852
|
});
|
|
657
853
|
s.stop("Rules updated");
|
|
658
854
|
}
|
|
855
|
+
if (shouldPullSkills) {
|
|
856
|
+
s.start("Pulling skills...");
|
|
857
|
+
await downloadTemplate(`${REPO_URL}/templates/skills#${REPO_REF}`, {
|
|
858
|
+
dir: skillsDir,
|
|
859
|
+
force: true
|
|
860
|
+
});
|
|
861
|
+
s.stop("Skills updated");
|
|
862
|
+
}
|
|
659
863
|
printDivider();
|
|
660
864
|
console.log();
|
|
661
865
|
const newCommands = listFiles(commandsDir, ".md");
|
|
662
866
|
const newRules = listFiles(rulesDir, ".mdc");
|
|
867
|
+
const newSkills = listDirs(skillsDir);
|
|
663
868
|
if (shouldPullCommands) {
|
|
664
869
|
const added = newCommands.length - existingCommands.length;
|
|
665
870
|
printSuccess(
|
|
@@ -672,6 +877,12 @@ var pullCommand = defineCommand3({
|
|
|
672
877
|
`Rules: ${highlight(newRules.length.toString())} total` + (added > 0 ? pc4.green(` (+${added} new)`) : "")
|
|
673
878
|
);
|
|
674
879
|
}
|
|
880
|
+
if (shouldPullSkills) {
|
|
881
|
+
const added = newSkills.length - existingSkills.length;
|
|
882
|
+
printSuccess(
|
|
883
|
+
`Skills: ${highlight(newSkills.length.toString())} total` + (added > 0 ? pc4.green(` (+${added} new)`) : "")
|
|
884
|
+
);
|
|
885
|
+
}
|
|
675
886
|
console.log();
|
|
676
887
|
p3.outro(pc4.green("\u2728 Successfully pulled latest updates!"));
|
|
677
888
|
} catch (error) {
|
|
@@ -683,10 +894,10 @@ var pullCommand = defineCommand3({
|
|
|
683
894
|
});
|
|
684
895
|
|
|
685
896
|
// src/commands/list.ts
|
|
686
|
-
import { defineCommand as defineCommand4 } from "citty";
|
|
687
897
|
import * as p4 from "@clack/prompts";
|
|
688
|
-
import
|
|
898
|
+
import { defineCommand as defineCommand4 } from "citty";
|
|
689
899
|
import { join as join5 } from "path";
|
|
900
|
+
import pc5 from "picocolors";
|
|
690
901
|
function extractDescription(content, isCommand) {
|
|
691
902
|
if (isCommand) {
|
|
692
903
|
const firstLine = content.trim().split("\n")[0];
|
|
@@ -713,10 +924,31 @@ function getItems(dir, extension, isCommand) {
|
|
|
713
924
|
};
|
|
714
925
|
});
|
|
715
926
|
}
|
|
927
|
+
function getSkills(dir) {
|
|
928
|
+
const skillDirs = listDirs(dir);
|
|
929
|
+
return skillDirs.map((skillName) => {
|
|
930
|
+
const skillPath = join5(dir, skillName);
|
|
931
|
+
const skillFile = join5(skillPath, "SKILL.mdc");
|
|
932
|
+
const altSkillFile = join5(skillPath, "SKILL.md");
|
|
933
|
+
let description;
|
|
934
|
+
if (fileExists(skillFile)) {
|
|
935
|
+
const content = readFile(skillFile);
|
|
936
|
+
description = extractDescription(content, false);
|
|
937
|
+
} else if (fileExists(altSkillFile)) {
|
|
938
|
+
const content = readFile(altSkillFile);
|
|
939
|
+
description = extractDescription(content, false);
|
|
940
|
+
}
|
|
941
|
+
return {
|
|
942
|
+
name: skillName,
|
|
943
|
+
path: skillPath,
|
|
944
|
+
description
|
|
945
|
+
};
|
|
946
|
+
});
|
|
947
|
+
}
|
|
716
948
|
var listCommand = defineCommand4({
|
|
717
949
|
meta: {
|
|
718
950
|
name: "list",
|
|
719
|
-
description: "List all commands and
|
|
951
|
+
description: "List all commands, rules, and skills"
|
|
720
952
|
},
|
|
721
953
|
args: {
|
|
722
954
|
commands: {
|
|
@@ -731,6 +963,12 @@ var listCommand = defineCommand4({
|
|
|
731
963
|
description: "Only list rules",
|
|
732
964
|
default: false
|
|
733
965
|
},
|
|
966
|
+
skills: {
|
|
967
|
+
type: "boolean",
|
|
968
|
+
alias: "s",
|
|
969
|
+
description: "Only list skills",
|
|
970
|
+
default: false
|
|
971
|
+
},
|
|
734
972
|
verbose: {
|
|
735
973
|
type: "boolean",
|
|
736
974
|
alias: "v",
|
|
@@ -739,18 +977,23 @@ var listCommand = defineCommand4({
|
|
|
739
977
|
}
|
|
740
978
|
},
|
|
741
979
|
async run({ args }) {
|
|
742
|
-
const
|
|
743
|
-
const shouldListCommands =
|
|
744
|
-
const shouldListRules =
|
|
980
|
+
const listAll = !args.commands && !args.rules && !args.skills;
|
|
981
|
+
const shouldListCommands = listAll || args.commands;
|
|
982
|
+
const shouldListRules = listAll || args.rules;
|
|
983
|
+
const shouldListSkills = listAll || args.skills;
|
|
745
984
|
p4.intro(pc5.bgCyan(pc5.black(" cursor-kit list ")));
|
|
746
985
|
const commandsDir = getCommandsDir();
|
|
747
986
|
const rulesDir = getRulesDir();
|
|
987
|
+
const skillsDir = getSkillsDir();
|
|
748
988
|
const commands = shouldListCommands ? getItems(commandsDir, ".md", true) : [];
|
|
749
989
|
const rules = shouldListRules ? getItems(rulesDir, ".mdc", false) : [];
|
|
750
|
-
|
|
990
|
+
const skills = shouldListSkills ? getSkills(skillsDir) : [];
|
|
991
|
+
if (commands.length === 0 && rules.length === 0 && skills.length === 0) {
|
|
751
992
|
console.log();
|
|
752
|
-
console.log(pc5.yellow(" No commands or
|
|
753
|
-
console.log(
|
|
993
|
+
console.log(pc5.yellow(" No commands, rules, or skills found."));
|
|
994
|
+
console.log(
|
|
995
|
+
pc5.dim(" Run ") + highlight("cursor-kit init") + pc5.dim(" to get started.")
|
|
996
|
+
);
|
|
754
997
|
console.log();
|
|
755
998
|
p4.outro(pc5.dim("Nothing to show"));
|
|
756
999
|
return;
|
|
@@ -758,7 +1001,9 @@ var listCommand = defineCommand4({
|
|
|
758
1001
|
printDivider();
|
|
759
1002
|
if (shouldListCommands && commands.length > 0) {
|
|
760
1003
|
console.log();
|
|
761
|
-
console.log(
|
|
1004
|
+
console.log(
|
|
1005
|
+
pc5.bold(pc5.cyan(" \u{1F4DC} Commands")) + pc5.dim(` (${commands.length})`)
|
|
1006
|
+
);
|
|
762
1007
|
console.log();
|
|
763
1008
|
commands.forEach((cmd) => {
|
|
764
1009
|
console.log(` ${pc5.green("\u25CF")} ${highlight(cmd.name)}`);
|
|
@@ -772,7 +1017,9 @@ var listCommand = defineCommand4({
|
|
|
772
1017
|
}
|
|
773
1018
|
if (shouldListRules && rules.length > 0) {
|
|
774
1019
|
console.log();
|
|
775
|
-
console.log(
|
|
1020
|
+
console.log(
|
|
1021
|
+
pc5.bold(pc5.cyan(" \u{1F4CB} Rules")) + pc5.dim(` (${rules.length})`)
|
|
1022
|
+
);
|
|
776
1023
|
console.log();
|
|
777
1024
|
rules.forEach((rule) => {
|
|
778
1025
|
console.log(` ${pc5.green("\u25CF")} ${highlight(rule.name)}`);
|
|
@@ -784,9 +1031,25 @@ var listCommand = defineCommand4({
|
|
|
784
1031
|
}
|
|
785
1032
|
});
|
|
786
1033
|
}
|
|
1034
|
+
if (shouldListSkills && skills.length > 0) {
|
|
1035
|
+
console.log();
|
|
1036
|
+
console.log(
|
|
1037
|
+
pc5.bold(pc5.cyan(" \u{1F3AF} Skills")) + pc5.dim(` (${skills.length})`)
|
|
1038
|
+
);
|
|
1039
|
+
console.log();
|
|
1040
|
+
skills.forEach((skill) => {
|
|
1041
|
+
console.log(` ${pc5.green("\u25CF")} ${highlight(skill.name)}`);
|
|
1042
|
+
if (skill.description) {
|
|
1043
|
+
console.log(pc5.dim(` ${skill.description}`));
|
|
1044
|
+
}
|
|
1045
|
+
if (args.verbose) {
|
|
1046
|
+
console.log(pc5.dim(` ${skill.path}`));
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
787
1050
|
console.log();
|
|
788
1051
|
printDivider();
|
|
789
|
-
const total = commands.length + rules.length;
|
|
1052
|
+
const total = commands.length + rules.length + skills.length;
|
|
790
1053
|
p4.outro(pc5.dim(`Total: ${total} item${total !== 1 ? "s" : ""}`));
|
|
791
1054
|
}
|
|
792
1055
|
});
|
|
@@ -799,18 +1062,18 @@ import { join as join6 } from "path";
|
|
|
799
1062
|
var removeCommand = defineCommand5({
|
|
800
1063
|
meta: {
|
|
801
1064
|
name: "remove",
|
|
802
|
-
description: "Remove a command or
|
|
1065
|
+
description: "Remove a command, rule, or skill"
|
|
803
1066
|
},
|
|
804
1067
|
args: {
|
|
805
1068
|
type: {
|
|
806
1069
|
type: "string",
|
|
807
1070
|
alias: "t",
|
|
808
|
-
description: "Type: 'command' or '
|
|
1071
|
+
description: "Type: 'command', 'rule', or 'skill'"
|
|
809
1072
|
},
|
|
810
1073
|
name: {
|
|
811
1074
|
type: "string",
|
|
812
1075
|
alias: "n",
|
|
813
|
-
description: "Name of the command or
|
|
1076
|
+
description: "Name of the command, rule, or skill to remove"
|
|
814
1077
|
},
|
|
815
1078
|
force: {
|
|
816
1079
|
type: "boolean",
|
|
@@ -823,18 +1086,20 @@ var removeCommand = defineCommand5({
|
|
|
823
1086
|
p5.intro(pc6.bgCyan(pc6.black(" cursor-kit remove ")));
|
|
824
1087
|
const commandsDir = getCommandsDir();
|
|
825
1088
|
const rulesDir = getRulesDir();
|
|
1089
|
+
const skillsDir = getSkillsDir();
|
|
826
1090
|
const commands = listFiles(commandsDir, ".md").map((f) => f.replace(".md", ""));
|
|
827
1091
|
const rules = listFiles(rulesDir, ".mdc").map((f) => f.replace(".mdc", ""));
|
|
828
|
-
|
|
1092
|
+
const skills = listDirs(skillsDir);
|
|
1093
|
+
if (commands.length === 0 && rules.length === 0 && skills.length === 0) {
|
|
829
1094
|
console.log();
|
|
830
|
-
console.log(pc6.yellow(" No commands or
|
|
1095
|
+
console.log(pc6.yellow(" No commands, rules, or skills to remove."));
|
|
831
1096
|
console.log();
|
|
832
1097
|
p5.outro(pc6.dim("Nothing to do"));
|
|
833
1098
|
return;
|
|
834
1099
|
}
|
|
835
1100
|
let itemType;
|
|
836
1101
|
let itemName;
|
|
837
|
-
if (args.type && ["command", "rule"].includes(args.type)) {
|
|
1102
|
+
if (args.type && ["command", "rule", "skill"].includes(args.type)) {
|
|
838
1103
|
itemType = args.type;
|
|
839
1104
|
} else {
|
|
840
1105
|
const typeOptions = [];
|
|
@@ -852,6 +1117,13 @@ var removeCommand = defineCommand5({
|
|
|
852
1117
|
hint: `${rules.length} available`
|
|
853
1118
|
});
|
|
854
1119
|
}
|
|
1120
|
+
if (skills.length > 0) {
|
|
1121
|
+
typeOptions.push({
|
|
1122
|
+
value: "skill",
|
|
1123
|
+
label: "Skill",
|
|
1124
|
+
hint: `${skills.length} available`
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
855
1127
|
const typeResult = await p5.select({
|
|
856
1128
|
message: "What do you want to remove?",
|
|
857
1129
|
options: typeOptions
|
|
@@ -863,9 +1135,11 @@ var removeCommand = defineCommand5({
|
|
|
863
1135
|
itemType = typeResult;
|
|
864
1136
|
}
|
|
865
1137
|
const isCommand = itemType === "command";
|
|
866
|
-
const
|
|
867
|
-
const
|
|
868
|
-
const
|
|
1138
|
+
const isRule = itemType === "rule";
|
|
1139
|
+
const isSkill = itemType === "skill";
|
|
1140
|
+
const items = isCommand ? commands : isRule ? rules : skills;
|
|
1141
|
+
const dir = isCommand ? commandsDir : isRule ? rulesDir : skillsDir;
|
|
1142
|
+
const extension = isCommand ? ".md" : isRule ? ".mdc" : "";
|
|
869
1143
|
if (items.length === 0) {
|
|
870
1144
|
p5.cancel(`No ${itemType}s found`);
|
|
871
1145
|
process.exit(0);
|
|
@@ -887,14 +1161,16 @@ var removeCommand = defineCommand5({
|
|
|
887
1161
|
}
|
|
888
1162
|
itemName = nameResult;
|
|
889
1163
|
}
|
|
890
|
-
const
|
|
891
|
-
|
|
1164
|
+
const targetPath = isSkill ? join6(dir, itemName) : join6(dir, `${itemName}${extension}`);
|
|
1165
|
+
const exists = isSkill ? dirExists(targetPath) : fileExists(targetPath);
|
|
1166
|
+
if (!exists) {
|
|
892
1167
|
p5.cancel(`${itemType} '${itemName}' not found`);
|
|
893
1168
|
process.exit(1);
|
|
894
1169
|
}
|
|
895
1170
|
if (!args.force) {
|
|
1171
|
+
const displayName = isSkill ? itemName : itemName + extension;
|
|
896
1172
|
const shouldDelete = await p5.confirm({
|
|
897
|
-
message: `Are you sure you want to delete ${highlight(
|
|
1173
|
+
message: `Are you sure you want to delete ${highlight(displayName)}?${isSkill ? " (This will remove the entire skill directory)" : ""}`,
|
|
898
1174
|
initialValue: false
|
|
899
1175
|
});
|
|
900
1176
|
if (p5.isCancel(shouldDelete) || !shouldDelete) {
|
|
@@ -903,9 +1179,10 @@ var removeCommand = defineCommand5({
|
|
|
903
1179
|
}
|
|
904
1180
|
}
|
|
905
1181
|
try {
|
|
906
|
-
removeFile(
|
|
1182
|
+
removeFile(targetPath);
|
|
1183
|
+
const displayName = isSkill ? itemName : itemName + extension;
|
|
907
1184
|
console.log();
|
|
908
|
-
printSuccess(`Removed ${highlight(
|
|
1185
|
+
printSuccess(`Removed ${highlight(displayName)}`);
|
|
909
1186
|
console.log();
|
|
910
1187
|
p5.outro(pc6.green("\u2728 Done!"));
|
|
911
1188
|
} catch (error) {
|
|
@@ -978,7 +1255,7 @@ var instanceCommand = defineCommand6({
|
|
|
978
1255
|
action: {
|
|
979
1256
|
type: "string",
|
|
980
1257
|
alias: "a",
|
|
981
|
-
description: "Action: 'create' or 'remove'"
|
|
1258
|
+
description: "Action: 'create', 'reinstall', or 'remove'"
|
|
982
1259
|
},
|
|
983
1260
|
name: {
|
|
984
1261
|
type: "string",
|
|
@@ -1027,7 +1304,8 @@ var instanceCommand = defineCommand6({
|
|
|
1027
1304
|
const binPath = getBinPath();
|
|
1028
1305
|
const createScript = join7(binPath, "cursor-new-instance");
|
|
1029
1306
|
const removeScript = join7(binPath, "cursor-remove-instance");
|
|
1030
|
-
const
|
|
1307
|
+
const reinstallScript = join7(binPath, "cursor-reinstall-instance.sh");
|
|
1308
|
+
const scriptsExist = existsSync2(createScript) && existsSync2(removeScript) && existsSync2(reinstallScript);
|
|
1031
1309
|
if (!scriptsExist) {
|
|
1032
1310
|
s.stop("Prerequisites check failed");
|
|
1033
1311
|
console.log();
|
|
@@ -1051,7 +1329,7 @@ var instanceCommand = defineCommand6({
|
|
|
1051
1329
|
const existingInstances = getExistingInstances();
|
|
1052
1330
|
let action;
|
|
1053
1331
|
let instanceName;
|
|
1054
|
-
if (args.action && ["create", "remove"].includes(args.action)) {
|
|
1332
|
+
if (args.action && ["create", "remove", "reinstall"].includes(args.action)) {
|
|
1055
1333
|
action = args.action;
|
|
1056
1334
|
} else {
|
|
1057
1335
|
const actionResult = await p6.select({
|
|
@@ -1062,6 +1340,11 @@ var instanceCommand = defineCommand6({
|
|
|
1062
1340
|
label: "Create new instance",
|
|
1063
1341
|
hint: "Clone Cursor with separate identity"
|
|
1064
1342
|
},
|
|
1343
|
+
{
|
|
1344
|
+
value: "reinstall",
|
|
1345
|
+
label: "Reinstall instance",
|
|
1346
|
+
hint: existingInstances.length > 0 ? "Fix broken instance after Cursor update" : "No instances to reinstall"
|
|
1347
|
+
},
|
|
1065
1348
|
{
|
|
1066
1349
|
value: "remove",
|
|
1067
1350
|
label: "Remove instance",
|
|
@@ -1077,9 +1360,10 @@ var instanceCommand = defineCommand6({
|
|
|
1077
1360
|
}
|
|
1078
1361
|
if (args.name) {
|
|
1079
1362
|
instanceName = args.name;
|
|
1080
|
-
} else if (action === "remove" && existingInstances.length > 0) {
|
|
1363
|
+
} else if ((action === "remove" || action === "reinstall") && existingInstances.length > 0) {
|
|
1364
|
+
const actionLabel2 = action === "remove" ? "remove" : "reinstall";
|
|
1081
1365
|
const instanceResult = await p6.select({
|
|
1082
|
-
message:
|
|
1366
|
+
message: `Select instance to ${actionLabel2}:`,
|
|
1083
1367
|
options: existingInstances.map((inst) => ({
|
|
1084
1368
|
value: inst.name,
|
|
1085
1369
|
label: inst.name,
|
|
@@ -1091,9 +1375,9 @@ var instanceCommand = defineCommand6({
|
|
|
1091
1375
|
process.exit(0);
|
|
1092
1376
|
}
|
|
1093
1377
|
instanceName = instanceResult;
|
|
1094
|
-
} else if (action === "remove" && existingInstances.length === 0) {
|
|
1378
|
+
} else if ((action === "remove" || action === "reinstall") && existingInstances.length === 0) {
|
|
1095
1379
|
console.log();
|
|
1096
|
-
printInfo(
|
|
1380
|
+
printInfo(`No custom Cursor instances found to ${action}.`);
|
|
1097
1381
|
console.log();
|
|
1098
1382
|
p6.outro(pc7.dim("Nothing to do"));
|
|
1099
1383
|
return;
|
|
@@ -1121,12 +1405,18 @@ var instanceCommand = defineCommand6({
|
|
|
1121
1405
|
console.log();
|
|
1122
1406
|
console.log(pc7.bold(pc7.cyan(" \u{1F4CB} Summary")));
|
|
1123
1407
|
console.log();
|
|
1124
|
-
|
|
1408
|
+
const actionColor = action === "create" ? pc7.green : action === "reinstall" ? pc7.blue : pc7.yellow;
|
|
1409
|
+
const actionLabel = action === "create" ? "Create" : action === "reinstall" ? "Reinstall" : "Remove";
|
|
1410
|
+
console.log(` ${pc7.dim("Action:")} ${actionColor(actionLabel)}`);
|
|
1125
1411
|
console.log(` ${pc7.dim("Instance:")} ${highlight(instanceName)}`);
|
|
1126
|
-
if (action === "create") {
|
|
1412
|
+
if (action === "create" || action === "reinstall") {
|
|
1127
1413
|
const slug = instanceName.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1128
1414
|
console.log(` ${pc7.dim("Bundle ID:")} ${pc7.dim("com.cursor.")}${highlight(slug)}`);
|
|
1129
1415
|
console.log(` ${pc7.dim("Location:")} ${pc7.dim("~/Applications/")}${highlight(instanceName + ".app")}`);
|
|
1416
|
+
if (action === "reinstall") {
|
|
1417
|
+
const dataDir = join7(process.env.HOME ?? "", "Library", "Application Support", instanceName.replace(/ /g, ""));
|
|
1418
|
+
console.log(` ${pc7.dim("Data:")} ${pc7.green("\u2713")} ${pc7.dim("Preserved at")} ${pc7.dim(dataDir)}`);
|
|
1419
|
+
}
|
|
1130
1420
|
} else {
|
|
1131
1421
|
const targetPath = join7(process.env.HOME ?? "", "Applications", `${instanceName}.app`);
|
|
1132
1422
|
console.log(` ${pc7.dim("Path:")} ${pc7.dim(targetPath)}`);
|
|
@@ -1135,8 +1425,8 @@ var instanceCommand = defineCommand6({
|
|
|
1135
1425
|
printDivider();
|
|
1136
1426
|
console.log();
|
|
1137
1427
|
const shouldContinue = await p6.confirm({
|
|
1138
|
-
message: action === "create" ? "Create this Cursor instance?" : "Remove this Cursor instance? This cannot be undone.",
|
|
1139
|
-
initialValue: action
|
|
1428
|
+
message: action === "create" ? "Create this Cursor instance?" : action === "reinstall" ? "Reinstall this instance? (User data will be preserved)" : "Remove this Cursor instance? This cannot be undone.",
|
|
1429
|
+
initialValue: action !== "remove"
|
|
1140
1430
|
});
|
|
1141
1431
|
if (p6.isCancel(shouldContinue) || !shouldContinue) {
|
|
1142
1432
|
p6.cancel("Operation cancelled");
|
|
@@ -1145,8 +1435,8 @@ var instanceCommand = defineCommand6({
|
|
|
1145
1435
|
console.log();
|
|
1146
1436
|
printDivider();
|
|
1147
1437
|
console.log();
|
|
1148
|
-
const scriptPath = action === "create" ? createScript : removeScript;
|
|
1149
|
-
const scriptArgs = action === "remove" ? ["--yes", instanceName] : [instanceName];
|
|
1438
|
+
const scriptPath = action === "create" ? createScript : action === "reinstall" ? reinstallScript : removeScript;
|
|
1439
|
+
const scriptArgs = action === "remove" || action === "reinstall" ? ["--yes", instanceName] : [instanceName];
|
|
1150
1440
|
const exitCode = await runScript(scriptPath, scriptArgs);
|
|
1151
1441
|
console.log();
|
|
1152
1442
|
printDivider();
|
|
@@ -1159,6 +1449,13 @@ var instanceCommand = defineCommand6({
|
|
|
1159
1449
|
console.log(pc7.dim(" \u2022 The new instance should launch automatically"));
|
|
1160
1450
|
console.log(pc7.dim(" \u2022 Sign in with a different Cursor account"));
|
|
1161
1451
|
console.log(pc7.dim(" \u2022 Find it in ~/Applications/"));
|
|
1452
|
+
} else if (action === "reinstall") {
|
|
1453
|
+
printSuccess(`Instance ${highlight(instanceName)} reinstalled successfully!`);
|
|
1454
|
+
console.log();
|
|
1455
|
+
console.log(pc7.dim(" The instance has been:"));
|
|
1456
|
+
console.log(pc7.dim(" \u2022 Refreshed with the latest Cursor version"));
|
|
1457
|
+
console.log(pc7.dim(" \u2022 Relaunched with your preserved data"));
|
|
1458
|
+
console.log(pc7.dim(" \u2022 Ready to use with your existing account"));
|
|
1162
1459
|
} else {
|
|
1163
1460
|
printSuccess(`Instance ${highlight(instanceName)} removed successfully!`);
|
|
1164
1461
|
}
|