@nolrm/contextkit 0.7.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.
@@ -0,0 +1,232 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs-extra');
3
+ const path = require('path');
4
+ const ora = require('ora');
5
+
6
+ class RunCommand {
7
+ constructor() {
8
+ this.workflowPath = null;
9
+ this.workflowContent = null;
10
+ this.currentStep = 0;
11
+ this.steps = [];
12
+ }
13
+
14
+ async run(workflowName, options = {}) {
15
+ console.log(chalk.magenta(`šŸš€ Running workflow: ${workflowName}\n`));
16
+
17
+ // Find workflow file
18
+ const possiblePaths = [
19
+ `.contextkit/instructions/core/${workflowName}.md`,
20
+ `.contextkit/instructions/${workflowName}.md`,
21
+ `.contextkit/commands/${workflowName}.md`
22
+ ];
23
+
24
+ let workflowPath = null;
25
+ for (const possiblePath of possiblePaths) {
26
+ if (await fs.pathExists(possiblePath)) {
27
+ workflowPath = possiblePath;
28
+ break;
29
+ }
30
+ }
31
+
32
+ if (!workflowPath) {
33
+ console.log(chalk.red(`āŒ Workflow not found: ${workflowName}`));
34
+ console.log(chalk.yellow(' Searched in:'));
35
+ possiblePaths.forEach(p => console.log(chalk.dim(` - ${p}`)));
36
+ return;
37
+ }
38
+
39
+ this.workflowPath = workflowPath;
40
+ this.workflowContent = await fs.readFile(workflowPath, 'utf-8');
41
+
42
+ // Parse workflow
43
+ const parsed = this.parseWorkflow(this.workflowContent);
44
+
45
+ if (!parsed) {
46
+ console.log(chalk.red('āŒ Failed to parse workflow'));
47
+ return;
48
+ }
49
+
50
+ // Execute pre-flight checks
51
+ if (parsed.preFlight) {
52
+ await this.executePreFlight(parsed.preFlight);
53
+ }
54
+
55
+ // Execute workflow steps
56
+ if (parsed.steps && parsed.steps.length > 0) {
57
+ console.log(chalk.blue(`\nšŸ“‹ Executing ${parsed.steps.length} step(s)...\n`));
58
+
59
+ for (let i = 0; i < parsed.steps.length; i++) {
60
+ const step = parsed.steps[i];
61
+ this.currentStep = i + 1;
62
+
63
+ console.log(chalk.cyan(`\n${'─'.repeat(60)}`));
64
+ console.log(chalk.bold(`Step ${step.number}: ${step.name || 'Unnamed Step'}`));
65
+ console.log(chalk.cyan(`${'─'.repeat(60)}\n`));
66
+
67
+ await this.executeStep(step, options);
68
+ }
69
+ }
70
+
71
+ // Execute post-flight checks
72
+ if (parsed.postFlight) {
73
+ await this.executePostFlight(parsed.postFlight);
74
+ }
75
+
76
+ console.log(chalk.green('\nāœ… Workflow completed successfully!\n'));
77
+ }
78
+
79
+ parseWorkflow(content) {
80
+ const result = {
81
+ preFlight: null,
82
+ steps: [],
83
+ postFlight: null
84
+ };
85
+
86
+ // Extract pre-flight
87
+ const preFlightMatch = content.match(/<pre_flight_check>([\s\S]*?)<\/pre_flight_check>/);
88
+ if (preFlightMatch) {
89
+ result.preFlight = preFlightMatch[1].trim();
90
+ }
91
+
92
+ // Extract process_flow and steps
93
+ const processFlowMatch = content.match(/<process_flow>([\s\S]*?)<\/process_flow>/);
94
+ if (processFlowMatch) {
95
+ const processFlow = processFlowMatch[1];
96
+
97
+ // Extract all steps
98
+ const stepRegex = /<step\s+number="(\d+)"(?:\s+subagent="([^"]+)")?(?:\s+name="([^"]+)")?>([\s\S]*?)<\/step>/g;
99
+ let stepMatch;
100
+
101
+ while ((stepMatch = stepRegex.exec(processFlow)) !== null) {
102
+ result.steps.push({
103
+ number: parseInt(stepMatch[1]),
104
+ subagent: stepMatch[2] || null,
105
+ name: stepMatch[3] || null,
106
+ content: stepMatch[4].trim()
107
+ });
108
+ }
109
+ }
110
+
111
+ // Extract post-flight
112
+ const postFlightMatch = content.match(/<post_flight_check>([\s\S]*?)<\/post_flight_check>/);
113
+ if (postFlightMatch) {
114
+ result.postFlight = postFlightMatch[1].trim();
115
+ }
116
+
117
+ return result;
118
+ }
119
+
120
+ async executePreFlight(preFlightContent) {
121
+ console.log(chalk.blue('šŸ” Pre-flight checks...\n'));
122
+
123
+ // Check for EXECUTE directive
124
+ const executeMatch = preFlightContent.match(/EXECUTE:\s*(.+)/);
125
+ if (executeMatch) {
126
+ const filePath = executeMatch[1].trim().replace('@.contextkit/', '.contextkit/');
127
+
128
+ if (await fs.pathExists(filePath)) {
129
+ const preFlightFile = await fs.readFile(filePath, 'utf-8');
130
+ console.log(chalk.dim(preFlightFile));
131
+ console.log('');
132
+ } else {
133
+ console.log(chalk.yellow(`āš ļø Pre-flight file not found: ${filePath}`));
134
+ }
135
+ } else {
136
+ console.log(chalk.dim(preFlightContent));
137
+ }
138
+ }
139
+
140
+ async executeStep(step, options) {
141
+ // Display step content
142
+ console.log(chalk.dim(step.content));
143
+ console.log('');
144
+
145
+ // Handle subagent (for now, just note it)
146
+ if (step.subagent) {
147
+ console.log(chalk.yellow(`šŸ“Œ Subagent: ${step.subagent}`));
148
+ console.log(chalk.dim(' (Subagent delegation would happen here in full implementation)'));
149
+ console.log('');
150
+ }
151
+
152
+ // Extract instructions from step content
153
+ const instructions = this.extractInstructions(step.content);
154
+
155
+ // For now, display instructions and wait for user/AI to execute
156
+ if (instructions.length > 0) {
157
+ console.log(chalk.blue('šŸ“ Instructions to execute:'));
158
+ instructions.forEach((inst, idx) => {
159
+ console.log(chalk.cyan(` ${idx + 1}. ${inst}`));
160
+ });
161
+ console.log('');
162
+ console.log(chalk.yellow('šŸ’” Use your AI assistant to execute these instructions'));
163
+ console.log(chalk.yellow(' Or continue manually following the workflow steps\n'));
164
+ }
165
+
166
+ // In interactive mode, wait for confirmation
167
+ if (options.interactive) {
168
+ const readline = require('readline').createInterface({
169
+ input: process.stdin,
170
+ output: process.stdout
171
+ });
172
+
173
+ return new Promise((resolve) => {
174
+ readline.question(chalk.yellow('Press Enter to continue to next step...'), () => {
175
+ readline.close();
176
+ resolve();
177
+ });
178
+ });
179
+ }
180
+ }
181
+
182
+ extractInstructions(content) {
183
+ const instructions = [];
184
+
185
+ // Extract ACTION directives
186
+ const actionMatches = content.matchAll(/ACTION:\s*(.+)/gi);
187
+ for (const match of actionMatches) {
188
+ instructions.push(match[1].trim());
189
+ }
190
+
191
+ // Extract numbered steps
192
+ const stepMatches = content.matchAll(/^\d+\.\s+(.+)$/gm);
193
+ for (const match of stepMatches) {
194
+ instructions.push(match[1].trim());
195
+ }
196
+
197
+ return instructions;
198
+ }
199
+
200
+ async executePostFlight(postFlightContent) {
201
+ console.log(chalk.blue('\nšŸ” Post-flight checks...\n'));
202
+
203
+ // Check for EXECUTE directive
204
+ const executeMatch = postFlightContent.match(/EXECUTE:\s*(.+)/);
205
+ if (executeMatch) {
206
+ const filePath = executeMatch[1].trim().replace('@.contextkit/', '.contextkit/');
207
+
208
+ if (await fs.pathExists(filePath)) {
209
+ const postFlightFile = await fs.readFile(filePath, 'utf-8');
210
+ console.log(chalk.dim(postFlightFile));
211
+ console.log('');
212
+
213
+ // Check for corrections log update instructions
214
+ if (postFlightFile.includes('corrections log')) {
215
+ console.log(chalk.yellow('šŸ’” Remember to update corrections.md if any issues occurred'));
216
+ }
217
+ } else {
218
+ console.log(chalk.yellow(`āš ļø Post-flight file not found: ${filePath}`));
219
+ }
220
+ } else {
221
+ console.log(chalk.dim(postFlightContent));
222
+ }
223
+ }
224
+ }
225
+
226
+ async function run(workflowName, options) {
227
+ const cmd = new RunCommand();
228
+ await cmd.run(workflowName, options);
229
+ }
230
+
231
+ module.exports = run;
232
+
@@ -0,0 +1,253 @@
1
+ const chalk = require('chalk');
2
+ const ora = require('ora');
3
+ const fs = require('fs-extra');
4
+ const path = require('path');
5
+ const StatusManager = require('../utils/status-manager');
6
+
7
+ class StatusCommand {
8
+ constructor() {
9
+ this.configPath = '.contextkit/config.yml';
10
+ this.statusManager = new StatusManager();
11
+ }
12
+
13
+ async status() {
14
+ if (!await fs.pathExists(this.configPath)) {
15
+ console.log(chalk.red('āŒ ContextKit is not installed in this project'));
16
+ console.log(chalk.yellow('šŸ’” Run: contextkit install'));
17
+ return;
18
+ }
19
+
20
+ try {
21
+ const config = await this.parseConfig();
22
+ const projectType = await this.detectProjectType();
23
+ const packageManager = await this.detectPackageManager();
24
+ const status = await this.statusManager.getStatus();
25
+ const analyzeInfo = await this.statusManager.getAnalyzeInfo();
26
+
27
+ console.log(chalk.green('šŸŽµ ContextKit Status'));
28
+ console.log('');
29
+
30
+ console.log(chalk.blue('šŸ“¦ Installation:'));
31
+ console.log(` Version: ${status.version}`);
32
+ console.log(` Installed: ${new Date(status.installed_at).toLocaleDateString()}`);
33
+ console.log(` Last Updated: ${new Date(status.last_updated).toLocaleDateString()}`);
34
+ console.log('');
35
+
36
+ console.log(chalk.blue('šŸ” Analysis:'));
37
+ if (analyzeInfo.isFirstTime) {
38
+ console.log(chalk.yellow(' Status: Not analyzed'));
39
+ console.log(chalk.blue(' Recommendation: Run @.contextkit/commands/analyze.md to customize standards'));
40
+ } else {
41
+ console.log(chalk.green(` Status: Completed (${new Date(analyzeInfo.lastRun).toLocaleDateString()})`));
42
+ console.log(chalk.blue(` Project: ${analyzeInfo.projectType || 'Unknown'}`));
43
+ console.log(chalk.blue(` Package Manager: ${analyzeInfo.packageManager || 'Unknown'}`));
44
+ if (analyzeInfo.customizations.length > 0) {
45
+ console.log(chalk.blue(` Customizations: ${analyzeInfo.customizations.length} applied`));
46
+ }
47
+ }
48
+ console.log('');
49
+
50
+ console.log(chalk.blue('āœ… Features:'));
51
+ console.log(` Git Hooks: ${status.features.git_hooks ? 'āœ…' : 'āŒ'}`);
52
+ console.log(` Standards: ${status.features.standards ? 'āœ…' : 'āŒ'}`);
53
+ console.log(` Templates: ${status.features.templates ? 'āœ…' : 'āŒ'}`);
54
+ console.log('');
55
+
56
+ // Check context files
57
+ console.log(chalk.blue('šŸ“š Context Files (Loaded with ck "prompt"):'));
58
+ const contextFiles = await this.checkContextFiles();
59
+ console.log(` context.md: ${contextFiles.context ? 'āœ…' : 'āŒ'}`);
60
+ console.log(` code-style.md: ${contextFiles.codeStyle ? 'āœ…' : 'āŒ'}`);
61
+ console.log(` testing.md: ${contextFiles.testing ? 'āœ…' : 'āŒ'}`);
62
+ console.log(` architecture.md: ${contextFiles.architecture ? 'āœ…' : 'āŒ'}`);
63
+ console.log(` ai-guidelines.md: ${contextFiles.guidelines ? 'āœ…' : 'āŒ'}`);
64
+ console.log(` glossary.md: ${contextFiles.glossary ? 'āœ…' : 'āŒ'}`);
65
+
66
+ if (contextFiles.allPresent) {
67
+ console.log(chalk.green('\nāœ… All context files ready for AI prompts!'));
68
+ } else {
69
+ console.log(chalk.yellow('\nāš ļø Some context files are missing. Run: contextkit update'));
70
+ }
71
+ console.log('');
72
+
73
+ // Platform Integrations
74
+ console.log(chalk.blue('šŸ”Œ Platform Integrations:'));
75
+ await this.checkPlatformIntegrations();
76
+ console.log('');
77
+
78
+ // Check for updates
79
+ const updateInfo = await this.checkForUpdates(status.version);
80
+ if (updateInfo.hasUpdate) {
81
+ console.log(chalk.yellow('šŸ”„ Update Available!'));
82
+ console.log(` Current: ${updateInfo.currentVersion}`);
83
+ console.log(` Latest: ${updateInfo.latestVersion}`);
84
+ console.log(chalk.yellow('šŸ’” Run: contextkit update'));
85
+ } else {
86
+ console.log(chalk.green('āœ… ContextKit is up to date'));
87
+ }
88
+
89
+ } catch (error) {
90
+ console.log(chalk.red('āŒ Error reading ContextKit configuration:'), error.message);
91
+ }
92
+ }
93
+
94
+ async parseConfig() {
95
+ const configContent = await fs.readFile(this.configPath, 'utf8');
96
+ const config = {};
97
+
98
+ // Simple YAML parsing for our config format
99
+ const lines = configContent.split('\n');
100
+ for (const line of lines) {
101
+ const trimmed = line.trim();
102
+ if (trimmed.startsWith('version:')) {
103
+ config.version = trimmed.split('version:')[1].trim().replace(/"/g, '');
104
+ } else if (trimmed.startsWith('project_name:')) {
105
+ config.project_name = trimmed.split('project_name:')[1].trim().replace(/"/g, '');
106
+ } else if (trimmed.startsWith('project_type:')) {
107
+ config.project_type = trimmed.split('project_type:')[1].trim().replace(/"/g, '');
108
+ } else if (trimmed.startsWith('testing:')) {
109
+ config.features = config.features || {};
110
+ config.features.testing = trimmed.split('testing:')[1].trim() === 'true';
111
+ } else if (trimmed.startsWith('documentation:')) {
112
+ config.features = config.features || {};
113
+ config.features.documentation = trimmed.split('documentation:')[1].trim() === 'true';
114
+ } else if (trimmed.startsWith('code_review:')) {
115
+ config.features = config.features || {};
116
+ config.features.code_review = trimmed.split('code_review:')[1].trim() === 'true';
117
+ } else if (trimmed.startsWith('linting:')) {
118
+ config.features = config.features || {};
119
+ config.features.linting = trimmed.split('linting:')[1].trim() === 'true';
120
+ } else if (trimmed.startsWith('type_safety:')) {
121
+ config.features = config.features || {};
122
+ config.features.type_safety = trimmed.split('type_safety:')[1].trim() === 'true';
123
+ } else if (trimmed.startsWith('git_hooks:')) {
124
+ config.features = config.features || {};
125
+ config.features.git_hooks = trimmed.split('git_hooks:')[1].trim() === 'true';
126
+ }
127
+ }
128
+
129
+ return config;
130
+ }
131
+
132
+ async detectProjectType() {
133
+ if (await fs.pathExists('package.json')) {
134
+ const packageJson = require(path.join(process.cwd(), 'package.json'));
135
+ if (packageJson.dependencies?.react || packageJson.devDependencies?.react) {
136
+ return 'react';
137
+ } else if (packageJson.dependencies?.vue || packageJson.devDependencies?.vue) {
138
+ return 'vue';
139
+ } else if (packageJson.dependencies?.['@angular/core'] || packageJson.devDependencies?.['@angular/core']) {
140
+ return 'angular';
141
+ } else if (packageJson.dependencies?.next || packageJson.devDependencies?.next) {
142
+ return 'nextjs';
143
+ } else if (packageJson.dependencies?.nuxt || packageJson.devDependencies?.nuxt) {
144
+ return 'nuxt';
145
+ } else if (packageJson.dependencies?.svelte || packageJson.devDependencies?.svelte) {
146
+ return 'svelte';
147
+ }
148
+ return 'node';
149
+ } else if (await fs.pathExists('requirements.txt') || await fs.pathExists('pyproject.toml')) {
150
+ return 'python';
151
+ } else if (await fs.pathExists('Cargo.toml')) {
152
+ return 'rust';
153
+ } else if (await fs.pathExists('go.mod')) {
154
+ return 'go';
155
+ }
156
+ return 'generic';
157
+ }
158
+
159
+ async detectPackageManager() {
160
+ if (await fs.pathExists('yarn.lock')) {
161
+ return 'yarn';
162
+ } else if (await fs.pathExists('pnpm-lock.yaml')) {
163
+ return 'pnpm';
164
+ } else if (await fs.pathExists('package-lock.json')) {
165
+ return 'npm';
166
+ } else if (await fs.pathExists('package.json')) {
167
+ return 'npm';
168
+ }
169
+ return 'none';
170
+ }
171
+
172
+ async checkForUpdates(currentVersion) {
173
+ try {
174
+ const axios = require('axios');
175
+ const response = await axios.get('https://api.github.com/repos/nolrm/contextkit/releases/latest', {
176
+ timeout: 5000
177
+ });
178
+
179
+ const latestVersion = response.data.tag_name.replace('v', '');
180
+ const hasUpdate = this.isNewerVersion(latestVersion, currentVersion);
181
+
182
+ return {
183
+ hasUpdate,
184
+ currentVersion,
185
+ latestVersion
186
+ };
187
+ } catch (error) {
188
+ return {
189
+ hasUpdate: false,
190
+ currentVersion,
191
+ latestVersion: 'unknown',
192
+ error: error.message
193
+ };
194
+ }
195
+ }
196
+
197
+ isNewerVersion(latest, current) {
198
+ const latestParts = latest.split('.').map(Number);
199
+ const currentParts = current.split('.').map(Number);
200
+
201
+ for (let i = 0; i < Math.max(latestParts.length, currentParts.length); i++) {
202
+ const latestPart = latestParts[i] || 0;
203
+ const currentPart = currentParts[i] || 0;
204
+
205
+ if (latestPart > currentPart) return true;
206
+ if (latestPart < currentPart) return false;
207
+ }
208
+
209
+ return false;
210
+ }
211
+
212
+ async checkPlatformIntegrations() {
213
+ const { getAllIntegrationNames, getIntegration } = require('../integrations');
214
+
215
+ for (const name of getAllIntegrationNames()) {
216
+ const integration = getIntegration(name);
217
+ const result = await integration.validate();
218
+ const allFiles = [...integration.bridgeFiles, ...integration.generatedFiles];
219
+
220
+ if (allFiles.length === 0) continue;
221
+
222
+ if (result.valid) {
223
+ console.log(` ${integration.displayName}: ${chalk.green('āœ…')} (${result.present.length} files)`);
224
+ } else if (result.present.length > 0) {
225
+ console.log(` ${integration.displayName}: ${chalk.yellow('āš ļø')} (${result.present.length}/${allFiles.length} files)`);
226
+ } else {
227
+ console.log(` ${integration.displayName}: ${chalk.dim('not installed')} → run: ck ${name}`);
228
+ }
229
+ }
230
+ }
231
+
232
+ async checkContextFiles() {
233
+ const checks = {
234
+ context: await fs.pathExists('.contextkit/context.md'),
235
+ codeStyle: await fs.pathExists('.contextkit/standards/code-style.md'),
236
+ testing: await fs.pathExists('.contextkit/standards/testing.md'),
237
+ architecture: await fs.pathExists('.contextkit/standards/architecture.md'),
238
+ guidelines: await fs.pathExists('.contextkit/standards/ai-guidelines.md'),
239
+ glossary: await fs.pathExists('.contextkit/standards/glossary.md')
240
+ };
241
+
242
+ checks.allPresent = checks.context && checks.codeStyle && checks.testing && checks.architecture && checks.guidelines && checks.glossary;
243
+
244
+ return checks;
245
+ }
246
+ }
247
+
248
+ async function status() {
249
+ const statusChecker = new StatusCommand();
250
+ await statusChecker.status();
251
+ }
252
+
253
+ module.exports = status;