@harness-engineering/cli 3.1.0 → 4.0.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/dist/agents/personas/harness-pm.yaml +33 -0
- package/dist/agents/skills/claude-code/acceptance-eval/SKILL.md +92 -0
- package/dist/agents/skills/claude-code/acceptance-eval/skill.yaml +54 -0
- package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +46 -38
- package/dist/agents/skills/claude-code/harness-brainstorming/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +10 -11
- package/dist/agents/skills/claude-code/harness-execution/SKILL.md +24 -26
- package/dist/agents/skills/claude-code/harness-integration/SKILL.md +21 -19
- package/dist/agents/skills/claude-code/harness-maintenance-pipeline/SKILL.md +173 -0
- package/dist/agents/skills/claude-code/harness-maintenance-pipeline/skill.yaml +43 -0
- package/dist/agents/skills/claude-code/harness-onboarding/SKILL.md +2 -0
- package/dist/agents/skills/claude-code/harness-planning/SKILL.md +17 -40
- package/dist/agents/skills/claude-code/harness-pulse/SKILL.md +1 -1
- package/dist/agents/skills/claude-code/harness-roadmap/SKILL.md +17 -0
- package/dist/agents/skills/claude-code/harness-roadmap-pilot/SKILL.md +8 -0
- package/dist/agents/skills/claude-code/harness-verification/SKILL.md +9 -12
- package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +112 -126
- package/dist/agents/skills/claude-code/outcome-eval/SKILL.md +1 -0
- package/dist/agents/skills/claude-code/product-advisor/SKILL.md +202 -0
- package/dist/agents/skills/claude-code/product-advisor/skill.yaml +74 -0
- package/dist/agents/skills/codex/acceptance-eval/SKILL.md +92 -0
- package/dist/agents/skills/codex/acceptance-eval/skill.yaml +54 -0
- package/dist/agents/skills/codex/harness-brainstorming/SKILL.md +46 -38
- package/dist/agents/skills/codex/harness-brainstorming/skill.yaml +1 -0
- package/dist/agents/skills/codex/harness-code-review/SKILL.md +10 -11
- package/dist/agents/skills/codex/harness-execution/SKILL.md +24 -26
- package/dist/agents/skills/codex/harness-integration/SKILL.md +21 -19
- package/dist/agents/skills/codex/harness-maintenance-pipeline/SKILL.md +173 -0
- package/dist/agents/skills/codex/harness-maintenance-pipeline/skill.yaml +43 -0
- package/dist/agents/skills/codex/harness-onboarding/SKILL.md +2 -0
- package/dist/agents/skills/codex/harness-planning/SKILL.md +17 -40
- package/dist/agents/skills/codex/harness-pulse/SKILL.md +1 -1
- package/dist/agents/skills/codex/harness-roadmap/SKILL.md +17 -0
- package/dist/agents/skills/codex/harness-roadmap-pilot/SKILL.md +8 -0
- package/dist/agents/skills/codex/harness-verification/SKILL.md +9 -12
- package/dist/agents/skills/codex/initialize-harness-project/SKILL.md +112 -126
- package/dist/agents/skills/codex/outcome-eval/SKILL.md +1 -0
- package/dist/agents/skills/codex/product-advisor/SKILL.md +202 -0
- package/dist/agents/skills/codex/product-advisor/skill.yaml +74 -0
- package/dist/agents/skills/cursor/acceptance-eval/SKILL.md +92 -0
- package/dist/agents/skills/cursor/acceptance-eval/skill.yaml +54 -0
- package/dist/agents/skills/cursor/harness-brainstorming/SKILL.md +46 -38
- package/dist/agents/skills/cursor/harness-brainstorming/skill.yaml +1 -0
- package/dist/agents/skills/cursor/harness-code-review/SKILL.md +10 -11
- package/dist/agents/skills/cursor/harness-execution/SKILL.md +24 -26
- package/dist/agents/skills/cursor/harness-integration/SKILL.md +21 -19
- package/dist/agents/skills/cursor/harness-maintenance-pipeline/SKILL.md +173 -0
- package/dist/agents/skills/cursor/harness-maintenance-pipeline/skill.yaml +43 -0
- package/dist/agents/skills/cursor/harness-onboarding/SKILL.md +2 -0
- package/dist/agents/skills/cursor/harness-planning/SKILL.md +17 -40
- package/dist/agents/skills/cursor/harness-pulse/SKILL.md +1 -1
- package/dist/agents/skills/cursor/harness-roadmap/SKILL.md +17 -0
- package/dist/agents/skills/cursor/harness-roadmap-pilot/SKILL.md +8 -0
- package/dist/agents/skills/cursor/harness-verification/SKILL.md +9 -12
- package/dist/agents/skills/cursor/initialize-harness-project/SKILL.md +112 -126
- package/dist/agents/skills/cursor/outcome-eval/SKILL.md +1 -0
- package/dist/agents/skills/cursor/product-advisor/SKILL.md +202 -0
- package/dist/agents/skills/cursor/product-advisor/skill.yaml +74 -0
- package/dist/agents/skills/gemini-cli/acceptance-eval/SKILL.md +92 -0
- package/dist/agents/skills/gemini-cli/acceptance-eval/skill.yaml +54 -0
- package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +46 -38
- package/dist/agents/skills/gemini-cli/harness-brainstorming/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-code-review/SKILL.md +10 -11
- package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +24 -26
- package/dist/agents/skills/gemini-cli/harness-integration/SKILL.md +21 -19
- package/dist/agents/skills/gemini-cli/harness-maintenance-pipeline/SKILL.md +173 -0
- package/dist/agents/skills/gemini-cli/harness-maintenance-pipeline/skill.yaml +43 -0
- package/dist/agents/skills/gemini-cli/harness-onboarding/SKILL.md +2 -0
- package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +17 -40
- package/dist/agents/skills/gemini-cli/harness-pulse/SKILL.md +1 -1
- package/dist/agents/skills/gemini-cli/harness-roadmap/SKILL.md +17 -0
- package/dist/agents/skills/gemini-cli/harness-roadmap-pilot/SKILL.md +8 -0
- package/dist/agents/skills/gemini-cli/harness-verification/SKILL.md +9 -12
- package/dist/agents/skills/gemini-cli/initialize-harness-project/SKILL.md +112 -126
- package/dist/agents/skills/gemini-cli/outcome-eval/SKILL.md +1 -0
- package/dist/agents/skills/gemini-cli/product-advisor/SKILL.md +202 -0
- package/dist/agents/skills/gemini-cli/product-advisor/skill.yaml +74 -0
- package/dist/agents/skills/tests/interaction-channel.test.ts +64 -0
- package/dist/{agents-md-YYCLGMBF.js → agents-md-VJLYEH2S.js} +4 -4
- package/dist/{analyzer-V633GUHY-MBCQWKDU.js → analyzer-V633GUHY-OV335HGM.js} +2 -2
- package/dist/{architecture-5KPP4ID4.js → architecture-YQH2NYXY.js} +5 -5
- package/dist/{assess-project-B6ENHUAU.js → assess-project-KOTAPAHD.js} +1 -1
- package/dist/bin/harness-mcp.js +19 -18
- package/dist/bin/harness.js +31 -29
- package/dist/{check-phase-gate-REG3HWYC.js → check-phase-gate-CHU2E3OU.js} +6 -5
- package/dist/{chunk-UBTMPO5H.js → chunk-36GQREOE.js} +3 -3
- package/dist/{chunk-CLI4K2CH.js → chunk-4U5LDFCY.js} +1 -1
- package/dist/{chunk-IF3JK3G5.js → chunk-4VXFZSYF.js} +1 -1
- package/dist/{chunk-TE5YHHHZ.js → chunk-5RSXUAMN.js} +1 -1
- package/dist/{chunk-YF3AY6KS.js → chunk-6SCYTIF4.js} +6 -6
- package/dist/{chunk-N55WOGN3.js → chunk-6YFHUIGT.js} +1 -1
- package/dist/{chunk-RGQXHCCH.js → chunk-7PJCK7UE.js} +8 -8
- package/dist/{chunk-LMZ2JTNP.js → chunk-7TIJXWG3.js} +5 -9
- package/dist/chunk-AAUY53CC.js +61 -0
- package/dist/{chunk-XEOSSKIB.js → chunk-AX5KGRM6.js} +48 -4
- package/dist/{chunk-FUH4J43G.js → chunk-E5EW5HVJ.js} +2 -2
- package/dist/{chunk-C2ZGWMTN.js → chunk-EYMOPFSD.js} +2 -2
- package/dist/{chunk-FL5SLUKZ.js → chunk-GHBFNLV2.js} +2374 -1095
- package/dist/{chunk-HIPBU2Q4.js → chunk-I3CGCZJF.js} +9 -9
- package/dist/{chunk-OQFEFVIN.js → chunk-JPVOI7GP.js} +7 -7
- package/dist/{chunk-DNX35Q5K.js → chunk-M7F2PPN3.js} +3 -3
- package/dist/{chunk-A65QO5KN.js → chunk-MMLQPHZ5.js} +3032 -1166
- package/dist/{chunk-ERZCC5VH.js → chunk-OQ6KOQEV.js} +9 -9
- package/dist/{chunk-ZOUJP3EY.js → chunk-RG3TNIUB.js} +1659 -808
- package/dist/{chunk-PZX2Y3RV.js → chunk-SDMV4QHM.js} +5 -5
- package/dist/{chunk-XZ2Q4UTW.js → chunk-SEA2PFVI.js} +1 -1
- package/dist/{chunk-TCVQVHEF.js → chunk-T746REAE.js} +1 -1
- package/dist/{chunk-6B6UN6SG.js → chunk-UTJJJDNN.js} +11 -1
- package/dist/{chunk-BXKNWSG4.js → chunk-UWVMJEUJ.js} +1 -1
- package/dist/{chunk-WWACIIBA.js → chunk-V3ZQUCRH.js} +1 -1
- package/dist/{chunk-27AJKSQY.js → chunk-WBVCN35T.js} +1 -1
- package/dist/{chunk-PP6ZRL5T.js → chunk-WZJR6SOI.js} +536 -422
- package/dist/{chunk-YQAFKOOL.js → chunk-XAVMTAUT.js} +2 -2
- package/dist/chunk-Y6SUQC32.js +9 -0
- package/dist/{chunk-ZRKFDE6M.js → chunk-YANR2RL7.js} +1 -1
- package/dist/{chunk-2N4OENGE.js → chunk-YYFSFSB3.js} +1 -1
- package/dist/{ci-workflow-JEYYCBOC.js → ci-workflow-HO4WKGNG.js} +4 -4
- package/dist/{dist-3HW4LCHE.js → dist-6D2F2J57.js} +73 -17
- package/dist/{dist-OWHMNL4W.js → dist-DWBTZXR5.js} +1 -1
- package/dist/{docs-YRMW7UED.js → docs-FP47JONV.js} +5 -5
- package/dist/{engine-E7H5U3AC.js → engine-YUA6IYOG.js} +4 -4
- package/dist/{entropy-3JBKCGJJ.js → entropy-DBW2INZU.js} +4 -4
- package/dist/{feedback-U6VJ6AUJ.js → feedback-BPHADTRQ.js} +1 -1
- package/dist/{generate-agent-definitions-S2FRZF4Y.js → generate-agent-definitions-KPVGBGDY.js} +6 -6
- package/dist/{glob-helper-GLZAURJC.js → glob-helper-VR6UCZZB.js} +1 -1
- package/dist/{graph-loader-HHXN5FLP.js → graph-loader-STFGYKZH.js} +1 -1
- package/dist/hooks/adoption-tracker.js +6 -5
- package/dist/hooks/protect-config.js +15 -5
- package/dist/{index-builder-3AOQ3ZII.js → index-builder-52IJJHJC.js} +2 -2
- package/dist/index.d.ts +8 -8
- package/dist/index.js +31 -29
- package/dist/{loader-RGQJYERV.js → loader-QOJQ6NZM.js} +4 -4
- package/dist/{mcp-NDTFZXWF.js → mcp-ZPX6O767.js} +21 -20
- package/dist/{performance-FPWKC4CN.js → performance-FXYTGJGQ.js} +5 -5
- package/dist/{review-pipeline-WUHG7PHO.js → review-pipeline-2TFQ5OAE.js} +4 -4
- package/dist/{runtime-Q3ORD7LW.js → runtime-XK6ZCHKE.js} +4 -4
- package/dist/{scan-P7YFKB77.js → scan-IYSVRPD2.js} +1 -1
- package/dist/{security-JDHTRBGC.js → security-4W2P5ZGI.js} +1 -1
- package/dist/{skill-executor-MOCUIAYS.js → skill-executor-BGUCAVBU.js} +2 -2
- package/dist/state-events-ECQAIZLU.js +25 -0
- package/dist/{validate-G3LKBOYA.js → validate-64KTEGIE.js} +5 -5
- package/dist/{validate-cross-check-4ITA72DF.js → validate-cross-check-J5PVGICB.js} +4 -4
- package/package.json +7 -7
|
@@ -1128,34 +1128,42 @@ function emptyIngestResult() {
|
|
|
1128
1128
|
durationMs: 0
|
|
1129
1129
|
};
|
|
1130
1130
|
}
|
|
1131
|
-
function
|
|
1132
|
-
const
|
|
1133
|
-
const
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
await new Promise((resolve) => setTimeout(resolve, jitteredDelay));
|
|
1131
|
+
function computeBackoffDelay(config, attempt) {
|
|
1132
|
+
const exponentialDelay = config.baseDelayMs * 2 ** attempt;
|
|
1133
|
+
const cappedDelay = Math.min(exponentialDelay, config.maxDelayMs);
|
|
1134
|
+
return cappedDelay * (0.5 + Math.random() * 0.5);
|
|
1135
|
+
}
|
|
1136
|
+
function shouldReturnResponse(response, attempt, maxRetries) {
|
|
1137
|
+
if (response.ok || !RETRYABLE_STATUSES.has(response.status ?? 0)) {
|
|
1138
|
+
return true;
|
|
1139
|
+
}
|
|
1140
|
+
return attempt === maxRetries;
|
|
1141
|
+
}
|
|
1142
|
+
async function executeWithRetry(client, url, requestOptions, config) {
|
|
1143
|
+
let lastError;
|
|
1144
|
+
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
|
|
1145
|
+
try {
|
|
1146
|
+
const response = await client(url, requestOptions);
|
|
1147
|
+
if (shouldReturnResponse(response, attempt, config.maxRetries)) {
|
|
1148
|
+
return response;
|
|
1149
|
+
}
|
|
1150
|
+
} catch (err) {
|
|
1151
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
1152
|
+
if (attempt === config.maxRetries) {
|
|
1153
|
+
throw lastError;
|
|
1154
|
+
}
|
|
1156
1155
|
}
|
|
1157
|
-
|
|
1156
|
+
await new Promise((resolve) => setTimeout(resolve, computeBackoffDelay(config, attempt)));
|
|
1157
|
+
}
|
|
1158
|
+
throw lastError ?? new Error("Request failed after retries");
|
|
1159
|
+
}
|
|
1160
|
+
function withRetry(client, options) {
|
|
1161
|
+
const config = {
|
|
1162
|
+
maxRetries: options?.maxRetries ?? 3,
|
|
1163
|
+
baseDelayMs: options?.baseDelayMs ?? 1e3,
|
|
1164
|
+
maxDelayMs: options?.maxDelayMs ?? 3e4
|
|
1158
1165
|
};
|
|
1166
|
+
return (url, requestOptions) => executeWithRetry(client, url, requestOptions, config);
|
|
1159
1167
|
}
|
|
1160
1168
|
function sanitizeExternalText(text, maxLength = 2e3) {
|
|
1161
1169
|
let sanitized = text;
|
|
@@ -1739,7 +1747,7 @@ function parseAntiPatterns(content) {
|
|
|
1739
1747
|
}
|
|
1740
1748
|
return patterns;
|
|
1741
1749
|
}
|
|
1742
|
-
var NODE_TYPES, EDGE_TYPES, OBSERVABILITY_TYPES, CURRENT_SCHEMA_VERSION, NODE_STABILITY, GraphNodeSchema, GraphEdgeSchema, POISONED_KEYS, GraphStore, VectorStore, DEFAULT_TTL_MS, PackedSummaryCache, ContextQL, TEST_TYPES, DOC_TYPES, CODE_TYPES, DEFAULT_SKIP_DIRS, SKIP_METHOD_NAMES, FUNCTION_PATTERNS, CLASS_PATTERNS, INTERFACE_PATTERNS, METHOD_PATTERNS, GO_METHOD_PATTERN, VARIABLE_PATTERNS, SUPPORTED_EXTENSIONS, SKIP_EXTENSIONS, CodeIngestor, execFileAsync, GitIngestor, TopologicalLinker, CODE_NODE_TYPES, DOCS_OWNED_BY_OTHER_INGESTORS, KnowledgeIngestor, BUG_TRACK_CATEGORIES, KNOWLEDGE_TRACK_CATEGORIES, ISO_DATE, SolutionBaseSchema, SolutionDocFrontmatterSchema, BUSINESS_KNOWLEDGE_TYPES, GOVERNS_SOURCE_TYPES, CODE_NODE_TYPES2, MEASURABLE_TYPES, STRATEGY_REQUIRED_SECTIONS, STRATEGY_OPTIONAL_SECTIONS, STRATEGY_KNOWN_SECTIONS, STRATEGY_PLACEHOLDER_RE, BusinessKnowledgeIngestor, CODE_NODE_TYPES3, ARCHITECTURE_ADR_H1, DecisionIngestor, REQUIREMENT_SECTIONS, SECTION_HEADING_RE, NUMBERED_ITEM_RE, CODE_NODE_TYPES4, RequirementIngestor, DEFAULT_PATTERNS, DEFAULT_BLOCKLIST, CODE_EXTENSIONS, MermaidParser, D2Parser, PlantUmlParser, DIAGRAM_EXTENSIONS, DiagramParser, HEURISTIC_PATTERNS, SCANNABLE_TYPES, KnowledgeLinker, StructuralDriftDetector, BUSINESS_NODE_TYPES, KnowledgeStagingAggregator, EXT_TO_LANGUAGE, SKIP_EXTENSIONS2, EXTRACTOR_EDGE_TYPE, ExtractionRunner, PATTERNS, TestDescriptionExtractor, EnumConstantExtractor, ValidationRuleExtractor, ApiPathExtractor, ALL_EXTRACTORS, ImageAnalysisExtractor, KNOWLEDGE_NODE_TYPES, SIMILARITY_THRESHOLD, SEVERITY_MAP, ContradictionDetector, KNOWLEDGE_TYPES, CODE_TYPES2, KNOWLEDGE_EDGE_TYPES, CoverageScorer, VALID_BUSINESS_TYPES, DEFAULT_MAX_DOCS, MAX_COLLISION_SUFFIX, KnowledgeDocMaterializer, BUSINESS_NODE_TYPES2, SNAPSHOT_NODE_TYPES, KnowledgePipelineRunner, CODE_NODE_TYPES5, RETRYABLE_STATUSES, SANITIZE_RULES, SyncManager, SUMMARIZE_PROMPT, JiraConnector, SlackConnector, ConfluenceConnector, CIConnector, CONSTRAINT_KEYWORDS, FigmaConnector, MIN_CONTENT_LENGTH, CONCEPT_ITEM_TYPES, MiroConnector, STOP_WORDS, FusionLayer, CODE_NODE_TYPES6, GraphEntropyAdapter, GraphComplexityAdapter, GraphCouplingAdapter, DEFAULT_THRESHOLD, DEFAULT_METRICS, RECOGNIZED_METRICS, GraphAnomalyAdapter, INTENTS, SIGNAL_WEIGHTS, INTENT_SIGNALS, IntentClassifier, INTENT_KEYWORDS, STOP_WORDS2, PASCAL_OR_CAMEL_RE, FILE_PATH_RE, QUOTED_RE, EntityExtractor, EntityResolver, ResponseFormatter, CompositeProbabilityStrategy, DEFAULT_PROBABILITY_FLOOR, DEFAULT_MAX_DEPTH, CascadeSimulator, ENTITY_REQUIRED_INTENTS, classifier, extractor, formatter, PHASE_NODE_TYPES, CODE_NODE_TYPES7, Assembler, GraphConstraintAdapter, DesignIngestor, CODE_PREFIX_LABELS, DesignConstraintAdapter, GraphFeedbackAdapter, DEFAULT_EDGE_TYPES, TaskIndependenceAnalyzer, ConflictPredictor, VERSION;
|
|
1750
|
+
var NODE_TYPES, EDGE_TYPES, OBSERVABILITY_TYPES, CURRENT_SCHEMA_VERSION, NODE_STABILITY, GraphNodeSchema, GraphEdgeSchema, POISONED_KEYS, GraphStore, VectorStore, DEFAULT_TTL_MS, PackedSummaryCache, ContextQL, TEST_TYPES, DOC_TYPES, CODE_TYPES, DEFAULT_SKIP_DIRS, SKIP_METHOD_NAMES, FUNCTION_PATTERNS, CLASS_PATTERNS, INTERFACE_PATTERNS, METHOD_PATTERNS, GO_METHOD_PATTERN, VARIABLE_PATTERNS, SUPPORTED_EXTENSIONS, SKIP_EXTENSIONS, CodeIngestor, execFileAsync, GitIngestor, TopologicalLinker, CODE_NODE_TYPES, DOCS_OWNED_BY_OTHER_INGESTORS, KnowledgeIngestor, BUG_TRACK_CATEGORIES, KNOWLEDGE_TRACK_CATEGORIES, ISO_DATE, SolutionBaseSchema, SolutionDocFrontmatterSchema, BUSINESS_KNOWLEDGE_TYPES, GOVERNS_SOURCE_TYPES, CODE_NODE_TYPES2, MEASURABLE_TYPES, STRATEGY_REQUIRED_SECTIONS, STRATEGY_OPTIONAL_SECTIONS, STRATEGY_KNOWN_SECTIONS, STRATEGY_PLACEHOLDER_RE, BusinessKnowledgeIngestor, CODE_NODE_TYPES3, ARCHITECTURE_ADR_H1, DecisionIngestor, REQUIREMENT_SECTIONS, SECTION_HEADING_RE, NUMBERED_ITEM_RE, CODE_NODE_TYPES4, RequirementIngestor, DEFAULT_PATTERNS, DEFAULT_BLOCKLIST, CODE_EXTENSIONS, MermaidParser, D2Parser, PlantUmlParser, DIAGRAM_EXTENSIONS, DiagramParser, HEURISTIC_PATTERNS, SCANNABLE_TYPES, KnowledgeLinker, StructuralDriftDetector, BUSINESS_NODE_TYPES, KnowledgeStagingAggregator, EXT_TO_LANGUAGE, SKIP_EXTENSIONS2, EXTRACTOR_EDGE_TYPE, ExtractionRunner, PATTERNS, RUST_FN_RE, JAVA_DISPLAY_RE, JAVA_METHOD_RE, TestDescriptionExtractor, TS_ENUM_RE, TS_AS_CONST_RE, TS_UNION_RE, JS_FREEZE_RE, JS_CONST_OBJECT_RE, JS_UPPER_KEY_RE, PY_ENUM_RE, PY_LITERAL_RE, GO_TYPE_RE, GO_CONST_BLOCK_RE, GO_IOTA_RE, GO_TYPED_RE, GO_BARE_RE, RUST_ENUM_RE, JAVA_ENUM_RE, EnumConstantExtractor, ValidationRuleExtractor, ApiPathExtractor, ALL_EXTRACTORS, ImageAnalysisExtractor, KNOWLEDGE_NODE_TYPES, SIMILARITY_THRESHOLD, SEVERITY_MAP, ContradictionDetector, KNOWLEDGE_TYPES, CODE_TYPES2, KNOWLEDGE_EDGE_TYPES, CoverageScorer, VALID_BUSINESS_TYPES, DEFAULT_MAX_DOCS, MAX_COLLISION_SUFFIX, KnowledgeDocMaterializer, BUSINESS_NODE_TYPES2, SNAPSHOT_NODE_TYPES, KnowledgePipelineRunner, CODE_NODE_TYPES5, RETRYABLE_STATUSES, SANITIZE_RULES, SyncManager, SUMMARIZE_PROMPT, JiraConnector, SlackConnector, ConfluenceConnector, CIConnector, CONSTRAINT_KEYWORDS, FigmaConnector, MIN_CONTENT_LENGTH, CONCEPT_ITEM_TYPES, MiroConnector, STOP_WORDS, FusionLayer, CODE_NODE_TYPES6, GraphEntropyAdapter, GraphComplexityAdapter, GraphCouplingAdapter, DEFAULT_THRESHOLD, DEFAULT_METRICS, RECOGNIZED_METRICS, GraphAnomalyAdapter, INTENTS, SIGNAL_WEIGHTS, INTENT_SIGNALS, IntentClassifier, INTENT_KEYWORDS, STOP_WORDS2, PASCAL_OR_CAMEL_RE, FILE_PATH_RE, QUOTED_RE, EntityExtractor, EntityResolver, ResponseFormatter, CompositeProbabilityStrategy, DEFAULT_PROBABILITY_FLOOR, DEFAULT_MAX_DEPTH, CascadeSimulator, ENTITY_REQUIRED_INTENTS, classifier, extractor, formatter, PHASE_NODE_TYPES, CODE_NODE_TYPES7, Assembler, GraphConstraintAdapter, DesignIngestor, CODE_PREFIX_LABELS, DesignConstraintAdapter, GraphFeedbackAdapter, DEFAULT_EDGE_TYPES, TaskIndependenceAnalyzer, ConflictPredictor, VERSION;
|
|
1743
1751
|
var init_dist = __esm({
|
|
1744
1752
|
"../graph/dist/index.mjs"() {
|
|
1745
1753
|
NODE_TYPES = [
|
|
@@ -4622,29 +4630,41 @@ var init_dist = __esm({
|
|
|
4622
4630
|
};
|
|
4623
4631
|
StructuralDriftDetector = class {
|
|
4624
4632
|
detect(current, fresh) {
|
|
4625
|
-
const findings = [];
|
|
4626
4633
|
const currentById = new Map(current.entries.map((e) => [e.id, e]));
|
|
4627
4634
|
const freshById = new Map(fresh.entries.map((e) => [e.id, e]));
|
|
4635
|
+
const findings = [
|
|
4636
|
+
...this.findNew(currentById, freshById),
|
|
4637
|
+
...this.findStale(currentById, freshById),
|
|
4638
|
+
...this.findDrifted(currentById, freshById)
|
|
4639
|
+
];
|
|
4640
|
+
findings.push(...this.findContradicting(fresh.entries, findings));
|
|
4641
|
+
const totalEntries = (/* @__PURE__ */ new Set([...currentById.keys(), ...freshById.keys()])).size;
|
|
4642
|
+
const driftScore = totalEntries > 0 ? findings.length / totalEntries : 0;
|
|
4643
|
+
return { findings, driftScore, summary: this.summarize(findings) };
|
|
4644
|
+
}
|
|
4645
|
+
/** 1. NEW: entries in fresh but not in current */
|
|
4646
|
+
findNew(currentById, freshById) {
|
|
4647
|
+
const findings = [];
|
|
4628
4648
|
for (const [id, entry] of freshById) {
|
|
4629
4649
|
if (!currentById.has(id)) {
|
|
4630
|
-
findings.push({
|
|
4631
|
-
entryId: id,
|
|
4632
|
-
classification: "new",
|
|
4633
|
-
fresh: entry,
|
|
4634
|
-
severity: "low"
|
|
4635
|
-
});
|
|
4650
|
+
findings.push({ entryId: id, classification: "new", fresh: entry, severity: "low" });
|
|
4636
4651
|
}
|
|
4637
4652
|
}
|
|
4653
|
+
return findings;
|
|
4654
|
+
}
|
|
4655
|
+
/** 2. STALE: entries in current but not in fresh */
|
|
4656
|
+
findStale(currentById, freshById) {
|
|
4657
|
+
const findings = [];
|
|
4638
4658
|
for (const [id, entry] of currentById) {
|
|
4639
4659
|
if (!freshById.has(id)) {
|
|
4640
|
-
findings.push({
|
|
4641
|
-
entryId: id,
|
|
4642
|
-
classification: "stale",
|
|
4643
|
-
current: entry,
|
|
4644
|
-
severity: "high"
|
|
4645
|
-
});
|
|
4660
|
+
findings.push({ entryId: id, classification: "stale", current: entry, severity: "high" });
|
|
4646
4661
|
}
|
|
4647
4662
|
}
|
|
4663
|
+
return findings;
|
|
4664
|
+
}
|
|
4665
|
+
/** 3. DRIFTED: entries in both but contentHash differs */
|
|
4666
|
+
findDrifted(currentById, freshById) {
|
|
4667
|
+
const findings = [];
|
|
4648
4668
|
for (const [id, freshEntry] of freshById) {
|
|
4649
4669
|
const currentEntry = currentById.get(id);
|
|
4650
4670
|
if (currentEntry && currentEntry.contentHash !== freshEntry.contentHash) {
|
|
@@ -4657,43 +4677,56 @@ var init_dist = __esm({
|
|
|
4657
4677
|
});
|
|
4658
4678
|
}
|
|
4659
4679
|
}
|
|
4680
|
+
return findings;
|
|
4681
|
+
}
|
|
4682
|
+
/** 4. CONTRADICTING: same entity name from different sources with different content */
|
|
4683
|
+
findContradicting(entries, existing) {
|
|
4684
|
+
const result = [];
|
|
4685
|
+
const alreadyContradicting = new Set(
|
|
4686
|
+
existing.filter((f) => f.classification === "contradicting").map((f) => f.entryId)
|
|
4687
|
+
);
|
|
4688
|
+
for (const [, group] of this.groupByName(entries)) {
|
|
4689
|
+
const finding = this.contradictionForGroup(group, alreadyContradicting);
|
|
4690
|
+
if (finding) {
|
|
4691
|
+
result.push(finding);
|
|
4692
|
+
alreadyContradicting.add(finding.entryId);
|
|
4693
|
+
}
|
|
4694
|
+
}
|
|
4695
|
+
return result;
|
|
4696
|
+
}
|
|
4697
|
+
groupByName(entries) {
|
|
4660
4698
|
const byName = /* @__PURE__ */ new Map();
|
|
4661
|
-
for (const entry of
|
|
4699
|
+
for (const entry of entries) {
|
|
4662
4700
|
const group = byName.get(entry.name) ?? [];
|
|
4663
4701
|
group.push(entry);
|
|
4664
4702
|
byName.set(entry.name, group);
|
|
4665
4703
|
}
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
});
|
|
4682
|
-
break;
|
|
4683
|
-
}
|
|
4684
|
-
}
|
|
4685
|
-
}
|
|
4704
|
+
return byName;
|
|
4705
|
+
}
|
|
4706
|
+
contradictionForGroup(group, alreadyContradicting) {
|
|
4707
|
+
if (group.length <= 1) return void 0;
|
|
4708
|
+
const sources = new Set(group.map((e) => e.source));
|
|
4709
|
+
const hashes = new Set(group.map((e) => e.contentHash));
|
|
4710
|
+
if (sources.size <= 1 || hashes.size <= 1) return void 0;
|
|
4711
|
+
for (const entry of group) {
|
|
4712
|
+
if (!alreadyContradicting.has(entry.id)) {
|
|
4713
|
+
return {
|
|
4714
|
+
entryId: entry.id,
|
|
4715
|
+
classification: "contradicting",
|
|
4716
|
+
fresh: entry,
|
|
4717
|
+
severity: "critical"
|
|
4718
|
+
};
|
|
4686
4719
|
}
|
|
4687
4720
|
}
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4721
|
+
return void 0;
|
|
4722
|
+
}
|
|
4723
|
+
summarize(findings) {
|
|
4724
|
+
return {
|
|
4691
4725
|
new: findings.filter((f) => f.classification === "new").length,
|
|
4692
4726
|
drifted: findings.filter((f) => f.classification === "drifted").length,
|
|
4693
4727
|
stale: findings.filter((f) => f.classification === "stale").length,
|
|
4694
4728
|
contradicting: findings.filter((f) => f.classification === "contradicting").length
|
|
4695
4729
|
};
|
|
4696
|
-
return { findings, driftScore, summary };
|
|
4697
4730
|
}
|
|
4698
4731
|
};
|
|
4699
4732
|
BUSINESS_NODE_TYPES = [
|
|
@@ -4738,6 +4771,29 @@ var init_dist = __esm({
|
|
|
4738
4771
|
return titleMatch ? titleMatch[1].trim() : path9.basename(filePath, ".md");
|
|
4739
4772
|
}
|
|
4740
4773
|
async generateGapReport(knowledgeDir, store) {
|
|
4774
|
+
const { domainDocNames, domainEntryCounts, totalEntries } = await this.collectDocumentedEntries(
|
|
4775
|
+
knowledgeDir,
|
|
4776
|
+
store
|
|
4777
|
+
);
|
|
4778
|
+
if (!store) {
|
|
4779
|
+
return this.buildEntryOnlyReport(domainEntryCounts, totalEntries);
|
|
4780
|
+
}
|
|
4781
|
+
const extractedByDomain = this.collectExtractedByDomain(store);
|
|
4782
|
+
const { domains, totalExtracted, totalGaps } = this.buildDomainCoverage(
|
|
4783
|
+
domainEntryCounts,
|
|
4784
|
+
extractedByDomain,
|
|
4785
|
+
domainDocNames
|
|
4786
|
+
);
|
|
4787
|
+
return {
|
|
4788
|
+
domains,
|
|
4789
|
+
totalEntries,
|
|
4790
|
+
totalExtracted,
|
|
4791
|
+
totalGaps,
|
|
4792
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4793
|
+
};
|
|
4794
|
+
}
|
|
4795
|
+
/** Step 1-2: count `.md` entries per domain, capturing normalized names when a store is present. */
|
|
4796
|
+
async collectDocumentedEntries(knowledgeDir, store) {
|
|
4741
4797
|
const domainDocNames = /* @__PURE__ */ new Map();
|
|
4742
4798
|
const domainEntryCounts = /* @__PURE__ */ new Map();
|
|
4743
4799
|
let totalEntries = 0;
|
|
@@ -4748,33 +4804,41 @@ var init_dist = __esm({
|
|
|
4748
4804
|
const domainPath = path9.join(knowledgeDir, dir.name);
|
|
4749
4805
|
const files = await fs8.readdir(domainPath);
|
|
4750
4806
|
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
domainEntryCounts.set(dir.name, entryCount);
|
|
4807
|
+
totalEntries += mdFiles.length;
|
|
4808
|
+
domainEntryCounts.set(dir.name, mdFiles.length);
|
|
4754
4809
|
if (store) {
|
|
4755
|
-
|
|
4756
|
-
for (const file of mdFiles) {
|
|
4757
|
-
const name = await this.extractDocName(path9.join(domainPath, file));
|
|
4758
|
-
names.push(name.toLowerCase().trim());
|
|
4759
|
-
}
|
|
4760
|
-
domainDocNames.set(dir.name, names);
|
|
4810
|
+
domainDocNames.set(dir.name, await this.extractDocNames(domainPath, mdFiles));
|
|
4761
4811
|
}
|
|
4762
4812
|
}
|
|
4763
4813
|
} catch {
|
|
4764
4814
|
}
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
totalExtracted: 0,
|
|
4774
|
-
totalGaps: 0,
|
|
4775
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4776
|
-
};
|
|
4815
|
+
return { domainDocNames, domainEntryCounts, totalEntries };
|
|
4816
|
+
}
|
|
4817
|
+
/** Extract and normalize the documented title from each markdown file in a domain. */
|
|
4818
|
+
async extractDocNames(domainPath, mdFiles) {
|
|
4819
|
+
const names = [];
|
|
4820
|
+
for (const file of mdFiles) {
|
|
4821
|
+
const name = await this.extractDocName(path9.join(domainPath, file));
|
|
4822
|
+
names.push(name.toLowerCase().trim());
|
|
4777
4823
|
}
|
|
4824
|
+
return names;
|
|
4825
|
+
}
|
|
4826
|
+
/** Step 3: backward-compatible report when no store is available. */
|
|
4827
|
+
buildEntryOnlyReport(domainEntryCounts, totalEntries) {
|
|
4828
|
+
const domains = [];
|
|
4829
|
+
for (const [domain, entryCount] of domainEntryCounts) {
|
|
4830
|
+
domains.push({ domain, entryCount, extractedCount: 0, gapCount: 0, gapEntries: [] });
|
|
4831
|
+
}
|
|
4832
|
+
return {
|
|
4833
|
+
domains,
|
|
4834
|
+
totalEntries,
|
|
4835
|
+
totalExtracted: 0,
|
|
4836
|
+
totalGaps: 0,
|
|
4837
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4838
|
+
};
|
|
4839
|
+
}
|
|
4840
|
+
/** Step 4: query store for all business nodes, group by domain, deduplicate by name. */
|
|
4841
|
+
collectExtractedByDomain(store) {
|
|
4778
4842
|
const extractedByDomain = /* @__PURE__ */ new Map();
|
|
4779
4843
|
for (const nodeType of BUSINESS_NODE_TYPES) {
|
|
4780
4844
|
const nodes = store.findNodes({ type: nodeType });
|
|
@@ -4786,15 +4850,22 @@ var init_dist = __esm({
|
|
|
4786
4850
|
}
|
|
4787
4851
|
}
|
|
4788
4852
|
for (const [domain, nodes] of extractedByDomain) {
|
|
4789
|
-
|
|
4790
|
-
const deduped = nodes.filter((n) => {
|
|
4791
|
-
const key = n.name.toLowerCase().trim();
|
|
4792
|
-
if (seen.has(key)) return false;
|
|
4793
|
-
seen.add(key);
|
|
4794
|
-
return true;
|
|
4795
|
-
});
|
|
4796
|
-
extractedByDomain.set(domain, deduped);
|
|
4853
|
+
extractedByDomain.set(domain, this.dedupeByName(nodes));
|
|
4797
4854
|
}
|
|
4855
|
+
return extractedByDomain;
|
|
4856
|
+
}
|
|
4857
|
+
/** Keep the first occurrence of each normalized name, preserving order. */
|
|
4858
|
+
dedupeByName(nodes) {
|
|
4859
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4860
|
+
return nodes.filter((n) => {
|
|
4861
|
+
const key = n.name.toLowerCase().trim();
|
|
4862
|
+
if (seen.has(key)) return false;
|
|
4863
|
+
seen.add(key);
|
|
4864
|
+
return true;
|
|
4865
|
+
});
|
|
4866
|
+
}
|
|
4867
|
+
/** Step 5: build per-domain coverage with gap analysis and roll up totals. */
|
|
4868
|
+
buildDomainCoverage(domainEntryCounts, extractedByDomain, domainDocNames) {
|
|
4798
4869
|
const allDomains = /* @__PURE__ */ new Set([...domainEntryCounts.keys(), ...extractedByDomain.keys()]);
|
|
4799
4870
|
const domains = [];
|
|
4800
4871
|
let totalExtracted = 0;
|
|
@@ -4805,29 +4876,28 @@ var init_dist = __esm({
|
|
|
4805
4876
|
const extractedCount = extractedNodes.length;
|
|
4806
4877
|
totalExtracted += extractedCount;
|
|
4807
4878
|
const docNames = domainDocNames.get(domain) ?? [];
|
|
4808
|
-
const gapEntries =
|
|
4809
|
-
for (const node of extractedNodes) {
|
|
4810
|
-
const normalizedName = node.name.toLowerCase().trim();
|
|
4811
|
-
if (!docNames.includes(normalizedName)) {
|
|
4812
|
-
gapEntries.push({
|
|
4813
|
-
nodeId: node.id,
|
|
4814
|
-
name: node.name,
|
|
4815
|
-
nodeType: node.type,
|
|
4816
|
-
source: node.metadata?.source ?? "unknown",
|
|
4817
|
-
hasContent: Boolean(node.content && node.content.trim().length >= 10)
|
|
4818
|
-
});
|
|
4819
|
-
}
|
|
4820
|
-
}
|
|
4879
|
+
const gapEntries = this.computeGapEntries(extractedNodes, docNames);
|
|
4821
4880
|
totalGaps += gapEntries.length;
|
|
4822
4881
|
domains.push({ domain, entryCount, extractedCount, gapCount: gapEntries.length, gapEntries });
|
|
4823
4882
|
}
|
|
4824
|
-
return {
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4883
|
+
return { domains, totalExtracted, totalGaps };
|
|
4884
|
+
}
|
|
4885
|
+
/** Collect extracted nodes that have no matching documented name. */
|
|
4886
|
+
computeGapEntries(extractedNodes, docNames) {
|
|
4887
|
+
const gapEntries = [];
|
|
4888
|
+
for (const node of extractedNodes) {
|
|
4889
|
+
const normalizedName = node.name.toLowerCase().trim();
|
|
4890
|
+
if (!docNames.includes(normalizedName)) {
|
|
4891
|
+
gapEntries.push({
|
|
4892
|
+
nodeId: node.id,
|
|
4893
|
+
name: node.name,
|
|
4894
|
+
nodeType: node.type,
|
|
4895
|
+
source: node.metadata?.source ?? "unknown",
|
|
4896
|
+
hasContent: Boolean(node.content && node.content.trim().length >= 10)
|
|
4897
|
+
});
|
|
4898
|
+
}
|
|
4899
|
+
}
|
|
4900
|
+
return gapEntries;
|
|
4831
4901
|
}
|
|
4832
4902
|
async writeGapReport(report) {
|
|
4833
4903
|
const gapsDir = path9.join(this.projectDir, ".harness", "knowledge");
|
|
@@ -5060,6 +5130,9 @@ var init_dist = __esm({
|
|
|
5060
5130
|
/@Test\s*\n\s*(?:public\s+|private\s+|protected\s+)?(?:static\s+)?(?:void|[\w<>]+)\s+(\w+)\s*\(/g
|
|
5061
5131
|
]
|
|
5062
5132
|
};
|
|
5133
|
+
RUST_FN_RE = /(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/;
|
|
5134
|
+
JAVA_DISPLAY_RE = /@DisplayName\s*\(\s*"([^"]+)"\s*\)/;
|
|
5135
|
+
JAVA_METHOD_RE = /^\s*(?:(?:public|private|protected)\s+)?(?:static\s+)?(?:void|[\w<>[\]]+)\s+(\w+)\s*\(/;
|
|
5063
5136
|
TestDescriptionExtractor = class {
|
|
5064
5137
|
name = "test-descriptions";
|
|
5065
5138
|
supportedExtensions = [".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java"];
|
|
@@ -5089,83 +5162,87 @@ var init_dist = __esm({
|
|
|
5089
5162
|
const records = [];
|
|
5090
5163
|
const describeStack = [];
|
|
5091
5164
|
for (let i = 0; i < lines.length; i++) {
|
|
5092
|
-
|
|
5093
|
-
const describeMatch = line.match(/describe\s*\(\s*(['"`])((?:(?!\1).)*)\1/);
|
|
5094
|
-
if (describeMatch) {
|
|
5095
|
-
describeStack.push(describeMatch[2]);
|
|
5096
|
-
}
|
|
5097
|
-
const itMatch = line.match(/(?:it|test)\s*\(\s*(['"`])((?:(?!\1).)*)\1/);
|
|
5098
|
-
if (itMatch) {
|
|
5099
|
-
const testName = itMatch[2];
|
|
5100
|
-
const fullPath = [...describeStack, testName].join(" > ");
|
|
5101
|
-
const patternKey = fullPath;
|
|
5102
|
-
records.push({
|
|
5103
|
-
id: `extracted:test-descriptions:${hash(filePath + ":" + patternKey)}`,
|
|
5104
|
-
extractor: "test-descriptions",
|
|
5105
|
-
language,
|
|
5106
|
-
filePath,
|
|
5107
|
-
line: i + 1,
|
|
5108
|
-
nodeType: "business_rule",
|
|
5109
|
-
name: testName,
|
|
5110
|
-
content: fullPath,
|
|
5111
|
-
confidence: 0.7,
|
|
5112
|
-
metadata: {
|
|
5113
|
-
suite: describeStack.length > 0 ? describeStack[describeStack.length - 1] : void 0,
|
|
5114
|
-
framework: "vitest"
|
|
5115
|
-
}
|
|
5116
|
-
});
|
|
5117
|
-
}
|
|
5118
|
-
if (line.match(/^\s*\}\s*\)\s*;?\s*$/) && describeStack.length > 0) {
|
|
5119
|
-
describeStack.pop();
|
|
5120
|
-
}
|
|
5165
|
+
this.scanJsTsLine(lines[i], i, language, filePath, describeStack, records);
|
|
5121
5166
|
}
|
|
5122
5167
|
return records;
|
|
5123
5168
|
}
|
|
5169
|
+
scanJsTsLine(line, index, language, filePath, describeStack, records) {
|
|
5170
|
+
const describeMatch = line.match(/describe\s*\(\s*(['"`])((?:(?!\1).)*)\1/);
|
|
5171
|
+
if (describeMatch) describeStack.push(describeMatch[2]);
|
|
5172
|
+
const itMatch = line.match(/(?:it|test)\s*\(\s*(['"`])((?:(?!\1).)*)\1/);
|
|
5173
|
+
if (itMatch) {
|
|
5174
|
+
records.push(this.buildJsTsRecord(itMatch[2], index, language, filePath, describeStack));
|
|
5175
|
+
}
|
|
5176
|
+
if (/^\s*\}\s*\)\s*;?\s*$/.test(line) && describeStack.length > 0) describeStack.pop();
|
|
5177
|
+
}
|
|
5178
|
+
buildJsTsRecord(testName, index, language, filePath, describeStack) {
|
|
5179
|
+
const fullPath = [...describeStack, testName].join(" > ");
|
|
5180
|
+
const patternKey = fullPath;
|
|
5181
|
+
return {
|
|
5182
|
+
id: `extracted:test-descriptions:${hash(filePath + ":" + patternKey)}`,
|
|
5183
|
+
extractor: "test-descriptions",
|
|
5184
|
+
language,
|
|
5185
|
+
filePath,
|
|
5186
|
+
line: index + 1,
|
|
5187
|
+
nodeType: "business_rule",
|
|
5188
|
+
name: testName,
|
|
5189
|
+
content: fullPath,
|
|
5190
|
+
confidence: 0.7,
|
|
5191
|
+
metadata: {
|
|
5192
|
+
suite: describeStack.length > 0 ? describeStack[describeStack.length - 1] : void 0,
|
|
5193
|
+
framework: "vitest"
|
|
5194
|
+
}
|
|
5195
|
+
};
|
|
5196
|
+
}
|
|
5124
5197
|
extractPython(_content, filePath, language, lines) {
|
|
5125
5198
|
const records = [];
|
|
5126
5199
|
let currentClass;
|
|
5127
5200
|
for (let i = 0; i < lines.length; i++) {
|
|
5128
5201
|
const line = lines[i];
|
|
5129
5202
|
const classMatch = line.match(/^class\s+(Test\w+)/);
|
|
5130
|
-
if (classMatch)
|
|
5131
|
-
currentClass = classMatch[1];
|
|
5132
|
-
}
|
|
5203
|
+
if (classMatch) currentClass = classMatch[1];
|
|
5133
5204
|
const funcMatch = line.match(/^\s*def\s+(test_\w+)\s*\(/);
|
|
5134
5205
|
if (funcMatch) {
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
if (i + 1 < lines.length) {
|
|
5139
|
-
const nextLine = lines[i + 1].trim();
|
|
5140
|
-
const docMatch = nextLine.match(/^"""(.+?)"""/);
|
|
5141
|
-
if (docMatch) {
|
|
5142
|
-
docstring = docMatch[1];
|
|
5143
|
-
}
|
|
5144
|
-
}
|
|
5145
|
-
const patternKey = currentClass ? `${currentClass}.${testName}` : testName;
|
|
5146
|
-
records.push({
|
|
5147
|
-
id: `extracted:test-descriptions:${hash(filePath + ":" + patternKey)}`,
|
|
5148
|
-
extractor: "test-descriptions",
|
|
5149
|
-
language,
|
|
5150
|
-
filePath,
|
|
5151
|
-
line: i + 1,
|
|
5152
|
-
nodeType: "business_rule",
|
|
5153
|
-
name: docstring ?? humanName,
|
|
5154
|
-
content: patternKey,
|
|
5155
|
-
confidence: docstring ? 0.7 : 0.5,
|
|
5156
|
-
metadata: {
|
|
5157
|
-
suite: currentClass,
|
|
5158
|
-
framework: "pytest",
|
|
5159
|
-
functionName: testName
|
|
5160
|
-
}
|
|
5161
|
-
});
|
|
5162
|
-
}
|
|
5163
|
-
if (currentClass && /^\S/.test(line) && !line.startsWith("class ") && !line.startsWith("#") && line.trim() !== "") {
|
|
5164
|
-
currentClass = void 0;
|
|
5206
|
+
records.push(
|
|
5207
|
+
this.buildPythonRecord(funcMatch[1], i, language, filePath, currentClass, lines)
|
|
5208
|
+
);
|
|
5165
5209
|
}
|
|
5210
|
+
if (this.isPythonClassReset(line, currentClass)) currentClass = void 0;
|
|
5166
5211
|
}
|
|
5167
5212
|
return records;
|
|
5168
5213
|
}
|
|
5214
|
+
isPythonClassReset(line, currentClass) {
|
|
5215
|
+
return Boolean(
|
|
5216
|
+
currentClass && /^\S/.test(line) && !line.startsWith("class ") && !line.startsWith("#") && line.trim() !== ""
|
|
5217
|
+
);
|
|
5218
|
+
}
|
|
5219
|
+
findPythonDocstring(lines, index) {
|
|
5220
|
+
if (index + 1 >= lines.length) return void 0;
|
|
5221
|
+
const nextLine = lines[index + 1].trim();
|
|
5222
|
+
const docMatch = nextLine.match(/^"""(.+?)"""/);
|
|
5223
|
+
return docMatch ? docMatch[1] : void 0;
|
|
5224
|
+
}
|
|
5225
|
+
buildPythonRecord(testName, index, language, filePath, currentClass, lines) {
|
|
5226
|
+
const humanName = testName.replace(/^test_/, "").replace(/_/g, " ");
|
|
5227
|
+
const docstring = this.findPythonDocstring(lines, index);
|
|
5228
|
+
const patternKey = currentClass ? `${currentClass}.${testName}` : testName;
|
|
5229
|
+
return {
|
|
5230
|
+
id: `extracted:test-descriptions:${hash(filePath + ":" + patternKey)}`,
|
|
5231
|
+
extractor: "test-descriptions",
|
|
5232
|
+
language,
|
|
5233
|
+
filePath,
|
|
5234
|
+
line: index + 1,
|
|
5235
|
+
nodeType: "business_rule",
|
|
5236
|
+
name: docstring ?? humanName,
|
|
5237
|
+
content: patternKey,
|
|
5238
|
+
confidence: docstring ? 0.7 : 0.5,
|
|
5239
|
+
metadata: {
|
|
5240
|
+
suite: currentClass,
|
|
5241
|
+
framework: "pytest",
|
|
5242
|
+
functionName: testName
|
|
5243
|
+
}
|
|
5244
|
+
};
|
|
5245
|
+
}
|
|
5169
5246
|
extractGo(_content, filePath, language, lines) {
|
|
5170
5247
|
const records = [];
|
|
5171
5248
|
let currentTest;
|
|
@@ -5214,87 +5291,105 @@ var init_dist = __esm({
|
|
|
5214
5291
|
extractRust(_content, filePath, language, lines) {
|
|
5215
5292
|
const records = [];
|
|
5216
5293
|
for (let i = 0; i < lines.length; i++) {
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
const fnLine = lines[j];
|
|
5221
|
-
const fnMatch = fnLine.match(/(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/);
|
|
5222
|
-
if (fnMatch) {
|
|
5223
|
-
const testName = fnMatch[1];
|
|
5224
|
-
const humanName = testName.replace(/^test_/, "").replace(/_/g, " ");
|
|
5225
|
-
let docComment;
|
|
5226
|
-
if (i > 0) {
|
|
5227
|
-
const prevLine = lines[i - 1].trim();
|
|
5228
|
-
const docMatch = prevLine.match(/^\/\/\/\s*(.+)/);
|
|
5229
|
-
if (docMatch) {
|
|
5230
|
-
docComment = docMatch[1];
|
|
5231
|
-
}
|
|
5232
|
-
}
|
|
5233
|
-
records.push({
|
|
5234
|
-
id: `extracted:test-descriptions:${hash(filePath + ":" + testName)}`,
|
|
5235
|
-
extractor: "test-descriptions",
|
|
5236
|
-
language,
|
|
5237
|
-
filePath,
|
|
5238
|
-
line: j + 1,
|
|
5239
|
-
nodeType: "business_rule",
|
|
5240
|
-
name: docComment ?? humanName,
|
|
5241
|
-
content: testName,
|
|
5242
|
-
confidence: docComment ? 0.7 : 0.5,
|
|
5243
|
-
metadata: { framework: "rust-test" }
|
|
5244
|
-
});
|
|
5245
|
-
break;
|
|
5246
|
-
}
|
|
5247
|
-
}
|
|
5248
|
-
}
|
|
5294
|
+
if (lines[i].trim() !== "#[test]") continue;
|
|
5295
|
+
const record = this.buildRustRecord(lines, i, language, filePath);
|
|
5296
|
+
if (record) records.push(record);
|
|
5249
5297
|
}
|
|
5250
5298
|
return records;
|
|
5251
5299
|
}
|
|
5300
|
+
buildRustRecord(lines, testIdx, language, filePath) {
|
|
5301
|
+
for (let j = testIdx + 1; j < lines.length && j <= testIdx + 3; j++) {
|
|
5302
|
+
const fnMatch = lines[j].match(RUST_FN_RE);
|
|
5303
|
+
if (!fnMatch) continue;
|
|
5304
|
+
const testName = fnMatch[1];
|
|
5305
|
+
const humanName = testName.replace(/^test_/, "").replace(/_/g, " ");
|
|
5306
|
+
const docComment = this.findRustDocComment(lines, testIdx);
|
|
5307
|
+
return {
|
|
5308
|
+
id: `extracted:test-descriptions:${hash(filePath + ":" + testName)}`,
|
|
5309
|
+
extractor: "test-descriptions",
|
|
5310
|
+
language,
|
|
5311
|
+
filePath,
|
|
5312
|
+
line: j + 1,
|
|
5313
|
+
nodeType: "business_rule",
|
|
5314
|
+
name: docComment ?? humanName,
|
|
5315
|
+
content: testName,
|
|
5316
|
+
confidence: docComment ? 0.7 : 0.5,
|
|
5317
|
+
metadata: { framework: "rust-test" }
|
|
5318
|
+
};
|
|
5319
|
+
}
|
|
5320
|
+
return void 0;
|
|
5321
|
+
}
|
|
5322
|
+
findRustDocComment(lines, testIdx) {
|
|
5323
|
+
if (testIdx <= 0) return void 0;
|
|
5324
|
+
const prevLine = lines[testIdx - 1].trim();
|
|
5325
|
+
const docMatch = prevLine.match(/^\/\/\/\s*(.+)/);
|
|
5326
|
+
return docMatch ? docMatch[1] : void 0;
|
|
5327
|
+
}
|
|
5252
5328
|
extractJava(_content, filePath, language, lines) {
|
|
5253
5329
|
const records = [];
|
|
5254
5330
|
for (let i = 0; i < lines.length; i++) {
|
|
5255
|
-
|
|
5256
|
-
const
|
|
5257
|
-
if (
|
|
5258
|
-
let displayName;
|
|
5259
|
-
for (let k = Math.max(0, i - 3); k < i; k++) {
|
|
5260
|
-
const prevLine = lines[k];
|
|
5261
|
-
const dm = prevLine.match(/@DisplayName\s*\(\s*"([^"]+)"\s*\)/);
|
|
5262
|
-
if (dm) displayName = dm[1];
|
|
5263
|
-
}
|
|
5264
|
-
for (let j = i + 1; j < lines.length && j <= i + 5; j++) {
|
|
5265
|
-
const scanLine = lines[j];
|
|
5266
|
-
const adjacentDisplay = scanLine.match(/@DisplayName\s*\(\s*"([^"]+)"\s*\)/);
|
|
5267
|
-
if (adjacentDisplay) {
|
|
5268
|
-
displayName = adjacentDisplay[1];
|
|
5269
|
-
continue;
|
|
5270
|
-
}
|
|
5271
|
-
const methodMatch = scanLine.match(
|
|
5272
|
-
/^\s*(?:(?:public|private|protected)\s+)?(?:static\s+)?(?:void|[\w<>[\]]+)\s+(\w+)\s*\(/
|
|
5273
|
-
);
|
|
5274
|
-
if (methodMatch) {
|
|
5275
|
-
const methodName = methodMatch[1];
|
|
5276
|
-
const name = displayName ?? methodName;
|
|
5277
|
-
const patternKey = displayName ?? methodName;
|
|
5278
|
-
records.push({
|
|
5279
|
-
id: `extracted:test-descriptions:${hash(filePath + ":" + patternKey)}`,
|
|
5280
|
-
extractor: "test-descriptions",
|
|
5281
|
-
language,
|
|
5282
|
-
filePath,
|
|
5283
|
-
line: j + 1,
|
|
5284
|
-
nodeType: "business_rule",
|
|
5285
|
-
name,
|
|
5286
|
-
content: patternKey,
|
|
5287
|
-
confidence: displayName ? 0.7 : 0.5,
|
|
5288
|
-
metadata: { framework: "junit5" }
|
|
5289
|
-
});
|
|
5290
|
-
break;
|
|
5291
|
-
}
|
|
5292
|
-
}
|
|
5293
|
-
}
|
|
5331
|
+
if (!/@Test\s*$/.test(lines[i])) continue;
|
|
5332
|
+
const record = this.buildJavaRecord(lines, i, language, filePath);
|
|
5333
|
+
if (record) records.push(record);
|
|
5294
5334
|
}
|
|
5295
5335
|
return records;
|
|
5296
5336
|
}
|
|
5337
|
+
buildJavaRecord(lines, testIdx, language, filePath) {
|
|
5338
|
+
let displayName = this.findJavaDisplayNameBefore(lines, testIdx);
|
|
5339
|
+
for (let j = testIdx + 1; j < lines.length && j <= testIdx + 5; j++) {
|
|
5340
|
+
const scanLine = lines[j];
|
|
5341
|
+
const adjacentDisplay = scanLine.match(JAVA_DISPLAY_RE);
|
|
5342
|
+
if (adjacentDisplay) {
|
|
5343
|
+
displayName = adjacentDisplay[1];
|
|
5344
|
+
continue;
|
|
5345
|
+
}
|
|
5346
|
+
const methodMatch = scanLine.match(JAVA_METHOD_RE);
|
|
5347
|
+
if (methodMatch) {
|
|
5348
|
+
return this.buildJavaRecordFromMethod(methodMatch[1], displayName, j, language, filePath);
|
|
5349
|
+
}
|
|
5350
|
+
}
|
|
5351
|
+
return void 0;
|
|
5352
|
+
}
|
|
5353
|
+
findJavaDisplayNameBefore(lines, testIdx) {
|
|
5354
|
+
let displayName;
|
|
5355
|
+
for (let k = Math.max(0, testIdx - 3); k < testIdx; k++) {
|
|
5356
|
+
const dm = lines[k].match(JAVA_DISPLAY_RE);
|
|
5357
|
+
if (dm) displayName = dm[1];
|
|
5358
|
+
}
|
|
5359
|
+
return displayName;
|
|
5360
|
+
}
|
|
5361
|
+
buildJavaRecordFromMethod(methodName, displayName, index, language, filePath) {
|
|
5362
|
+
const name = displayName ?? methodName;
|
|
5363
|
+
const patternKey = displayName ?? methodName;
|
|
5364
|
+
return {
|
|
5365
|
+
id: `extracted:test-descriptions:${hash(filePath + ":" + patternKey)}`,
|
|
5366
|
+
extractor: "test-descriptions",
|
|
5367
|
+
language,
|
|
5368
|
+
filePath,
|
|
5369
|
+
line: index + 1,
|
|
5370
|
+
nodeType: "business_rule",
|
|
5371
|
+
name,
|
|
5372
|
+
content: patternKey,
|
|
5373
|
+
confidence: displayName ? 0.7 : 0.5,
|
|
5374
|
+
metadata: { framework: "junit5" }
|
|
5375
|
+
};
|
|
5376
|
+
}
|
|
5297
5377
|
};
|
|
5378
|
+
TS_ENUM_RE = /(?:export\s+)?enum\s+(\w+)/;
|
|
5379
|
+
TS_AS_CONST_RE = /(?:export\s+)?const\s+(\w+)\s*=\s*\{/;
|
|
5380
|
+
TS_UNION_RE = /(?:export\s+)?type\s+(\w+)\s*=\s*(['"`][\w]+['"`](?:\s*\|\s*['"`][\w]+['"`])+)/;
|
|
5381
|
+
JS_FREEZE_RE = /(?:export\s+)?const\s+(\w+)\s*=\s*Object\.freeze\s*\(\s*\{/;
|
|
5382
|
+
JS_CONST_OBJECT_RE = /(?:export\s+)?const\s+([A-Z][A-Z_\d]*)\s*=\s*\{/;
|
|
5383
|
+
JS_UPPER_KEY_RE = /^[A-Z][A-Z_\d]*$/;
|
|
5384
|
+
PY_ENUM_RE = /^class\s+(\w+)\s*\(\s*(?:str\s*,\s*)?(?:Enum|StrEnum|IntEnum|Flag|IntFlag)\s*\)/;
|
|
5385
|
+
PY_LITERAL_RE = /(\w+)\s*=\s*Literal\s*\[([^\]]+)\]/;
|
|
5386
|
+
GO_TYPE_RE = /^type\s+(\w+)\s+(?:int|string|uint|int32|int64|uint32|uint64)/;
|
|
5387
|
+
GO_CONST_BLOCK_RE = /^const\s*\(/;
|
|
5388
|
+
GO_IOTA_RE = /^(\w+)\s+(\w+)\s*=\s*iota/;
|
|
5389
|
+
GO_TYPED_RE = /^(\w+)\s+(\w+)\s*=\s*"[^"]*"/;
|
|
5390
|
+
GO_BARE_RE = /^(\w+)\s*$/;
|
|
5391
|
+
RUST_ENUM_RE = /^(?:pub\s+)?enum\s+(\w+)/;
|
|
5392
|
+
JAVA_ENUM_RE = /(?:public\s+|private\s+|protected\s+)?enum\s+(\w+)/;
|
|
5298
5393
|
EnumConstantExtractor = class {
|
|
5299
5394
|
name = "enum-constants";
|
|
5300
5395
|
supportedExtensions = [".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java"];
|
|
@@ -5318,213 +5413,235 @@ var init_dist = __esm({
|
|
|
5318
5413
|
const records = [];
|
|
5319
5414
|
const lines = content.split("\n");
|
|
5320
5415
|
for (let i = 0; i < lines.length; i++) {
|
|
5321
|
-
const
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
id: `extracted:enum-constants:${hash(filePath + ":" + enumName)}`,
|
|
5328
|
-
extractor: "enum-constants",
|
|
5329
|
-
language,
|
|
5330
|
-
filePath,
|
|
5331
|
-
line: i + 1,
|
|
5332
|
-
nodeType: "business_term",
|
|
5333
|
-
name: enumName,
|
|
5334
|
-
content: `enum ${enumName} { ${members.join(", ")} }`,
|
|
5335
|
-
confidence: 0.8,
|
|
5336
|
-
metadata: { kind: "enum", members }
|
|
5337
|
-
});
|
|
5338
|
-
}
|
|
5339
|
-
const constMatch = line.match(/(?:export\s+)?const\s+(\w+)\s*=\s*\{/);
|
|
5340
|
-
if (constMatch && content.includes("as const")) {
|
|
5341
|
-
const blockEnd = this.findClosingBrace(lines, i);
|
|
5342
|
-
const block = lines.slice(i, blockEnd + 1).join("\n");
|
|
5343
|
-
if (block.includes("as const")) {
|
|
5344
|
-
const constName = constMatch[1];
|
|
5345
|
-
const members = this.collectObjectKeys(lines, i + 1);
|
|
5346
|
-
records.push({
|
|
5347
|
-
id: `extracted:enum-constants:${hash(filePath + ":" + constName)}`,
|
|
5348
|
-
extractor: "enum-constants",
|
|
5349
|
-
language,
|
|
5350
|
-
filePath,
|
|
5351
|
-
line: i + 1,
|
|
5352
|
-
nodeType: "business_term",
|
|
5353
|
-
name: constName,
|
|
5354
|
-
content: `const ${constName} = { ${members.join(", ")} } as const`,
|
|
5355
|
-
confidence: 0.8,
|
|
5356
|
-
metadata: { kind: "as-const", members }
|
|
5357
|
-
});
|
|
5358
|
-
}
|
|
5359
|
-
}
|
|
5360
|
-
const unionMatch = line.match(
|
|
5361
|
-
/(?:export\s+)?type\s+(\w+)\s*=\s*(['"`][\w]+['"`](?:\s*\|\s*['"`][\w]+['"`])+)/
|
|
5362
|
-
);
|
|
5363
|
-
if (unionMatch) {
|
|
5364
|
-
const typeName = unionMatch[1];
|
|
5365
|
-
const values = unionMatch[2].split("|").map((v) => v.trim().replace(/['"`]/g, ""));
|
|
5366
|
-
records.push({
|
|
5367
|
-
id: `extracted:enum-constants:${hash(filePath + ":" + typeName)}`,
|
|
5368
|
-
extractor: "enum-constants",
|
|
5369
|
-
language,
|
|
5370
|
-
filePath,
|
|
5371
|
-
line: i + 1,
|
|
5372
|
-
nodeType: "business_term",
|
|
5373
|
-
name: typeName,
|
|
5374
|
-
content: `type ${typeName} = ${values.map((v) => `'${v}'`).join(" | ")}`,
|
|
5375
|
-
confidence: 0.7,
|
|
5376
|
-
metadata: { kind: "union-type", members: values }
|
|
5377
|
-
});
|
|
5378
|
-
}
|
|
5416
|
+
const enumRecord = this.matchTsEnum(lines, i, filePath, language);
|
|
5417
|
+
if (enumRecord) records.push(enumRecord);
|
|
5418
|
+
const asConstRecord = this.matchTsAsConst(content, lines, i, filePath, language);
|
|
5419
|
+
if (asConstRecord) records.push(asConstRecord);
|
|
5420
|
+
const unionRecord = this.matchTsUnion(lines, i, filePath, language);
|
|
5421
|
+
if (unionRecord) records.push(unionRecord);
|
|
5379
5422
|
}
|
|
5380
5423
|
return records;
|
|
5381
5424
|
}
|
|
5425
|
+
matchTsEnum(lines, i, filePath, language) {
|
|
5426
|
+
const enumMatch = lines[i].match(TS_ENUM_RE);
|
|
5427
|
+
if (!enumMatch) return void 0;
|
|
5428
|
+
const enumName = enumMatch[1];
|
|
5429
|
+
const members = this.collectEnumMembers(lines, i + 1);
|
|
5430
|
+
return {
|
|
5431
|
+
id: `extracted:enum-constants:${hash(filePath + ":" + enumName)}`,
|
|
5432
|
+
extractor: "enum-constants",
|
|
5433
|
+
language,
|
|
5434
|
+
filePath,
|
|
5435
|
+
line: i + 1,
|
|
5436
|
+
nodeType: "business_term",
|
|
5437
|
+
name: enumName,
|
|
5438
|
+
content: `enum ${enumName} { ${members.join(", ")} }`,
|
|
5439
|
+
confidence: 0.8,
|
|
5440
|
+
metadata: { kind: "enum", members }
|
|
5441
|
+
};
|
|
5442
|
+
}
|
|
5443
|
+
matchTsAsConst(content, lines, i, filePath, language) {
|
|
5444
|
+
const constMatch = lines[i].match(TS_AS_CONST_RE);
|
|
5445
|
+
if (!constMatch || !content.includes("as const")) return void 0;
|
|
5446
|
+
const blockEnd = this.findClosingBrace(lines, i);
|
|
5447
|
+
const block = lines.slice(i, blockEnd + 1).join("\n");
|
|
5448
|
+
if (!block.includes("as const")) return void 0;
|
|
5449
|
+
const constName = constMatch[1];
|
|
5450
|
+
const members = this.collectObjectKeys(lines, i + 1);
|
|
5451
|
+
return {
|
|
5452
|
+
id: `extracted:enum-constants:${hash(filePath + ":" + constName)}`,
|
|
5453
|
+
extractor: "enum-constants",
|
|
5454
|
+
language,
|
|
5455
|
+
filePath,
|
|
5456
|
+
line: i + 1,
|
|
5457
|
+
nodeType: "business_term",
|
|
5458
|
+
name: constName,
|
|
5459
|
+
content: `const ${constName} = { ${members.join(", ")} } as const`,
|
|
5460
|
+
confidence: 0.8,
|
|
5461
|
+
metadata: { kind: "as-const", members }
|
|
5462
|
+
};
|
|
5463
|
+
}
|
|
5464
|
+
matchTsUnion(lines, i, filePath, language) {
|
|
5465
|
+
const unionMatch = lines[i].match(TS_UNION_RE);
|
|
5466
|
+
if (!unionMatch) return void 0;
|
|
5467
|
+
const typeName = unionMatch[1];
|
|
5468
|
+
const values = unionMatch[2].split("|").map((v) => v.trim().replace(/['"`]/g, ""));
|
|
5469
|
+
return {
|
|
5470
|
+
id: `extracted:enum-constants:${hash(filePath + ":" + typeName)}`,
|
|
5471
|
+
extractor: "enum-constants",
|
|
5472
|
+
language,
|
|
5473
|
+
filePath,
|
|
5474
|
+
line: i + 1,
|
|
5475
|
+
nodeType: "business_term",
|
|
5476
|
+
name: typeName,
|
|
5477
|
+
content: `type ${typeName} = ${values.map((v) => `'${v}'`).join(" | ")}`,
|
|
5478
|
+
confidence: 0.7,
|
|
5479
|
+
metadata: { kind: "union-type", members: values }
|
|
5480
|
+
};
|
|
5481
|
+
}
|
|
5382
5482
|
extractJavaScript(content, filePath, language) {
|
|
5383
5483
|
const records = [];
|
|
5384
5484
|
const lines = content.split("\n");
|
|
5385
5485
|
for (let i = 0; i < lines.length; i++) {
|
|
5386
|
-
const
|
|
5387
|
-
const freezeMatch = line.match(/(?:export\s+)?const\s+(\w+)\s*=\s*Object\.freeze\s*\(\s*\{/);
|
|
5486
|
+
const freezeMatch = lines[i].match(JS_FREEZE_RE);
|
|
5388
5487
|
if (freezeMatch) {
|
|
5389
|
-
|
|
5390
|
-
const members = this.collectObjectKeys(lines, i + 1);
|
|
5391
|
-
records.push({
|
|
5392
|
-
id: `extracted:enum-constants:${hash(filePath + ":" + name)}`,
|
|
5393
|
-
extractor: "enum-constants",
|
|
5394
|
-
language,
|
|
5395
|
-
filePath,
|
|
5396
|
-
line: i + 1,
|
|
5397
|
-
nodeType: "business_term",
|
|
5398
|
-
name,
|
|
5399
|
-
content: `const ${name} = Object.freeze({ ${members.join(", ")} })`,
|
|
5400
|
-
confidence: 0.8,
|
|
5401
|
-
metadata: { kind: "frozen-object", members }
|
|
5402
|
-
});
|
|
5488
|
+
records.push(this.buildJsFreezeRecord(freezeMatch[1], lines, i, filePath, language));
|
|
5403
5489
|
}
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
const members = this.collectObjectKeys(lines, i + 1);
|
|
5408
|
-
if (members.length > 0 && members.every((m) => /^[A-Z][A-Z_\d]*$/.test(m))) {
|
|
5409
|
-
records.push({
|
|
5410
|
-
id: `extracted:enum-constants:${hash(filePath + ":" + name)}`,
|
|
5411
|
-
extractor: "enum-constants",
|
|
5412
|
-
language,
|
|
5413
|
-
filePath,
|
|
5414
|
-
line: i + 1,
|
|
5415
|
-
nodeType: "business_term",
|
|
5416
|
-
name,
|
|
5417
|
-
content: `const ${name} = { ${members.join(", ")} }`,
|
|
5418
|
-
confidence: 0.6,
|
|
5419
|
-
metadata: { kind: "const-object", members }
|
|
5420
|
-
});
|
|
5421
|
-
}
|
|
5490
|
+
if (!freezeMatch) {
|
|
5491
|
+
const constRecord = this.matchJsConstObject(lines, i, filePath, language);
|
|
5492
|
+
if (constRecord) records.push(constRecord);
|
|
5422
5493
|
}
|
|
5423
5494
|
}
|
|
5424
5495
|
return records;
|
|
5425
5496
|
}
|
|
5497
|
+
buildJsFreezeRecord(name, lines, i, filePath, language) {
|
|
5498
|
+
const members = this.collectObjectKeys(lines, i + 1);
|
|
5499
|
+
return {
|
|
5500
|
+
id: `extracted:enum-constants:${hash(filePath + ":" + name)}`,
|
|
5501
|
+
extractor: "enum-constants",
|
|
5502
|
+
language,
|
|
5503
|
+
filePath,
|
|
5504
|
+
line: i + 1,
|
|
5505
|
+
nodeType: "business_term",
|
|
5506
|
+
name,
|
|
5507
|
+
content: `const ${name} = Object.freeze({ ${members.join(", ")} })`,
|
|
5508
|
+
confidence: 0.8,
|
|
5509
|
+
metadata: { kind: "frozen-object", members }
|
|
5510
|
+
};
|
|
5511
|
+
}
|
|
5512
|
+
matchJsConstObject(lines, i, filePath, language) {
|
|
5513
|
+
const constMatch = lines[i].match(JS_CONST_OBJECT_RE);
|
|
5514
|
+
if (!constMatch) return void 0;
|
|
5515
|
+
const name = constMatch[1];
|
|
5516
|
+
const members = this.collectObjectKeys(lines, i + 1);
|
|
5517
|
+
if (members.length === 0 || !members.every((m) => JS_UPPER_KEY_RE.test(m))) return void 0;
|
|
5518
|
+
return {
|
|
5519
|
+
id: `extracted:enum-constants:${hash(filePath + ":" + name)}`,
|
|
5520
|
+
extractor: "enum-constants",
|
|
5521
|
+
language,
|
|
5522
|
+
filePath,
|
|
5523
|
+
line: i + 1,
|
|
5524
|
+
nodeType: "business_term",
|
|
5525
|
+
name,
|
|
5526
|
+
content: `const ${name} = { ${members.join(", ")} }`,
|
|
5527
|
+
confidence: 0.6,
|
|
5528
|
+
metadata: { kind: "const-object", members }
|
|
5529
|
+
};
|
|
5530
|
+
}
|
|
5426
5531
|
extractPython(content, filePath, language) {
|
|
5427
5532
|
const records = [];
|
|
5428
5533
|
const lines = content.split("\n");
|
|
5429
5534
|
for (let i = 0; i < lines.length; i++) {
|
|
5430
|
-
const
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
);
|
|
5434
|
-
if (enumMatch) {
|
|
5435
|
-
const enumName = enumMatch[1];
|
|
5436
|
-
const members = this.collectPythonEnumMembers(lines, i + 1);
|
|
5437
|
-
records.push({
|
|
5438
|
-
id: `extracted:enum-constants:${hash(filePath + ":" + enumName)}`,
|
|
5439
|
-
extractor: "enum-constants",
|
|
5440
|
-
language,
|
|
5441
|
-
filePath,
|
|
5442
|
-
line: i + 1,
|
|
5443
|
-
nodeType: "business_term",
|
|
5444
|
-
name: enumName,
|
|
5445
|
-
content: `class ${enumName}(Enum) { ${members.join(", ")} }`,
|
|
5446
|
-
confidence: 0.8,
|
|
5447
|
-
metadata: { kind: "enum", members }
|
|
5448
|
-
});
|
|
5449
|
-
}
|
|
5450
|
-
const literalMatch = line.match(/(\w+)\s*=\s*Literal\s*\[([^\]]+)\]/);
|
|
5451
|
-
if (literalMatch) {
|
|
5452
|
-
const typeName = literalMatch[1];
|
|
5453
|
-
const values = literalMatch[2].split(",").map((v) => v.trim().replace(/["']/g, ""));
|
|
5454
|
-
records.push({
|
|
5455
|
-
id: `extracted:enum-constants:${hash(filePath + ":" + typeName)}`,
|
|
5456
|
-
extractor: "enum-constants",
|
|
5457
|
-
language,
|
|
5458
|
-
filePath,
|
|
5459
|
-
line: i + 1,
|
|
5460
|
-
nodeType: "business_term",
|
|
5461
|
-
name: typeName,
|
|
5462
|
-
content: `${typeName} = Literal[${values.map((v) => `"${v}"`).join(", ")}]`,
|
|
5463
|
-
confidence: 0.7,
|
|
5464
|
-
metadata: { kind: "literal-type", members: values }
|
|
5465
|
-
});
|
|
5466
|
-
}
|
|
5535
|
+
const enumRecord = this.matchPythonEnum(lines, i, filePath, language);
|
|
5536
|
+
if (enumRecord) records.push(enumRecord);
|
|
5537
|
+
const literalRecord = this.matchPythonLiteral(lines, i, filePath, language);
|
|
5538
|
+
if (literalRecord) records.push(literalRecord);
|
|
5467
5539
|
}
|
|
5468
5540
|
return records;
|
|
5469
5541
|
}
|
|
5542
|
+
matchPythonEnum(lines, i, filePath, language) {
|
|
5543
|
+
const enumMatch = lines[i].match(PY_ENUM_RE);
|
|
5544
|
+
if (!enumMatch) return void 0;
|
|
5545
|
+
const enumName = enumMatch[1];
|
|
5546
|
+
const members = this.collectPythonEnumMembers(lines, i + 1);
|
|
5547
|
+
return {
|
|
5548
|
+
id: `extracted:enum-constants:${hash(filePath + ":" + enumName)}`,
|
|
5549
|
+
extractor: "enum-constants",
|
|
5550
|
+
language,
|
|
5551
|
+
filePath,
|
|
5552
|
+
line: i + 1,
|
|
5553
|
+
nodeType: "business_term",
|
|
5554
|
+
name: enumName,
|
|
5555
|
+
content: `class ${enumName}(Enum) { ${members.join(", ")} }`,
|
|
5556
|
+
confidence: 0.8,
|
|
5557
|
+
metadata: { kind: "enum", members }
|
|
5558
|
+
};
|
|
5559
|
+
}
|
|
5560
|
+
matchPythonLiteral(lines, i, filePath, language) {
|
|
5561
|
+
const literalMatch = lines[i].match(PY_LITERAL_RE);
|
|
5562
|
+
if (!literalMatch) return void 0;
|
|
5563
|
+
const typeName = literalMatch[1];
|
|
5564
|
+
const values = literalMatch[2].split(",").map((v) => v.trim().replace(/["']/g, ""));
|
|
5565
|
+
return {
|
|
5566
|
+
id: `extracted:enum-constants:${hash(filePath + ":" + typeName)}`,
|
|
5567
|
+
extractor: "enum-constants",
|
|
5568
|
+
language,
|
|
5569
|
+
filePath,
|
|
5570
|
+
line: i + 1,
|
|
5571
|
+
nodeType: "business_term",
|
|
5572
|
+
name: typeName,
|
|
5573
|
+
content: `${typeName} = Literal[${values.map((v) => `"${v}"`).join(", ")}]`,
|
|
5574
|
+
confidence: 0.7,
|
|
5575
|
+
metadata: { kind: "literal-type", members: values }
|
|
5576
|
+
};
|
|
5577
|
+
}
|
|
5470
5578
|
extractGo(content, filePath, language) {
|
|
5471
5579
|
const records = [];
|
|
5472
5580
|
const lines = content.split("\n");
|
|
5473
5581
|
for (let i = 0; i < lines.length; i++) {
|
|
5474
5582
|
const line = lines[i];
|
|
5475
|
-
const typeMatch = line.match(
|
|
5583
|
+
const typeMatch = line.match(GO_TYPE_RE);
|
|
5476
5584
|
if (typeMatch) {
|
|
5477
5585
|
}
|
|
5478
|
-
const constBlockMatch = line.match(
|
|
5586
|
+
const constBlockMatch = line.match(GO_CONST_BLOCK_RE);
|
|
5479
5587
|
if (constBlockMatch) {
|
|
5480
|
-
const
|
|
5481
|
-
|
|
5482
|
-
for (let j = i + 1; j < lines.length; j++) {
|
|
5483
|
-
const constLine = lines[j].trim();
|
|
5484
|
-
if (constLine === ")") break;
|
|
5485
|
-
if (constLine === "" || constLine.startsWith("//")) continue;
|
|
5486
|
-
const iotaMatch = constLine.match(/^(\w+)\s+(\w+)\s*=\s*iota/);
|
|
5487
|
-
if (iotaMatch) {
|
|
5488
|
-
typeName = iotaMatch[2];
|
|
5489
|
-
consts.push(iotaMatch[1]);
|
|
5490
|
-
continue;
|
|
5491
|
-
}
|
|
5492
|
-
const typedMatch = constLine.match(/^(\w+)\s+(\w+)\s*=\s*"[^"]*"/);
|
|
5493
|
-
if (typedMatch) {
|
|
5494
|
-
typeName = typeName ?? typedMatch[2];
|
|
5495
|
-
consts.push(typedMatch[1]);
|
|
5496
|
-
continue;
|
|
5497
|
-
}
|
|
5498
|
-
const bareMatch = constLine.match(/^(\w+)\s*$/);
|
|
5499
|
-
if (bareMatch) {
|
|
5500
|
-
consts.push(bareMatch[1]);
|
|
5501
|
-
}
|
|
5502
|
-
}
|
|
5503
|
-
if (consts.length > 0) {
|
|
5504
|
-
const name = typeName ?? consts[0];
|
|
5505
|
-
records.push({
|
|
5506
|
-
id: `extracted:enum-constants:${hash(filePath + ":" + name)}`,
|
|
5507
|
-
extractor: "enum-constants",
|
|
5508
|
-
language,
|
|
5509
|
-
filePath,
|
|
5510
|
-
line: i + 1,
|
|
5511
|
-
nodeType: "business_term",
|
|
5512
|
-
name,
|
|
5513
|
-
content: `const ( ${consts.join(", ")} )`,
|
|
5514
|
-
confidence: typeName ? 0.8 : 0.6,
|
|
5515
|
-
metadata: { kind: typeName ? "typed-const" : "const-block", members: consts }
|
|
5516
|
-
});
|
|
5517
|
-
}
|
|
5588
|
+
const record = this.buildGoConstBlockRecord(lines, i, filePath, language);
|
|
5589
|
+
if (record) records.push(record);
|
|
5518
5590
|
}
|
|
5519
5591
|
}
|
|
5520
5592
|
return records;
|
|
5521
5593
|
}
|
|
5594
|
+
buildGoConstBlockRecord(lines, i, filePath, language) {
|
|
5595
|
+
const { consts, typeName } = this.collectGoConsts(lines, i + 1);
|
|
5596
|
+
if (consts.length === 0) return void 0;
|
|
5597
|
+
const name = typeName ?? consts[0];
|
|
5598
|
+
return {
|
|
5599
|
+
id: `extracted:enum-constants:${hash(filePath + ":" + name)}`,
|
|
5600
|
+
extractor: "enum-constants",
|
|
5601
|
+
language,
|
|
5602
|
+
filePath,
|
|
5603
|
+
line: i + 1,
|
|
5604
|
+
nodeType: "business_term",
|
|
5605
|
+
name,
|
|
5606
|
+
content: `const ( ${consts.join(", ")} )`,
|
|
5607
|
+
confidence: typeName ? 0.8 : 0.6,
|
|
5608
|
+
metadata: { kind: typeName ? "typed-const" : "const-block", members: consts }
|
|
5609
|
+
};
|
|
5610
|
+
}
|
|
5611
|
+
collectGoConsts(lines, startLine) {
|
|
5612
|
+
const consts = [];
|
|
5613
|
+
let typeName;
|
|
5614
|
+
for (let j = startLine; j < lines.length; j++) {
|
|
5615
|
+
const constLine = lines[j].trim();
|
|
5616
|
+
if (constLine === ")") break;
|
|
5617
|
+
if (constLine === "" || constLine.startsWith("//")) continue;
|
|
5618
|
+
const parsed = this.parseGoConstLine(constLine);
|
|
5619
|
+
if (!parsed) continue;
|
|
5620
|
+
typeName = this.resolveGoTypeName(typeName, parsed);
|
|
5621
|
+
consts.push(parsed.name);
|
|
5622
|
+
}
|
|
5623
|
+
return { consts, typeName };
|
|
5624
|
+
}
|
|
5625
|
+
parseGoConstLine(constLine) {
|
|
5626
|
+
const iotaMatch = constLine.match(GO_IOTA_RE);
|
|
5627
|
+
if (iotaMatch) return { name: iotaMatch[1], typeName: iotaMatch[2], overwriteType: true };
|
|
5628
|
+
const typedMatch = constLine.match(GO_TYPED_RE);
|
|
5629
|
+
if (typedMatch) return { name: typedMatch[1], typeName: typedMatch[2], overwriteType: false };
|
|
5630
|
+
const bareMatch = constLine.match(GO_BARE_RE);
|
|
5631
|
+
if (bareMatch) return { name: bareMatch[1] };
|
|
5632
|
+
return void 0;
|
|
5633
|
+
}
|
|
5634
|
+
resolveGoTypeName(current, parsed) {
|
|
5635
|
+
if (parsed.overwriteType) return parsed.typeName;
|
|
5636
|
+
if (parsed.typeName !== void 0 && current === void 0) return parsed.typeName;
|
|
5637
|
+
return current;
|
|
5638
|
+
}
|
|
5522
5639
|
extractRust(content, filePath, language) {
|
|
5523
5640
|
const records = [];
|
|
5524
5641
|
const lines = content.split("\n");
|
|
5525
5642
|
for (let i = 0; i < lines.length; i++) {
|
|
5526
5643
|
const line = lines[i];
|
|
5527
|
-
const enumMatch = line.match(
|
|
5644
|
+
const enumMatch = line.match(RUST_ENUM_RE);
|
|
5528
5645
|
if (enumMatch) {
|
|
5529
5646
|
const enumName = enumMatch[1];
|
|
5530
5647
|
const members = this.collectRustEnumVariants(lines, i + 1);
|
|
@@ -5549,7 +5666,7 @@ var init_dist = __esm({
|
|
|
5549
5666
|
const lines = content.split("\n");
|
|
5550
5667
|
for (let i = 0; i < lines.length; i++) {
|
|
5551
5668
|
const line = lines[i];
|
|
5552
|
-
const enumMatch = line.match(
|
|
5669
|
+
const enumMatch = line.match(JAVA_ENUM_RE);
|
|
5553
5670
|
if (enumMatch) {
|
|
5554
5671
|
const enumName = enumMatch[1];
|
|
5555
5672
|
const members = this.collectJavaEnumConstants(lines, i + 1);
|
|
@@ -5597,10 +5714,7 @@ var init_dist = __esm({
|
|
|
5597
5714
|
for (let i = startLine; i < lines.length; i++) {
|
|
5598
5715
|
for (const ch of lines[i]) {
|
|
5599
5716
|
if (ch === "{") depth++;
|
|
5600
|
-
if (ch === "}")
|
|
5601
|
-
depth--;
|
|
5602
|
-
if (depth === 0) return i;
|
|
5603
|
-
}
|
|
5717
|
+
else if (ch === "}" && --depth === 0) return i;
|
|
5604
5718
|
}
|
|
5605
5719
|
}
|
|
5606
5720
|
return lines.length - 1;
|