@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,120 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs-extra');
3
+ const path = require('path');
4
+
5
+ class NoteCommand {
6
+ constructor() {
7
+ this.correctionsPath = '.contextkit/corrections.md';
8
+ }
9
+
10
+ async run(message, options = {}) {
11
+ if (!message) {
12
+ console.log(chalk.red('❌ Please provide a message'));
13
+ console.log(chalk.yellow('Usage: contextkit note "<message>"'));
14
+ return;
15
+ }
16
+
17
+ if (!await fs.pathExists(this.correctionsPath)) {
18
+ console.log(chalk.red('❌ Corrections log not found'));
19
+ console.log(chalk.yellow(' Run: contextkit install'));
20
+ return;
21
+ }
22
+
23
+ try {
24
+ const content = await fs.readFile(this.correctionsPath, 'utf-8');
25
+ const today = new Date().toISOString().split('T')[0];
26
+
27
+ // Find or create today's session
28
+ const sessionHeader = `### ${today} - ${options.task || 'Development Session'}`;
29
+
30
+ let updatedContent = content;
31
+
32
+ // Check if today's session exists
33
+ if (content.includes(sessionHeader)) {
34
+ // Add to existing session
35
+ const category = options.category || 'AI Behavior';
36
+ const priority = options.priority || 'MEDIUM';
37
+ const note = `- ${category} | ${message} [${priority}]`;
38
+
39
+ // Find the session and add note to appropriate section
40
+ const sections = ['Rule Updates', 'AI Behavior', 'Preferences', 'Trend Indicators'];
41
+ let sectionFound = false;
42
+
43
+ for (const section of sections) {
44
+ if (category.toLowerCase().includes(section.toLowerCase().substring(0, 5))) {
45
+ const sectionHeader = `#### ${section}`;
46
+ const sectionRegex = new RegExp(`(${sectionHeader}[\\s\\S]*?)(?=####|###|##|$)`, 'm');
47
+ const match = content.match(sectionRegex);
48
+
49
+ if (match) {
50
+ updatedContent = content.replace(
51
+ sectionRegex,
52
+ `$1\n${note}`
53
+ );
54
+ sectionFound = true;
55
+ break;
56
+ }
57
+ }
58
+ }
59
+
60
+ if (!sectionFound) {
61
+ // Add to AI Behavior section as default
62
+ const aiBehaviorRegex = /(#### AI Behavior[\s\S]*?)(?=####|###|##|$)/m;
63
+ if (content.match(aiBehaviorRegex)) {
64
+ updatedContent = content.replace(
65
+ aiBehaviorRegex,
66
+ `$1\n${note}`
67
+ );
68
+ }
69
+ }
70
+ } else {
71
+ // Create new session
72
+ const newSession = `
73
+ ${sessionHeader}
74
+
75
+ **Changes**: ${options.changes || 'Development work'}
76
+
77
+ #### Rule Updates
78
+
79
+ - [No updates yet]
80
+
81
+ #### AI Behavior
82
+
83
+ - ${options.category || 'AI Behavior'} | ${message} [${options.priority || 'MEDIUM'}]
84
+
85
+ #### Preferences
86
+
87
+ - [No preferences yet]
88
+
89
+ #### Trend Indicators
90
+
91
+ - [No trends yet]
92
+
93
+ `;
94
+
95
+ // Insert after "## Recent Sessions"
96
+ const sessionsRegex = /(## Recent Sessions\n)/;
97
+ if (content.match(sessionsRegex)) {
98
+ updatedContent = content.replace(sessionsRegex, `$1${newSession}`);
99
+ } else {
100
+ // Fallback: add at the beginning
101
+ updatedContent = `## Recent Sessions${newSession}\n${content}`;
102
+ }
103
+ }
104
+
105
+ await fs.writeFile(this.correctionsPath, updatedContent);
106
+ console.log(chalk.green('✅ Note added to corrections log'));
107
+ console.log(chalk.dim(` ${message}`));
108
+ } catch (error) {
109
+ console.log(chalk.red('❌ Failed to add note:'), error.message);
110
+ }
111
+ }
112
+ }
113
+
114
+ async function note(message, options) {
115
+ const cmd = new NoteCommand();
116
+ await cmd.run(message, options);
117
+ }
118
+
119
+ module.exports = note;
120
+
@@ -0,0 +1,184 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs-extra');
3
+ const path = require('path');
4
+ const yaml = require('js-yaml');
5
+ const { execSync } = require('child_process');
6
+
7
+ class PublishCommand {
8
+ constructor() {
9
+ this.registryPath = path.join(process.env.HOME || process.env.USERPROFILE, '.contextkit-registry');
10
+ }
11
+
12
+ async run(options = {}) {
13
+ console.log(chalk.magenta('📦 Publishing ContextKit Configuration\n'));
14
+
15
+ // Check if .contextkit exists
16
+ if (!await fs.pathExists('.contextkit/config.yml')) {
17
+ console.log(chalk.red('❌ ContextKit not installed in this directory'));
18
+ console.log(chalk.yellow(' Run: contextkit install'));
19
+ return;
20
+ }
21
+
22
+ // Get package name and version
23
+ const name = options.name || await this.promptName();
24
+ const version = options.version || await this.promptVersion();
25
+
26
+ if (!name || !version) {
27
+ console.log(chalk.red('❌ Package name and version are required'));
28
+ return;
29
+ }
30
+
31
+ // Validate version format
32
+ if (!/^\d+\.\d+\.\d+$/.test(version)) {
33
+ console.log(chalk.red('❌ Invalid version format. Use semantic versioning (e.g., 1.0.0)'));
34
+ return;
35
+ }
36
+
37
+ // Create registry structure
38
+ await this.ensureRegistry();
39
+
40
+ // Create package directory
41
+ const packageDir = path.join(this.registryPath, name.replace('@', '').replace('/', '-'), version);
42
+ await fs.ensureDir(packageDir);
43
+
44
+ // Copy .contextkit files (exclude some)
45
+ const excludePatterns = [
46
+ 'corrections.md',
47
+ 'status.json',
48
+ 'node_modules',
49
+ '.git'
50
+ ];
51
+
52
+ await this.copyVibeKitFiles('.contextkit', packageDir, excludePatterns);
53
+
54
+ // Create package.json for the published package
55
+ const config = await this.loadConfig();
56
+ const packageJson = {
57
+ name: name,
58
+ version: version,
59
+ description: `ContextKit configuration for ${config.project_name || 'project'}`,
60
+ vibeKit: {
61
+ vk: config.vk || 1,
62
+ profile: config.profile,
63
+ generated_at: new Date().toISOString(),
64
+ published_at: new Date().toISOString()
65
+ },
66
+ files: [
67
+ '**/*.md',
68
+ '**/*.yml',
69
+ '**/*.yaml',
70
+ '**/*.ts',
71
+ '**/*.tsx',
72
+ '**/*.sh'
73
+ ]
74
+ };
75
+
76
+ await fs.writeJson(path.join(packageDir, 'package.json'), packageJson, { spaces: 2 });
77
+
78
+ // Create README
79
+ const readme = `# ${name} v${version}
80
+
81
+ ContextKit configuration package.
82
+
83
+ ## Installation
84
+
85
+ \`\`\`bash
86
+ contextkit pull ${name}@${version}
87
+ \`\`\`
88
+
89
+ ## Contents
90
+
91
+ This package includes:
92
+ - Standards files
93
+ - Templates
94
+ - Commands
95
+ - Product context
96
+ - Policies
97
+
98
+ ## Version
99
+
100
+ ${version} - Published ${new Date().toISOString().split('T')[0]}
101
+ `;
102
+
103
+ await fs.writeFile(path.join(packageDir, 'README.md'), readme);
104
+
105
+ console.log(chalk.green(`\n✅ Published ${name}@${version}`));
106
+ console.log(chalk.dim(` Location: ${packageDir}`));
107
+ console.log(chalk.blue(`\n💡 To use: contextkit pull ${name}@${version}`));
108
+ }
109
+
110
+ async promptName() {
111
+ const readline = require('readline').createInterface({
112
+ input: process.stdin,
113
+ output: process.stdout
114
+ });
115
+
116
+ return new Promise((resolve) => {
117
+ readline.question(chalk.yellow('Package name (e.g., @company/react-standards): '), (name) => {
118
+ readline.close();
119
+ resolve(name.trim() || null);
120
+ });
121
+ });
122
+ }
123
+
124
+ async promptVersion() {
125
+ const readline = require('readline').createInterface({
126
+ input: process.stdin,
127
+ output: process.stdout
128
+ });
129
+
130
+ return new Promise((resolve) => {
131
+ readline.question(chalk.yellow('Version (e.g., 1.0.0): '), (version) => {
132
+ readline.close();
133
+ resolve(version.trim() || null);
134
+ });
135
+ });
136
+ }
137
+
138
+ async ensureRegistry() {
139
+ await fs.ensureDir(this.registryPath);
140
+ console.log(chalk.dim(`Registry location: ${this.registryPath}`));
141
+ }
142
+
143
+ async copyVibeKitFiles(sourceDir, targetDir, excludePatterns) {
144
+ const files = await fs.readdir(sourceDir, { withFileTypes: true });
145
+
146
+ for (const file of files) {
147
+ const sourcePath = path.join(sourceDir, file.name);
148
+ const targetPath = path.join(targetDir, file.name);
149
+
150
+ // Check if should exclude
151
+ const shouldExclude = excludePatterns.some(pattern =>
152
+ file.name.includes(pattern) || sourcePath.includes(pattern)
153
+ );
154
+
155
+ if (shouldExclude) {
156
+ continue;
157
+ }
158
+
159
+ if (file.isDirectory()) {
160
+ await fs.ensureDir(targetPath);
161
+ await this.copyVibeKitFiles(sourcePath, targetPath, excludePatterns);
162
+ } else {
163
+ await fs.copy(sourcePath, targetPath);
164
+ }
165
+ }
166
+ }
167
+
168
+ async loadConfig() {
169
+ try {
170
+ const configContent = await fs.readFile('.contextkit/config.yml', 'utf-8');
171
+ return yaml.load(configContent);
172
+ } catch (error) {
173
+ return {};
174
+ }
175
+ }
176
+ }
177
+
178
+ async function publish(options) {
179
+ const cmd = new PublishCommand();
180
+ await cmd.run(options);
181
+ }
182
+
183
+ module.exports = publish;
184
+
@@ -0,0 +1,191 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs-extra');
3
+ const path = require('path');
4
+ const yaml = require('js-yaml');
5
+
6
+ class PullCommand {
7
+ constructor() {
8
+ this.registryPath = path.join(process.env.HOME || process.env.USERPROFILE, '.contextkit-registry');
9
+ }
10
+
11
+ async run(packageSpec, options = {}) {
12
+ console.log(chalk.magenta(`📥 Pulling ContextKit Configuration: ${packageSpec}\n`));
13
+
14
+ // Parse package spec (name@version or just name)
15
+ const [packageName, version] = packageSpec.includes('@')
16
+ ? packageSpec.split('@')
17
+ : [packageSpec, 'latest'];
18
+
19
+ // Find package
20
+ const packageDir = await this.findPackage(packageName, version);
21
+
22
+ if (!packageDir) {
23
+ console.log(chalk.red(`❌ Package not found: ${packageSpec}`));
24
+ console.log(chalk.yellow('\n💡 Available packages:'));
25
+ await this.listPackages();
26
+ return;
27
+ }
28
+
29
+ // Check if .contextkit exists
30
+ const backupDir = options.backup ? `.contextkit.backup.${Date.now()}` : null;
31
+
32
+ if (await fs.pathExists('.contextkit') && !options.force) {
33
+ if (backupDir) {
34
+ await fs.copy('.contextkit', backupDir);
35
+ console.log(chalk.green(`✅ Backed up existing .contextkit to ${backupDir}`));
36
+ } else {
37
+ const { confirm } = await this.promptOverwrite();
38
+ if (!confirm) {
39
+ console.log(chalk.yellow('⏭️ Cancelled'));
40
+ return;
41
+ }
42
+ }
43
+ }
44
+
45
+ // Copy package files
46
+ await this.copyPackageFiles(packageDir, '.contextkit', options);
47
+
48
+ // Update config.yml with package info
49
+ await this.updateConfig(packageName, version);
50
+
51
+ console.log(chalk.green(`\n✅ Pulled ${packageSpec} successfully!`));
52
+
53
+ if (backupDir) {
54
+ console.log(chalk.dim(` Backup: ${backupDir}`));
55
+ }
56
+ }
57
+
58
+ async findPackage(packageName, version) {
59
+ const packagePath = path.join(this.registryPath, packageName.replace('@', '').replace('/', '-'));
60
+
61
+ if (!await fs.pathExists(packagePath)) {
62
+ return null;
63
+ }
64
+
65
+ if (version === 'latest') {
66
+ // Find latest version
67
+ const versions = await fs.readdir(packagePath);
68
+ const sortedVersions = versions
69
+ .filter(v => /^\d+\.\d+\.\d+$/.test(v))
70
+ .sort((a, b) => {
71
+ const aParts = a.split('.').map(Number);
72
+ const bParts = b.split('.').map(Number);
73
+ for (let i = 0; i < 3; i++) {
74
+ if (aParts[i] !== bParts[i]) {
75
+ return bParts[i] - aParts[i];
76
+ }
77
+ }
78
+ return 0;
79
+ });
80
+
81
+ if (sortedVersions.length > 0) {
82
+ return path.join(packagePath, sortedVersions[0]);
83
+ }
84
+ } else {
85
+ const versionPath = path.join(packagePath, version);
86
+ if (await fs.pathExists(versionPath)) {
87
+ return versionPath;
88
+ }
89
+ }
90
+
91
+ return null;
92
+ }
93
+
94
+ async listPackages() {
95
+ if (!await fs.pathExists(this.registryPath)) {
96
+ console.log(chalk.dim(' (No packages in registry)'));
97
+ return;
98
+ }
99
+
100
+ const packages = await fs.readdir(this.registryPath, { withFileTypes: true });
101
+
102
+ for (const pkg of packages.filter(p => p.isDirectory())) {
103
+ const packagePath = path.join(this.registryPath, pkg.name);
104
+ const versions = await fs.readdir(packagePath);
105
+ const validVersions = versions.filter(v => /^\d+\.\d+\.\d+$/.test(v));
106
+
107
+ if (validVersions.length > 0) {
108
+ const latest = validVersions.sort().reverse()[0];
109
+ console.log(chalk.cyan(` ${pkg.name.replace('-', '/')}@${latest}`));
110
+ }
111
+ }
112
+ }
113
+
114
+ async promptOverwrite() {
115
+ const readline = require('readline').createInterface({
116
+ input: process.stdin,
117
+ output: process.stdout
118
+ });
119
+
120
+ return new Promise((resolve) => {
121
+ readline.question(chalk.yellow('⚠️ .contextkit already exists. Overwrite? (y/N): '), (answer) => {
122
+ readline.close();
123
+ resolve({ confirm: answer.toLowerCase() === 'y' });
124
+ });
125
+ });
126
+ }
127
+
128
+ async copyPackageFiles(sourceDir, targetDir, options) {
129
+ // Read package.json if exists
130
+ const packageJsonPath = path.join(sourceDir, 'package.json');
131
+ let packageJson = {};
132
+
133
+ if (await fs.pathExists(packageJsonPath)) {
134
+ packageJson = await fs.readJson(packageJsonPath);
135
+ }
136
+
137
+ // Copy all files from package
138
+ const files = await fs.readdir(sourceDir, { withFileTypes: true });
139
+
140
+ for (const file of files) {
141
+ const sourcePath = path.join(sourceDir, file.name);
142
+ const targetPath = path.join(targetDir, file.name);
143
+
144
+ // Skip package.json and README.md
145
+ if (file.name === 'package.json' || file.name === 'README.md') {
146
+ continue;
147
+ }
148
+
149
+ if (file.isDirectory()) {
150
+ await fs.ensureDir(targetPath);
151
+ await this.copyPackageFiles(sourcePath, targetPath, options);
152
+ } else {
153
+ await fs.copy(sourcePath, targetPath);
154
+ }
155
+ }
156
+ }
157
+
158
+ async updateConfig(packageName, version) {
159
+ const configPath = '.contextkit/config.yml';
160
+
161
+ if (!await fs.pathExists(configPath)) {
162
+ return;
163
+ }
164
+
165
+ try {
166
+ const configContent = await fs.readFile(configPath, 'utf-8');
167
+ const config = yaml.load(configContent);
168
+
169
+ // Add package info
170
+ if (!config.metadata) {
171
+ config.metadata = {};
172
+ }
173
+
174
+ config.metadata.pulled_from = packageName;
175
+ config.metadata.pulled_version = version;
176
+ config.metadata.pulled_at = new Date().toISOString();
177
+
178
+ await fs.writeFile(configPath, yaml.dump(config, { lineWidth: 120 }));
179
+ } catch (error) {
180
+ console.log(chalk.yellow(`⚠️ Could not update config.yml: ${error.message}`));
181
+ }
182
+ }
183
+ }
184
+
185
+ async function pull(packageSpec, options) {
186
+ const cmd = new PullCommand();
187
+ await cmd.run(packageSpec, options);
188
+ }
189
+
190
+ module.exports = pull;
191
+