@nolrm/contextkit 0.8.1 → 0.8.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 CHANGED
@@ -138,6 +138,37 @@ ck ai "create checkout flow for customer"
138
138
 
139
139
  ---
140
140
 
141
+ ## Git Hooks
142
+
143
+ ContextKit can optionally install Git hooks during `ck install`:
144
+
145
+ | Hook | What it does |
146
+ |------|-------------|
147
+ | **pre-push** | Runs tests, linting, and type checks before pushing |
148
+ | **commit-msg** | Enforces [Conventional Commits](https://www.conventionalcommits.org/) format |
149
+
150
+ ### Commit Message Format
151
+
152
+ When the `commit-msg` hook is enabled, all commits must follow this format:
153
+
154
+ ```
155
+ <type>(<scope>): <description>
156
+ ```
157
+
158
+ **Types:** `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`
159
+
160
+ **Examples:**
161
+ ```bash
162
+ git commit -m "feat(auth): add login page"
163
+ git commit -m "fix: resolve null pointer in checkout"
164
+ git commit -m "docs: update API reference"
165
+ git commit -m "test(cart): add edge case coverage"
166
+ ```
167
+
168
+ Hooks are optional and can be skipped with `ck install --no-hooks`.
169
+
170
+ ---
171
+
141
172
  ## Key Features
142
173
 
143
174
  - 🧠 **Context Engineering** - Structured MD files your AI reads automatically
@@ -101,24 +101,26 @@ class InstallCommand {
101
101
  await this.downloadFiles(projectType, options, detectedTools);
102
102
 
103
103
  // Ask about Git hooks
104
- let installHooks = true;
104
+ let hookChoices = { prePush: true, commitMsg: true };
105
105
  if (!options.nonInteractive && !options.noHooks) {
106
- installHooks = await this.promptGitHooks();
106
+ hookChoices = await this.promptGitHooks();
107
+ } else if (options.noHooks) {
108
+ hookChoices = { prePush: false, commitMsg: false };
107
109
  }
108
110
 
109
111
  // Install Git hooks if requested
110
- if (installHooks) {
111
- await this.gitHooksManager.installHooks(packageManager);
112
+ if (hookChoices.prePush || hookChoices.commitMsg) {
113
+ await this.gitHooksManager.installHooks(packageManager, hookChoices);
112
114
  }
113
115
 
114
116
  // Create configuration
115
- await this.createConfiguration(projectType, installHooks);
117
+ await this.createConfiguration(projectType, hookChoices);
116
118
 
117
119
  // Create status tracking
118
- await this.createStatusFile(projectType, packageManager, installHooks);
120
+ await this.createStatusFile(projectType, packageManager, hookChoices);
119
121
 
120
122
  // Success message
121
- this.showSuccessMessage(installHooks, detectedTools, projectType, packageManager);
123
+ this.showSuccessMessage(hookChoices, detectedTools, projectType, packageManager);
122
124
  }
123
125
 
124
126
  async installPlatformIntegration(platform) {
@@ -173,41 +175,70 @@ class InstallCommand {
173
175
  // Check for non-interactive mode
174
176
  if (process.env.CI === 'true' || process.env.NON_INTERACTIVE === 'true') {
175
177
  console.log(chalk.yellow('🤖 Non-interactive mode detected, skipping Git hooks'));
176
- return false;
178
+ return { prePush: false, commitMsg: false };
177
179
  }
178
180
 
179
181
  if (!await fs.pathExists('package.json')) {
180
182
  console.log(chalk.yellow('⚠️ Skipping Git hooks setup (no package.json found)'));
181
- return false;
183
+ return { prePush: false, commitMsg: false };
182
184
  }
183
185
 
184
186
  console.log('');
185
187
  console.log('──────────────────────────────────────────────');
186
188
  console.log(chalk.blue('⚙️ Git Hooks Setup'));
187
189
  console.log('──────────────────────────────────────────────');
188
- console.log('ContextKit can install **pre-push** and **commit-msg** hooks');
189
- console.log('to automatically run tests, linting, and type checks before pushing.');
190
190
  console.log('');
191
+
192
+ // Ask about pre-push hook
193
+ console.log(chalk.bold('Pre-push hook'));
194
+ console.log(chalk.dim('Runs tests, linting, and type checks before pushing.'));
195
+ console.log('');
196
+ const { prePush } = await inquirer.prompt([
197
+ {
198
+ type: 'confirm',
199
+ name: 'prePush',
200
+ message: 'Enable pre-push hook? (runs quality checks before push)',
201
+ default: false
202
+ }
203
+ ]);
204
+
205
+ if (prePush) {
206
+ console.log(chalk.green(' ✅ Pre-push hook enabled'));
207
+ } else {
208
+ console.log(chalk.yellow(' ⏭️ Skipping pre-push hook'));
209
+ }
191
210
  console.log('');
192
211
 
193
- const { installHooks } = await inquirer.prompt([
212
+ // Ask about commit-msg hook
213
+ console.log(chalk.bold('Commit message hook'));
214
+ console.log(chalk.dim('Enforces conventional commit format:'));
215
+ console.log(chalk.dim(' <type>(<scope>): <description>'));
216
+ console.log(chalk.dim(' types: feat, fix, docs, style, refactor, test, chore'));
217
+ console.log(chalk.dim(' example: feat(auth): add login page'));
218
+ console.log('');
219
+ const { commitMsg } = await inquirer.prompt([
194
220
  {
195
221
  type: 'confirm',
196
- name: 'installHooks',
197
- message: 'Do you want to enable Git hooks?',
222
+ name: 'commitMsg',
223
+ message: 'Enable commit-msg hook? (enforces conventional commit format)',
198
224
  default: false
199
225
  }
200
226
  ]);
201
227
 
202
- if (installHooks) {
203
- console.log(chalk.green('✅ Git hooks enabled'));
228
+ if (commitMsg) {
229
+ console.log(chalk.green(' Commit message hook enabled'));
230
+ console.log(chalk.blue(' 💡 Commits must use: <type>(scope): description'));
204
231
  } else {
205
- console.log(chalk.yellow('⏭️ Skipping Git hooks for now'));
206
- console.log(chalk.blue('💡 You can enable them anytime with: `ck update --hooks`'));
232
+ console.log(chalk.yellow(' ⏭️ Skipping commit message hook'));
207
233
  }
208
234
  console.log('');
209
235
 
210
- return installHooks;
236
+ if (!prePush && !commitMsg) {
237
+ console.log(chalk.blue('💡 You can enable hooks anytime with: `ck update --hooks`'));
238
+ console.log('');
239
+ }
240
+
241
+ return { prePush, commitMsg };
211
242
  }
212
243
 
213
244
  async createDirectoryStructure() {
@@ -751,9 +782,9 @@ esac
751
782
  console.log(chalk.green('✅ CLI helpers installed'));
752
783
  }
753
784
 
754
- async createConfiguration(projectType, gitHooksEnabled) {
785
+ async createConfiguration(projectType, hookChoices) {
755
786
  const projectName = path.basename(process.cwd());
756
-
787
+
757
788
  const config = {
758
789
  version: '1.0.0',
759
790
  project_name: projectName,
@@ -764,7 +795,8 @@ esac
764
795
  code_review: true,
765
796
  linting: true,
766
797
  type_safety: true,
767
- git_hooks: gitHooksEnabled
798
+ pre_push_hook: hookChoices.prePush,
799
+ commit_msg_hook: hookChoices.commitMsg
768
800
  },
769
801
  paths: {
770
802
  components: 'src/components',
@@ -830,7 +862,8 @@ features:
830
862
  code_review: ${config.features.code_review}
831
863
  linting: ${config.features.linting}
832
864
  type_safety: ${config.features.type_safety}
833
- git_hooks: ${config.features.git_hooks}
865
+ pre_push_hook: ${config.features.pre_push_hook}
866
+ commit_msg_hook: ${config.features.commit_msg_hook}
834
867
 
835
868
  # Paths (customize for your project)
836
869
  paths:
@@ -857,12 +890,13 @@ metadata:
857
890
  );
858
891
  }
859
892
 
860
- async createStatusFile(projectType, packageManager, gitHooksEnabled) {
893
+ async createStatusFile(projectType, packageManager, hookChoices) {
861
894
  try {
862
895
  const status = this.statusManager.getDefaultStatus();
863
896
  status.project_type = projectType;
864
897
  status.package_manager = packageManager;
865
- status.features.git_hooks = gitHooksEnabled;
898
+ status.features.pre_push_hook = hookChoices.prePush;
899
+ status.features.commit_msg_hook = hookChoices.commitMsg;
866
900
 
867
901
  await this.statusManager.saveStatus(status);
868
902
  console.log(chalk.green('✅ Status tracking initialized'));
@@ -1378,7 +1412,7 @@ enforcement:
1378
1412
  console.log(chalk.green('✅ Policy file created'));
1379
1413
  }
1380
1414
 
1381
- showSuccessMessage(gitHooksEnabled, detectedTools = {}, projectType = '', packageManager = '') {
1415
+ showSuccessMessage(hookChoices, detectedTools = {}, projectType = '', packageManager = '') {
1382
1416
  console.log('');
1383
1417
  console.log(chalk.green('🎉 ContextKit v1.0.0 successfully installed!'));
1384
1418
  console.log('');
@@ -48,7 +48,8 @@ class StatusCommand {
48
48
  console.log('');
49
49
 
50
50
  console.log(chalk.blue('✅ Features:'));
51
- console.log(` Git Hooks: ${status.features.git_hooks ? '✅' : '❌'}`);
51
+ console.log(` Pre-push hook: ${status.features.pre_push_hook ? '✅' : '❌'}`);
52
+ console.log(` Commit-msg hook: ${status.features.commit_msg_hook ? '✅' : '❌'}`);
52
53
  console.log(` Standards: ${status.features.standards ? '✅' : '❌'}`);
53
54
  console.log(` Templates: ${status.features.templates ? '✅' : '❌'}`);
54
55
  console.log('');
@@ -121,8 +122,15 @@ class StatusCommand {
121
122
  config.features = config.features || {};
122
123
  config.features.type_safety = trimmed.split('type_safety:')[1].trim() === 'true';
123
124
  } else if (trimmed.startsWith('git_hooks:')) {
125
+ // Legacy single-flag compat
124
126
  config.features = config.features || {};
125
127
  config.features.git_hooks = trimmed.split('git_hooks:')[1].trim() === 'true';
128
+ } else if (trimmed.startsWith('pre_push_hook:')) {
129
+ config.features = config.features || {};
130
+ config.features.pre_push_hook = trimmed.split('pre_push_hook:')[1].trim() === 'true';
131
+ } else if (trimmed.startsWith('commit_msg_hook:')) {
132
+ config.features = config.features || {};
133
+ config.features.commit_msg_hook = trimmed.split('commit_msg_hook:')[1].trim() === 'true';
126
134
  }
127
135
  }
128
136
 
@@ -59,8 +59,12 @@ class UpdateCommand {
59
59
  await this.restoreUserConfig(config);
60
60
 
61
61
  // Update Git hooks if they were enabled
62
- if (config.features?.git_hooks) {
63
- await this.gitHooksManager.installHooks(packageManager);
62
+ const hookChoices = {
63
+ prePush: config.features?.pre_push_hook || config.features?.git_hooks || false,
64
+ commitMsg: config.features?.commit_msg_hook || config.features?.git_hooks || false
65
+ };
66
+ if (hookChoices.prePush || hookChoices.commitMsg) {
67
+ await this.gitHooksManager.installHooks(packageManager, hookChoices);
64
68
  }
65
69
 
66
70
  // Refresh installed platform integrations
@@ -176,8 +180,15 @@ class UpdateCommand {
176
180
  config.features = config.features || {};
177
181
  config.features.type_safety = trimmed.split('type_safety:')[1].trim() === 'true';
178
182
  } else if (trimmed.startsWith('git_hooks:')) {
183
+ // Legacy single-flag compat
179
184
  config.features = config.features || {};
180
185
  config.features.git_hooks = trimmed.split('git_hooks:')[1].trim() === 'true';
186
+ } else if (trimmed.startsWith('pre_push_hook:')) {
187
+ config.features = config.features || {};
188
+ config.features.pre_push_hook = trimmed.split('pre_push_hook:')[1].trim() === 'true';
189
+ } else if (trimmed.startsWith('commit_msg_hook:')) {
190
+ config.features = config.features || {};
191
+ config.features.commit_msg_hook = trimmed.split('commit_msg_hook:')[1].trim() === 'true';
181
192
  }
182
193
  }
183
194
 
@@ -294,7 +305,8 @@ features:
294
305
  code_review: ${config.features?.code_review || true}
295
306
  linting: ${config.features?.linting || true}
296
307
  type_safety: ${config.features?.type_safety || true}
297
- git_hooks: ${config.features?.git_hooks || false}
308
+ pre_push_hook: ${config.features?.pre_push_hook || config.features?.git_hooks || false}
309
+ commit_msg_hook: ${config.features?.commit_msg_hook || config.features?.git_hooks || false}
298
310
 
299
311
  # Paths (customize for your project)
300
312
  paths:
@@ -7,7 +7,7 @@ class GitHooksManager {
7
7
  this.hooksDir = '.husky';
8
8
  }
9
9
 
10
- async installHooks(packageManager) {
10
+ async installHooks(packageManager, hookChoices = { prePush: true, commitMsg: true }) {
11
11
  console.log(chalk.yellow('🪝 Setting up Git hooks...'));
12
12
 
13
13
  // Check if Node.js is available
@@ -24,7 +24,7 @@ class GitHooksManager {
24
24
  await this.initializeHusky(packageManager);
25
25
 
26
26
  // Add hooks
27
- await this.addHooks(packageManager);
27
+ await this.addHooks(packageManager, hookChoices);
28
28
 
29
29
  console.log(chalk.green('✅ Git hooks setup complete'));
30
30
 
@@ -148,7 +148,7 @@ fi
148
148
  console.log(chalk.green('✅ Husky initialized'));
149
149
  }
150
150
 
151
- async addHooks(packageManager) {
151
+ async addHooks(packageManager, hookChoices = { prePush: true, commitMsg: true }) {
152
152
  // Backup existing hooks
153
153
  await this.backupExistingHooks();
154
154
 
@@ -162,14 +162,12 @@ fi
162
162
  }
163
163
  }
164
164
 
165
- // Add new hooks
166
- const hooks = [
167
- { name: 'pre-push', script: '.contextkit/hooks/pre-push.sh' },
168
- { name: 'commit-msg', script: '.contextkit/hooks/commit-msg.sh' }
169
- ];
170
-
171
- for (const hook of hooks) {
172
- await this.addHook(packageManager, hook.name, hook.script);
165
+ // Add selected hooks
166
+ if (hookChoices.prePush) {
167
+ await this.addHook(packageManager, 'pre-push', '.contextkit/hooks/pre-push.sh');
168
+ }
169
+ if (hookChoices.commitMsg) {
170
+ await this.addHook(packageManager, 'commit-msg', '.contextkit/hooks/commit-msg.sh');
173
171
  }
174
172
  }
175
173
 
@@ -183,7 +181,7 @@ fi
183
181
  const hookContent = `#!/usr/bin/env sh
184
182
  . "$(dirname -- "$0")/_/husky.sh"
185
183
 
186
- ${scriptPath}
184
+ ${scriptPath} "$@"
187
185
  `;
188
186
 
189
187
  await fs.writeFile(hookPath, hookContent);
@@ -31,7 +31,8 @@ class StatusManager {
31
31
  package_manager: null
32
32
  },
33
33
  features: {
34
- git_hooks: false,
34
+ pre_push_hook: false,
35
+ commit_msg_hook: false,
35
36
  standards: true,
36
37
  templates: true
37
38
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nolrm/contextkit",
3
- "version": "0.8.1",
3
+ "version": "0.8.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": {