@nolrm/contextkit 0.8.4 → 0.9.4
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 +47 -7
- package/lib/commands/install.js +42 -23
- package/lib/commands/update.js +30 -15
- package/lib/integrations/claude-integration.js +50 -11
- package/lib/integrations/cursor-integration.js +57 -7
- package/lib/utils/git-hooks.js +112 -171
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -111,13 +111,17 @@ Each platform generates bridge files that the AI tool auto-reads. If a bridge fi
|
|
|
111
111
|
|
|
112
112
|
## Use it in your tool
|
|
113
113
|
|
|
114
|
-
**Cursor** — rules auto-load from `.cursor/rules/`
|
|
114
|
+
**Cursor** — rules auto-load from `.cursor/rules/`, slash commands in `.cursor/prompts/`
|
|
115
115
|
```
|
|
116
|
-
|
|
116
|
+
/analyze # scan codebase and generate standards
|
|
117
|
+
/review # code review with checklist
|
|
118
|
+
/fix # diagnose and fix bugs
|
|
117
119
|
```
|
|
118
120
|
|
|
119
|
-
**Claude Code** — reads `CLAUDE.md` + `.claude/rules/`
|
|
121
|
+
**Claude Code** — reads `CLAUDE.md` + `.claude/rules/`, slash commands in `.claude/commands/`
|
|
120
122
|
```bash
|
|
123
|
+
/analyze # scan codebase and generate standards
|
|
124
|
+
/review # code review with checklist
|
|
121
125
|
claude "create checkout flow for customer"
|
|
122
126
|
```
|
|
123
127
|
|
|
@@ -133,20 +137,56 @@ codex "create checkout flow for customer"
|
|
|
133
137
|
|
|
134
138
|
**CLI** (Chat with AI)
|
|
135
139
|
```bash
|
|
136
|
-
ck ai "create
|
|
140
|
+
ck ai "create a button"
|
|
137
141
|
```
|
|
138
142
|
|
|
139
143
|
---
|
|
140
144
|
|
|
141
|
-
##
|
|
145
|
+
## Slash Commands
|
|
142
146
|
|
|
143
|
-
ContextKit
|
|
147
|
+
ContextKit installs reusable slash commands for supported platforms:
|
|
148
|
+
|
|
149
|
+
| Command | What it does |
|
|
150
|
+
|---------|-------------|
|
|
151
|
+
| `/analyze` | Scan codebase and generate standards content |
|
|
152
|
+
| `/review` | Code review with checklist |
|
|
153
|
+
| `/fix` | Diagnose and fix bugs |
|
|
154
|
+
| `/refactor` | Refactor code with safety checks |
|
|
155
|
+
| `/test` | Generate comprehensive tests |
|
|
156
|
+
| `/doc` | Add documentation |
|
|
157
|
+
|
|
158
|
+
**Claude Code** — available as `/analyze`, `/review`, etc. in `.claude/commands/`
|
|
159
|
+
**Cursor** — available as slash commands in Chat via `.cursor/prompts/`
|
|
160
|
+
|
|
161
|
+
Both platforms delegate to the universal command files in `.contextkit/commands/`, so you maintain one set of workflows.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Git Hooks & Quality Gates
|
|
166
|
+
|
|
167
|
+
ContextKit can optionally install Git hooks during `ck install`. Uses `git config core.hooksPath` to point Git at `.contextkit/hooks/` — no external dependencies like Husky required. Works in any git repo, not just Node.js projects.
|
|
168
|
+
|
|
169
|
+
For **Node.js projects**, a `prepare` script is automatically added to `package.json` so hooks activate for all developers after `npm install` — no need for everyone to run `ck install`.
|
|
144
170
|
|
|
145
171
|
| Hook | What it does |
|
|
146
172
|
|------|-------------|
|
|
147
|
-
| **pre-push** |
|
|
173
|
+
| **pre-push** | **Quality Gates** — auto-detects your project framework and runs the appropriate checks |
|
|
148
174
|
| **commit-msg** | Enforces [Conventional Commits](https://www.conventionalcommits.org/) format |
|
|
149
175
|
|
|
176
|
+
### Framework-Aware Quality Gates
|
|
177
|
+
|
|
178
|
+
The pre-push hook detects your project type and runs the right quality checks automatically. All gates skip gracefully when tools aren't installed.
|
|
179
|
+
|
|
180
|
+
| Framework | Checks |
|
|
181
|
+
|-----------|--------|
|
|
182
|
+
| **Node.js** | TypeScript, ESLint, Prettier, build, test (auto-detects npm/yarn/pnpm/bun) |
|
|
183
|
+
| **Python** | ruff/flake8, mypy, black/ruff format, pytest |
|
|
184
|
+
| **Rust** | cargo check, clippy, cargo test |
|
|
185
|
+
| **Go** | go vet, golangci-lint, go test |
|
|
186
|
+
| **PHP** | PHPStan, PHPUnit |
|
|
187
|
+
| **Ruby** | RuboCop, RSpec/rake test |
|
|
188
|
+
| **Java** | Maven verify / Gradle check |
|
|
189
|
+
|
|
150
190
|
### Commit Message Format
|
|
151
191
|
|
|
152
192
|
When the `commit-msg` hook is enabled, all commits must follow this format:
|
package/lib/commands/install.js
CHANGED
|
@@ -178,20 +178,21 @@ class InstallCommand {
|
|
|
178
178
|
return { prePush: false, commitMsg: false };
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
if (!await fs.pathExists('
|
|
182
|
-
console.log(chalk.yellow('⚠️ Skipping Git hooks setup (
|
|
181
|
+
if (!await fs.pathExists('.git')) {
|
|
182
|
+
console.log(chalk.yellow('⚠️ Skipping Git hooks setup (not a git repository)'));
|
|
183
183
|
return { prePush: false, commitMsg: false };
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
console.log('');
|
|
187
187
|
console.log('──────────────────────────────────────────────');
|
|
188
|
-
console.log(chalk.blue('⚙️ Git Hooks
|
|
188
|
+
console.log(chalk.blue('⚙️ Quality Gates — Git Hooks'));
|
|
189
189
|
console.log('──────────────────────────────────────────────');
|
|
190
190
|
console.log('');
|
|
191
191
|
|
|
192
192
|
// Ask about pre-push hook
|
|
193
|
-
console.log(chalk.bold('Pre-push
|
|
194
|
-
console.log(chalk.dim('
|
|
193
|
+
console.log(chalk.bold('Pre-push Quality Gates'));
|
|
194
|
+
console.log(chalk.dim('Auto-detects your framework (Node, Python, Rust, Go, etc.)'));
|
|
195
|
+
console.log(chalk.dim('and runs the right checks before pushing.'));
|
|
195
196
|
console.log('');
|
|
196
197
|
const { prePush } = await inquirer.prompt([
|
|
197
198
|
{
|
|
@@ -514,12 +515,20 @@ Run \`ck analyze\` to generate this content, or manually add your API pattern be
|
|
|
514
515
|
|
|
515
516
|
// Download commands
|
|
516
517
|
await this.downloadManager.downloadFile(
|
|
517
|
-
`${this.repoUrl}/commands/
|
|
518
|
-
'.contextkit/commands/
|
|
518
|
+
`${this.repoUrl}/commands/analyze.md`,
|
|
519
|
+
'.contextkit/commands/analyze.md'
|
|
519
520
|
);
|
|
520
521
|
await this.downloadManager.downloadFile(
|
|
521
|
-
`${this.repoUrl}/commands/
|
|
522
|
-
'.contextkit/commands/
|
|
522
|
+
`${this.repoUrl}/commands/review.md`,
|
|
523
|
+
'.contextkit/commands/review.md'
|
|
524
|
+
);
|
|
525
|
+
await this.downloadManager.downloadFile(
|
|
526
|
+
`${this.repoUrl}/commands/fix.md`,
|
|
527
|
+
'.contextkit/commands/fix.md'
|
|
528
|
+
);
|
|
529
|
+
await this.downloadManager.downloadFile(
|
|
530
|
+
`${this.repoUrl}/commands/refactor.md`,
|
|
531
|
+
'.contextkit/commands/refactor.md'
|
|
523
532
|
);
|
|
524
533
|
await this.downloadManager.downloadFile(
|
|
525
534
|
`${this.repoUrl}/commands/run-tests.md`,
|
|
@@ -534,18 +543,22 @@ Run \`ck analyze\` to generate this content, or manually add your API pattern be
|
|
|
534
543
|
'.contextkit/commands/quality-check.md'
|
|
535
544
|
);
|
|
536
545
|
await this.downloadManager.downloadFile(
|
|
537
|
-
`${this.repoUrl}/commands/
|
|
538
|
-
'.contextkit/commands/
|
|
546
|
+
`${this.repoUrl}/commands/create-feature.md`,
|
|
547
|
+
'.contextkit/commands/create-feature.md'
|
|
548
|
+
);
|
|
549
|
+
await this.downloadManager.downloadFile(
|
|
550
|
+
`${this.repoUrl}/commands/create-component.md`,
|
|
551
|
+
'.contextkit/commands/create-component.md'
|
|
539
552
|
);
|
|
540
553
|
|
|
541
554
|
// Download hooks (pre-push and commit-msg only, no pre-commit)
|
|
542
555
|
await this.downloadManager.downloadFile(
|
|
543
|
-
`${this.repoUrl}/hooks/pre-push
|
|
544
|
-
'.contextkit/hooks/pre-push
|
|
556
|
+
`${this.repoUrl}/hooks/pre-push`,
|
|
557
|
+
'.contextkit/hooks/pre-push'
|
|
545
558
|
);
|
|
546
559
|
await this.downloadManager.downloadFile(
|
|
547
|
-
`${this.repoUrl}/hooks/commit-msg
|
|
548
|
-
'.contextkit/hooks/commit-msg
|
|
560
|
+
`${this.repoUrl}/hooks/commit-msg`,
|
|
561
|
+
'.contextkit/hooks/commit-msg'
|
|
549
562
|
);
|
|
550
563
|
await this.downloadManager.downloadFile(
|
|
551
564
|
`${this.repoUrl}/hooks/setup-hooks.sh`,
|
|
@@ -580,8 +593,8 @@ Run \`ck analyze\` to generate this content, or manually add your API pattern be
|
|
|
580
593
|
);
|
|
581
594
|
|
|
582
595
|
// Make scripts executable
|
|
583
|
-
await fs.chmod('.contextkit/hooks/pre-push
|
|
584
|
-
await fs.chmod('.contextkit/hooks/commit-msg
|
|
596
|
+
await fs.chmod('.contextkit/hooks/pre-push', '755');
|
|
597
|
+
await fs.chmod('.contextkit/hooks/commit-msg', '755');
|
|
585
598
|
await fs.chmod('.contextkit/hooks/setup-hooks.sh', '755');
|
|
586
599
|
await fs.chmod('.contextkit/types/type-check.sh', '755');
|
|
587
600
|
await fs.chmod('.contextkit/scripts/update.sh', '755');
|
|
@@ -682,11 +695,14 @@ claude "read .contextkit/context.md to see available standards, then create a bu
|
|
|
682
695
|
|
|
683
696
|
### Commands
|
|
684
697
|
- \`.contextkit/commands/analyze.md\` - Analyze & customize standards
|
|
698
|
+
- \`.contextkit/commands/review.md\` - Code review
|
|
699
|
+
- \`.contextkit/commands/fix.md\` - Diagnose and fix bugs
|
|
700
|
+
- \`.contextkit/commands/refactor.md\` - Refactor code structure
|
|
701
|
+
- \`.contextkit/commands/run-tests.md\` - Generate or run tests
|
|
702
|
+
- \`.contextkit/commands/add-documentation.md\` - Add documentation
|
|
703
|
+
- \`.contextkit/commands/quality-check.md\` - Quality checks
|
|
685
704
|
- \`.contextkit/commands/create-component.md\` - Create component
|
|
686
705
|
- \`.contextkit/commands/create-feature.md\` - Create feature
|
|
687
|
-
- \`.contextkit/commands/run-tests.md\` - Run tests
|
|
688
|
-
- \`.contextkit/commands/quality-check.md\` - Quality checks
|
|
689
|
-
- \`.contextkit/commands/add-documentation.md\` - Add documentation
|
|
690
706
|
|
|
691
707
|
### Instructions
|
|
692
708
|
- \`.contextkit/instructions/meta/pre-flight.md\` - Pre-flight checks
|
|
@@ -805,12 +821,15 @@ esac
|
|
|
805
821
|
docs: 'docs'
|
|
806
822
|
},
|
|
807
823
|
commands: {
|
|
808
|
-
|
|
809
|
-
|
|
824
|
+
analyze: '@.contextkit/commands/analyze.md',
|
|
825
|
+
review: '@.contextkit/commands/review.md',
|
|
826
|
+
fix: '@.contextkit/commands/fix.md',
|
|
827
|
+
refactor: '@.contextkit/commands/refactor.md',
|
|
810
828
|
run_tests: '@.contextkit/commands/run-tests.md',
|
|
811
829
|
add_docs: '@.contextkit/commands/add-documentation.md',
|
|
812
830
|
quality_check: '@.contextkit/commands/quality-check.md',
|
|
813
|
-
|
|
831
|
+
create_component: '@.contextkit/commands/create-component.md',
|
|
832
|
+
create_feature: '@.contextkit/commands/create-feature.md'
|
|
814
833
|
}
|
|
815
834
|
};
|
|
816
835
|
|
package/lib/commands/update.js
CHANGED
|
@@ -213,12 +213,20 @@ class UpdateCommand {
|
|
|
213
213
|
|
|
214
214
|
// Download commands
|
|
215
215
|
await this.downloadManager.downloadFile(
|
|
216
|
-
`${this.repoUrl}/commands/
|
|
217
|
-
'.contextkit/commands/
|
|
216
|
+
`${this.repoUrl}/commands/analyze.md`,
|
|
217
|
+
'.contextkit/commands/analyze.md'
|
|
218
218
|
);
|
|
219
219
|
await this.downloadManager.downloadFile(
|
|
220
|
-
`${this.repoUrl}/commands/
|
|
221
|
-
'.contextkit/commands/
|
|
220
|
+
`${this.repoUrl}/commands/review.md`,
|
|
221
|
+
'.contextkit/commands/review.md'
|
|
222
|
+
);
|
|
223
|
+
await this.downloadManager.downloadFile(
|
|
224
|
+
`${this.repoUrl}/commands/fix.md`,
|
|
225
|
+
'.contextkit/commands/fix.md'
|
|
226
|
+
);
|
|
227
|
+
await this.downloadManager.downloadFile(
|
|
228
|
+
`${this.repoUrl}/commands/refactor.md`,
|
|
229
|
+
'.contextkit/commands/refactor.md'
|
|
222
230
|
);
|
|
223
231
|
await this.downloadManager.downloadFile(
|
|
224
232
|
`${this.repoUrl}/commands/run-tests.md`,
|
|
@@ -233,18 +241,22 @@ class UpdateCommand {
|
|
|
233
241
|
'.contextkit/commands/quality-check.md'
|
|
234
242
|
);
|
|
235
243
|
await this.downloadManager.downloadFile(
|
|
236
|
-
`${this.repoUrl}/commands/
|
|
237
|
-
'.contextkit/commands/
|
|
244
|
+
`${this.repoUrl}/commands/create-feature.md`,
|
|
245
|
+
'.contextkit/commands/create-feature.md'
|
|
246
|
+
);
|
|
247
|
+
await this.downloadManager.downloadFile(
|
|
248
|
+
`${this.repoUrl}/commands/create-component.md`,
|
|
249
|
+
'.contextkit/commands/create-component.md'
|
|
238
250
|
);
|
|
239
251
|
|
|
240
252
|
// Download hooks (pre-push and commit-msg only, no pre-commit)
|
|
241
253
|
await this.downloadManager.downloadFile(
|
|
242
|
-
`${this.repoUrl}/hooks/pre-push
|
|
243
|
-
'.contextkit/hooks/pre-push
|
|
254
|
+
`${this.repoUrl}/hooks/pre-push`,
|
|
255
|
+
'.contextkit/hooks/pre-push'
|
|
244
256
|
);
|
|
245
257
|
await this.downloadManager.downloadFile(
|
|
246
|
-
`${this.repoUrl}/hooks/commit-msg
|
|
247
|
-
'.contextkit/hooks/commit-msg
|
|
258
|
+
`${this.repoUrl}/hooks/commit-msg`,
|
|
259
|
+
'.contextkit/hooks/commit-msg'
|
|
248
260
|
);
|
|
249
261
|
await this.downloadManager.downloadFile(
|
|
250
262
|
`${this.repoUrl}/hooks/setup-hooks.sh`,
|
|
@@ -278,8 +290,8 @@ class UpdateCommand {
|
|
|
278
290
|
);
|
|
279
291
|
|
|
280
292
|
// Make scripts executable
|
|
281
|
-
await fs.chmod('.contextkit/hooks/pre-push
|
|
282
|
-
await fs.chmod('.contextkit/hooks/commit-msg
|
|
293
|
+
await fs.chmod('.contextkit/hooks/pre-push', '755');
|
|
294
|
+
await fs.chmod('.contextkit/hooks/commit-msg', '755');
|
|
283
295
|
await fs.chmod('.contextkit/hooks/setup-hooks.sh', '755');
|
|
284
296
|
await fs.chmod('.contextkit/types/type-check.sh', '755');
|
|
285
297
|
await fs.chmod('.contextkit/scripts/update.sh', '755');
|
|
@@ -317,12 +329,15 @@ paths:
|
|
|
317
329
|
|
|
318
330
|
# Commands
|
|
319
331
|
commands:
|
|
320
|
-
|
|
321
|
-
|
|
332
|
+
analyze: "${config.commands?.analyze || '@.contextkit/commands/analyze.md'}"
|
|
333
|
+
review: "${config.commands?.review || '@.contextkit/commands/review.md'}"
|
|
334
|
+
fix: "${config.commands?.fix || '@.contextkit/commands/fix.md'}"
|
|
335
|
+
refactor: "${config.commands?.refactor || '@.contextkit/commands/refactor.md'}"
|
|
322
336
|
run_tests: "${config.commands?.run_tests || '@.contextkit/commands/run-tests.md'}"
|
|
323
337
|
add_docs: "${config.commands?.add_docs || '@.contextkit/commands/add-documentation.md'}"
|
|
324
338
|
quality_check: "${config.commands?.quality_check || '@.contextkit/commands/quality-check.md'}"
|
|
325
|
-
|
|
339
|
+
create_component: "${config.commands?.create_component || '@.contextkit/commands/create-component.md'}"
|
|
340
|
+
create_feature: "${config.commands?.create_feature || '@.contextkit/commands/create-feature.md'}"
|
|
326
341
|
`;
|
|
327
342
|
|
|
328
343
|
await fs.writeFile('.contextkit/config.yml', configContent);
|
|
@@ -12,6 +12,11 @@ class ClaudeIntegration extends BaseIntegration {
|
|
|
12
12
|
'.claude/rules/contextkit-testing.md',
|
|
13
13
|
'.claude/rules/contextkit-code-style.md',
|
|
14
14
|
'.claude/commands/analyze.md',
|
|
15
|
+
'.claude/commands/review.md',
|
|
16
|
+
'.claude/commands/fix.md',
|
|
17
|
+
'.claude/commands/refactor.md',
|
|
18
|
+
'.claude/commands/test.md',
|
|
19
|
+
'.claude/commands/doc.md',
|
|
15
20
|
];
|
|
16
21
|
this.platformDir = '.claude/rules';
|
|
17
22
|
}
|
|
@@ -112,14 +117,48 @@ When writing or modifying source code, follow:
|
|
|
112
117
|
`;
|
|
113
118
|
await this.writeGeneratedFile('.claude/rules/contextkit-code-style.md', codeStyleRule);
|
|
114
119
|
|
|
115
|
-
//
|
|
116
|
-
|
|
120
|
+
// Slash commands — thin wrappers that delegate to .contextkit/commands/
|
|
121
|
+
await this.writeGeneratedFile('.claude/commands/analyze.md', `# Analyze Project
|
|
117
122
|
|
|
118
123
|
Read \`.contextkit/commands/analyze.md\` and execute the analysis workflow for this project.
|
|
119
124
|
|
|
120
125
|
Scan the codebase structure, detect frameworks and patterns, then generate customized standards files in \`.contextkit/standards/\`.
|
|
121
|
-
|
|
122
|
-
|
|
126
|
+
`);
|
|
127
|
+
|
|
128
|
+
await this.writeGeneratedFile('.claude/commands/review.md', `# Code Review
|
|
129
|
+
|
|
130
|
+
Read \`.contextkit/commands/review.md\` and execute the review workflow.
|
|
131
|
+
|
|
132
|
+
Review current changes for correctness, standards compliance, and potential issues.
|
|
133
|
+
`);
|
|
134
|
+
|
|
135
|
+
await this.writeGeneratedFile('.claude/commands/fix.md', `# Fix Bug
|
|
136
|
+
|
|
137
|
+
Read \`.contextkit/commands/fix.md\` and execute the bug fix workflow.
|
|
138
|
+
|
|
139
|
+
Diagnose the root cause, implement the minimal fix, and add a regression test.
|
|
140
|
+
`);
|
|
141
|
+
|
|
142
|
+
await this.writeGeneratedFile('.claude/commands/refactor.md', `# Refactor
|
|
143
|
+
|
|
144
|
+
Read \`.contextkit/commands/refactor.md\` and execute the refactoring workflow.
|
|
145
|
+
|
|
146
|
+
Improve code structure without changing behavior, keeping tests green at every step.
|
|
147
|
+
`);
|
|
148
|
+
|
|
149
|
+
await this.writeGeneratedFile('.claude/commands/test.md', `# Run Tests
|
|
150
|
+
|
|
151
|
+
Read \`.contextkit/commands/run-tests.md\` and execute the testing workflow.
|
|
152
|
+
|
|
153
|
+
Generate or run tests for the specified code, covering happy paths, edge cases, and errors.
|
|
154
|
+
`);
|
|
155
|
+
|
|
156
|
+
await this.writeGeneratedFile('.claude/commands/doc.md', `# Add Documentation
|
|
157
|
+
|
|
158
|
+
Read \`.contextkit/commands/add-documentation.md\` and execute the documentation workflow.
|
|
159
|
+
|
|
160
|
+
Add inline docs, README sections, and usage examples for the specified code.
|
|
161
|
+
`);
|
|
123
162
|
}
|
|
124
163
|
|
|
125
164
|
showUsage() {
|
|
@@ -127,14 +166,14 @@ Scan the codebase structure, detect frameworks and patterns, then generate custo
|
|
|
127
166
|
console.log(chalk.bold(' Claude Code Usage:'));
|
|
128
167
|
console.log(' CLAUDE.md is auto-loaded every session');
|
|
129
168
|
console.log(' .claude/rules/ are loaded based on file context');
|
|
130
|
-
console.log(' Use /analyze slash command for project analysis');
|
|
131
169
|
console.log('');
|
|
132
|
-
console.log(chalk.dim('
|
|
133
|
-
console.log(chalk.dim('
|
|
134
|
-
console.log(chalk.dim('
|
|
135
|
-
console.log(chalk.dim('
|
|
136
|
-
console.log(chalk.dim('
|
|
137
|
-
console.log(chalk.dim('
|
|
170
|
+
console.log(chalk.dim(' Slash commands:'));
|
|
171
|
+
console.log(chalk.dim(' /analyze — Analyze project and generate standards'));
|
|
172
|
+
console.log(chalk.dim(' /review — Review current changes'));
|
|
173
|
+
console.log(chalk.dim(' /fix — Diagnose and fix a bug'));
|
|
174
|
+
console.log(chalk.dim(' /refactor — Refactor code structure'));
|
|
175
|
+
console.log(chalk.dim(' /test — Generate or run tests'));
|
|
176
|
+
console.log(chalk.dim(' /doc — Add documentation'));
|
|
138
177
|
}
|
|
139
178
|
}
|
|
140
179
|
|
|
@@ -12,6 +12,12 @@ class CursorIntegration extends BaseIntegration {
|
|
|
12
12
|
'.cursor/rules/contextkit-testing.mdc',
|
|
13
13
|
'.cursor/rules/contextkit-components.mdc',
|
|
14
14
|
'.cursor/rules/contextkit-api.mdc',
|
|
15
|
+
'.cursor/prompts/analyze.md',
|
|
16
|
+
'.cursor/prompts/review.md',
|
|
17
|
+
'.cursor/prompts/fix.md',
|
|
18
|
+
'.cursor/prompts/refactor.md',
|
|
19
|
+
'.cursor/prompts/test.md',
|
|
20
|
+
'.cursor/prompts/doc.md',
|
|
15
21
|
];
|
|
16
22
|
this.bridgeFiles = [];
|
|
17
23
|
this.platformDir = '.cursor/rules';
|
|
@@ -19,6 +25,7 @@ class CursorIntegration extends BaseIntegration {
|
|
|
19
25
|
|
|
20
26
|
async install() {
|
|
21
27
|
await super.install();
|
|
28
|
+
await fs.ensureDir('.cursor/prompts');
|
|
22
29
|
// Remove old monolithic rule file if present
|
|
23
30
|
await this.removeLegacyFiles();
|
|
24
31
|
}
|
|
@@ -142,20 +149,63 @@ Reference: @.contextkit/standards/architecture.md
|
|
|
142
149
|
- @.contextkit/commands/create-feature.md — Create feature workflow
|
|
143
150
|
`;
|
|
144
151
|
await this.writeGeneratedFile('.cursor/rules/contextkit-api.mdc', apiRule);
|
|
152
|
+
|
|
153
|
+
// Cursor prompts — reusable slash commands in Cursor Chat
|
|
154
|
+
await this.writeGeneratedFile('.cursor/prompts/analyze.md', `# Analyze Project
|
|
155
|
+
|
|
156
|
+
Read \`.contextkit/commands/analyze.md\` and execute the analysis workflow for this project.
|
|
157
|
+
|
|
158
|
+
Scan the codebase structure, detect frameworks and patterns, then generate customized standards files in \`.contextkit/standards/\`.
|
|
159
|
+
`);
|
|
160
|
+
|
|
161
|
+
await this.writeGeneratedFile('.cursor/prompts/review.md', `# Code Review
|
|
162
|
+
|
|
163
|
+
Read \`.contextkit/commands/review.md\` and execute the review workflow.
|
|
164
|
+
|
|
165
|
+
Review current changes for correctness, standards compliance, and potential issues. Flag bugs, security concerns, and standards violations.
|
|
166
|
+
`);
|
|
167
|
+
|
|
168
|
+
await this.writeGeneratedFile('.cursor/prompts/fix.md', `# Fix Bug
|
|
169
|
+
|
|
170
|
+
Read \`.contextkit/commands/fix.md\` and execute the bug fix workflow.
|
|
171
|
+
|
|
172
|
+
Diagnose the root cause, implement the minimal fix, and add a regression test.
|
|
173
|
+
`);
|
|
174
|
+
|
|
175
|
+
await this.writeGeneratedFile('.cursor/prompts/refactor.md', `# Refactor
|
|
176
|
+
|
|
177
|
+
Read \`.contextkit/commands/refactor.md\` and execute the refactoring workflow.
|
|
178
|
+
|
|
179
|
+
Improve code structure without changing behavior, keeping tests green at every step.
|
|
180
|
+
`);
|
|
181
|
+
|
|
182
|
+
await this.writeGeneratedFile('.cursor/prompts/test.md', `# Run Tests
|
|
183
|
+
|
|
184
|
+
Read \`.contextkit/commands/run-tests.md\` and execute the testing workflow.
|
|
185
|
+
|
|
186
|
+
Generate or run tests for the specified code, covering happy paths, edge cases, and errors.
|
|
187
|
+
`);
|
|
188
|
+
|
|
189
|
+
await this.writeGeneratedFile('.cursor/prompts/doc.md', `# Add Documentation
|
|
190
|
+
|
|
191
|
+
Read \`.contextkit/commands/add-documentation.md\` and execute the documentation workflow.
|
|
192
|
+
|
|
193
|
+
Add inline docs, README sections, and usage examples for the specified code.
|
|
194
|
+
`);
|
|
145
195
|
}
|
|
146
196
|
|
|
147
197
|
showUsage() {
|
|
148
198
|
console.log('');
|
|
149
199
|
console.log(chalk.bold(' Cursor Usage:'));
|
|
150
200
|
console.log(' Rules auto-load based on file context');
|
|
151
|
-
console.log(' In Cursor Chat: @.contextkit/commands/analyze.md');
|
|
152
|
-
console.log(' Or: @.contextkit Create a button component');
|
|
153
201
|
console.log('');
|
|
154
|
-
console.log(chalk.dim('
|
|
155
|
-
console.log(chalk.dim('
|
|
156
|
-
console.log(chalk.dim('
|
|
157
|
-
console.log(chalk.dim('
|
|
158
|
-
console.log(chalk.dim('
|
|
202
|
+
console.log(chalk.dim(' Slash commands (in Cursor Chat):'));
|
|
203
|
+
console.log(chalk.dim(' /analyze — Analyze project and generate standards'));
|
|
204
|
+
console.log(chalk.dim(' /review — Review current changes'));
|
|
205
|
+
console.log(chalk.dim(' /fix — Diagnose and fix a bug'));
|
|
206
|
+
console.log(chalk.dim(' /refactor — Refactor code structure'));
|
|
207
|
+
console.log(chalk.dim(' /test — Generate or run tests'));
|
|
208
|
+
console.log(chalk.dim(' /doc — Add documentation'));
|
|
159
209
|
}
|
|
160
210
|
}
|
|
161
211
|
|
package/lib/utils/git-hooks.js
CHANGED
|
@@ -4,27 +4,40 @@ const chalk = require('chalk');
|
|
|
4
4
|
|
|
5
5
|
class GitHooksManager {
|
|
6
6
|
constructor() {
|
|
7
|
-
this.
|
|
7
|
+
this.hooksPath = '.contextkit/hooks';
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
async installHooks(packageManager, hookChoices = { prePush: true, commitMsg: true }) {
|
|
11
11
|
console.log(chalk.yellow('🪝 Setting up Git hooks...'));
|
|
12
12
|
|
|
13
|
-
// Check if
|
|
14
|
-
if (!
|
|
15
|
-
console.log(chalk.yellow('⚠️
|
|
13
|
+
// Check if this is a git repo
|
|
14
|
+
if (!fs.existsSync('.git')) {
|
|
15
|
+
console.log(chalk.yellow('⚠️ Not a git repository, skipping Git hooks setup'));
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
try {
|
|
20
|
-
//
|
|
21
|
-
await this.
|
|
20
|
+
// Clean up legacy Husky directory if present
|
|
21
|
+
await this.cleanupLegacyHusky();
|
|
22
22
|
|
|
23
|
-
//
|
|
24
|
-
await this.
|
|
23
|
+
// Clean up legacy .git/hooks/ files from previous ContextKit versions
|
|
24
|
+
await this.cleanupLegacyGitHooks();
|
|
25
25
|
|
|
26
|
-
//
|
|
27
|
-
await this.
|
|
26
|
+
// Remove hooks the user didn't select
|
|
27
|
+
await this.removeUnselectedHooks(hookChoices);
|
|
28
|
+
|
|
29
|
+
// Set core.hooksPath so git uses .contextkit/hooks/ directly
|
|
30
|
+
execSync(`git config core.hooksPath ${this.hooksPath}`, { stdio: 'pipe' });
|
|
31
|
+
console.log(chalk.green(`✅ Git hooks path set to ${this.hooksPath}`));
|
|
32
|
+
|
|
33
|
+
// Add prepare script to package.json for automatic setup on npm install
|
|
34
|
+
await this.addPrepareScript();
|
|
35
|
+
|
|
36
|
+
// Show non-Node setup hint if no package.json
|
|
37
|
+
if (!fs.existsSync('package.json')) {
|
|
38
|
+
console.log(chalk.dim(' 💡 For other developers, add to your setup:'));
|
|
39
|
+
console.log(chalk.dim(` git config core.hooksPath ${this.hooksPath}`));
|
|
40
|
+
}
|
|
28
41
|
|
|
29
42
|
console.log(chalk.green('✅ Git hooks setup complete'));
|
|
30
43
|
|
|
@@ -34,200 +47,128 @@ class GitHooksManager {
|
|
|
34
47
|
}
|
|
35
48
|
}
|
|
36
49
|
|
|
37
|
-
async
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (!
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
break;
|
|
51
|
-
case 'npm':
|
|
52
|
-
default:
|
|
53
|
-
execSync('npm install --save-dev husky', { stdio: 'inherit' });
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
56
|
-
console.log(chalk.green(`✅ Husky installed with ${packageManager}`));
|
|
57
|
-
} catch (error) {
|
|
58
|
-
console.log(chalk.yellow(`⚠️ Failed to install Husky with ${packageManager}, trying fallback...`));
|
|
59
|
-
// Fallback to npm if the detected package manager fails
|
|
60
|
-
if (packageManager !== 'npm') {
|
|
61
|
-
try {
|
|
62
|
-
execSync('npm install --save-dev husky', { stdio: 'inherit' });
|
|
63
|
-
console.log(chalk.green('✅ Husky installed with npm (fallback)'));
|
|
64
|
-
} catch (fallbackError) {
|
|
65
|
-
console.log(chalk.red('❌ Failed to install Husky with any package manager'));
|
|
66
|
-
throw new Error(`Failed to install Husky: ${fallbackError.message}`);
|
|
67
|
-
}
|
|
68
|
-
} else {
|
|
69
|
-
throw error;
|
|
70
|
-
}
|
|
50
|
+
async removeUnselectedHooks(hookChoices) {
|
|
51
|
+
// If user didn't select a hook, remove it from .contextkit/hooks/
|
|
52
|
+
// so core.hooksPath doesn't run hooks they didn't want
|
|
53
|
+
if (!hookChoices.prePush) {
|
|
54
|
+
const hookPath = `${this.hooksPath}/pre-push`;
|
|
55
|
+
if (fs.existsSync(hookPath)) {
|
|
56
|
+
await fs.remove(hookPath);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (!hookChoices.commitMsg) {
|
|
60
|
+
const hookPath = `${this.hooksPath}/commit-msg`;
|
|
61
|
+
if (fs.existsSync(hookPath)) {
|
|
62
|
+
await fs.remove(hookPath);
|
|
71
63
|
}
|
|
72
|
-
} else {
|
|
73
|
-
console.log(chalk.green('✅ Husky already installed'));
|
|
74
64
|
}
|
|
75
65
|
}
|
|
76
66
|
|
|
77
|
-
async
|
|
67
|
+
async addPrepareScript() {
|
|
68
|
+
if (!fs.existsSync('package.json')) return;
|
|
69
|
+
|
|
78
70
|
try {
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (allDeps.husky) {
|
|
88
|
-
return true;
|
|
71
|
+
const pkg = await fs.readJson('package.json');
|
|
72
|
+
const prepareCmd = `git config core.hooksPath ${this.hooksPath}`;
|
|
73
|
+
|
|
74
|
+
if (!pkg.scripts) pkg.scripts = {};
|
|
75
|
+
|
|
76
|
+
// Don't overwrite if prepare already has our command
|
|
77
|
+
if (pkg.scripts.prepare && pkg.scripts.prepare.includes('core.hooksPath')) {
|
|
78
|
+
return;
|
|
89
79
|
}
|
|
90
|
-
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
case 'pnpm':
|
|
97
|
-
execSync('pnpm list husky', { stdio: 'pipe' });
|
|
98
|
-
return true;
|
|
99
|
-
case 'npm':
|
|
100
|
-
default:
|
|
101
|
-
execSync('npm list husky', { stdio: 'pipe' });
|
|
102
|
-
return true;
|
|
80
|
+
|
|
81
|
+
// Append to existing prepare script or create new one
|
|
82
|
+
if (pkg.scripts.prepare) {
|
|
83
|
+
pkg.scripts.prepare = `${pkg.scripts.prepare} && ${prepareCmd}`;
|
|
84
|
+
} else {
|
|
85
|
+
pkg.scripts.prepare = prepareCmd;
|
|
103
86
|
}
|
|
87
|
+
|
|
88
|
+
await fs.writeJson('package.json', pkg, { spaces: 2 });
|
|
89
|
+
console.log(chalk.green('✅ Added prepare script to package.json'));
|
|
104
90
|
} catch (error) {
|
|
105
|
-
|
|
91
|
+
console.log(chalk.yellow('⚠️ Could not update package.json prepare script'));
|
|
106
92
|
}
|
|
107
93
|
}
|
|
108
94
|
|
|
109
|
-
async
|
|
110
|
-
|
|
111
|
-
// Just ensure .husky directory exists
|
|
112
|
-
await fs.ensureDir(this.hooksDir);
|
|
113
|
-
|
|
114
|
-
// Create husky.sh if it doesn't exist (for compatibility)
|
|
115
|
-
const huskyShPath = `${this.hooksDir}/_/husky.sh`;
|
|
116
|
-
if (!await fs.pathExists(huskyShPath)) {
|
|
117
|
-
await fs.ensureDir(`${this.hooksDir}/_`);
|
|
118
|
-
const huskyShContent = `#!/usr/bin/env sh
|
|
119
|
-
if [ -z "$husky_skip_init" ]; then
|
|
120
|
-
debug () {
|
|
121
|
-
if [ "$HUSKY_DEBUG" = "1" ]; then
|
|
122
|
-
echo "husky (debug) - $1"
|
|
123
|
-
fi
|
|
124
|
-
}
|
|
95
|
+
async cleanupLegacyHusky() {
|
|
96
|
+
if (!fs.existsSync('.husky')) return;
|
|
125
97
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if [ "$HUSKY" = "0" ]; then
|
|
130
|
-
debug "HUSKY env variable is set to 0, skipping hook"
|
|
131
|
-
exit 0
|
|
132
|
-
fi
|
|
133
|
-
|
|
134
|
-
if [ -f ~/.huskyrc ]; then
|
|
135
|
-
debug "sourcing ~/.huskyrc"
|
|
136
|
-
. ~/.huskyrc
|
|
137
|
-
fi
|
|
138
|
-
|
|
139
|
-
readonly husky_skip_init=1
|
|
140
|
-
export husky_skip_init
|
|
141
|
-
sh -e "$0" "$@"
|
|
142
|
-
fi
|
|
143
|
-
`;
|
|
144
|
-
await fs.writeFile(huskyShPath, huskyShContent);
|
|
145
|
-
await fs.chmod(huskyShPath, '755');
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
console.log(chalk.green('✅ Husky initialized'));
|
|
149
|
-
}
|
|
98
|
+
// Check if the .husky dir contains ContextKit/Vibe Kit markers
|
|
99
|
+
const huskyHooks = ['pre-push', 'commit-msg', 'pre-commit'];
|
|
100
|
+
let hasContextKitHooks = false;
|
|
150
101
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (content.includes('.contextkit/') || content.includes('.vibe-kit/')) {
|
|
160
|
-
await fs.remove(legacyPreCommitHook);
|
|
161
|
-
console.log(chalk.yellow('🧹 Removed legacy pre-commit hook (replaced by pre-push)'));
|
|
102
|
+
for (const hook of huskyHooks) {
|
|
103
|
+
const hookPath = `.husky/${hook}`;
|
|
104
|
+
if (fs.existsSync(hookPath)) {
|
|
105
|
+
const content = await fs.readFile(hookPath, 'utf8');
|
|
106
|
+
if (content.includes('.contextkit/') || content.includes('.vibe-kit/')) {
|
|
107
|
+
hasContextKitHooks = true;
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
162
110
|
}
|
|
163
111
|
}
|
|
164
112
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (hookChoices.commitMsg) {
|
|
170
|
-
await this.addHook(packageManager, 'commit-msg', '.contextkit/hooks/commit-msg.sh');
|
|
113
|
+
if (hasContextKitHooks) {
|
|
114
|
+
await fs.remove('.husky');
|
|
115
|
+
console.log(chalk.yellow('🧹 Removed legacy .husky/ directory'));
|
|
116
|
+
console.log(chalk.dim(' 💡 You can also run: npm uninstall husky'));
|
|
171
117
|
}
|
|
172
118
|
}
|
|
173
119
|
|
|
174
|
-
async
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
// Ensure .husky directory exists
|
|
178
|
-
await fs.ensureDir(this.hooksDir);
|
|
179
|
-
|
|
180
|
-
// Create hook file directly (modern Husky approach)
|
|
181
|
-
const hookContent = `#!/usr/bin/env sh
|
|
182
|
-
. "$(dirname -- "$0")/_/husky.sh"
|
|
183
|
-
|
|
184
|
-
${scriptPath} "$@"
|
|
185
|
-
`;
|
|
186
|
-
|
|
187
|
-
await fs.writeFile(hookPath, hookContent);
|
|
188
|
-
await fs.chmod(hookPath, '755');
|
|
189
|
-
|
|
190
|
-
console.log(chalk.green(`✅ Created hook: ${hookName}`));
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
async backupExistingHooks() {
|
|
120
|
+
async cleanupLegacyGitHooks() {
|
|
121
|
+
// Remove wrapper hooks from .git/hooks/ left by previous ContextKit versions
|
|
194
122
|
const hooks = ['pre-push', 'commit-msg'];
|
|
195
|
-
|
|
196
123
|
for (const hook of hooks) {
|
|
197
|
-
const hookPath =
|
|
124
|
+
const hookPath = `.git/hooks/${hook}`;
|
|
198
125
|
if (fs.existsSync(hookPath)) {
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
126
|
+
const content = await fs.readFile(hookPath, 'utf8');
|
|
127
|
+
if (content.includes('ContextKit managed hook')) {
|
|
128
|
+
await fs.remove(hookPath);
|
|
129
|
+
}
|
|
202
130
|
}
|
|
203
131
|
}
|
|
204
132
|
}
|
|
205
133
|
|
|
206
|
-
|
|
134
|
+
async uninstallHooks() {
|
|
135
|
+
console.log(chalk.yellow('🪝 Removing Git hooks...'));
|
|
136
|
+
|
|
137
|
+
// Unset core.hooksPath
|
|
207
138
|
try {
|
|
208
|
-
execSync(
|
|
209
|
-
|
|
139
|
+
execSync('git config --unset core.hooksPath', { stdio: 'pipe' });
|
|
140
|
+
console.log(chalk.green('✅ Removed core.hooksPath config'));
|
|
210
141
|
} catch (error) {
|
|
211
|
-
|
|
142
|
+
// Already unset, that's fine
|
|
212
143
|
}
|
|
144
|
+
|
|
145
|
+
// Remove prepare script from package.json
|
|
146
|
+
await this.removePrepareScript();
|
|
147
|
+
|
|
148
|
+
console.log(chalk.green('✅ Git hooks removed'));
|
|
213
149
|
}
|
|
214
150
|
|
|
215
|
-
async
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const hooks = ['pre-push', 'commit-msg'];
|
|
151
|
+
async removePrepareScript() {
|
|
152
|
+
if (!fs.existsSync('package.json')) return;
|
|
219
153
|
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
154
|
+
try {
|
|
155
|
+
const pkg = await fs.readJson('package.json');
|
|
156
|
+
if (!pkg.scripts?.prepare) return;
|
|
157
|
+
|
|
158
|
+
const prepareCmd = `git config core.hooksPath ${this.hooksPath}`;
|
|
159
|
+
|
|
160
|
+
if (pkg.scripts.prepare === prepareCmd) {
|
|
161
|
+
delete pkg.scripts.prepare;
|
|
162
|
+
} else if (pkg.scripts.prepare.includes(prepareCmd)) {
|
|
163
|
+
// Remove our command from a chained prepare script
|
|
164
|
+
pkg.scripts.prepare = pkg.scripts.prepare
|
|
165
|
+
.replace(` && ${prepareCmd}`, '')
|
|
166
|
+
.replace(`${prepareCmd} && `, '');
|
|
230
167
|
}
|
|
168
|
+
|
|
169
|
+
await fs.writeJson('package.json', pkg, { spaces: 2 });
|
|
170
|
+
} catch (error) {
|
|
171
|
+
// Best effort
|
|
231
172
|
}
|
|
232
173
|
}
|
|
233
174
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nolrm/contextkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.4",
|
|
4
4
|
"description": "ContextKit - Context Engineering for AI Development. Provide rich context to AI through structured MD files with standards, code guides, and documentation. Works with Cursor, Claude, Aider, VS Code Copilot, and more.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|