@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.
- package/dist/checker/index.d.ts +34 -0
- package/dist/checker/index.d.ts.map +1 -0
- package/dist/checker/index.js +154 -0
- package/dist/checker/staleness.d.ts +26 -0
- package/dist/checker/staleness.d.ts.map +1 -0
- package/dist/checker/staleness.js +56 -0
- package/dist/classifier/index.d.ts +26 -0
- package/dist/classifier/index.d.ts.map +1 -0
- package/dist/classifier/index.js +146 -0
- package/dist/classifier/llm-prompt.d.ts +12 -0
- package/dist/classifier/llm-prompt.d.ts.map +1 -0
- package/dist/classifier/llm-prompt.js +123 -0
- package/dist/classifier/scoring-engine.d.ts +41 -0
- package/dist/classifier/scoring-engine.d.ts.map +1 -0
- package/dist/classifier/scoring-engine.js +197 -0
- package/dist/classifier/signals.d.ts +16 -0
- package/dist/classifier/signals.d.ts.map +1 -0
- package/dist/classifier/signals.js +305 -0
- package/dist/gap-analyzer/breadcrumbs.d.ts +18 -0
- package/dist/gap-analyzer/breadcrumbs.d.ts.map +1 -0
- package/dist/gap-analyzer/breadcrumbs.js +314 -0
- package/dist/gap-analyzer/index.d.ts +13 -0
- package/dist/gap-analyzer/index.d.ts.map +1 -0
- package/dist/gap-analyzer/index.js +88 -0
- package/dist/gap-analyzer/matrix.d.ts +29 -0
- package/dist/gap-analyzer/matrix.d.ts.map +1 -0
- package/dist/gap-analyzer/matrix.js +137 -0
- package/dist/gap-analyzer/tier-assigner.d.ts +22 -0
- package/dist/gap-analyzer/tier-assigner.d.ts.map +1 -0
- package/dist/gap-analyzer/tier-assigner.js +112 -0
- package/dist/generator/docx-writer.d.ts +15 -0
- package/dist/generator/docx-writer.d.ts.map +1 -0
- package/dist/generator/docx-writer.js +271 -0
- package/dist/generator/extractor.d.ts +11 -0
- package/dist/generator/extractor.d.ts.map +1 -0
- package/dist/generator/extractor.js +459 -0
- package/dist/generator/index.d.ts +25 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +106 -0
- package/dist/generator/markdown-writer.d.ts +27 -0
- package/dist/generator/markdown-writer.d.ts.map +1 -0
- package/dist/generator/markdown-writer.js +85 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +372 -0
- package/dist/scanner/artifact-scanner.d.ts +16 -0
- package/dist/scanner/artifact-scanner.d.ts.map +1 -0
- package/dist/scanner/artifact-scanner.js +189 -0
- package/dist/scanner/code-scanner.d.ts +17 -0
- package/dist/scanner/code-scanner.d.ts.map +1 -0
- package/dist/scanner/code-scanner.js +69 -0
- package/dist/scanner/file-scanner.d.ts +16 -0
- package/dist/scanner/file-scanner.d.ts.map +1 -0
- package/dist/scanner/file-scanner.js +119 -0
- package/dist/scanner/git-scanner.d.ts +10 -0
- package/dist/scanner/git-scanner.d.ts.map +1 -0
- package/dist/scanner/git-scanner.js +120 -0
- package/dist/scanner/index.d.ts +15 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +106 -0
- package/dist/state/index.d.ts +20 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +141 -0
- package/dist/state/schema.d.ts +101 -0
- package/dist/state/schema.d.ts.map +1 -0
- package/dist/state/schema.js +6 -0
- package/dist/templates/embedded/adr.md +45 -0
- package/dist/templates/embedded/api-spec.md +55 -0
- package/dist/templates/embedded/data-model.md +55 -0
- package/dist/templates/embedded/deployment-procedure.md +63 -0
- package/dist/templates/embedded/runbook.md +55 -0
- package/dist/templates/embedded/test-plan.md +55 -0
- package/dist/templates/embedded/threat-model.md +47 -0
- package/dist/templates/index.d.ts +20 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +106 -0
- package/dist/templates/registry.d.ts +31 -0
- package/dist/templates/registry.d.ts.map +1 -0
- package/dist/templates/registry.js +172 -0
- package/dist/templates/renderer.d.ts +26 -0
- package/dist/templates/renderer.d.ts.map +1 -0
- package/dist/templates/renderer.js +145 -0
- package/dist/utils/language-detect.d.ts +14 -0
- package/dist/utils/language-detect.d.ts.map +1 -0
- package/dist/utils/language-detect.js +58 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +35 -0
- package/dist/versioning/differ.d.ts +20 -0
- package/dist/versioning/differ.d.ts.map +1 -0
- package/dist/versioning/differ.js +160 -0
- package/dist/versioning/index.d.ts +44 -0
- package/dist/versioning/index.d.ts.map +1 -0
- package/dist/versioning/index.js +165 -0
- package/package.json +40 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CI Check Logic
|
|
3
|
+
* Validates that all required documentation exists and is not stale
|
|
4
|
+
*/
|
|
5
|
+
export interface CheckOptions {
|
|
6
|
+
threshold?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface CheckResult {
|
|
9
|
+
pass: boolean;
|
|
10
|
+
missing: string[];
|
|
11
|
+
stale: string[];
|
|
12
|
+
details: string;
|
|
13
|
+
exitCode: 0 | 1;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Run CI checks on the project
|
|
17
|
+
* Verifies that all required docs exist and are not stale
|
|
18
|
+
* @param projectPath - Root path of the project
|
|
19
|
+
* @param options - Check options (threshold in commits)
|
|
20
|
+
* @returns CheckResult with pass/fail status and details
|
|
21
|
+
*/
|
|
22
|
+
export declare function runCheck(projectPath: string, options?: CheckOptions): Promise<CheckResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Get detailed staleness info for a specific doc type
|
|
25
|
+
* Useful for debugging/verbose output
|
|
26
|
+
*/
|
|
27
|
+
export declare function getDocStalenessDetails(projectPath: string, docType: string): Promise<{
|
|
28
|
+
docType: string;
|
|
29
|
+
commitsSince: number;
|
|
30
|
+
daysSince: number;
|
|
31
|
+
generatedAt: string;
|
|
32
|
+
exists: boolean;
|
|
33
|
+
} | null>;
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/checker/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAC5B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CAyDtB;AAqCD;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IACT,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CACjB,GAAG,IAAI,CAAC,CA0BR"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CI Check Logic
|
|
4
|
+
* Validates that all required documentation exists and is not stale
|
|
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.runCheck = runCheck;
|
|
41
|
+
exports.getDocStalenessDetails = getDocStalenessDetails;
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const state_1 = require("../state");
|
|
45
|
+
const staleness_1 = require("./staleness");
|
|
46
|
+
/**
|
|
47
|
+
* Run CI checks on the project
|
|
48
|
+
* Verifies that all required docs exist and are not stale
|
|
49
|
+
* @param projectPath - Root path of the project
|
|
50
|
+
* @param options - Check options (threshold in commits)
|
|
51
|
+
* @returns CheckResult with pass/fail status and details
|
|
52
|
+
*/
|
|
53
|
+
async function runCheck(projectPath, options = {}) {
|
|
54
|
+
const threshold = options.threshold ?? 20;
|
|
55
|
+
const missing = [];
|
|
56
|
+
const stale = [];
|
|
57
|
+
// Read state
|
|
58
|
+
const state = (0, state_1.readState)(projectPath);
|
|
59
|
+
if (!state) {
|
|
60
|
+
return {
|
|
61
|
+
pass: false,
|
|
62
|
+
missing: [],
|
|
63
|
+
stale: [],
|
|
64
|
+
details: 'No vibe-doc state found. Run `vibe-doc scan` first.',
|
|
65
|
+
exitCode: 1,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// Get all required gaps (tier === 'required')
|
|
69
|
+
const requiredGaps = state.gapReport.gaps.filter((gap) => gap.tier === 'required');
|
|
70
|
+
// Check each required gap
|
|
71
|
+
for (const gap of requiredGaps) {
|
|
72
|
+
const docPath = path.join(projectPath, 'docs', 'generated', `${gap.docType}.md`);
|
|
73
|
+
// Check if doc exists
|
|
74
|
+
if (!fs.existsSync(docPath)) {
|
|
75
|
+
missing.push(gap.docType);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
// Find the generated doc in state
|
|
79
|
+
const generatedDoc = state.generatedDocs.find((d) => d.docType === gap.docType);
|
|
80
|
+
if (!generatedDoc) {
|
|
81
|
+
missing.push(gap.docType);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
// Check staleness
|
|
85
|
+
const docIsStale = await (0, staleness_1.isStale)(generatedDoc, projectPath, threshold);
|
|
86
|
+
if (docIsStale) {
|
|
87
|
+
stale.push(gap.docType);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Determine pass/fail
|
|
91
|
+
const pass = missing.length === 0 && stale.length === 0;
|
|
92
|
+
// Build details message
|
|
93
|
+
const details = buildDetailsMessage(requiredGaps.length, missing, stale, threshold);
|
|
94
|
+
return {
|
|
95
|
+
pass,
|
|
96
|
+
missing,
|
|
97
|
+
stale,
|
|
98
|
+
details,
|
|
99
|
+
exitCode: pass ? 0 : 1,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Build a human-readable details message
|
|
104
|
+
*/
|
|
105
|
+
function buildDetailsMessage(totalRequired, missing, stale, threshold) {
|
|
106
|
+
const lines = [];
|
|
107
|
+
lines.push(`Documentation Check Results`);
|
|
108
|
+
lines.push(`Required docs: ${totalRequired}`);
|
|
109
|
+
if (missing.length > 0) {
|
|
110
|
+
lines.push(`\nMissing (${missing.length}):`);
|
|
111
|
+
for (const doc of missing) {
|
|
112
|
+
lines.push(` - ${doc}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (stale.length > 0) {
|
|
116
|
+
lines.push(`\nStale - more than ${threshold} commits since generation (${stale.length}):`);
|
|
117
|
+
for (const doc of stale) {
|
|
118
|
+
lines.push(` - ${doc}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (missing.length === 0 && stale.length === 0) {
|
|
122
|
+
lines.push(`\n✓ All required documentation is present and current`);
|
|
123
|
+
}
|
|
124
|
+
return lines.join('\n');
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get detailed staleness info for a specific doc type
|
|
128
|
+
* Useful for debugging/verbose output
|
|
129
|
+
*/
|
|
130
|
+
async function getDocStalenessDetails(projectPath, docType) {
|
|
131
|
+
const state = (0, state_1.readState)(projectPath);
|
|
132
|
+
if (!state) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
const generatedDoc = state.generatedDocs.find((d) => d.docType === docType);
|
|
136
|
+
if (!generatedDoc) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
const docPath = path.join(projectPath, 'docs', 'generated', `${docType}.md`);
|
|
140
|
+
const exists = fs.existsSync(docPath);
|
|
141
|
+
try {
|
|
142
|
+
const staleness = await (0, staleness_1.getStalenessInfo)(generatedDoc, projectPath);
|
|
143
|
+
return {
|
|
144
|
+
docType,
|
|
145
|
+
commitsSince: staleness.commitsSince,
|
|
146
|
+
daysSince: staleness.daysSince,
|
|
147
|
+
generatedAt: generatedDoc.generatedAt,
|
|
148
|
+
exists,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Staleness Detection
|
|
3
|
+
* Determines if generated documentation is stale based on git commit history
|
|
4
|
+
*/
|
|
5
|
+
import { GeneratedDoc } from '../state/schema';
|
|
6
|
+
export interface StalenessInfo {
|
|
7
|
+
commitsSince: number;
|
|
8
|
+
daysSince: number;
|
|
9
|
+
isStale: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Check if a document is stale based on commit count since generation
|
|
13
|
+
* @param doc - The generated document
|
|
14
|
+
* @param projectPath - Root path of the project
|
|
15
|
+
* @param threshold - Number of commits before doc is considered stale (default: 20)
|
|
16
|
+
* @returns true if commits since generation >= threshold
|
|
17
|
+
*/
|
|
18
|
+
export declare function isStale(doc: GeneratedDoc, projectPath: string, threshold?: number): Promise<boolean>;
|
|
19
|
+
/**
|
|
20
|
+
* Get detailed staleness information for a document
|
|
21
|
+
* @param doc - The generated document
|
|
22
|
+
* @param projectPath - Root path of the project
|
|
23
|
+
* @returns Staleness info including commit count and days since generation
|
|
24
|
+
*/
|
|
25
|
+
export declare function getStalenessInfo(doc: GeneratedDoc, projectPath: string): Promise<StalenessInfo>;
|
|
26
|
+
//# sourceMappingURL=staleness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staleness.d.ts","sourceRoot":"","sources":["../../src/checker/staleness.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,YAAY,EACjB,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,MAAW,GACrB,OAAO,CAAC,OAAO,CAAC,CAWlB;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,YAAY,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,CAAC,CAsBxB"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Staleness Detection
|
|
4
|
+
* Determines if generated documentation is stale based on git commit history
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.isStale = isStale;
|
|
11
|
+
exports.getStalenessInfo = getStalenessInfo;
|
|
12
|
+
const simple_git_1 = __importDefault(require("simple-git"));
|
|
13
|
+
/**
|
|
14
|
+
* Check if a document is stale based on commit count since generation
|
|
15
|
+
* @param doc - The generated document
|
|
16
|
+
* @param projectPath - Root path of the project
|
|
17
|
+
* @param threshold - Number of commits before doc is considered stale (default: 20)
|
|
18
|
+
* @returns true if commits since generation >= threshold
|
|
19
|
+
*/
|
|
20
|
+
async function isStale(doc, projectPath, threshold = 20) {
|
|
21
|
+
try {
|
|
22
|
+
const staleness = await getStalenessInfo(doc, projectPath);
|
|
23
|
+
return staleness.commitsSince >= threshold;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
// If we can't determine staleness, conservatively assume stale to prevent deploying with outdated docs
|
|
27
|
+
console.warn(`Failed to check staleness for ${doc.docType}: ${error}. Assuming stale for safety.`);
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get detailed staleness information for a document
|
|
33
|
+
* @param doc - The generated document
|
|
34
|
+
* @param projectPath - Root path of the project
|
|
35
|
+
* @returns Staleness info including commit count and days since generation
|
|
36
|
+
*/
|
|
37
|
+
async function getStalenessInfo(doc, projectPath) {
|
|
38
|
+
try {
|
|
39
|
+
const git = (0, simple_git_1.default)(projectPath);
|
|
40
|
+
// Get the timestamp of the document generation
|
|
41
|
+
const docDate = new Date(doc.generatedAt);
|
|
42
|
+
// Get all commits since that time
|
|
43
|
+
const log = await git.log({ from: doc.generatedAt });
|
|
44
|
+
// Calculate days since generation
|
|
45
|
+
const now = new Date();
|
|
46
|
+
const daysSince = Math.floor((now.getTime() - docDate.getTime()) / (1000 * 60 * 60 * 24));
|
|
47
|
+
return {
|
|
48
|
+
commitsSince: log.total,
|
|
49
|
+
daysSince,
|
|
50
|
+
isStale: false, // Will be set by isStale() function
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new Error(`Failed to get staleness info for ${doc.docType}: ${error}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classifier Orchestrator
|
|
3
|
+
* Main entry point for hybrid classification
|
|
4
|
+
*/
|
|
5
|
+
import { ArtifactInventory, Classification } from '../state/schema';
|
|
6
|
+
export interface ClassificationOptions {
|
|
7
|
+
confidenceThreshold?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ClassificationResult {
|
|
10
|
+
resolved: boolean;
|
|
11
|
+
classification?: Classification;
|
|
12
|
+
llmPrompt?: string;
|
|
13
|
+
candidates?: Array<{
|
|
14
|
+
category: string;
|
|
15
|
+
score: number;
|
|
16
|
+
}>;
|
|
17
|
+
contexts?: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Classify a project based on artifact inventory
|
|
21
|
+
* Returns either a high-confidence classification or a prompt for LLM fallback
|
|
22
|
+
* @param inventory - Artifact inventory from scanner
|
|
23
|
+
* @param options - Classification options (confidenceThreshold, etc.)
|
|
24
|
+
*/
|
|
25
|
+
export declare function classify(inventory: ArtifactInventory, options?: ClassificationOptions): ClassificationResult;
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/classifier/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAqB,MAAM,iBAAiB,CAAC;AAMvF,MAAM,WAAW,qBAAqB;IACpC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,iBAAiB,EAC5B,OAAO,CAAC,EAAE,qBAAqB,GAC9B,oBAAoB,CAkDtB"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Classifier Orchestrator
|
|
4
|
+
* Main entry point for hybrid classification
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.classify = classify;
|
|
8
|
+
const logger_1 = require("../utils/logger");
|
|
9
|
+
const signals_1 = require("./signals");
|
|
10
|
+
const scoring_engine_1 = require("./scoring-engine");
|
|
11
|
+
const llm_prompt_1 = require("./llm-prompt");
|
|
12
|
+
/**
|
|
13
|
+
* Classify a project based on artifact inventory
|
|
14
|
+
* Returns either a high-confidence classification or a prompt for LLM fallback
|
|
15
|
+
* @param inventory - Artifact inventory from scanner
|
|
16
|
+
* @param options - Classification options (confidenceThreshold, etc.)
|
|
17
|
+
*/
|
|
18
|
+
function classify(inventory, options) {
|
|
19
|
+
const confidenceThreshold = options?.confidenceThreshold ?? 0.85;
|
|
20
|
+
logger_1.logger.info('Starting hybrid classification', { confidenceThreshold });
|
|
21
|
+
// Step 1: Extract signals from inventory
|
|
22
|
+
const signals = (0, signals_1.extractSignals)(inventory);
|
|
23
|
+
logger_1.logger.info('Signals extracted', { count: signals.length });
|
|
24
|
+
// Step 2: Run scoring engine
|
|
25
|
+
const ruleResults = (0, scoring_engine_1.scoreClassification)(signals, confidenceThreshold);
|
|
26
|
+
logger_1.logger.info('Rule-based scoring complete', {
|
|
27
|
+
confidence: ruleResults.confidence,
|
|
28
|
+
topCategory: ruleResults.categories[0],
|
|
29
|
+
});
|
|
30
|
+
// Step 3: Check confidence threshold
|
|
31
|
+
if (ruleResults.confidence >= confidenceThreshold) {
|
|
32
|
+
// High confidence - return classification directly
|
|
33
|
+
const classification = buildClassification(ruleResults, inventory);
|
|
34
|
+
logger_1.logger.info('Classification resolved with high confidence', {
|
|
35
|
+
category: classification.primaryCategory,
|
|
36
|
+
confidence: classification.confidence,
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
resolved: true,
|
|
40
|
+
classification,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Low confidence - build classification from best candidate and prepare LLM prompt
|
|
44
|
+
logger_1.logger.info('Classification confidence too low, building from best candidate', {
|
|
45
|
+
confidence: ruleResults.confidence,
|
|
46
|
+
topCandidate: ruleResults.categories[0]?.category,
|
|
47
|
+
});
|
|
48
|
+
const llmPrompt = (0, llm_prompt_1.buildClassificationPrompt)(inventory, ruleResults);
|
|
49
|
+
const classification = buildLowConfidenceClassification(ruleResults, inventory);
|
|
50
|
+
return {
|
|
51
|
+
resolved: false,
|
|
52
|
+
classification,
|
|
53
|
+
llmPrompt,
|
|
54
|
+
candidates: ruleResults.categories.map((c) => ({
|
|
55
|
+
category: c.category,
|
|
56
|
+
score: c.score,
|
|
57
|
+
})),
|
|
58
|
+
contexts: ruleResults.contexts.map((c) => c.context),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Build a Classification object from scoring results
|
|
63
|
+
*/
|
|
64
|
+
function buildClassification(ruleResults, inventory) {
|
|
65
|
+
const topCategory = ruleResults.categories[0];
|
|
66
|
+
const secondaryCategory = ruleResults.categories.length > 1 ? ruleResults.categories[1] : null;
|
|
67
|
+
const contexts = ruleResults.contexts.map((c) => c.context);
|
|
68
|
+
// Map category to deployment context
|
|
69
|
+
const deploymentContext = mapCategoryToDeploymentContext(topCategory.category, contexts);
|
|
70
|
+
return {
|
|
71
|
+
primaryCategory: topCategory.category,
|
|
72
|
+
secondaryCategory: secondaryCategory?.category || '',
|
|
73
|
+
deploymentContext,
|
|
74
|
+
contextModifiers: contexts,
|
|
75
|
+
confidence: ruleResults.confidence,
|
|
76
|
+
rationale: buildRationale(topCategory.category, contexts),
|
|
77
|
+
userConfirmed: false,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build a Classification object from low-confidence scoring results
|
|
82
|
+
* Uses the best candidate with actual confidence score and contexts
|
|
83
|
+
*/
|
|
84
|
+
function buildLowConfidenceClassification(ruleResults, inventory) {
|
|
85
|
+
const topCategory = ruleResults.categories[0];
|
|
86
|
+
const secondaryCategory = ruleResults.categories.length > 1 ? ruleResults.categories[1] : null;
|
|
87
|
+
const contexts = ruleResults.contexts.map((c) => c.context);
|
|
88
|
+
// Map category to deployment context
|
|
89
|
+
const deploymentContext = mapCategoryToDeploymentContext(topCategory.category, contexts);
|
|
90
|
+
// Build rationale noting that LLM review is available
|
|
91
|
+
const baseRationale = buildRationale(topCategory.category, contexts);
|
|
92
|
+
const reviewNote = ' [LLM review available to increase confidence]';
|
|
93
|
+
return {
|
|
94
|
+
primaryCategory: topCategory.category,
|
|
95
|
+
secondaryCategory: secondaryCategory?.category || '',
|
|
96
|
+
deploymentContext,
|
|
97
|
+
contextModifiers: contexts,
|
|
98
|
+
confidence: ruleResults.confidence,
|
|
99
|
+
rationale: baseRationale + reviewNote,
|
|
100
|
+
userConfirmed: false,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Map category and contexts to deployment context
|
|
105
|
+
*/
|
|
106
|
+
function mapCategoryToDeploymentContext(category, contexts) {
|
|
107
|
+
const result = [];
|
|
108
|
+
// Determine platform based on category
|
|
109
|
+
let platform = 'cloud';
|
|
110
|
+
if (category === scoring_engine_1.Category.MobileApplication) {
|
|
111
|
+
platform = 'mobile';
|
|
112
|
+
}
|
|
113
|
+
else if (category === scoring_engine_1.Category.InfrastructurePlatform) {
|
|
114
|
+
platform = 'kubernetes';
|
|
115
|
+
}
|
|
116
|
+
// Check for EdgeEmbedded context
|
|
117
|
+
if (contexts.includes(scoring_engine_1.Context.EdgeEmbedded)) {
|
|
118
|
+
platform = 'edge';
|
|
119
|
+
}
|
|
120
|
+
// Determine environment based on contexts
|
|
121
|
+
let environment = 'production';
|
|
122
|
+
if (contexts.includes(scoring_engine_1.Context.InternalTooling)) {
|
|
123
|
+
environment = 'staging';
|
|
124
|
+
}
|
|
125
|
+
// Determine scale based on contexts
|
|
126
|
+
let scale = 'small';
|
|
127
|
+
if (contexts.includes(scoring_engine_1.Context.CustomerFacing)) {
|
|
128
|
+
scale = 'large';
|
|
129
|
+
}
|
|
130
|
+
else if (contexts.includes(scoring_engine_1.Context.MultiTenant)) {
|
|
131
|
+
scale = 'large';
|
|
132
|
+
}
|
|
133
|
+
result.push({ platform, environment, scale });
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Build a rationale string for the classification
|
|
138
|
+
*/
|
|
139
|
+
function buildRationale(category, contexts) {
|
|
140
|
+
const parts = [];
|
|
141
|
+
parts.push(`Primary category: ${category}`);
|
|
142
|
+
if (contexts.length > 0) {
|
|
143
|
+
parts.push(`Contexts: ${contexts.join(', ')}`);
|
|
144
|
+
}
|
|
145
|
+
return parts.join('. ');
|
|
146
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Prompt Builder
|
|
3
|
+
* Generates structured prompts for LLM-based classification fallback
|
|
4
|
+
*/
|
|
5
|
+
import { ArtifactInventory } from '../state/schema';
|
|
6
|
+
import { ScoringResult } from './scoring-engine';
|
|
7
|
+
/**
|
|
8
|
+
* Build a structured prompt for LLM classification
|
|
9
|
+
* Used when rule-based confidence is < 0.85
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildClassificationPrompt(inventory: ArtifactInventory, ruleResults: ScoringResult): string;
|
|
12
|
+
//# sourceMappingURL=llm-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-prompt.d.ts","sourceRoot":"","sources":["../../src/classifier/llm-prompt.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAA+B,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE9E;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,iBAAiB,EAC5B,WAAW,EAAE,aAAa,GACzB,MAAM,CA0DR"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LLM Prompt Builder
|
|
4
|
+
* Generates structured prompts for LLM-based classification fallback
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.buildClassificationPrompt = buildClassificationPrompt;
|
|
8
|
+
/**
|
|
9
|
+
* Build a structured prompt for LLM classification
|
|
10
|
+
* Used when rule-based confidence is < 0.85
|
|
11
|
+
*/
|
|
12
|
+
function buildClassificationPrompt(inventory, ruleResults) {
|
|
13
|
+
const topCategories = ruleResults.categories.slice(0, 3);
|
|
14
|
+
const detectedContexts = ruleResults.contexts.slice(0, 3);
|
|
15
|
+
const projectSummary = buildProjectSummary(inventory);
|
|
16
|
+
const candidateSummary = buildCandidateSummary(topCategories, detectedContexts);
|
|
17
|
+
return `# Project Classification Task
|
|
18
|
+
|
|
19
|
+
You are an expert software architect reviewing a codebase to determine its primary category and operational contexts.
|
|
20
|
+
|
|
21
|
+
## Project Scan Summary
|
|
22
|
+
|
|
23
|
+
${projectSummary}
|
|
24
|
+
|
|
25
|
+
## Rule Engine Candidates
|
|
26
|
+
|
|
27
|
+
The rule-based classifier generated these candidates with confidence ${(ruleResults.confidence * 100).toFixed(0)}%:
|
|
28
|
+
|
|
29
|
+
${candidateSummary}
|
|
30
|
+
|
|
31
|
+
## Classification Categories
|
|
32
|
+
|
|
33
|
+
Choose ONE primary category that best describes this project:
|
|
34
|
+
|
|
35
|
+
- **WebApplication**: A user-facing web application (SPA, server-rendered, etc.)
|
|
36
|
+
- **APIMicroservice**: A REST API, GraphQL service, or microservice
|
|
37
|
+
- **DataPipeline**: ETL pipelines, data warehouses, batch processors
|
|
38
|
+
- **InfrastructurePlatform**: Infrastructure-as-code, deployment systems, cloud platforms
|
|
39
|
+
- **MobileApplication**: Native or cross-platform mobile apps
|
|
40
|
+
- **AIMLSystem**: ML/AI-focused projects with models, training, inference
|
|
41
|
+
- **IntegrationConnector**: Adapters, SDKs, connectors for third-party services
|
|
42
|
+
|
|
43
|
+
## Operational Contexts
|
|
44
|
+
|
|
45
|
+
Identify applicable contexts (can select multiple):
|
|
46
|
+
|
|
47
|
+
- **Regulated**: Subject to compliance requirements (HIPAA, SOX, PCI, etc.)
|
|
48
|
+
- **CustomerFacing**: Public-facing or customer-critical service
|
|
49
|
+
- **InternalTooling**: Internal tools, admin dashboards, support systems
|
|
50
|
+
- **MultiTenant**: Serves multiple independent customers/tenants
|
|
51
|
+
- **EdgeEmbedded**: Runs on edge devices, embedded systems, or IoT
|
|
52
|
+
|
|
53
|
+
## Your Response
|
|
54
|
+
|
|
55
|
+
Return a JSON object with this exact structure:
|
|
56
|
+
\`\`\`json
|
|
57
|
+
{
|
|
58
|
+
"primaryCategory": "string (one of the categories above)",
|
|
59
|
+
"secondaryCategory": "string (optional, for ambiguous cases)",
|
|
60
|
+
"contexts": ["string", "string"],
|
|
61
|
+
"confidence": 0.75,
|
|
62
|
+
"rationale": "Explain your classification in 2-3 sentences"
|
|
63
|
+
}
|
|
64
|
+
\`\`\`
|
|
65
|
+
|
|
66
|
+
Focus on the strongest signals in the codebase. If multiple categories are equally plausible, explain the tie-breaker in rationale.
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
function buildProjectSummary(inventory) {
|
|
70
|
+
const sc = inventory.categories.sourceCode;
|
|
71
|
+
const conf = inventory.categories.configuration;
|
|
72
|
+
const doc = inventory.categories.documentation;
|
|
73
|
+
const tests = inventory.categories.tests;
|
|
74
|
+
const arch = inventory.categories.architecture;
|
|
75
|
+
const infra = inventory.categories.infrastructure;
|
|
76
|
+
const languages = inventory.gitStats.mainLanguages.slice(0, 5).join(', ') || 'Unknown';
|
|
77
|
+
return `
|
|
78
|
+
### File Distribution
|
|
79
|
+
- Source code: ${sc.count} files (${languages})
|
|
80
|
+
- Configuration: ${conf.count} files
|
|
81
|
+
- Documentation: ${doc.count} files
|
|
82
|
+
- Tests: ${tests.count} files
|
|
83
|
+
- Architecture artifacts: ${arch.count} files
|
|
84
|
+
- Infrastructure: ${infra.count} files
|
|
85
|
+
- **Total artifacts: ${inventory.totalArtifacts}**
|
|
86
|
+
|
|
87
|
+
### Git Activity
|
|
88
|
+
- Total commits: ${inventory.gitStats.totalCommits}
|
|
89
|
+
- Contributors: ${inventory.gitStats.contributors}
|
|
90
|
+
- Last commit: ${inventory.gitStats.lastCommitDate}
|
|
91
|
+
|
|
92
|
+
### Top Source Files (Sample)
|
|
93
|
+
\`\`\`
|
|
94
|
+
${sc.files.slice(0, 5).join('\n')}
|
|
95
|
+
${sc.files.length > 5 ? `... and ${sc.files.length - 5} more source files` : ''}
|
|
96
|
+
\`\`\`
|
|
97
|
+
|
|
98
|
+
### Configuration Files (Sample)
|
|
99
|
+
\`\`\`
|
|
100
|
+
${conf.files.slice(0, 5).join('\n')}
|
|
101
|
+
${conf.files.length > 5 ? `... and ${conf.files.length - 5} more config files` : ''}
|
|
102
|
+
\`\`\`
|
|
103
|
+
|
|
104
|
+
### Infrastructure Files (Sample)
|
|
105
|
+
\`\`\`
|
|
106
|
+
${infra.files.slice(0, 5).join('\n')}
|
|
107
|
+
${infra.files.length > 5 ? `... and ${infra.files.length - 5} more infrastructure files` : ''}
|
|
108
|
+
\`\`\`
|
|
109
|
+
`;
|
|
110
|
+
}
|
|
111
|
+
function buildCandidateSummary(categories, contexts) {
|
|
112
|
+
let summary = '### Categories (Rule Score)\n';
|
|
113
|
+
for (const cat of categories) {
|
|
114
|
+
summary += `- ${cat.category}: ${cat.score.toFixed(1)}\n`;
|
|
115
|
+
}
|
|
116
|
+
if (contexts.length > 0) {
|
|
117
|
+
summary += '\n### Detected Contexts (Rule Score)\n';
|
|
118
|
+
for (const ctx of contexts) {
|
|
119
|
+
summary += `- ${ctx.context}: ${ctx.score.toFixed(1)}\n`;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return summary;
|
|
123
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scoring Engine Module
|
|
3
|
+
* Rule-based matrix for categorizing projects and contexts
|
|
4
|
+
*/
|
|
5
|
+
import { Signal } from './signals';
|
|
6
|
+
export declare enum Category {
|
|
7
|
+
WebApplication = "WebApplication",
|
|
8
|
+
APIMicroservice = "APIMicroservice",
|
|
9
|
+
DataPipeline = "DataPipeline",
|
|
10
|
+
InfrastructurePlatform = "InfrastructurePlatform",
|
|
11
|
+
MobileApplication = "MobileApplication",
|
|
12
|
+
AIMLSystem = "AIMLSystem",
|
|
13
|
+
IntegrationConnector = "IntegrationConnector"
|
|
14
|
+
}
|
|
15
|
+
export declare enum Context {
|
|
16
|
+
Regulated = "Regulated",
|
|
17
|
+
CustomerFacing = "CustomerFacing",
|
|
18
|
+
InternalTooling = "InternalTooling",
|
|
19
|
+
MultiTenant = "MultiTenant",
|
|
20
|
+
EdgeEmbedded = "EdgeEmbedded"
|
|
21
|
+
}
|
|
22
|
+
export interface CategoryScore {
|
|
23
|
+
category: Category;
|
|
24
|
+
score: number;
|
|
25
|
+
}
|
|
26
|
+
export interface ContextScore {
|
|
27
|
+
context: Context;
|
|
28
|
+
score: number;
|
|
29
|
+
}
|
|
30
|
+
export interface ScoringResult {
|
|
31
|
+
categories: CategoryScore[];
|
|
32
|
+
contexts: ContextScore[];
|
|
33
|
+
confidence: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Score classification based on signals
|
|
37
|
+
* @param signals - Array of detected signals
|
|
38
|
+
* @param confidenceThreshold - Threshold for high confidence classification (default: 0.85)
|
|
39
|
+
*/
|
|
40
|
+
export declare function scoreClassification(signals: Signal[], confidenceThreshold?: number): ScoringResult;
|
|
41
|
+
//# sourceMappingURL=scoring-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scoring-engine.d.ts","sourceRoot":"","sources":["../../src/classifier/scoring-engine.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGnC,oBAAY,QAAQ;IAClB,cAAc,mBAAmB;IACjC,eAAe,oBAAoB;IACnC,YAAY,iBAAiB;IAC7B,sBAAsB,2BAA2B;IACjD,iBAAiB,sBAAsB;IACvC,UAAU,eAAe;IACzB,oBAAoB,yBAAyB;CAC9C;AAED,oBAAY,OAAO;IACjB,SAAS,cAAc;IACvB,cAAc,mBAAmB;IACjC,eAAe,oBAAoB;IACnC,WAAW,gBAAgB;IAC3B,YAAY,iBAAiB;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EAAE,EACjB,mBAAmB,GAAE,MAAa,GACjC,aAAa,CAuMf"}
|