@esthernandez/vibe-doc 0.1.0

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.
Files changed (95) hide show
  1. package/dist/checker/index.d.ts +34 -0
  2. package/dist/checker/index.d.ts.map +1 -0
  3. package/dist/checker/index.js +154 -0
  4. package/dist/checker/staleness.d.ts +26 -0
  5. package/dist/checker/staleness.d.ts.map +1 -0
  6. package/dist/checker/staleness.js +56 -0
  7. package/dist/classifier/index.d.ts +26 -0
  8. package/dist/classifier/index.d.ts.map +1 -0
  9. package/dist/classifier/index.js +146 -0
  10. package/dist/classifier/llm-prompt.d.ts +12 -0
  11. package/dist/classifier/llm-prompt.d.ts.map +1 -0
  12. package/dist/classifier/llm-prompt.js +123 -0
  13. package/dist/classifier/scoring-engine.d.ts +41 -0
  14. package/dist/classifier/scoring-engine.d.ts.map +1 -0
  15. package/dist/classifier/scoring-engine.js +197 -0
  16. package/dist/classifier/signals.d.ts +16 -0
  17. package/dist/classifier/signals.d.ts.map +1 -0
  18. package/dist/classifier/signals.js +305 -0
  19. package/dist/gap-analyzer/breadcrumbs.d.ts +18 -0
  20. package/dist/gap-analyzer/breadcrumbs.d.ts.map +1 -0
  21. package/dist/gap-analyzer/breadcrumbs.js +314 -0
  22. package/dist/gap-analyzer/index.d.ts +13 -0
  23. package/dist/gap-analyzer/index.d.ts.map +1 -0
  24. package/dist/gap-analyzer/index.js +88 -0
  25. package/dist/gap-analyzer/matrix.d.ts +29 -0
  26. package/dist/gap-analyzer/matrix.d.ts.map +1 -0
  27. package/dist/gap-analyzer/matrix.js +137 -0
  28. package/dist/gap-analyzer/tier-assigner.d.ts +22 -0
  29. package/dist/gap-analyzer/tier-assigner.d.ts.map +1 -0
  30. package/dist/gap-analyzer/tier-assigner.js +112 -0
  31. package/dist/generator/docx-writer.d.ts +15 -0
  32. package/dist/generator/docx-writer.d.ts.map +1 -0
  33. package/dist/generator/docx-writer.js +271 -0
  34. package/dist/generator/extractor.d.ts +11 -0
  35. package/dist/generator/extractor.d.ts.map +1 -0
  36. package/dist/generator/extractor.js +459 -0
  37. package/dist/generator/index.d.ts +25 -0
  38. package/dist/generator/index.d.ts.map +1 -0
  39. package/dist/generator/index.js +106 -0
  40. package/dist/generator/markdown-writer.d.ts +27 -0
  41. package/dist/generator/markdown-writer.d.ts.map +1 -0
  42. package/dist/generator/markdown-writer.js +85 -0
  43. package/dist/index.d.ts +7 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +372 -0
  46. package/dist/scanner/artifact-scanner.d.ts +16 -0
  47. package/dist/scanner/artifact-scanner.d.ts.map +1 -0
  48. package/dist/scanner/artifact-scanner.js +189 -0
  49. package/dist/scanner/code-scanner.d.ts +17 -0
  50. package/dist/scanner/code-scanner.d.ts.map +1 -0
  51. package/dist/scanner/code-scanner.js +69 -0
  52. package/dist/scanner/file-scanner.d.ts +16 -0
  53. package/dist/scanner/file-scanner.d.ts.map +1 -0
  54. package/dist/scanner/file-scanner.js +119 -0
  55. package/dist/scanner/git-scanner.d.ts +10 -0
  56. package/dist/scanner/git-scanner.d.ts.map +1 -0
  57. package/dist/scanner/git-scanner.js +120 -0
  58. package/dist/scanner/index.d.ts +15 -0
  59. package/dist/scanner/index.d.ts.map +1 -0
  60. package/dist/scanner/index.js +106 -0
  61. package/dist/state/index.d.ts +20 -0
  62. package/dist/state/index.d.ts.map +1 -0
  63. package/dist/state/index.js +141 -0
  64. package/dist/state/schema.d.ts +101 -0
  65. package/dist/state/schema.d.ts.map +1 -0
  66. package/dist/state/schema.js +6 -0
  67. package/dist/templates/embedded/adr.md +45 -0
  68. package/dist/templates/embedded/api-spec.md +55 -0
  69. package/dist/templates/embedded/data-model.md +55 -0
  70. package/dist/templates/embedded/deployment-procedure.md +63 -0
  71. package/dist/templates/embedded/runbook.md +55 -0
  72. package/dist/templates/embedded/test-plan.md +55 -0
  73. package/dist/templates/embedded/threat-model.md +47 -0
  74. package/dist/templates/index.d.ts +20 -0
  75. package/dist/templates/index.d.ts.map +1 -0
  76. package/dist/templates/index.js +106 -0
  77. package/dist/templates/registry.d.ts +31 -0
  78. package/dist/templates/registry.d.ts.map +1 -0
  79. package/dist/templates/registry.js +172 -0
  80. package/dist/templates/renderer.d.ts +26 -0
  81. package/dist/templates/renderer.d.ts.map +1 -0
  82. package/dist/templates/renderer.js +145 -0
  83. package/dist/utils/language-detect.d.ts +14 -0
  84. package/dist/utils/language-detect.d.ts.map +1 -0
  85. package/dist/utils/language-detect.js +58 -0
  86. package/dist/utils/logger.d.ts +16 -0
  87. package/dist/utils/logger.d.ts.map +1 -0
  88. package/dist/utils/logger.js +35 -0
  89. package/dist/versioning/differ.d.ts +20 -0
  90. package/dist/versioning/differ.d.ts.map +1 -0
  91. package/dist/versioning/differ.js +160 -0
  92. package/dist/versioning/index.d.ts +44 -0
  93. package/dist/versioning/index.d.ts.map +1 -0
  94. package/dist/versioning/index.js +165 -0
  95. package/package.json +40 -0
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ /**
3
+ * Markdown Writer Module
4
+ * Writes rendered content to .md files with metadata headers
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.writeMarkdown = writeMarkdown;
41
+ const path = __importStar(require("path"));
42
+ const fs = __importStar(require("fs"));
43
+ const logger_1 = require("../utils/logger");
44
+ /**
45
+ * Write rendered content to a markdown file with metadata header
46
+ * @param renderedContent - The rendered markdown content
47
+ * @param docType - Type of document (e.g., 'adr', 'runbook')
48
+ * @param projectPath - Root path of the project
49
+ * @param metadata - Document metadata
50
+ * @returns Full path to the written file
51
+ */
52
+ function writeMarkdown(renderedContent, docType, projectPath, metadata) {
53
+ // Create docs/generated directory
54
+ const docsDir = path.join(projectPath, 'docs', 'generated');
55
+ if (!fs.existsSync(docsDir)) {
56
+ fs.mkdirSync(docsDir, { recursive: true });
57
+ logger_1.logger.debug('Created docs/generated directory', { path: docsDir });
58
+ }
59
+ // Generate metadata header comment
60
+ const metadataHeader = generateMetadataHeader(metadata, docType);
61
+ // Combine metadata header with content
62
+ const fullContent = metadataHeader + '\n\n' + renderedContent;
63
+ // Write to file
64
+ const outputPath = path.join(docsDir, `${docType}.md`);
65
+ fs.writeFileSync(outputPath, fullContent, 'utf-8');
66
+ logger_1.logger.info('Markdown written', {
67
+ docType,
68
+ path: outputPath,
69
+ size: fullContent.length,
70
+ });
71
+ return outputPath;
72
+ }
73
+ /**
74
+ * Generate the metadata header comment for a document
75
+ */
76
+ function generateMetadataHeader(metadata, docType) {
77
+ const lines = [
78
+ '<!-- Generated by Vibe Doc v0.1.0 -->',
79
+ `<!-- Date: ${metadata.generatedAt} -->`,
80
+ `<!-- Classification: ${metadata.classification} -->`,
81
+ `<!-- Source artifacts: ${metadata.sourceArtifacts} files scanned -->`,
82
+ `<!-- Confidence: ${metadata.confidenceSummary.high} high, ${metadata.confidenceSummary.medium} medium, ${metadata.confidenceSummary.low} low sections -->`,
83
+ ];
84
+ return lines.join('\n');
85
+ }
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Vibe Doc CLI
4
+ * Main entry point for documentation generation pipeline
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG"}
package/dist/index.js ADDED
@@ -0,0 +1,372 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Vibe Doc CLI
5
+ * Main entry point for documentation generation pipeline
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ const path = __importStar(require("path"));
42
+ const fs = __importStar(require("fs"));
43
+ const commander_1 = require("commander");
44
+ const logger_1 = require("./utils/logger");
45
+ const scanner_1 = require("./scanner");
46
+ const state_1 = require("./state");
47
+ const classifier_1 = require("./classifier");
48
+ const gap_analyzer_1 = require("./gap-analyzer");
49
+ const generator_1 = require("./generator");
50
+ const templates_1 = require("./templates");
51
+ const extractor_1 = require("./generator/extractor");
52
+ const program = new commander_1.Command();
53
+ program
54
+ .name('vibe-doc')
55
+ .description('AI-powered documentation gap analyzer for any codebase')
56
+ .version('0.1.0');
57
+ /**
58
+ * Scan command: Run artifact scanner and save inventory
59
+ */
60
+ program
61
+ .command('scan [projectPath]')
62
+ .description('Scan a project and analyze its artifacts')
63
+ .option('-c, --confidence-threshold <number>', 'Classification confidence threshold (0-1, default: 0.85)', '0.85')
64
+ .option('--profile <path>', 'Path to interview answers JSON file to populate project profile')
65
+ .action(async (projectPath, options) => {
66
+ const resolvedPath = projectPath ? path.resolve(projectPath) : process.cwd();
67
+ const confidenceThreshold = parseFloat(options.confidenceThreshold);
68
+ try {
69
+ logger_1.logger.info('Starting vibe-doc scan', { projectPath: resolvedPath });
70
+ // Initialize state
71
+ let state = (0, state_1.readState)(resolvedPath) || (0, state_1.initState)();
72
+ state.lastScan = new Date().toISOString();
73
+ // Load interview answers from profile if provided
74
+ if (options.profile) {
75
+ try {
76
+ const profilePath = path.resolve(options.profile);
77
+ const profileContent = fs.readFileSync(profilePath, 'utf-8');
78
+ const profileData = JSON.parse(profileContent);
79
+ // Populate interviewAnswers with provided data, using defaults for missing fields
80
+ state.projectProfile.interviewAnswers = {
81
+ projectName: profileData.projectName || '',
82
+ projectDescription: profileData.projectDescription || '',
83
+ mainPurpose: profileData.mainPurpose || '',
84
+ primaryUsers: profileData.primaryUsers || '',
85
+ coreFeatures: profileData.coreFeatures || [],
86
+ technologies: profileData.technologies || [],
87
+ deploymentModel: profileData.deploymentModel || '',
88
+ architectureStyle: profileData.architectureStyle || '',
89
+ };
90
+ // Set providedContext flag
91
+ state.projectProfile.providedContext = 'profile';
92
+ logger_1.logger.info('Loaded interview answers from profile', { path: profilePath });
93
+ }
94
+ catch (error) {
95
+ logger_1.logger.warn('Failed to load profile file', { path: options.profile, error });
96
+ // Continue without profile data - not a fatal error
97
+ }
98
+ }
99
+ // Run scanner
100
+ logger_1.logger.info('Running artifact inventory scan...');
101
+ state.artifactInventory = await (0, scanner_1.scan)(resolvedPath);
102
+ // Run classifier
103
+ logger_1.logger.info('Running hybrid classification...');
104
+ const classificationResult = (0, classifier_1.classify)(state.artifactInventory, { confidenceThreshold });
105
+ if (classificationResult.resolved) {
106
+ state.classification = classificationResult.classification;
107
+ logger_1.logger.info('Classification complete', {
108
+ category: state.classification.primaryCategory,
109
+ confidence: state.classification.confidence,
110
+ });
111
+ }
112
+ else {
113
+ // Low confidence - use best candidate classification with LLM review available
114
+ state.classification = classificationResult.classification;
115
+ logger_1.logger.info('Low confidence classification, LLM prompt available', {
116
+ category: state.classification.primaryCategory,
117
+ confidence: state.classification.confidence,
118
+ });
119
+ }
120
+ // Run gap analyzer
121
+ logger_1.logger.info('Running gap analyzer...');
122
+ state.gapReport = (0, gap_analyzer_1.analyzeGaps)(state.classification, state.artifactInventory);
123
+ // Save state
124
+ (0, state_1.writeState)(resolvedPath, state);
125
+ logger_1.logger.info('Scan complete', {
126
+ category: state.classification.primaryCategory,
127
+ docsCovered: state.gapReport.summary.docsCovered,
128
+ docsMissing: state.gapReport.summary.docsMissing,
129
+ coverage: `${state.gapReport.summary.coveragePercent}%`,
130
+ });
131
+ // Output summary
132
+ console.log('\n=== Vibe Doc Scan Complete ===\n');
133
+ console.log(`Project: ${resolvedPath}`);
134
+ console.log(`Category: ${state.classification.primaryCategory}`);
135
+ console.log(`Confidence: ${(state.classification.confidence * 100).toFixed(0)}%`);
136
+ console.log(`\nDocumentation Coverage: ${state.gapReport.summary.coveragePercent}%`);
137
+ console.log(` Covered: ${state.gapReport.summary.docsCovered}`);
138
+ console.log(` Partial: ${state.gapReport.summary.docsPartial}`);
139
+ console.log(` Missing: ${state.gapReport.summary.docsMissing}`);
140
+ console.log(`\nState saved to: ${path.join(resolvedPath, '.vibe-doc', 'state.json')}\n`);
141
+ }
142
+ catch (error) {
143
+ logger_1.logger.error('Scan failed', { error });
144
+ process.exit(1);
145
+ }
146
+ });
147
+ /**
148
+ * Report command: Display gap analysis report
149
+ */
150
+ program
151
+ .command('report [projectPath]')
152
+ .description('Display documentation gap report')
153
+ .action((projectPath) => {
154
+ const resolvedPath = projectPath ? path.resolve(projectPath) : process.cwd();
155
+ try {
156
+ const state = (0, state_1.readState)(resolvedPath);
157
+ if (!state) {
158
+ console.error('No vibe-doc state found. Run "vibe-doc scan" first.');
159
+ process.exit(1);
160
+ }
161
+ console.log('\n=== Documentation Gap Report ===\n');
162
+ console.log(`Category: ${state.classification.primaryCategory}`);
163
+ console.log(`Confidence: ${(state.classification.confidence * 100).toFixed(0)}%`);
164
+ console.log(`\nGaps by Tier:\n`);
165
+ const byTier = {
166
+ required: [],
167
+ recommended: [],
168
+ optional: [],
169
+ };
170
+ for (const gap of state.gapReport.gaps) {
171
+ if (!byTier[gap.tier]) {
172
+ byTier[gap.tier] = [];
173
+ }
174
+ byTier[gap.tier].push(gap);
175
+ }
176
+ for (const tier of ['required', 'recommended', 'optional']) {
177
+ const gaps = byTier[tier];
178
+ if (gaps.length > 0) {
179
+ console.log(`${tier.toUpperCase()}:`);
180
+ for (const gap of gaps) {
181
+ const status = gap.found === 0 ? '❌' : gap.missing === 0 ? '✅' : '⚠️';
182
+ console.log(` ${status} ${gap.docType}`);
183
+ console.log(` ${gap.rationale}`);
184
+ }
185
+ console.log();
186
+ }
187
+ }
188
+ console.log(`Coverage: ${state.gapReport.summary.coveragePercent}%\n`);
189
+ }
190
+ catch (error) {
191
+ logger_1.logger.error('Report failed', { error });
192
+ process.exit(1);
193
+ }
194
+ });
195
+ /**
196
+ * Status command: Check current state
197
+ */
198
+ program
199
+ .command('status [projectPath]')
200
+ .description('Check vibe-doc status')
201
+ .action((projectPath) => {
202
+ const resolvedPath = projectPath ? path.resolve(projectPath) : process.cwd();
203
+ try {
204
+ const state = (0, state_1.readState)(resolvedPath);
205
+ if (!state) {
206
+ console.log('No vibe-doc state found. Run "vibe-doc scan" to initialize.');
207
+ return;
208
+ }
209
+ console.log('\n=== Vibe Doc Status ===\n');
210
+ console.log(`Last scan: ${new Date(state.lastScan).toLocaleString()}`);
211
+ console.log(`Artifacts: ${state.artifactInventory.totalArtifacts}`);
212
+ console.log(`Category: ${state.classification.primaryCategory}`);
213
+ console.log(`Coverage: ${state.gapReport.summary.coveragePercent}% (${state.gapReport.summary.docsCovered} covered, ${state.gapReport.summary.docsMissing} missing)\n`);
214
+ }
215
+ catch (error) {
216
+ logger_1.logger.error('Status check failed', { error });
217
+ process.exit(1);
218
+ }
219
+ });
220
+ /**
221
+ * Confirm command: Mark classification as user-confirmed
222
+ */
223
+ program
224
+ .command('confirm [projectPath]')
225
+ .description('Confirm the classification and mark as approved by user')
226
+ .action((projectPath) => {
227
+ const resolvedPath = projectPath ? path.resolve(projectPath) : process.cwd();
228
+ try {
229
+ const state = (0, state_1.readState)(resolvedPath);
230
+ if (!state) {
231
+ console.error('No vibe-doc state found. Run "vibe-doc scan" first.');
232
+ process.exit(1);
233
+ }
234
+ state.classification.userConfirmed = true;
235
+ (0, state_1.writeState)(resolvedPath, state);
236
+ logger_1.logger.info('Classification confirmed', {
237
+ category: state.classification.primaryCategory,
238
+ });
239
+ console.log('\n=== Classification Confirmed ===\n');
240
+ console.log(`Category "${state.classification.primaryCategory}" has been confirmed by user.\n`);
241
+ }
242
+ catch (error) {
243
+ logger_1.logger.error('Confirmation failed', { error });
244
+ process.exit(1);
245
+ }
246
+ });
247
+ /**
248
+ * Check command: CI-safe documentation check
249
+ */
250
+ program
251
+ .command('check [projectPath]')
252
+ .description('CI-safe documentation check')
253
+ .option('-t, --threshold <commits>', 'Staleness threshold in commits', '20')
254
+ .action(async (projectPath, options) => {
255
+ const resolvedPath = projectPath ? path.resolve(projectPath) : process.cwd();
256
+ const threshold = parseInt(options.threshold, 10);
257
+ try {
258
+ const { runCheck } = await Promise.resolve().then(() => __importStar(require('./checker')));
259
+ const result = await runCheck(resolvedPath, { threshold });
260
+ console.log('\n=== Documentation Check ===\n');
261
+ console.log(result.details);
262
+ console.log();
263
+ if (!result.pass) {
264
+ process.exit(result.exitCode);
265
+ }
266
+ }
267
+ catch (error) {
268
+ logger_1.logger.error('Check failed', { error });
269
+ process.exit(1);
270
+ }
271
+ });
272
+ /**
273
+ * Generate command: Generate a document from template
274
+ */
275
+ program
276
+ .command('generate <docType> [projectPath]')
277
+ .description('Generate a document from template')
278
+ .option('-f, --format <format>', 'Output format: md, docx, or both', 'both')
279
+ .option('-a, --answers <answers.json>', 'Path to answers JSON file')
280
+ .action(async (docType, projectPath, options) => {
281
+ const resolvedPath = projectPath ? path.resolve(projectPath) : process.cwd();
282
+ const format = options.format;
283
+ try {
284
+ logger_1.logger.info('Starting document generation', { docType, format });
285
+ // Read state
286
+ const state = (0, state_1.readState)(resolvedPath);
287
+ if (!state) {
288
+ console.error('No vibe-doc state found. Run "vibe-doc scan" first.');
289
+ process.exit(1);
290
+ }
291
+ // Load answers if provided
292
+ let userAnswers = {};
293
+ if (options.answers) {
294
+ const answersPath = path.resolve(options.answers);
295
+ try {
296
+ const content = fs.readFileSync(answersPath, 'utf-8');
297
+ userAnswers = JSON.parse(content);
298
+ logger_1.logger.debug('Loaded user answers', { path: answersPath });
299
+ }
300
+ catch (error) {
301
+ logger_1.logger.warn('Failed to load answers file', { path: answersPath, error });
302
+ }
303
+ }
304
+ // Extract data from artifacts
305
+ const extractedData = (0, extractor_1.extractDataForDocType)(docType, state, resolvedPath);
306
+ // Build render data
307
+ const renderData = {
308
+ extracted: extractedData,
309
+ user: userAnswers,
310
+ metadata: {
311
+ docType,
312
+ generatedAt: new Date().toISOString(),
313
+ classification: state.classification.primaryCategory,
314
+ sourceArtifacts: state.artifactInventory.totalArtifacts,
315
+ },
316
+ };
317
+ // Generate document
318
+ const result = await (0, generator_1.generateDocument)(docType, resolvedPath, state, renderData, format);
319
+ // Save updated state
320
+ (0, state_1.writeState)(resolvedPath, state);
321
+ // Output summary
322
+ console.log('\n=== Document Generated ===\n');
323
+ console.log(`Document: ${docType}`);
324
+ console.log(`Version: ${result.version}`);
325
+ console.log(`Format(s): ${format}`);
326
+ console.log(`\nGenerated files:`);
327
+ for (const filePath of result.paths) {
328
+ console.log(` ${filePath}`);
329
+ }
330
+ console.log();
331
+ }
332
+ catch (error) {
333
+ logger_1.logger.error('Generation failed', { error });
334
+ process.exit(1);
335
+ }
336
+ });
337
+ /**
338
+ * Templates command group: Manage document templates
339
+ */
340
+ const templatesCmd = program.command('templates').description('Manage document templates');
341
+ templatesCmd
342
+ .command('list')
343
+ .description('List all available document templates')
344
+ .action(() => {
345
+ try {
346
+ const embeddedTemplates = (0, templates_1.listTemplates)();
347
+ const cacheDir = path.join(process.cwd(), '.vibe-doc');
348
+ const cachedPath = path.join(cacheDir, 'templates');
349
+ console.log('\n=== Available Templates ===\n');
350
+ console.log('EMBEDDED (Built-in):');
351
+ for (const template of embeddedTemplates) {
352
+ console.log(` • ${template}`);
353
+ }
354
+ // Check for cached remote templates
355
+ if (fs.existsSync(cachedPath)) {
356
+ const cachedFiles = fs.readdirSync(cachedPath).filter((f) => f.endsWith('.md'));
357
+ const cachedTemplates = cachedFiles.map((f) => f.replace(/\.md$/, ''));
358
+ const remoteOnly = cachedTemplates.filter((t) => !embeddedTemplates.includes(t));
359
+ if (remoteOnly.length > 0) {
360
+ console.log('\nREMOTE (Cached):');
361
+ for (const template of remoteOnly) {
362
+ console.log(` • ${template}`);
363
+ }
364
+ }
365
+ }
366
+ }
367
+ catch (error) {
368
+ logger_1.logger.error('Template list failed', { error });
369
+ process.exit(1);
370
+ }
371
+ });
372
+ program.parse(process.argv);
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Artifact Scanner
3
+ * Reads artifact files and extracts summaries and metadata
4
+ */
5
+ interface ArtifactMetadata {
6
+ path: string;
7
+ type: 'markdown' | 'skill' | 'config';
8
+ summary: string;
9
+ title?: string;
10
+ }
11
+ /**
12
+ * Enriches artifact files with summaries and metadata
13
+ */
14
+ export declare function enrichArtifacts(markdownFiles: string[], skillFiles: string[], configFiles: string[]): Promise<ArtifactMetadata[]>;
15
+ export {};
16
+ //# sourceMappingURL=artifact-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-scanner.d.ts","sourceRoot":"","sources":["../../src/scanner/artifact-scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAyID;;GAEG;AACH,wBAAsB,eAAe,CACnC,aAAa,EAAE,MAAM,EAAE,EACvB,UAAU,EAAE,MAAM,EAAE,EACpB,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA8B7B"}
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ /**
3
+ * Artifact Scanner
4
+ * Reads artifact files and extracts summaries and metadata
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.enrichArtifacts = enrichArtifacts;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const logger_1 = require("../utils/logger");
44
+ const YAML_FRONTMATTER_REGEX = /^---\n([\s\S]*?)\n---/;
45
+ /**
46
+ * Extracts YAML frontmatter from a file
47
+ */
48
+ function extractYamlFrontmatter(content) {
49
+ const match = content.match(YAML_FRONTMATTER_REGEX);
50
+ if (!match) {
51
+ return null;
52
+ }
53
+ const yamlContent = match[1];
54
+ const result = {};
55
+ const lines = yamlContent.split('\n').filter((line) => line.trim());
56
+ for (const line of lines) {
57
+ const [key, ...valueParts] = line.split(':');
58
+ const value = valueParts.join(':').trim();
59
+ if (key && value) {
60
+ result[key.trim()] = value;
61
+ }
62
+ }
63
+ return result;
64
+ }
65
+ /**
66
+ * Extracts first meaningful paragraph from markdown content
67
+ */
68
+ function extractMarkdownSummary(content, maxChars = 200) {
69
+ // Remove frontmatter
70
+ const withoutFrontmatter = content.replace(YAML_FRONTMATTER_REGEX, '').trim();
71
+ // Get lines and skip empty ones
72
+ const lines = withoutFrontmatter.split('\n').filter((line) => line.trim().length > 0);
73
+ let summary = '';
74
+ for (const line of lines) {
75
+ // Skip headers, code blocks, etc.
76
+ if (line.startsWith('#') || line.startsWith('```') || line.startsWith(' ')) {
77
+ continue;
78
+ }
79
+ summary += (summary ? ' ' : '') + line.trim();
80
+ if (summary.length >= maxChars) {
81
+ break;
82
+ }
83
+ }
84
+ return summary.substring(0, maxChars).trim();
85
+ }
86
+ /**
87
+ * Reads markdown artifact and returns metadata
88
+ */
89
+ async function readMarkdownArtifact(filePath) {
90
+ try {
91
+ const content = fs.readFileSync(filePath, 'utf-8');
92
+ // Extract first header as title
93
+ const titleMatch = content.match(/^#\s+(.+?)$/m);
94
+ const title = titleMatch ? titleMatch[1].trim() : undefined;
95
+ // Extract summary
96
+ const summary = extractMarkdownSummary(content);
97
+ return {
98
+ path: filePath,
99
+ type: 'markdown',
100
+ summary,
101
+ title,
102
+ };
103
+ }
104
+ catch (error) {
105
+ logger_1.logger.warn('Failed to read markdown artifact', { path: filePath, error });
106
+ return {
107
+ path: filePath,
108
+ type: 'markdown',
109
+ summary: '',
110
+ };
111
+ }
112
+ }
113
+ /**
114
+ * Reads skill artifact and returns metadata from YAML frontmatter
115
+ */
116
+ async function readSkillArtifact(filePath) {
117
+ try {
118
+ const content = fs.readFileSync(filePath, 'utf-8');
119
+ const frontmatter = extractYamlFrontmatter(content);
120
+ const title = frontmatter?.name || path.basename(filePath);
121
+ const summary = frontmatter?.description || '';
122
+ return {
123
+ path: filePath,
124
+ type: 'skill',
125
+ summary,
126
+ title,
127
+ };
128
+ }
129
+ catch (error) {
130
+ logger_1.logger.warn('Failed to read skill artifact', { path: filePath, error });
131
+ return {
132
+ path: filePath,
133
+ type: 'skill',
134
+ summary: '',
135
+ };
136
+ }
137
+ }
138
+ /**
139
+ * Reads config-as-docs artifact
140
+ */
141
+ async function readConfigArtifact(filePath) {
142
+ try {
143
+ const content = fs.readFileSync(filePath, 'utf-8');
144
+ const summary = extractMarkdownSummary(content, 300);
145
+ const title = path.basename(filePath);
146
+ return {
147
+ path: filePath,
148
+ type: 'config',
149
+ summary,
150
+ title,
151
+ };
152
+ }
153
+ catch (error) {
154
+ logger_1.logger.warn('Failed to read config artifact', { path: filePath, error });
155
+ return {
156
+ path: filePath,
157
+ type: 'config',
158
+ summary: '',
159
+ };
160
+ }
161
+ }
162
+ /**
163
+ * Enriches artifact files with summaries and metadata
164
+ */
165
+ async function enrichArtifacts(markdownFiles, skillFiles, configFiles) {
166
+ logger_1.logger.debug('Starting artifact enrichment', {
167
+ markdownCount: markdownFiles.length,
168
+ skillCount: skillFiles.length,
169
+ configCount: configFiles.length,
170
+ });
171
+ const allMetadata = [];
172
+ // Process markdown files
173
+ for (const file of markdownFiles) {
174
+ const metadata = await readMarkdownArtifact(file);
175
+ allMetadata.push(metadata);
176
+ }
177
+ // Process skill files
178
+ for (const file of skillFiles) {
179
+ const metadata = await readSkillArtifact(file);
180
+ allMetadata.push(metadata);
181
+ }
182
+ // Process config files
183
+ for (const file of configFiles) {
184
+ const metadata = await readConfigArtifact(file);
185
+ allMetadata.push(metadata);
186
+ }
187
+ logger_1.logger.info('Artifact enrichment completed', { total: allMetadata.length });
188
+ return allMetadata;
189
+ }