@vdkit/cli 3.0.1 → 3.0.2
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 +1 -1
- package/cli.js +30 -1
- package/package.json +8 -8
- package/src/blueprints/BlueprintManifest.js +1 -1
- package/src/blueprints/PluginPackager.js +1 -1
- package/src/blueprints/retrieval/BlueprintRetrievalEngine.js +8 -6
- package/src/blueprints-client.js +1 -1
- package/src/commands/base/BaseCommand.js +1 -1
- package/src/commands/blueprints/BrowseCommand.js +1 -0
- package/src/commands/blueprints/CreateCommand.js +1 -1
- package/src/commands/blueprints/DeployCommand.js +65 -2
- package/src/commands/blueprints/RepoStatsCommand.js +6 -6
- package/src/commands/blueprints/SyncCommand.js +8 -4
- package/src/commands/community/PublishCommand.js +10 -10
- package/src/commands/core/ConvertCommand.js +2 -2
- package/src/commands/core/ImportCommand.js +1 -3
- package/src/commands/core/InitCommand.js +3 -3
- package/src/commands/core/ScanCommand.js +6 -2
- package/src/commands/core/StatusCommand.js +6 -2
- package/src/commands/core/ValidateCommand.js +1 -1
- package/src/commands/hub/HubGenerateCommand.js +413 -11
- package/src/commands/migration/SchemaMigrateCommand.js +5 -1
- package/src/commands/migration/UnifiedMigrateCommand.js +21 -7
- package/src/commands/shared/CommandContext.js +7 -3
- package/src/commands/team/ShareCommand.js +44 -9
- package/src/community/CommunityDeployer.js +109 -33
- package/src/hub/ConfigManager.js +3 -3
- package/src/hub/HubIntegration.js +3 -3
- package/src/hub/TelemetryManager.js +3 -3
- package/src/hub/VDKHubClient.js +141 -92
- package/src/hub/index.js +8 -8
- package/src/integrations/base-integration.js +3 -1
- package/src/integrations/claude-code-integration.js +6 -6
- package/src/integrations/cursor-integration.js +2 -2
- package/src/integrations/generic-ai-integration.js +9 -9
- package/src/integrations/generic-ide-integration.js +5 -5
- package/src/integrations/integration-manager.js +1 -1
- package/src/integrations/jetbrains-integration.js +3 -3
- package/src/integrations/vscode-variants-integration.js +2 -2
- package/src/integrations/windsurf-integration.js +1 -1
- package/src/integrations/zed-integration.js +2 -2
- package/src/ir/README.md +2 -2
- package/src/ir/generators.js +4 -5
- package/src/ir/index.js +1 -6
- package/src/ir/performance.js +3 -3
- package/src/mcp/McpManager.js +3 -3
- package/src/migration/AutoMigrator.js +46 -32
- package/src/migration/converters/context-converter.js +3 -3
- package/src/migration/converters/schema-v3-migrator.js +1 -1
- package/src/migration/core/MigrationBackup.js +23 -17
- package/src/migration/core/migration-detector.js +3 -3
- package/src/migration/detectors/rule-detector.js +2 -2
- package/src/migration/migration-manager.js +7 -6
- package/src/plugins/registry.js +1 -1
- package/src/publishing/PublishManager.js +294 -24
- package/src/publishing/UniversalFormatConverter.js +113 -1
- package/src/publishing/clients/GitHubPRClient.js +169 -27
- package/src/scanner/README.md +1 -1
- package/src/scanner/USER-GUIDE.md +1 -1
- package/src/scanner/core/BlueprintLoader.js +18 -7
- package/src/scanner/core/ClaudeCodeAdapter.js +18 -12
- package/src/scanner/core/CopilotAdapter.js +1 -1
- package/src/scanner/core/PatternDetector.js +1 -1
- package/src/scanner/core/PlatformConfigExtractor.js +4 -4
- package/src/scanner/core/RuleAdapter.js +6 -6
- package/src/scanner/core/RuleGenerator.js +8 -3
- package/src/scanner/core/TechnologyAnalyzer.js +1 -1
- package/src/scanner/utils/constants.js +1 -1
- package/src/scanner/utils/package-analyzer.js +2 -2
- package/src/scanner/utils/version.js +1 -1
- package/src/shared/ProjectContextAnalyzer.js +4 -0
- package/src/shared/blueprint-artifact-paths.js +32 -0
- package/src/shared/ide-configuration.js +8 -8
- package/src/shared/sync-operations.js +83 -16
- package/src/utils/file-system.js +17 -15
- package/src/utils/filename-generator.js +2 -4
- package/src/utils/schema-validator.js +1 -1
- package/src/utils/update-mcp-config.js +2 -2
- package/src/validation/check-duplicates.js +1 -1
- package/src/validation/validate-rules.js +7 -7
|
@@ -730,7 +730,7 @@ export class RuleAdapter {
|
|
|
730
730
|
}
|
|
731
731
|
|
|
732
732
|
// Sort rules by priority (higher priority first)
|
|
733
|
-
const prioritizedRules = rules.
|
|
733
|
+
const prioritizedRules = rules.toSorted((a, b) => {
|
|
734
734
|
const aPriority = a.frontmatter?.priority || priority;
|
|
735
735
|
const bPriority = b.frontmatter?.priority || priority;
|
|
736
736
|
return bPriority - aPriority;
|
|
@@ -987,7 +987,7 @@ ${r.content}`
|
|
|
987
987
|
const fileName = this.getCursorFileName(rule);
|
|
988
988
|
|
|
989
989
|
adaptedFiles.push({
|
|
990
|
-
path: path.join(rulesDir, `${prefix}-${fileName}`),
|
|
990
|
+
path: path.join(rulesDir, `${prefix}-${fileName}.mdc`),
|
|
991
991
|
content: result.content,
|
|
992
992
|
type: 'rule',
|
|
993
993
|
activation: activationType,
|
|
@@ -2039,7 +2039,7 @@ This project uses VDK CLI for AI assistant integration and follows specific patt
|
|
|
2039
2039
|
@CLAUDE-personal.md
|
|
2040
2040
|
|
|
2041
2041
|
## Important Conventions
|
|
2042
|
-
- All AI
|
|
2042
|
+
- All AI rule artifacts are stored in \`.vdk/blueprints/rules/\` directory
|
|
2043
2043
|
- Rules follow unified YAML frontmatter format
|
|
2044
2044
|
- Project follows VDK CLI naming conventions
|
|
2045
2045
|
- Memory persistence is enabled for context continuity
|
|
@@ -2418,7 +2418,7 @@ ${this.formatForWindsurf(keyContent)}
|
|
|
2418
2418
|
// Prioritize rules based on their effectiveness for code review
|
|
2419
2419
|
return rules
|
|
2420
2420
|
.filter(rule => rule.frontmatter?.category !== 'assistant') // Skip assistant-specific rules
|
|
2421
|
-
.
|
|
2421
|
+
.toSorted((a, b) => {
|
|
2422
2422
|
const aPriority = this.getCopilotPriority(a);
|
|
2423
2423
|
const bPriority = this.getCopilotPriority(b);
|
|
2424
2424
|
return bPriority - aPriority;
|
|
@@ -2722,14 +2722,14 @@ This directory contains GitHub Copilot Enterprise coding guidelines generated by
|
|
|
2722
2722
|
async adaptForGeneric(rules, projectContext, platformConfig = {}) {
|
|
2723
2723
|
const adaptedFiles = [];
|
|
2724
2724
|
const configPath = platformConfig.configPath || '.vdk';
|
|
2725
|
-
const rulesPath = platformConfig.rulesPath || '.vdk/rules';
|
|
2725
|
+
const rulesPath = platformConfig.rulesPath || '.vdk/blueprints/rules';
|
|
2726
2726
|
const priority = platformConfig.priority || 5;
|
|
2727
2727
|
|
|
2728
2728
|
const baseDir = path.join(this.projectPath, configPath);
|
|
2729
2729
|
const rulesDir = path.join(this.projectPath, rulesPath);
|
|
2730
2730
|
|
|
2731
2731
|
// Sort rules by priority
|
|
2732
|
-
const prioritizedRules = rules.
|
|
2732
|
+
const prioritizedRules = rules.toSorted((a, b) => {
|
|
2733
2733
|
const aPriority = a.frontmatter?.priority || priority;
|
|
2734
2734
|
const bPriority = b.frontmatter?.priority || priority;
|
|
2735
2735
|
return bPriority - aPriority;
|
|
@@ -20,10 +20,15 @@ import { TechnologyRuleMapper } from './TechnologyRuleMapper.js';
|
|
|
20
20
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
21
21
|
|
|
22
22
|
export class RuleGenerator {
|
|
23
|
-
constructor(
|
|
23
|
+
constructor(
|
|
24
|
+
outputPath = './.vdk/blueprints/rules',
|
|
25
|
+
template = 'default',
|
|
26
|
+
overwrite = false,
|
|
27
|
+
options = {}
|
|
28
|
+
) {
|
|
24
29
|
if (typeof outputPath === 'object') {
|
|
25
30
|
options = outputPath;
|
|
26
|
-
outputPath = options.outputPath || './.vdk/rules';
|
|
31
|
+
outputPath = options.outputPath || './.vdk/blueprints/rules';
|
|
27
32
|
template = options.template || 'default';
|
|
28
33
|
overwrite = options.overwrite;
|
|
29
34
|
}
|
|
@@ -35,7 +40,7 @@ export class RuleGenerator {
|
|
|
35
40
|
this.projectPath = options.projectPath || process.cwd();
|
|
36
41
|
this.enableAnalytics = options.enableAnalytics !== false;
|
|
37
42
|
this.hubEndpoint = options.hubEndpoint || 'https://vdk.tools';
|
|
38
|
-
this.ecosystemVersion = '
|
|
43
|
+
this.ecosystemVersion = '3.0.0';
|
|
39
44
|
|
|
40
45
|
// Initialize Components
|
|
41
46
|
this.mapper = new TechnologyRuleMapper();
|
|
@@ -72,7 +72,7 @@ export class TechnologyAnalyzer {
|
|
|
72
72
|
console.error(chalk.red(`Error in technology analysis: ${error.message}`));
|
|
73
73
|
console.error(chalk.gray(error.stack));
|
|
74
74
|
}
|
|
75
|
-
throw new Error(`Technology analysis failed: ${error.message}
|
|
75
|
+
throw new Error(`Technology analysis failed: ${error.message}`, { cause: error });
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -594,8 +594,8 @@ export class PackageAnalyzer {
|
|
|
594
594
|
|
|
595
595
|
// Extract dependencies
|
|
596
596
|
const allDependencies = {
|
|
597
|
-
...
|
|
598
|
-
...
|
|
597
|
+
...packageJson.dependencies,
|
|
598
|
+
...packageJson.devDependencies,
|
|
599
599
|
};
|
|
600
600
|
|
|
601
601
|
// Detect technologies based on dependencies
|
|
@@ -33,5 +33,5 @@ export async function getVersionAsync() {
|
|
|
33
33
|
export function getVersion() {
|
|
34
34
|
// For simplicity in the synchronous version, we'll just return the current version
|
|
35
35
|
// This could be enhanced to use fs.readFileSync if needed
|
|
36
|
-
return '
|
|
36
|
+
return '3.0.1';
|
|
37
37
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical VDK blueprint artifact paths
|
|
3
|
+
* --------------------------------------
|
|
4
|
+
* Raw fetched/generated artifacts are stored by kind under:
|
|
5
|
+
* .vdk/blueprints/{rules,commands,agents,skills,workflows,plugins}
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export const VDK_ROOT_DIR = '.vdk';
|
|
9
|
+
export const BLUEPRINT_ARTIFACTS_ROOT = `${VDK_ROOT_DIR}/blueprints`;
|
|
10
|
+
|
|
11
|
+
export const BLUEPRINT_ARTIFACT_KINDS = Object.freeze([
|
|
12
|
+
'rules',
|
|
13
|
+
'commands',
|
|
14
|
+
'agents',
|
|
15
|
+
'skills',
|
|
16
|
+
'workflows',
|
|
17
|
+
'plugins',
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
export const DEFAULT_BLUEPRINT_RULES_PATH = `${BLUEPRINT_ARTIFACTS_ROOT}/rules`;
|
|
21
|
+
|
|
22
|
+
export function getBlueprintKindPath(kind) {
|
|
23
|
+
const normalizedKind = String(kind || '')
|
|
24
|
+
.toLowerCase()
|
|
25
|
+
.trim();
|
|
26
|
+
|
|
27
|
+
if (!BLUEPRINT_ARTIFACT_KINDS.includes(normalizedKind)) {
|
|
28
|
+
throw new Error(`Unsupported blueprint artifact kind: ${kind}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return `${BLUEPRINT_ARTIFACTS_ROOT}/${normalizedKind}`;
|
|
32
|
+
}
|
|
@@ -359,17 +359,17 @@ const IDE_CONFIGURATIONS = [
|
|
|
359
359
|
{
|
|
360
360
|
id: 'generic-ai',
|
|
361
361
|
name: 'Generic AI Platform',
|
|
362
|
-
configFolder: '.
|
|
363
|
-
rulesFolder: '.
|
|
364
|
-
configFiles: ['.
|
|
362
|
+
configFolder: '.vdk',
|
|
363
|
+
rulesFolder: '.vdk/blueprints/rules',
|
|
364
|
+
configFiles: ['.vdk/config.json'],
|
|
365
365
|
description: 'Works with most AI coding assistants and platforms.',
|
|
366
366
|
},
|
|
367
367
|
{
|
|
368
368
|
id: 'generic',
|
|
369
369
|
name: 'Generic AI Tool',
|
|
370
|
-
configFolder: '.
|
|
371
|
-
rulesFolder: '.
|
|
372
|
-
configFiles: ['.
|
|
370
|
+
configFolder: '.vdk',
|
|
371
|
+
rulesFolder: '.vdk/blueprints/rules',
|
|
372
|
+
configFiles: ['.vdk/config.json'],
|
|
373
373
|
description: 'Works with most AI coding assistants and is the VDK CLI standard.',
|
|
374
374
|
},
|
|
375
375
|
];
|
|
@@ -532,7 +532,7 @@ function detectSpecificJetBrainsIDEs(projectPath) {
|
|
|
532
532
|
});
|
|
533
533
|
if (hasMatch) matchCount++;
|
|
534
534
|
}
|
|
535
|
-
} catch
|
|
535
|
+
} catch {
|
|
536
536
|
// Ignore directory read errors
|
|
537
537
|
}
|
|
538
538
|
} else if (fs.existsSync(filePath)) {
|
|
@@ -559,7 +559,7 @@ function detectSpecificJetBrainsIDEs(projectPath) {
|
|
|
559
559
|
}
|
|
560
560
|
|
|
561
561
|
// Sort by confidence (highest first)
|
|
562
|
-
return detectedIDEs.
|
|
562
|
+
return detectedIDEs.toSorted((a, b) => b.confidence - a.confidence);
|
|
563
563
|
}
|
|
564
564
|
|
|
565
565
|
/**
|
|
@@ -9,6 +9,7 @@ import { execSync } from 'node:child_process';
|
|
|
9
9
|
import fs from 'node:fs/promises';
|
|
10
10
|
import path from 'node:path';
|
|
11
11
|
import { downloadRule, fetchRuleList } from '../blueprints-client.js';
|
|
12
|
+
import { BLUEPRINT_ARTIFACT_KINDS } from './blueprint-artifact-paths.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Base sync operations that both blueprint and team sync can use
|
|
@@ -45,14 +46,18 @@ export class SyncOperations {
|
|
|
45
46
|
/**
|
|
46
47
|
* Sync blueprints from Hub (original blueprint sync logic)
|
|
47
48
|
*/
|
|
48
|
-
async syncBlueprintsFromHub(
|
|
49
|
+
async syncBlueprintsFromHub(artifactsRoot, options, spinner) {
|
|
49
50
|
const hubResult = await this.hubOps.syncBlueprints(options);
|
|
50
51
|
const synced = hubResult.blueprints.length;
|
|
51
52
|
|
|
52
|
-
// Save Hub blueprints
|
|
53
|
+
// Save Hub blueprints by kind
|
|
53
54
|
for (const blueprint of hubResult.blueprints) {
|
|
55
|
+
const kind = this.resolveBlueprintKind(blueprint);
|
|
56
|
+
const kindDir = path.join(artifactsRoot, kind);
|
|
57
|
+
await fs.mkdir(kindDir, { recursive: true });
|
|
58
|
+
|
|
54
59
|
const fileName = `${blueprint.slug || blueprint.id}.hub.md`;
|
|
55
|
-
const filePath = path.join(
|
|
60
|
+
const filePath = path.join(kindDir, fileName);
|
|
56
61
|
await fs.writeFile(filePath, blueprint.content);
|
|
57
62
|
}
|
|
58
63
|
|
|
@@ -73,7 +78,7 @@ export class SyncOperations {
|
|
|
73
78
|
* Sync team configuration from Hub (team sync logic)
|
|
74
79
|
*/
|
|
75
80
|
async syncTeamConfigFromHub(projectPath, options, spinner) {
|
|
76
|
-
const { teamId
|
|
81
|
+
const { teamId } = options;
|
|
77
82
|
const finalTeamId = teamId || process.env.VDK_TEAM_ID;
|
|
78
83
|
|
|
79
84
|
if (!finalTeamId) {
|
|
@@ -134,10 +139,13 @@ export class SyncOperations {
|
|
|
134
139
|
/**
|
|
135
140
|
* Sync blueprints from repository (original repository sync logic)
|
|
136
141
|
*/
|
|
137
|
-
async syncBlueprintsFromRepository(
|
|
142
|
+
async syncBlueprintsFromRepository(artifactsRoot, options, spinner) {
|
|
138
143
|
const { force, category } = options;
|
|
139
144
|
const remoteRules = await fetchRuleList();
|
|
140
145
|
|
|
146
|
+
const rulesDir = path.join(artifactsRoot, 'rules');
|
|
147
|
+
await fs.mkdir(rulesDir, { recursive: true });
|
|
148
|
+
|
|
141
149
|
if (remoteRules.length === 0) {
|
|
142
150
|
spinner.fail('No blueprints found in repository or failed to connect');
|
|
143
151
|
return { synced: 0 };
|
|
@@ -189,8 +197,6 @@ export class SyncOperations {
|
|
|
189
197
|
* Sync team configuration from Git (team sync logic)
|
|
190
198
|
*/
|
|
191
199
|
async syncTeamConfigFromGit(projectPath, options, spinner) {
|
|
192
|
-
const { force = false } = options;
|
|
193
|
-
|
|
194
200
|
// Check if this is a Git repository
|
|
195
201
|
try {
|
|
196
202
|
execSync('git rev-parse --git-dir', { cwd: projectPath, stdio: 'ignore' });
|
|
@@ -202,14 +208,14 @@ export class SyncOperations {
|
|
|
202
208
|
if (!options.dryRun) {
|
|
203
209
|
try {
|
|
204
210
|
execSync('git pull', { cwd: projectPath, stdio: 'inherit' });
|
|
205
|
-
} catch
|
|
211
|
+
} catch {
|
|
206
212
|
this.command.logWarning('⚠️ Git pull failed - continuing with local files');
|
|
207
213
|
}
|
|
208
214
|
}
|
|
209
215
|
|
|
210
216
|
// Check for VDK files in repository
|
|
211
217
|
const vdkFiles = [];
|
|
212
|
-
const filesToCheck = ['.vdk/
|
|
218
|
+
const filesToCheck = ['.vdk/blueprints/', '.vdk/config.json'];
|
|
213
219
|
|
|
214
220
|
for (const file of filesToCheck) {
|
|
215
221
|
const fullPath = path.join(projectPath, file);
|
|
@@ -300,9 +306,11 @@ export class SyncOperations {
|
|
|
300
306
|
async applyHubConfiguration(projectPath, teamConfig) {
|
|
301
307
|
const appliedFiles = [];
|
|
302
308
|
const vdkPath = path.join(projectPath, '.vdk');
|
|
309
|
+
const blueprintsPath = path.join(vdkPath, 'blueprints');
|
|
303
310
|
|
|
304
311
|
// Ensure .vdk directory exists
|
|
305
312
|
await fs.mkdir(vdkPath, { recursive: true });
|
|
313
|
+
await fs.mkdir(blueprintsPath, { recursive: true });
|
|
306
314
|
|
|
307
315
|
// Apply main configuration
|
|
308
316
|
if (teamConfig.main) {
|
|
@@ -311,18 +319,77 @@ export class SyncOperations {
|
|
|
311
319
|
appliedFiles.push('.vdk/config.json');
|
|
312
320
|
}
|
|
313
321
|
|
|
314
|
-
// Apply
|
|
322
|
+
// Apply rule artifacts from legacy team payload
|
|
315
323
|
if (teamConfig.rules) {
|
|
316
|
-
|
|
317
|
-
|
|
324
|
+
await this.writeBlueprintKindFiles(blueprintsPath, 'rules', teamConfig.rules, appliedFiles);
|
|
325
|
+
}
|
|
318
326
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
327
|
+
// Apply structured artifact payload by kind
|
|
328
|
+
if (teamConfig.blueprints && typeof teamConfig.blueprints === 'object') {
|
|
329
|
+
for (const [kind, files] of Object.entries(teamConfig.blueprints)) {
|
|
330
|
+
await this.writeBlueprintKindFiles(blueprintsPath, kind, files, appliedFiles);
|
|
323
331
|
}
|
|
324
332
|
}
|
|
325
333
|
|
|
326
334
|
return appliedFiles;
|
|
327
335
|
}
|
|
336
|
+
|
|
337
|
+
resolveBlueprintKind(blueprint) {
|
|
338
|
+
const normalizedKind = String(blueprint?.kind || '')
|
|
339
|
+
.toLowerCase()
|
|
340
|
+
.trim();
|
|
341
|
+
|
|
342
|
+
if (BLUEPRINT_ARTIFACT_KINDS.includes(normalizedKind)) {
|
|
343
|
+
return normalizedKind;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const sourceCandidates = [
|
|
347
|
+
blueprint?.sourcePath,
|
|
348
|
+
blueprint?.path,
|
|
349
|
+
blueprint?.slug,
|
|
350
|
+
blueprint?.id,
|
|
351
|
+
]
|
|
352
|
+
.filter(Boolean)
|
|
353
|
+
.map(value => String(value).toLowerCase());
|
|
354
|
+
|
|
355
|
+
for (const candidate of sourceCandidates) {
|
|
356
|
+
for (const kind of BLUEPRINT_ARTIFACT_KINDS) {
|
|
357
|
+
if (
|
|
358
|
+
candidate.includes(`/library/${kind}/`) ||
|
|
359
|
+
candidate.includes(`/${kind}/`) ||
|
|
360
|
+
candidate.startsWith(`${kind}/`)
|
|
361
|
+
) {
|
|
362
|
+
return kind;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
throw new Error(
|
|
368
|
+
`Unable to determine blueprint kind for item: ${blueprint?.id || blueprint?.slug || 'unknown'}`
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async writeBlueprintKindFiles(blueprintsPath, kind, files, appliedFiles) {
|
|
373
|
+
const normalizedKind = String(kind || '')
|
|
374
|
+
.toLowerCase()
|
|
375
|
+
.trim();
|
|
376
|
+
|
|
377
|
+
if (!BLUEPRINT_ARTIFACT_KINDS.includes(normalizedKind)) {
|
|
378
|
+
throw new Error(`Unsupported blueprint artifact kind: ${kind}`);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (!files || typeof files !== 'object') {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const kindPath = path.join(blueprintsPath, normalizedKind);
|
|
386
|
+
await fs.mkdir(kindPath, { recursive: true });
|
|
387
|
+
|
|
388
|
+
for (const [relativeFilePath, content] of Object.entries(files)) {
|
|
389
|
+
const outputPath = path.join(kindPath, relativeFilePath);
|
|
390
|
+
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
|
391
|
+
await fs.writeFile(outputPath, content);
|
|
392
|
+
appliedFiles.push(`.vdk/blueprints/${normalizedKind}/${relativeFilePath}`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
328
395
|
}
|
package/src/utils/file-system.js
CHANGED
|
@@ -20,7 +20,7 @@ export const fileSystem = {
|
|
|
20
20
|
try {
|
|
21
21
|
return await fs.readFile(filePath, encoding);
|
|
22
22
|
} catch (error) {
|
|
23
|
-
throw new Error(`Failed to read file ${filePath}: ${error.message}
|
|
23
|
+
throw new Error(`Failed to read file ${filePath}: ${error.message}`, { cause: error });
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
|
|
@@ -35,7 +35,7 @@ export const fileSystem = {
|
|
|
35
35
|
|
|
36
36
|
return await fs.writeFile(filePath, data, options);
|
|
37
37
|
} catch (error) {
|
|
38
|
-
throw new Error(`Failed to write file ${filePath}: ${error.message}
|
|
38
|
+
throw new Error(`Failed to write file ${filePath}: ${error.message}`, { cause: error });
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
|
|
@@ -49,7 +49,7 @@ export const fileSystem = {
|
|
|
49
49
|
|
|
50
50
|
return await fs.appendFile(filePath, data, options);
|
|
51
51
|
} catch (error) {
|
|
52
|
-
throw new Error(`Failed to append to file ${filePath}: ${error.message}
|
|
52
|
+
throw new Error(`Failed to append to file ${filePath}: ${error.message}`, { cause: error });
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
55
|
|
|
@@ -72,7 +72,7 @@ export const fileSystem = {
|
|
|
72
72
|
try {
|
|
73
73
|
return await fs.stat(filePath);
|
|
74
74
|
} catch (error) {
|
|
75
|
-
throw new Error(`Failed to get stats for ${filePath}: ${error.message}
|
|
75
|
+
throw new Error(`Failed to get stats for ${filePath}: ${error.message}`, { cause: error });
|
|
76
76
|
}
|
|
77
77
|
},
|
|
78
78
|
|
|
@@ -107,7 +107,7 @@ export const fileSystem = {
|
|
|
107
107
|
try {
|
|
108
108
|
await fs.mkdir(dirPath, { recursive: true });
|
|
109
109
|
} catch (error) {
|
|
110
|
-
throw new Error(`Failed to create directory ${dirPath}: ${error.message}
|
|
110
|
+
throw new Error(`Failed to create directory ${dirPath}: ${error.message}`, { cause: error });
|
|
111
111
|
}
|
|
112
112
|
},
|
|
113
113
|
|
|
@@ -119,7 +119,7 @@ export const fileSystem = {
|
|
|
119
119
|
await fs.unlink(filePath);
|
|
120
120
|
} catch (error) {
|
|
121
121
|
if (error.code !== 'ENOENT') {
|
|
122
|
-
throw new Error(`Failed to remove file ${filePath}: ${error.message}
|
|
122
|
+
throw new Error(`Failed to remove file ${filePath}: ${error.message}`, { cause: error });
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
},
|
|
@@ -131,7 +131,7 @@ export const fileSystem = {
|
|
|
131
131
|
try {
|
|
132
132
|
await fs.rm(dirPath, { recursive: true, force: true });
|
|
133
133
|
} catch (error) {
|
|
134
|
-
throw new Error(`Failed to remove directory ${dirPath}: ${error.message}
|
|
134
|
+
throw new Error(`Failed to remove directory ${dirPath}: ${error.message}`, { cause: error });
|
|
135
135
|
}
|
|
136
136
|
},
|
|
137
137
|
|
|
@@ -142,7 +142,7 @@ export const fileSystem = {
|
|
|
142
142
|
try {
|
|
143
143
|
return await fs.readdir(dirPath);
|
|
144
144
|
} catch (error) {
|
|
145
|
-
throw new Error(`Failed to read directory ${dirPath}: ${error.message}
|
|
145
|
+
throw new Error(`Failed to read directory ${dirPath}: ${error.message}`, { cause: error });
|
|
146
146
|
}
|
|
147
147
|
},
|
|
148
148
|
|
|
@@ -156,7 +156,7 @@ export const fileSystem = {
|
|
|
156
156
|
|
|
157
157
|
await fs.copyFile(src, dest);
|
|
158
158
|
} catch (error) {
|
|
159
|
-
throw new Error(`Failed to copy ${src} to ${dest}: ${error.message}
|
|
159
|
+
throw new Error(`Failed to copy ${src} to ${dest}: ${error.message}`, { cause: error });
|
|
160
160
|
}
|
|
161
161
|
},
|
|
162
162
|
|
|
@@ -170,7 +170,7 @@ export const fileSystem = {
|
|
|
170
170
|
|
|
171
171
|
await fs.rename(src, dest);
|
|
172
172
|
} catch (error) {
|
|
173
|
-
throw new Error(`Failed to move ${src} to ${dest}: ${error.message}
|
|
173
|
+
throw new Error(`Failed to move ${src} to ${dest}: ${error.message}`, { cause: error });
|
|
174
174
|
}
|
|
175
175
|
},
|
|
176
176
|
|
|
@@ -182,7 +182,7 @@ export const fileSystem = {
|
|
|
182
182
|
const content = await this.readFile(filePath);
|
|
183
183
|
return JSON.parse(content);
|
|
184
184
|
} catch (error) {
|
|
185
|
-
throw new Error(`Failed to read JSON from ${filePath}: ${error.message}
|
|
185
|
+
throw new Error(`Failed to read JSON from ${filePath}: ${error.message}`, { cause: error });
|
|
186
186
|
}
|
|
187
187
|
},
|
|
188
188
|
|
|
@@ -194,7 +194,7 @@ export const fileSystem = {
|
|
|
194
194
|
const content = JSON.stringify(data, null, indent);
|
|
195
195
|
await this.writeFile(filePath, content);
|
|
196
196
|
} catch (error) {
|
|
197
|
-
throw new Error(`Failed to write JSON to ${filePath}: ${error.message}
|
|
197
|
+
throw new Error(`Failed to write JSON to ${filePath}: ${error.message}`, { cause: error });
|
|
198
198
|
}
|
|
199
199
|
},
|
|
200
200
|
|
|
@@ -225,7 +225,7 @@ export const fileSystem = {
|
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
|
-
} catch
|
|
228
|
+
} catch {
|
|
229
229
|
// Skip directories we can't read
|
|
230
230
|
}
|
|
231
231
|
}
|
|
@@ -242,7 +242,7 @@ export const fileSystem = {
|
|
|
242
242
|
const stats = await fs.stat(filePath);
|
|
243
243
|
return stats.size;
|
|
244
244
|
} catch (error) {
|
|
245
|
-
throw new Error(`Failed to get size of ${filePath}: ${error.message}
|
|
245
|
+
throw new Error(`Failed to get size of ${filePath}: ${error.message}`, { cause: error });
|
|
246
246
|
}
|
|
247
247
|
},
|
|
248
248
|
|
|
@@ -254,7 +254,9 @@ export const fileSystem = {
|
|
|
254
254
|
const stats = await fs.stat(filePath);
|
|
255
255
|
return stats.mtime;
|
|
256
256
|
} catch (error) {
|
|
257
|
-
throw new Error(`Failed to get modification time of ${filePath}: ${error.message}
|
|
257
|
+
throw new Error(`Failed to get modification time of ${filePath}: ${error.message}`, {
|
|
258
|
+
cause: error,
|
|
259
|
+
});
|
|
258
260
|
}
|
|
259
261
|
},
|
|
260
262
|
|
|
@@ -25,7 +25,6 @@ export function generateSafeFilename(input, options = {}) {
|
|
|
25
25
|
extension = '',
|
|
26
26
|
preserveCase = false,
|
|
27
27
|
separator = '-',
|
|
28
|
-
allowedChars = /[a-z0-9-_]/,
|
|
29
28
|
fallbackName = 'untitled',
|
|
30
29
|
} = options;
|
|
31
30
|
|
|
@@ -60,9 +59,9 @@ export function generateSafeFilename(input, options = {}) {
|
|
|
60
59
|
|
|
61
60
|
/**
|
|
62
61
|
* Generate unique filename for Cursor IDE rules
|
|
63
|
-
* Handles
|
|
62
|
+
* Handles canonical Cursor `.cursor/rules/*.mdc` naming requirements
|
|
64
63
|
* @param {Object} rule - Rule object with frontmatter
|
|
65
|
-
* @returns {string} Unique filename
|
|
64
|
+
* @returns {string} Unique base filename (without extension)
|
|
66
65
|
*/
|
|
67
66
|
export function generateCursorFilename(rule) {
|
|
68
67
|
const category = rule.frontmatter?.category || 'general';
|
|
@@ -96,7 +95,6 @@ export function generateCursorFilename(rule) {
|
|
|
96
95
|
|
|
97
96
|
return generateSafeFilename(baseName, {
|
|
98
97
|
maxLength: 40,
|
|
99
|
-
extension: '.md',
|
|
100
98
|
separator: '-',
|
|
101
99
|
});
|
|
102
100
|
}
|
|
@@ -58,7 +58,7 @@ async function loadSchemaDefinition(schemaName) {
|
|
|
58
58
|
const schemaContent = await fs.readFile(schemaPath, 'utf8');
|
|
59
59
|
return JSON.parse(schemaContent);
|
|
60
60
|
} catch (error) {
|
|
61
|
-
throw new Error(`Failed to load schema '${schemaName}': ${error.message}
|
|
61
|
+
throw new Error(`Failed to load schema '${schemaName}': ${error.message}`, { cause: error });
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -133,7 +133,7 @@ async function updateMCPConfig() {
|
|
|
133
133
|
// Then, check common rule directories if none found from IDEs
|
|
134
134
|
if (ruleDirectories.length === 0) {
|
|
135
135
|
const commonPaths = [
|
|
136
|
-
'.vdk/rules',
|
|
136
|
+
'.vdk/blueprints/rules',
|
|
137
137
|
'.vscode/ai-rules',
|
|
138
138
|
'.vscode-insiders/ai-rules',
|
|
139
139
|
'.vscode-oss/ai-rules',
|
|
@@ -164,7 +164,7 @@ async function updateMCPConfig() {
|
|
|
164
164
|
|
|
165
165
|
// If force option is provided, use the default path
|
|
166
166
|
if (options.force) {
|
|
167
|
-
const defaultPath = path.join(options.path, '.vdk/rules');
|
|
167
|
+
const defaultPath = path.join(options.path, '.vdk/blueprints/rules');
|
|
168
168
|
console.log(`${colors.yellow}Creating default rule directory: ${defaultPath}${colors.reset}`);
|
|
169
169
|
|
|
170
170
|
if (!fs.existsSync(defaultPath)) {
|
|
@@ -21,13 +21,13 @@ const __dirname = pathUtils.getDirname(__filename);
|
|
|
21
21
|
// Rule repository paths
|
|
22
22
|
const rulesRootDir = pathUtils.join(__dirname, '../..');
|
|
23
23
|
const ruleDirectories = [
|
|
24
|
-
'.vdk/rules',
|
|
25
|
-
'.vdk/rules/assistants',
|
|
26
|
-
'.vdk/rules/languages',
|
|
27
|
-
'.vdk/rules/stacks',
|
|
28
|
-
'.vdk/rules/tasks',
|
|
29
|
-
'.vdk/rules/technologies',
|
|
30
|
-
'.vdk/rules/tools',
|
|
24
|
+
'.vdk/blueprints/rules',
|
|
25
|
+
'.vdk/blueprints/rules/assistants',
|
|
26
|
+
'.vdk/blueprints/rules/languages',
|
|
27
|
+
'.vdk/blueprints/rules/stacks',
|
|
28
|
+
'.vdk/blueprints/rules/tasks',
|
|
29
|
+
'.vdk/blueprints/rules/technologies',
|
|
30
|
+
'.vdk/blueprints/rules/tools',
|
|
31
31
|
];
|
|
32
32
|
|
|
33
33
|
// Track all rule IDs to check for duplicates
|