@nolrm/contextkit 0.13.4 → 0.13.7
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/README.md +65 -46
- package/bin/contextkit.js +4 -2
- package/lib/commands/analyze.js +131 -91
- package/lib/commands/check.js +24 -18
- package/lib/commands/install.js +274 -71
- package/lib/commands/note.js +12 -20
- package/lib/commands/run.js +20 -22
- package/lib/commands/status.js +61 -32
- package/lib/commands/update.js +25 -26
- package/lib/index.js +1 -1
- package/lib/integrations/aider-integration.js +1 -1
- package/lib/integrations/base-integration.js +13 -6
- package/lib/integrations/claude-integration.js +103 -41
- package/lib/integrations/continue-integration.js +5 -5
- package/lib/integrations/copilot-integration.js +1 -1
- package/lib/integrations/cursor-integration.js +70 -28
- package/lib/integrations/gemini-integration.js +13 -11
- package/lib/integrations/index.js +11 -1
- package/lib/utils/banner.js +14 -11
- package/lib/utils/download.js +3 -4
- package/lib/utils/git-hooks.js +3 -4
- package/lib/utils/migrations.js +6 -4
- package/lib/utils/migrations.md +4 -3
- package/lib/utils/notifier.js +1 -1
- package/lib/utils/project-detector.js +11 -5
- package/lib/utils/status-manager.js +6 -7
- package/lib/utils/tool-detector.js +19 -21
- package/package.json +8 -2
package/lib/commands/install.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const ora = require('ora');
|
|
3
2
|
const inquirer = require('inquirer');
|
|
4
3
|
const fs = require('fs-extra');
|
|
5
4
|
const path = require('path');
|
|
6
|
-
const
|
|
5
|
+
const childProcess = require('child_process');
|
|
7
6
|
|
|
8
7
|
const DownloadManager = require('../utils/download');
|
|
9
8
|
const ProjectDetector = require('../utils/project-detector');
|
|
@@ -22,7 +21,7 @@ class InstallCommand {
|
|
|
22
21
|
|
|
23
22
|
async install(options = {}) {
|
|
24
23
|
// Migrate legacy .vibe-kit/ directory
|
|
25
|
-
if (await fs.pathExists('.vibe-kit') && !await fs.pathExists('.contextkit')) {
|
|
24
|
+
if ((await fs.pathExists('.vibe-kit')) && !(await fs.pathExists('.contextkit'))) {
|
|
26
25
|
console.log(chalk.yellow('Found legacy .vibe-kit/ directory'));
|
|
27
26
|
console.log(chalk.yellow('Renaming to .contextkit/...'));
|
|
28
27
|
await fs.move('.vibe-kit', '.contextkit');
|
|
@@ -41,8 +40,12 @@ class InstallCommand {
|
|
|
41
40
|
const hasGit = await this._findFileUpward('.git', 3);
|
|
42
41
|
const hasPkg = await fs.pathExists('package.json');
|
|
43
42
|
if (!hasGit && !hasPkg) {
|
|
44
|
-
console.log(
|
|
45
|
-
|
|
43
|
+
console.log(
|
|
44
|
+
chalk.yellow('⚠️ No project detected (no .git or package.json found in this directory).')
|
|
45
|
+
);
|
|
46
|
+
console.log(
|
|
47
|
+
chalk.yellow(' Make sure you are inside your project before running `ck install`.')
|
|
48
|
+
);
|
|
46
49
|
console.log('');
|
|
47
50
|
}
|
|
48
51
|
|
|
@@ -87,7 +90,9 @@ class InstallCommand {
|
|
|
87
90
|
const { shouldContinue } = await this.promptReinstall();
|
|
88
91
|
if (!shouldContinue) {
|
|
89
92
|
console.log(chalk.yellow('⏭️ Installation cancelled'));
|
|
90
|
-
console.log(
|
|
93
|
+
console.log(
|
|
94
|
+
chalk.dim('💡 To get the latest command and squad files, run: ') + chalk.cyan('ck update')
|
|
95
|
+
);
|
|
91
96
|
return;
|
|
92
97
|
}
|
|
93
98
|
}
|
|
@@ -114,6 +119,11 @@ class InstallCommand {
|
|
|
114
119
|
await this.gitHooksManager.installHooks(packageManager, hookChoices);
|
|
115
120
|
}
|
|
116
121
|
|
|
122
|
+
// Offer quality tooling scaffold for Node.js projects with pre-push enabled
|
|
123
|
+
if (hookChoices.prePush && !options.nonInteractive) {
|
|
124
|
+
await this.promptQualityTooling(packageManager, options);
|
|
125
|
+
}
|
|
126
|
+
|
|
117
127
|
// Ask about GitHub Actions CI squad workflow
|
|
118
128
|
let squadCi = false;
|
|
119
129
|
if (!options.nonInteractive) {
|
|
@@ -151,7 +161,11 @@ class InstallCommand {
|
|
|
151
161
|
|
|
152
162
|
if (!integration) {
|
|
153
163
|
console.log(chalk.red(`❌ Unknown platform: ${platform}`));
|
|
154
|
-
console.log(
|
|
164
|
+
console.log(
|
|
165
|
+
chalk.yellow(
|
|
166
|
+
'💡 Available: claude, cursor, copilot, codex, opencode, gemini, aider, continue, windsurf'
|
|
167
|
+
)
|
|
168
|
+
);
|
|
155
169
|
return;
|
|
156
170
|
}
|
|
157
171
|
|
|
@@ -161,7 +175,6 @@ class InstallCommand {
|
|
|
161
175
|
console.log(chalk.green(`🎉 ${integration.displayName} integration installed!`));
|
|
162
176
|
|
|
163
177
|
integration.showUsage();
|
|
164
|
-
|
|
165
178
|
} catch (error) {
|
|
166
179
|
console.log(chalk.red(`❌ Failed to install ${platform} integration`));
|
|
167
180
|
console.log(chalk.yellow(error.message));
|
|
@@ -186,30 +199,32 @@ class InstallCommand {
|
|
|
186
199
|
type: 'confirm',
|
|
187
200
|
name: 'shouldContinue',
|
|
188
201
|
message: 'ContextKit is already installed. Do you want to reinstall?',
|
|
189
|
-
default: false
|
|
190
|
-
}
|
|
202
|
+
default: false,
|
|
203
|
+
},
|
|
191
204
|
]);
|
|
192
205
|
return { shouldContinue };
|
|
193
206
|
}
|
|
194
207
|
|
|
195
208
|
async promptPlatformChoice() {
|
|
196
|
-
const { platform } = await inquirer.prompt([
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
209
|
+
const { platform } = await inquirer.prompt([
|
|
210
|
+
{
|
|
211
|
+
type: 'list',
|
|
212
|
+
name: 'platform',
|
|
213
|
+
message: 'Which AI tool are you using?',
|
|
214
|
+
choices: [
|
|
215
|
+
{ name: 'Claude Code', value: 'claude' },
|
|
216
|
+
{ name: 'Cursor', value: 'cursor' },
|
|
217
|
+
{ name: 'Copilot (GitHub)', value: 'copilot' },
|
|
218
|
+
{ name: 'Codex (OpenAI)', value: 'codex' },
|
|
219
|
+
{ name: 'OpenCode', value: 'opencode' },
|
|
220
|
+
{ name: 'Gemini', value: 'gemini' },
|
|
221
|
+
{ name: 'Windsurf', value: 'windsurf' },
|
|
222
|
+
{ name: 'Aider', value: 'aider' },
|
|
223
|
+
{ name: 'Continue', value: 'continue' },
|
|
224
|
+
{ name: 'Skip (base only)', value: null },
|
|
225
|
+
],
|
|
226
|
+
},
|
|
227
|
+
]);
|
|
213
228
|
return platform;
|
|
214
229
|
}
|
|
215
230
|
|
|
@@ -257,7 +272,9 @@ class InstallCommand {
|
|
|
257
272
|
`${this.repoUrl}/templates/github-actions/squad-issue.yml`,
|
|
258
273
|
'.github/workflows/squad-issue.yml'
|
|
259
274
|
);
|
|
260
|
-
console.log(
|
|
275
|
+
console.log(
|
|
276
|
+
chalk.green('✅ CI squad workflow installed → .github/workflows/squad-issue.yml')
|
|
277
|
+
);
|
|
261
278
|
} catch (error) {
|
|
262
279
|
console.log(chalk.yellow('⚠️ Could not install CI squad workflow:'), error.message);
|
|
263
280
|
}
|
|
@@ -270,7 +287,7 @@ class InstallCommand {
|
|
|
270
287
|
return { prePush: false, commitMsg: false };
|
|
271
288
|
}
|
|
272
289
|
|
|
273
|
-
if (!await fs.pathExists('.git')) {
|
|
290
|
+
if (!(await fs.pathExists('.git'))) {
|
|
274
291
|
console.log(chalk.yellow('⚠️ Skipping Git hooks setup (not a git repository)'));
|
|
275
292
|
return { prePush: false, commitMsg: false };
|
|
276
293
|
}
|
|
@@ -291,8 +308,8 @@ class InstallCommand {
|
|
|
291
308
|
type: 'confirm',
|
|
292
309
|
name: 'prePush',
|
|
293
310
|
message: 'Enable pre-push hook? (runs quality checks before push)',
|
|
294
|
-
default: false
|
|
295
|
-
}
|
|
311
|
+
default: false,
|
|
312
|
+
},
|
|
296
313
|
]);
|
|
297
314
|
|
|
298
315
|
if (prePush) {
|
|
@@ -314,8 +331,8 @@ class InstallCommand {
|
|
|
314
331
|
type: 'confirm',
|
|
315
332
|
name: 'commitMsg',
|
|
316
333
|
message: 'Enable commit-msg hook? (enforces conventional commit format)',
|
|
317
|
-
default: false
|
|
318
|
-
}
|
|
334
|
+
default: false,
|
|
335
|
+
},
|
|
319
336
|
]);
|
|
320
337
|
|
|
321
338
|
if (commitMsg) {
|
|
@@ -336,7 +353,7 @@ class InstallCommand {
|
|
|
336
353
|
|
|
337
354
|
async createDirectoryStructure() {
|
|
338
355
|
console.log(chalk.blue('📁 Creating structure...'));
|
|
339
|
-
|
|
356
|
+
|
|
340
357
|
const directories = [
|
|
341
358
|
'.contextkit/standards',
|
|
342
359
|
'.contextkit/standards/code-style', // Granular code style files
|
|
@@ -350,7 +367,7 @@ class InstallCommand {
|
|
|
350
367
|
'.contextkit/templates',
|
|
351
368
|
'.contextkit/scripts',
|
|
352
369
|
'.contextkit/integrations',
|
|
353
|
-
'.contextkit/policies' // Policy enforcement configs
|
|
370
|
+
'.contextkit/policies', // Policy enforcement configs
|
|
354
371
|
];
|
|
355
372
|
|
|
356
373
|
for (const dir of directories) {
|
|
@@ -393,7 +410,7 @@ Use conditional loading tags:
|
|
|
393
410
|
[TypeScript-specific content]
|
|
394
411
|
\`\`\`
|
|
395
412
|
`,
|
|
396
|
-
|
|
413
|
+
|
|
397
414
|
'standards/testing.md': `# Testing Standards
|
|
398
415
|
|
|
399
416
|
<!-- Content will be generated by running: /analyze -->
|
|
@@ -428,7 +445,7 @@ describe("ComponentName", () => {
|
|
|
428
445
|
- Consistent organization across all test files
|
|
429
446
|
- Quick debugging and maintenance
|
|
430
447
|
`,
|
|
431
|
-
|
|
448
|
+
|
|
432
449
|
'standards/architecture.md': `# Architecture
|
|
433
450
|
|
|
434
451
|
## Documentation Levels
|
|
@@ -476,7 +493,7 @@ Documentation for a single component or a small, cohesive set of components.
|
|
|
476
493
|
Your architecture patterns will be documented based on your project structure and organization.
|
|
477
494
|
|
|
478
495
|
Run \`/analyze\` to generate this content.`,
|
|
479
|
-
|
|
496
|
+
|
|
480
497
|
'standards/ai-guidelines.md': `# AI Guidelines
|
|
481
498
|
|
|
482
499
|
<!-- Content will be generated by running: /analyze -->
|
|
@@ -484,14 +501,14 @@ Run \`/analyze\` to generate this content.`,
|
|
|
484
501
|
Guidelines for AI assistance will be defined based on your project's needs and patterns.
|
|
485
502
|
|
|
486
503
|
Run \`/analyze\` to generate this content.`,
|
|
487
|
-
|
|
504
|
+
|
|
488
505
|
'standards/workflows.md': `# Workflows
|
|
489
506
|
|
|
490
507
|
<!-- Content will be generated by running: /analyze -->
|
|
491
508
|
|
|
492
509
|
Development workflows and processes will be documented based on your project's practices.
|
|
493
510
|
|
|
494
|
-
Run \`/analyze\` to generate this content
|
|
511
|
+
Run \`/analyze\` to generate this content.`,
|
|
495
512
|
};
|
|
496
513
|
|
|
497
514
|
// Create granular code-style skeleton files
|
|
@@ -562,7 +579,7 @@ This file is loaded when HTML-related tasks are detected:
|
|
|
562
579
|
<!-- when:html -->
|
|
563
580
|
[HTML-specific content]
|
|
564
581
|
\`\`\`
|
|
565
|
-
|
|
582
|
+
`,
|
|
566
583
|
};
|
|
567
584
|
|
|
568
585
|
for (const [relativePath, content] of Object.entries(skeletonFiles)) {
|
|
@@ -688,7 +705,7 @@ Main paths through this feature:
|
|
|
688
705
|
## Notes
|
|
689
706
|
|
|
690
707
|
Any design decisions, trade-offs, or open questions to resolve before coding.
|
|
691
|
-
|
|
708
|
+
`,
|
|
692
709
|
};
|
|
693
710
|
|
|
694
711
|
for (const [relativePath, content] of Object.entries(skeletonFiles)) {
|
|
@@ -696,22 +713,22 @@ Any design decisions, trade-offs, or open questions to resolve before coding.
|
|
|
696
713
|
}
|
|
697
714
|
}
|
|
698
715
|
|
|
699
|
-
async downloadFiles(projectType,
|
|
716
|
+
async downloadFiles(projectType, _options = {}) {
|
|
700
717
|
try {
|
|
701
718
|
// Create skeleton standards files (will be customized by analyze)
|
|
702
719
|
console.log(chalk.blue('📝 Creating skeleton standards files...'));
|
|
703
720
|
await this.createSkeletonStandards();
|
|
704
|
-
|
|
721
|
+
|
|
705
722
|
console.log(chalk.green('✅ Skeleton files created'));
|
|
706
723
|
console.log(chalk.yellow('💡 Run: /analyze to generate content based on your codebase'));
|
|
707
724
|
console.log('');
|
|
708
|
-
|
|
725
|
+
|
|
709
726
|
// Download base files
|
|
710
727
|
await this.downloadManager.downloadFile(
|
|
711
728
|
`${this.repoUrl}/standards/README.md`,
|
|
712
729
|
'.contextkit/standards/README.md'
|
|
713
730
|
);
|
|
714
|
-
|
|
731
|
+
|
|
715
732
|
// Download the actual glossary (keep it as-is, universal across all projects)
|
|
716
733
|
await this.downloadManager.downloadFile(
|
|
717
734
|
`${this.repoUrl}/standards/glossary.md`,
|
|
@@ -982,7 +999,7 @@ claude "read .contextkit/standards/README.md .contextkit/standards/glossary.md a
|
|
|
982
999
|
claude "read .contextkit/product/mission-lite.md .contextkit/standards/code-style.md and create a feature"
|
|
983
1000
|
\`\`\`
|
|
984
1001
|
`;
|
|
985
|
-
|
|
1002
|
+
|
|
986
1003
|
await fs.writeFile('.contextkit/context.md', context);
|
|
987
1004
|
await fs.writeFile('.contextkit/CONTEXT.md', context); // Keep uppercase for backward compatibility
|
|
988
1005
|
|
|
@@ -993,14 +1010,14 @@ claude "read .contextkit/product/mission-lite.md .contextkit/standards/code-styl
|
|
|
993
1010
|
|
|
994
1011
|
CONTEXT_FILE=".contextkit/context.md"
|
|
995
1012
|
AI_TOOL="\${AI_TOOL:-aider}"
|
|
996
|
-
PROMPT="
|
|
1013
|
+
PROMPT="$@"
|
|
997
1014
|
|
|
998
1015
|
if [ ! -f "$CONTEXT_FILE" ]; then
|
|
999
1016
|
echo "❌ ContextKit not initialized. Run: contextkit install"
|
|
1000
1017
|
exit 1
|
|
1001
1018
|
fi
|
|
1002
1019
|
|
|
1003
|
-
CONTEXT
|
|
1020
|
+
CONTEXT=$(cat "$CONTEXT_FILE")
|
|
1004
1021
|
|
|
1005
1022
|
case "$AI_TOOL" in
|
|
1006
1023
|
"aider")
|
|
@@ -1021,7 +1038,7 @@ esac
|
|
|
1021
1038
|
|
|
1022
1039
|
await fs.writeFile('.contextkit/scripts/ai-cli.sh', cliScript);
|
|
1023
1040
|
await fs.chmod('.contextkit/scripts/ai-cli.sh', '755');
|
|
1024
|
-
|
|
1041
|
+
|
|
1025
1042
|
console.log(chalk.green('✅ CLI helpers installed'));
|
|
1026
1043
|
}
|
|
1027
1044
|
|
|
@@ -1046,7 +1063,7 @@ esac
|
|
|
1046
1063
|
components: 'src/components',
|
|
1047
1064
|
tests: 'src/__tests__',
|
|
1048
1065
|
stories: 'src/stories',
|
|
1049
|
-
docs: 'docs'
|
|
1066
|
+
docs: 'docs',
|
|
1050
1067
|
},
|
|
1051
1068
|
commands: {
|
|
1052
1069
|
analyze: '@.contextkit/commands/analyze.md',
|
|
@@ -1057,16 +1074,19 @@ esac
|
|
|
1057
1074
|
add_docs: '@.contextkit/commands/add-documentation.md',
|
|
1058
1075
|
quality_check: '@.contextkit/commands/quality-check.md',
|
|
1059
1076
|
create_component: '@.contextkit/commands/create-component.md',
|
|
1060
|
-
create_feature: '@.contextkit/commands/create-feature.md'
|
|
1061
|
-
}
|
|
1077
|
+
create_feature: '@.contextkit/commands/create-feature.md',
|
|
1078
|
+
},
|
|
1062
1079
|
};
|
|
1063
1080
|
|
|
1064
1081
|
const now = new Date().toISOString();
|
|
1065
|
-
const isMonorepo =
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1082
|
+
const isMonorepo =
|
|
1083
|
+
(await fs.pathExists('packages')) ||
|
|
1084
|
+
(await fs.pathExists('apps')) ||
|
|
1085
|
+
((await fs.pathExists('package.json')) &&
|
|
1086
|
+
(await fs.readJson('package.json').catch(() => ({}))).workspaces);
|
|
1087
|
+
|
|
1088
|
+
await fs.writeFile(
|
|
1089
|
+
'.contextkit/config.yml',
|
|
1070
1090
|
`# ContextKit Configuration
|
|
1071
1091
|
_source:
|
|
1072
1092
|
tool: "@nolrm/contextkit"
|
|
@@ -1165,7 +1185,7 @@ https://www.npmjs.com/package/@nolrm/contextkit
|
|
|
1165
1185
|
status.features.pre_push_hook = hookChoices.prePush;
|
|
1166
1186
|
status.features.commit_msg_hook = hookChoices.commitMsg;
|
|
1167
1187
|
status.features.squad_ci_workflow = squadCi;
|
|
1168
|
-
|
|
1188
|
+
|
|
1169
1189
|
await this.statusManager.saveStatus(status);
|
|
1170
1190
|
console.log(chalk.green('✅ Status tracking initialized'));
|
|
1171
1191
|
} catch (error) {
|
|
@@ -1175,7 +1195,7 @@ https://www.npmjs.com/package/@nolrm/contextkit
|
|
|
1175
1195
|
|
|
1176
1196
|
async createProductContext() {
|
|
1177
1197
|
console.log(chalk.blue('📦 Creating product context files...'));
|
|
1178
|
-
|
|
1198
|
+
|
|
1179
1199
|
const missionContent = `# Product Mission
|
|
1180
1200
|
|
|
1181
1201
|
<!-- Content will be generated by running: ck analyze or manually fill this in -->
|
|
@@ -1373,13 +1393,13 @@ Unlike [COMPETITOR_OR_ALTERNATIVE], we provide [SPECIFIC_ADVANTAGE]. This result
|
|
|
1373
1393
|
await fs.writeFile('.contextkit/product/roadmap.md', roadmapContent);
|
|
1374
1394
|
await fs.writeFile('.contextkit/product/decisions.md', decisionsContent);
|
|
1375
1395
|
await fs.writeFile('.contextkit/product/context.md', contextContent);
|
|
1376
|
-
|
|
1396
|
+
|
|
1377
1397
|
console.log(chalk.green('✅ Product context files created'));
|
|
1378
1398
|
}
|
|
1379
1399
|
|
|
1380
1400
|
async createCorrectionsLog() {
|
|
1381
1401
|
console.log(chalk.blue('📝 Creating corrections log system...'));
|
|
1382
|
-
|
|
1402
|
+
|
|
1383
1403
|
const correctionsContent = `# ContextKit Corrections Log
|
|
1384
1404
|
|
|
1385
1405
|
## Description
|
|
@@ -1565,14 +1585,17 @@ Automatically track and log ContextKit performance issues during development ses
|
|
|
1565
1585
|
`;
|
|
1566
1586
|
|
|
1567
1587
|
await fs.writeFile('.contextkit/corrections.md', correctionsContent);
|
|
1568
|
-
await fs.writeFile(
|
|
1569
|
-
|
|
1588
|
+
await fs.writeFile(
|
|
1589
|
+
'.contextkit/instructions/core/auto-corrections-log.md',
|
|
1590
|
+
autoCorrectionsContent
|
|
1591
|
+
);
|
|
1592
|
+
|
|
1570
1593
|
console.log(chalk.green('✅ Corrections log system created'));
|
|
1571
1594
|
}
|
|
1572
1595
|
|
|
1573
1596
|
async createMetaInstructions() {
|
|
1574
1597
|
console.log(chalk.blue('📋 Creating meta instructions...'));
|
|
1575
|
-
|
|
1598
|
+
|
|
1576
1599
|
const preFlightContent = `---
|
|
1577
1600
|
description: Common Pre-Flight Steps for ContextKit Instructions
|
|
1578
1601
|
globs:
|
|
@@ -1646,13 +1669,13 @@ After completing any development session, automatically update the corrections l
|
|
|
1646
1669
|
|
|
1647
1670
|
await fs.writeFile('.contextkit/instructions/meta/pre-flight.md', preFlightContent);
|
|
1648
1671
|
await fs.writeFile('.contextkit/instructions/meta/post-flight.md', postFlightContent);
|
|
1649
|
-
|
|
1672
|
+
|
|
1650
1673
|
console.log(chalk.green('✅ Meta instructions created'));
|
|
1651
1674
|
}
|
|
1652
1675
|
|
|
1653
1676
|
async createPolicyFile() {
|
|
1654
1677
|
console.log(chalk.blue('⚖️ Creating policy file...'));
|
|
1655
|
-
|
|
1678
|
+
|
|
1656
1679
|
const policyContent = `# ContextKit Policy Configuration
|
|
1657
1680
|
|
|
1658
1681
|
## Enforcement Levels
|
|
@@ -1676,11 +1699,11 @@ enforcement:
|
|
|
1676
1699
|
`;
|
|
1677
1700
|
|
|
1678
1701
|
await fs.writeFile('.contextkit/policies/policy.yml', policyContent);
|
|
1679
|
-
|
|
1702
|
+
|
|
1680
1703
|
console.log(chalk.green('✅ Policy file created'));
|
|
1681
1704
|
}
|
|
1682
1705
|
|
|
1683
|
-
showSuccessMessage(hookChoices, platform = null,
|
|
1706
|
+
showSuccessMessage(hookChoices, platform = null, _projectType = '', _packageManager = '') {
|
|
1684
1707
|
console.log('');
|
|
1685
1708
|
console.log(chalk.green('🎉 ContextKit v1.0.0 successfully installed!'));
|
|
1686
1709
|
console.log('');
|
|
@@ -1702,7 +1725,9 @@ enforcement:
|
|
|
1702
1725
|
console.log(chalk.bold('📖 Quick Reference'));
|
|
1703
1726
|
console.log(''.padEnd(48, '─'));
|
|
1704
1727
|
console.log(`ck status → Check installation & integrations`);
|
|
1705
|
-
console.log(
|
|
1728
|
+
console.log(
|
|
1729
|
+
`ck <platform> → Add platform (claude, cursor, copilot, codex, opencode, gemini, aider, continue, windsurf)`
|
|
1730
|
+
);
|
|
1706
1731
|
console.log('');
|
|
1707
1732
|
console.log(`Docs → ${chalk.blue('https://contextkit-docs.vercel.app')}`);
|
|
1708
1733
|
console.log(`Issues → ${chalk.blue('https://github.com/nolrm/contextkit/issues')}`);
|
|
@@ -1747,7 +1772,11 @@ enforcement:
|
|
|
1747
1772
|
}
|
|
1748
1773
|
|
|
1749
1774
|
console.log(chalk.bold('In CLI'));
|
|
1750
|
-
console.log(
|
|
1775
|
+
console.log(
|
|
1776
|
+
chalk.dim(
|
|
1777
|
+
"Use your AI tool's slash command, e.g. /analyze or @.contextkit/commands/create-component.md"
|
|
1778
|
+
)
|
|
1779
|
+
);
|
|
1751
1780
|
console.log('');
|
|
1752
1781
|
|
|
1753
1782
|
if (platform === 'claude' || platform === 'gemini') {
|
|
@@ -1761,6 +1790,179 @@ enforcement:
|
|
|
1761
1790
|
console.log('');
|
|
1762
1791
|
}
|
|
1763
1792
|
|
|
1793
|
+
async promptQualityTooling(packageManager, _options = {}) {
|
|
1794
|
+
// Only relevant for Node.js projects
|
|
1795
|
+
if (!(await fs.pathExists('package.json'))) return;
|
|
1796
|
+
|
|
1797
|
+
// Skip in CI / non-interactive mode
|
|
1798
|
+
if (process.env.CI === 'true' || process.env.NON_INTERACTIVE === 'true') return;
|
|
1799
|
+
|
|
1800
|
+
const pkg = await fs.readJson('package.json').catch(() => null);
|
|
1801
|
+
if (!pkg) return;
|
|
1802
|
+
|
|
1803
|
+
const hasFormat = !!(pkg.scripts && pkg.scripts.format);
|
|
1804
|
+
const hasLint = !!(pkg.scripts && pkg.scripts.lint);
|
|
1805
|
+
|
|
1806
|
+
// Both already present — nothing to do
|
|
1807
|
+
if (hasFormat && hasLint) return;
|
|
1808
|
+
|
|
1809
|
+
console.log('');
|
|
1810
|
+
console.log('──────────────────────────────────────────────');
|
|
1811
|
+
console.log(chalk.blue('🛠️ Format + Lint Quality Gates'));
|
|
1812
|
+
console.log('──────────────────────────────────────────────');
|
|
1813
|
+
console.log(chalk.dim('The pre-push hook runs format and lint scripts automatically'));
|
|
1814
|
+
console.log(chalk.dim('when present. Your project has none — add a minimal setup now?'));
|
|
1815
|
+
console.log('');
|
|
1816
|
+
|
|
1817
|
+
const { scaffold } = await inquirer.prompt([
|
|
1818
|
+
{
|
|
1819
|
+
type: 'confirm',
|
|
1820
|
+
name: 'scaffold',
|
|
1821
|
+
message: 'Add prettier + eslint setup? (adds scripts + config files)',
|
|
1822
|
+
default: false,
|
|
1823
|
+
},
|
|
1824
|
+
]);
|
|
1825
|
+
|
|
1826
|
+
if (scaffold) {
|
|
1827
|
+
await this.scaffoldQualityTooling(pkg, packageManager);
|
|
1828
|
+
} else {
|
|
1829
|
+
console.log(chalk.dim('💡 Add format/lint scripts later to activate these quality gates'));
|
|
1830
|
+
}
|
|
1831
|
+
console.log('');
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
async scaffoldQualityTooling(pkg, packageManager) {
|
|
1835
|
+
const pmInstallFlags = {
|
|
1836
|
+
npm: 'install --save-dev',
|
|
1837
|
+
yarn: 'add --dev',
|
|
1838
|
+
pnpm: 'add -D',
|
|
1839
|
+
bun: 'add -d',
|
|
1840
|
+
};
|
|
1841
|
+
const installFlag = pmInstallFlags[packageManager] || 'install --save-dev';
|
|
1842
|
+
const pm = packageManager === 'none' ? 'npm' : packageManager;
|
|
1843
|
+
|
|
1844
|
+
try {
|
|
1845
|
+
const created = [];
|
|
1846
|
+
|
|
1847
|
+
// 1. Add missing scripts to package.json
|
|
1848
|
+
if (!pkg.scripts) pkg.scripts = {};
|
|
1849
|
+
if (!pkg.scripts.format) {
|
|
1850
|
+
pkg.scripts.format = 'prettier --write .';
|
|
1851
|
+
created.push('format script');
|
|
1852
|
+
}
|
|
1853
|
+
if (!pkg.scripts.lint) {
|
|
1854
|
+
pkg.scripts.lint = 'eslint .';
|
|
1855
|
+
created.push('lint script');
|
|
1856
|
+
}
|
|
1857
|
+
await fs.writeFile('package.json', JSON.stringify(pkg, null, 2) + '\n');
|
|
1858
|
+
|
|
1859
|
+
// 2. Create .prettierrc if no existing config
|
|
1860
|
+
if (!(await this._hasExistingPrettierConfig(pkg))) {
|
|
1861
|
+
await fs.writeFile(
|
|
1862
|
+
'.prettierrc',
|
|
1863
|
+
JSON.stringify(
|
|
1864
|
+
{ singleQuote: true, semi: true, tabWidth: 2, printWidth: 100, trailingComma: 'es5' },
|
|
1865
|
+
null,
|
|
1866
|
+
2
|
|
1867
|
+
) + '\n'
|
|
1868
|
+
);
|
|
1869
|
+
created.push('.prettierrc');
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
// 3. Create .prettierignore if absent
|
|
1873
|
+
if (!(await fs.pathExists('.prettierignore'))) {
|
|
1874
|
+
await fs.writeFile('.prettierignore', 'node_modules/\ncoverage/\ndist/\nbuild/\n');
|
|
1875
|
+
created.push('.prettierignore');
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
// 4. Create eslint.config.js if no existing config
|
|
1879
|
+
if (!(await this._hasExistingEslintConfig(pkg))) {
|
|
1880
|
+
await fs.writeFile(
|
|
1881
|
+
'eslint.config.js',
|
|
1882
|
+
`const js = require('@eslint/js');
|
|
1883
|
+
const globals = require('globals');
|
|
1884
|
+
|
|
1885
|
+
module.exports = [
|
|
1886
|
+
js.configs.recommended,
|
|
1887
|
+
{
|
|
1888
|
+
languageOptions: {
|
|
1889
|
+
ecmaVersion: 2022,
|
|
1890
|
+
globals: {
|
|
1891
|
+
...globals.node,
|
|
1892
|
+
},
|
|
1893
|
+
},
|
|
1894
|
+
rules: {
|
|
1895
|
+
'no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
|
1896
|
+
},
|
|
1897
|
+
},
|
|
1898
|
+
{
|
|
1899
|
+
files: ['**/__tests__/**/*.js', '**/*.test.js'],
|
|
1900
|
+
languageOptions: {
|
|
1901
|
+
globals: {
|
|
1902
|
+
...globals.jest,
|
|
1903
|
+
},
|
|
1904
|
+
},
|
|
1905
|
+
},
|
|
1906
|
+
];\n`
|
|
1907
|
+
);
|
|
1908
|
+
created.push('eslint.config.js');
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
// 5. Install devDependencies
|
|
1912
|
+
console.log(chalk.blue(`\n📦 Installing prettier + eslint...`));
|
|
1913
|
+
childProcess.execSync(`${pm} ${installFlag} prettier eslint @eslint/js globals`, {
|
|
1914
|
+
stdio: 'inherit',
|
|
1915
|
+
});
|
|
1916
|
+
|
|
1917
|
+
console.log('');
|
|
1918
|
+
console.log(chalk.green('✅ Quality tooling ready:'));
|
|
1919
|
+
created.forEach((item) => console.log(chalk.dim(` • ${item}`)));
|
|
1920
|
+
console.log(chalk.dim(' Run npm run format to apply formatting to existing files'));
|
|
1921
|
+
} catch (error) {
|
|
1922
|
+
console.log(chalk.yellow('⚠️ Could not complete quality tooling setup:'), error.message);
|
|
1923
|
+
console.log(chalk.dim(' You can set this up manually later'));
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
async _hasExistingPrettierConfig(pkg) {
|
|
1928
|
+
if (pkg.prettier) return true;
|
|
1929
|
+
const configs = [
|
|
1930
|
+
'.prettierrc',
|
|
1931
|
+
'.prettierrc.json',
|
|
1932
|
+
'.prettierrc.js',
|
|
1933
|
+
'.prettierrc.mjs',
|
|
1934
|
+
'.prettierrc.cjs',
|
|
1935
|
+
'.prettierrc.yaml',
|
|
1936
|
+
'.prettierrc.yml',
|
|
1937
|
+
'.prettierrc.toml',
|
|
1938
|
+
'prettier.config.js',
|
|
1939
|
+
'prettier.config.mjs',
|
|
1940
|
+
'prettier.config.cjs',
|
|
1941
|
+
];
|
|
1942
|
+
for (const f of configs) {
|
|
1943
|
+
if (await fs.pathExists(f)) return true;
|
|
1944
|
+
}
|
|
1945
|
+
return false;
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
async _hasExistingEslintConfig(pkg) {
|
|
1949
|
+
if (pkg.eslintConfig) return true;
|
|
1950
|
+
const configs = [
|
|
1951
|
+
'eslint.config.js',
|
|
1952
|
+
'eslint.config.mjs',
|
|
1953
|
+
'eslint.config.cjs',
|
|
1954
|
+
'.eslintrc',
|
|
1955
|
+
'.eslintrc.js',
|
|
1956
|
+
'.eslintrc.json',
|
|
1957
|
+
'.eslintrc.yml',
|
|
1958
|
+
'.eslintrc.yaml',
|
|
1959
|
+
];
|
|
1960
|
+
for (const f of configs) {
|
|
1961
|
+
if (await fs.pathExists(f)) return true;
|
|
1962
|
+
}
|
|
1963
|
+
return false;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1764
1966
|
async _findFileUpward(name, maxLevels) {
|
|
1765
1967
|
let dir = process.cwd();
|
|
1766
1968
|
for (let i = 0; i <= maxLevels; i++) {
|
|
@@ -1779,3 +1981,4 @@ async function install(options) {
|
|
|
1779
1981
|
}
|
|
1780
1982
|
|
|
1781
1983
|
module.exports = install;
|
|
1984
|
+
module.exports.InstallCommand = InstallCommand;
|