vaspera-pm 2.3.0 → 2.3.1
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/dist/cli.js +123 -45
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -182,7 +182,7 @@ npx vaspera-pm install # Configures Claude Code
|
|
|
182
182
|
|
|
183
183
|
Features:
|
|
184
184
|
- Team collaboration & sharing
|
|
185
|
-
- Usage tracking & quotas (Free:
|
|
185
|
+
- Usage tracking & quotas (Free: 100, Starter: 500, Pro: 2,500/month)
|
|
186
186
|
- Jira/Linear/GitHub/ADO integrations
|
|
187
187
|
- Historical drift tracking
|
|
188
188
|
- No Anthropic key needed (we proxy requests)
|
package/dist/cli.js
CHANGED
|
@@ -25390,26 +25390,102 @@ function formatCodeIndexForAI(index, importanceScores) {
|
|
|
25390
25390
|
}
|
|
25391
25391
|
return lines.join("\n");
|
|
25392
25392
|
}
|
|
25393
|
-
async function crossValidateWithAST(docsRequirements, codeIndex, docsContent, semanticHints, importanceScores) {
|
|
25393
|
+
async function crossValidateWithAST(docsRequirements, codeIndex, docsContent, semanticHints, importanceScores, onProgress) {
|
|
25394
25394
|
const codeIndexText = formatCodeIndexForAI(codeIndex, importanceScores);
|
|
25395
|
-
|
|
25396
|
-
|
|
25397
|
-
|
|
25398
|
-
|
|
25399
|
-
|
|
25400
|
-
|
|
25401
|
-
if (match.matches.length > 0) {
|
|
25402
|
-
hintLines.push(`### ${reqId}`);
|
|
25403
|
-
hintLines.push(`Top matches (${match.confidence}% confidence):`);
|
|
25404
|
-
for (const m of match.matches.slice(0, 3)) {
|
|
25405
|
-
hintLines.push(` - ${m.type}: ${m.name} [${m.filePath}:${m.lineNumber}] (${Math.round(m.score * 100)}%)`);
|
|
25406
|
-
}
|
|
25407
|
-
hintLines.push("");
|
|
25408
|
-
}
|
|
25395
|
+
const estimatedPromptSize = JSON.stringify(docsRequirements).length + codeIndexText.length + docsContent.substring(0, 3e4).length;
|
|
25396
|
+
const needsBatching = docsRequirements.length > MAX_REQUIREMENTS_PER_BATCH || estimatedPromptSize > MAX_CODE_INDEX_CHARS_PER_BATCH * 2;
|
|
25397
|
+
if (needsBatching) {
|
|
25398
|
+
if (onProgress) {
|
|
25399
|
+
const batchCount = Math.ceil(docsRequirements.length / MAX_REQUIREMENTS_PER_BATCH);
|
|
25400
|
+
onProgress("verification", 66, `Large codebase detected: splitting into ${batchCount} batches of ${MAX_REQUIREMENTS_PER_BATCH} requirements`);
|
|
25409
25401
|
}
|
|
25410
|
-
|
|
25402
|
+
return crossValidateWithASTBatched(docsRequirements, codeIndex, codeIndexText, docsContent, semanticHints, importanceScores, onProgress);
|
|
25403
|
+
}
|
|
25404
|
+
return crossValidateWithASTSingle(docsRequirements, codeIndexText, docsContent, semanticHints);
|
|
25405
|
+
}
|
|
25406
|
+
async function crossValidateWithASTSingle(docsRequirements, codeIndexText, docsContent, semanticHints) {
|
|
25407
|
+
const semanticHintsText = buildSemanticHintsText(semanticHints, docsRequirements.map((r) => r.id));
|
|
25408
|
+
const systemPrompt = buildVerificationSystemPrompt(true);
|
|
25409
|
+
const docsReqJson = JSON.stringify(docsRequirements, null, 2);
|
|
25410
|
+
const userMessage = `## REQUIREMENTS TO VERIFY
|
|
25411
|
+
${docsReqJson}
|
|
25412
|
+
|
|
25413
|
+
## COMPLETE CODE INDEX
|
|
25414
|
+
${codeIndexText}
|
|
25415
|
+
${semanticHintsText ? `
|
|
25416
|
+
${semanticHintsText}` : ""}
|
|
25417
|
+
## DOCUMENTATION (for context)
|
|
25418
|
+
${docsContent.substring(0, 3e4)}
|
|
25419
|
+
|
|
25420
|
+
For each requirement, find matching code in the index and determine verification status.
|
|
25421
|
+
Code entries include [file:line] references - use these in your evidence.
|
|
25422
|
+
${semanticHintsText ? "Use the semantic match hints above as starting points for your verification." : ""}`;
|
|
25423
|
+
const result = await createJsonCompletion({
|
|
25424
|
+
systemPrompt,
|
|
25425
|
+
userMessage,
|
|
25426
|
+
model: "balanced",
|
|
25427
|
+
maxTokens: 16384
|
|
25428
|
+
});
|
|
25429
|
+
return parseVerificationResult(result);
|
|
25430
|
+
}
|
|
25431
|
+
async function crossValidateWithASTBatched(docsRequirements, codeIndex, codeIndexText, docsContent, semanticHints, importanceScores, onProgress) {
|
|
25432
|
+
const batches = [];
|
|
25433
|
+
for (let i = 0; i < docsRequirements.length; i += MAX_REQUIREMENTS_PER_BATCH) {
|
|
25434
|
+
batches.push(docsRequirements.slice(i, i + MAX_REQUIREMENTS_PER_BATCH));
|
|
25435
|
+
}
|
|
25436
|
+
const allRequirements = [];
|
|
25437
|
+
let totalInputTokens = 0;
|
|
25438
|
+
let totalOutputTokens = 0;
|
|
25439
|
+
const docsContextLimit = Math.min(2e4, Math.floor(3e4 / batches.length * 2));
|
|
25440
|
+
for (let batchIdx = 0; batchIdx < batches.length; batchIdx++) {
|
|
25441
|
+
const batch = batches[batchIdx];
|
|
25442
|
+
const isFirstBatch = batchIdx === 0;
|
|
25443
|
+
const batchIds = batch.map((r) => r.id);
|
|
25444
|
+
if (onProgress) {
|
|
25445
|
+
const batchPercent = 65 + Math.round(batchIdx / batches.length * 15);
|
|
25446
|
+
onProgress("verification", batchPercent, `Verifying batch ${batchIdx + 1}/${batches.length} (${batch.length} requirements)...`);
|
|
25447
|
+
}
|
|
25448
|
+
const batchSemanticHints = buildSemanticHintsText(semanticHints, batchIds);
|
|
25449
|
+
const systemPrompt = buildVerificationSystemPrompt(isFirstBatch);
|
|
25450
|
+
const docsReqJson = JSON.stringify(batch, null, 2);
|
|
25451
|
+
const batchLabel = `[Batch ${batchIdx + 1}/${batches.length}]`;
|
|
25452
|
+
const userMessage = `${batchLabel} Verify these ${batch.length} requirements against the code index.
|
|
25453
|
+
|
|
25454
|
+
## REQUIREMENTS TO VERIFY
|
|
25455
|
+
${docsReqJson}
|
|
25456
|
+
|
|
25457
|
+
## COMPLETE CODE INDEX
|
|
25458
|
+
${codeIndexText}
|
|
25459
|
+
${batchSemanticHints ? `
|
|
25460
|
+
${batchSemanticHints}` : ""}
|
|
25461
|
+
## DOCUMENTATION (for context)
|
|
25462
|
+
${docsContent.substring(0, docsContextLimit)}
|
|
25463
|
+
|
|
25464
|
+
For each requirement, find matching code in the index and determine verification status.
|
|
25465
|
+
Code entries include [file:line] references - use these in your evidence.
|
|
25466
|
+
${batchSemanticHints ? "Use the semantic match hints above as starting points for your verification." : ""}`;
|
|
25467
|
+
const result = await createJsonCompletion({
|
|
25468
|
+
systemPrompt,
|
|
25469
|
+
userMessage,
|
|
25470
|
+
model: "balanced",
|
|
25471
|
+
maxTokens: 16384
|
|
25472
|
+
});
|
|
25473
|
+
const parsed = parseVerificationResult(result);
|
|
25474
|
+
allRequirements.push(...parsed.requirements);
|
|
25475
|
+
totalInputTokens += parsed.tokensUsed.input;
|
|
25476
|
+
totalOutputTokens += parsed.tokensUsed.output;
|
|
25411
25477
|
}
|
|
25412
|
-
|
|
25478
|
+
return {
|
|
25479
|
+
requirements: allRequirements,
|
|
25480
|
+
tokensUsed: { input: totalInputTokens, output: totalOutputTokens }
|
|
25481
|
+
};
|
|
25482
|
+
}
|
|
25483
|
+
function buildVerificationSystemPrompt(includeUndocumented) {
|
|
25484
|
+
const undocSection = includeUndocumented ? `
|
|
25485
|
+
For code features not matching any requirement:
|
|
25486
|
+
UNDOCUMENTED: Feature exists in code but has no corresponding requirement.` : "";
|
|
25487
|
+
const returnFormat = includeUndocumented ? 'Return JSON: {"requirements": [...], "undocumented": [...]}' : 'Return JSON: {"requirements": [...]}';
|
|
25488
|
+
return `You are a specification verification expert. Compare documentation requirements against a structured code index.
|
|
25413
25489
|
|
|
25414
25490
|
The code index shows ALL functions, routes, classes, types, and CONFIG ENTRIES in the codebase with their EXACT locations.
|
|
25415
25491
|
This is a complete inventory - if something is not listed, it does not exist.
|
|
@@ -25426,14 +25502,11 @@ For each requirement, find matching code OR config entries and determine:
|
|
|
25426
25502
|
VERIFIED: The requirement is implemented in code OR config. Cite the specific file:line.
|
|
25427
25503
|
DRIFT: The requirement is partially implemented or differs from spec. Explain the difference.
|
|
25428
25504
|
UNIMPLEMENTED: No matching code or config found in the index. This is a gap.
|
|
25429
|
-
|
|
25430
|
-
For code features not matching any requirement:
|
|
25431
|
-
UNDOCUMENTED: Feature exists in code but has no corresponding requirement.
|
|
25432
|
-
|
|
25505
|
+
${undocSection}
|
|
25433
25506
|
CRITICAL: Provide file:line references for ALL matches. The code index includes exact locations.
|
|
25434
25507
|
For config files, use the format "package.json:5" or "action.yml:12".
|
|
25435
25508
|
|
|
25436
|
-
|
|
25509
|
+
${returnFormat}
|
|
25437
25510
|
|
|
25438
25511
|
Each requirement entry:
|
|
25439
25512
|
{
|
|
@@ -25452,30 +25525,32 @@ Each requirement entry:
|
|
|
25452
25525
|
"recommendation": "update_docs|update_code|needs_discussion"
|
|
25453
25526
|
}
|
|
25454
25527
|
}`;
|
|
25455
|
-
|
|
25456
|
-
|
|
25457
|
-
|
|
25458
|
-
|
|
25459
|
-
|
|
25460
|
-
|
|
25461
|
-
|
|
25462
|
-
|
|
25463
|
-
|
|
25464
|
-
|
|
25465
|
-
|
|
25466
|
-
|
|
25467
|
-
|
|
25468
|
-
|
|
25469
|
-
|
|
25470
|
-
|
|
25471
|
-
|
|
25472
|
-
|
|
25473
|
-
|
|
25474
|
-
|
|
25528
|
+
}
|
|
25529
|
+
function buildSemanticHintsText(semanticHints, requirementIds) {
|
|
25530
|
+
if (!semanticHints || semanticHints.size === 0) return "";
|
|
25531
|
+
const hintLines = ["## SEMANTIC MATCH HINTS", ""];
|
|
25532
|
+
hintLines.push("Pre-computed semantic matches between requirements and code (use these as starting points):");
|
|
25533
|
+
hintLines.push("");
|
|
25534
|
+
let hasHints = false;
|
|
25535
|
+
for (const reqId of requirementIds) {
|
|
25536
|
+
const match = semanticHints.get(reqId);
|
|
25537
|
+
if (match && match.matches.length > 0) {
|
|
25538
|
+
hasHints = true;
|
|
25539
|
+
hintLines.push(`### ${reqId}`);
|
|
25540
|
+
hintLines.push(`Top matches (${match.confidence}% confidence):`);
|
|
25541
|
+
for (const m of match.matches.slice(0, 3)) {
|
|
25542
|
+
hintLines.push(` - ${m.type}: ${m.name} [${m.filePath}:${m.lineNumber}] (${Math.round(m.score * 100)}%)`);
|
|
25543
|
+
}
|
|
25544
|
+
hintLines.push("");
|
|
25545
|
+
}
|
|
25546
|
+
}
|
|
25547
|
+
return hasHints ? hintLines.join("\n") : "";
|
|
25548
|
+
}
|
|
25549
|
+
function parseVerificationResult(result) {
|
|
25475
25550
|
const allRequirements = [];
|
|
25476
25551
|
const reqs = Array.isArray(result.data) ? result.data : result.data.requirements || [];
|
|
25477
25552
|
allRequirements.push(...reqs);
|
|
25478
|
-
if (result.data.undocumented) {
|
|
25553
|
+
if (!Array.isArray(result.data) && result.data.undocumented) {
|
|
25479
25554
|
for (const undoc of result.data.undocumented) {
|
|
25480
25555
|
allRequirements.push({
|
|
25481
25556
|
id: undoc.id,
|
|
@@ -25643,7 +25718,8 @@ async function verifyWithAST(docsContent, codeFiles, options = {}) {
|
|
|
25643
25718
|
codeIndex,
|
|
25644
25719
|
docsContent,
|
|
25645
25720
|
semanticHints,
|
|
25646
|
-
importanceScores
|
|
25721
|
+
importanceScores,
|
|
25722
|
+
onProgress
|
|
25647
25723
|
);
|
|
25648
25724
|
progress("verification", 80, `Cross-validation complete: ${verified.requirements.length} items analyzed`);
|
|
25649
25725
|
progress("finishing", 85, "Adjusting drift severity based on file importance...");
|
|
@@ -25947,7 +26023,7 @@ function formatDriftReportMarkdown(report) {
|
|
|
25947
26023
|
}
|
|
25948
26024
|
return lines.join("\n");
|
|
25949
26025
|
}
|
|
25950
|
-
var CHUNK_SIZE_THRESHOLD2, TARGET_CHUNK_SIZE2, CHUNK_OVERLAP2, DEFAULT_PARSE_CONCURRENCY, MAX_PARSE_CONCURRENCY, MAX_FUNCTIONS_THRESHOLD, MAX_TYPES_THRESHOLD, MAX_CONSTANTS_THRESHOLD, MAX_FILE_SIZE_BYTES, LARGE_FILE_WARNING_BYTES;
|
|
26026
|
+
var CHUNK_SIZE_THRESHOLD2, TARGET_CHUNK_SIZE2, CHUNK_OVERLAP2, MAX_REQUIREMENTS_PER_BATCH, MAX_CODE_INDEX_CHARS_PER_BATCH, DEFAULT_PARSE_CONCURRENCY, MAX_PARSE_CONCURRENCY, MAX_FUNCTIONS_THRESHOLD, MAX_TYPES_THRESHOLD, MAX_CONSTANTS_THRESHOLD, MAX_FILE_SIZE_BYTES, LARGE_FILE_WARNING_BYTES;
|
|
25951
26027
|
var init_verification = __esm({
|
|
25952
26028
|
"src/verification/index.ts"() {
|
|
25953
26029
|
"use strict";
|
|
@@ -25963,6 +26039,8 @@ var init_verification = __esm({
|
|
|
25963
26039
|
CHUNK_SIZE_THRESHOLD2 = 4e4;
|
|
25964
26040
|
TARGET_CHUNK_SIZE2 = 35e3;
|
|
25965
26041
|
CHUNK_OVERLAP2 = 3e3;
|
|
26042
|
+
MAX_REQUIREMENTS_PER_BATCH = 25;
|
|
26043
|
+
MAX_CODE_INDEX_CHARS_PER_BATCH = 8e4;
|
|
25966
26044
|
DEFAULT_PARSE_CONCURRENCY = 8;
|
|
25967
26045
|
MAX_PARSE_CONCURRENCY = 16;
|
|
25968
26046
|
MAX_FUNCTIONS_THRESHOLD = 5e3;
|