@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.
- package/LICENSE +21 -0
- package/README.md +216 -0
- package/bin/contextkit.js +324 -0
- package/bin/vibe-kit.js +3 -0
- package/install-fallback.sh +59 -0
- package/lib/commands/ai.js +147 -0
- package/lib/commands/analyze.js +544 -0
- package/lib/commands/check.js +290 -0
- package/lib/commands/dashboard.js +383 -0
- package/lib/commands/install.js +1454 -0
- package/lib/commands/note.js +120 -0
- package/lib/commands/publish.js +184 -0
- package/lib/commands/pull.js +191 -0
- package/lib/commands/run.js +232 -0
- package/lib/commands/status.js +253 -0
- package/lib/commands/update.js +376 -0
- package/lib/index.js +9 -0
- package/lib/integrations/aider-integration.js +93 -0
- package/lib/integrations/base-integration.js +123 -0
- package/lib/integrations/claude-integration.js +141 -0
- package/lib/integrations/codex-integration.js +45 -0
- package/lib/integrations/continue-integration.js +99 -0
- package/lib/integrations/copilot-integration.js +73 -0
- package/lib/integrations/cursor-integration.js +162 -0
- package/lib/integrations/gemini-integration.js +62 -0
- package/lib/integrations/index.js +33 -0
- package/lib/integrations/windsurf-integration.js +88 -0
- package/lib/utils/download.js +50 -0
- package/lib/utils/git-hooks.js +228 -0
- package/lib/utils/project-detector.js +110 -0
- package/lib/utils/status-manager.js +107 -0
- package/lib/utils/tool-detector.js +137 -0
- package/package.json +85 -0
|
@@ -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
|
+
|