structx 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/benchmark/baseline.d.ts +10 -0
  2. package/dist/benchmark/baseline.d.ts.map +1 -0
  3. package/dist/benchmark/baseline.js +84 -0
  4. package/dist/benchmark/baseline.js.map +1 -0
  5. package/dist/benchmark/questions.d.ts +2 -0
  6. package/dist/benchmark/questions.d.ts.map +1 -0
  7. package/dist/benchmark/questions.js +14 -0
  8. package/dist/benchmark/questions.js.map +1 -0
  9. package/dist/benchmark/reporter.d.ts +8 -0
  10. package/dist/benchmark/reporter.d.ts.map +1 -0
  11. package/dist/benchmark/reporter.js +120 -0
  12. package/dist/benchmark/reporter.js.map +1 -0
  13. package/dist/benchmark/runner.d.ts +24 -0
  14. package/dist/benchmark/runner.d.ts.map +1 -0
  15. package/dist/benchmark/runner.js +110 -0
  16. package/dist/benchmark/runner.js.map +1 -0
  17. package/dist/cli.d.ts +3 -0
  18. package/dist/cli.d.ts.map +1 -0
  19. package/dist/cli.js +753 -0
  20. package/dist/cli.js.map +1 -0
  21. package/dist/config.d.ts +15 -0
  22. package/dist/config.d.ts.map +1 -0
  23. package/dist/config.js +83 -0
  24. package/dist/config.js.map +1 -0
  25. package/dist/db/connection.d.ts +5 -0
  26. package/dist/db/connection.d.ts.map +1 -0
  27. package/dist/db/connection.js +89 -0
  28. package/dist/db/connection.js.map +1 -0
  29. package/dist/db/queries.d.ts +122 -0
  30. package/dist/db/queries.d.ts.map +1 -0
  31. package/dist/db/queries.js +191 -0
  32. package/dist/db/queries.js.map +1 -0
  33. package/dist/db/schema.sql +85 -0
  34. package/dist/ingest/differ.d.ts +13 -0
  35. package/dist/ingest/differ.d.ts.map +1 -0
  36. package/dist/ingest/differ.js +63 -0
  37. package/dist/ingest/differ.js.map +1 -0
  38. package/dist/ingest/parser.d.ts +15 -0
  39. package/dist/ingest/parser.d.ts.map +1 -0
  40. package/dist/ingest/parser.js +154 -0
  41. package/dist/ingest/parser.js.map +1 -0
  42. package/dist/ingest/relationships.d.ts +8 -0
  43. package/dist/ingest/relationships.d.ts.map +1 -0
  44. package/dist/ingest/relationships.js +93 -0
  45. package/dist/ingest/relationships.js.map +1 -0
  46. package/dist/ingest/scanner.d.ts +2 -0
  47. package/dist/ingest/scanner.d.ts.map +1 -0
  48. package/dist/ingest/scanner.js +67 -0
  49. package/dist/ingest/scanner.js.map +1 -0
  50. package/dist/instructions/claude.md +41 -0
  51. package/dist/instructions/copilot.md +39 -0
  52. package/dist/instructions/cursor.md +39 -0
  53. package/dist/instructions/generic.md +41 -0
  54. package/dist/query/answerer.d.ts +9 -0
  55. package/dist/query/answerer.d.ts.map +1 -0
  56. package/dist/query/answerer.js +46 -0
  57. package/dist/query/answerer.js.map +1 -0
  58. package/dist/query/classifier.d.ts +10 -0
  59. package/dist/query/classifier.d.ts.map +1 -0
  60. package/dist/query/classifier.js +60 -0
  61. package/dist/query/classifier.js.map +1 -0
  62. package/dist/query/context-builder.d.ts +3 -0
  63. package/dist/query/context-builder.d.ts.map +1 -0
  64. package/dist/query/context-builder.js +104 -0
  65. package/dist/query/context-builder.js.map +1 -0
  66. package/dist/query/retriever.d.ts +23 -0
  67. package/dist/query/retriever.d.ts.map +1 -0
  68. package/dist/query/retriever.js +142 -0
  69. package/dist/query/retriever.js.map +1 -0
  70. package/dist/semantic/analyzer.d.ts +15 -0
  71. package/dist/semantic/analyzer.d.ts.map +1 -0
  72. package/dist/semantic/analyzer.js +179 -0
  73. package/dist/semantic/analyzer.js.map +1 -0
  74. package/dist/semantic/cost.d.ts +11 -0
  75. package/dist/semantic/cost.d.ts.map +1 -0
  76. package/dist/semantic/cost.js +31 -0
  77. package/dist/semantic/cost.js.map +1 -0
  78. package/dist/semantic/prompt.d.ts +11 -0
  79. package/dist/semantic/prompt.d.ts.map +1 -0
  80. package/dist/semantic/prompt.js +71 -0
  81. package/dist/semantic/prompt.js.map +1 -0
  82. package/dist/semantic/validator.d.ts +15 -0
  83. package/dist/semantic/validator.d.ts.map +1 -0
  84. package/dist/semantic/validator.js +95 -0
  85. package/dist/semantic/validator.js.map +1 -0
  86. package/dist/utils/logger.d.ts +9 -0
  87. package/dist/utils/logger.d.ts.map +1 -0
  88. package/dist/utils/logger.js +48 -0
  89. package/dist/utils/logger.js.map +1 -0
  90. package/dist/utils/tokens.d.ts +3 -0
  91. package/dist/utils/tokens.d.ts.map +1 -0
  92. package/dist/utils/tokens.js +21 -0
  93. package/dist/utils/tokens.js.map +1 -0
  94. package/package.json +39 -0
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.analyzeBatch = analyzeBatch;
7
+ exports.rebuildSearchIndex = rebuildSearchIndex;
8
+ const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
9
+ const queries_1 = require("../db/queries");
10
+ const prompt_1 = require("./prompt");
11
+ const validator_1 = require("./validator");
12
+ const tokens_1 = require("../utils/tokens");
13
+ const logger_1 = require("../utils/logger");
14
+ async function analyzeBatch(db, queueItems, model, apiKey) {
15
+ const client = new sdk_1.default({ apiKey });
16
+ const result = { analyzed: 0, cached: 0, failed: 0, totalInputTokens: 0, totalOutputTokens: 0, totalCost: 0 };
17
+ // Build prompt functions from queue items
18
+ const promptFunctions = [];
19
+ const functionMap = new Map();
20
+ for (const item of queueItems) {
21
+ const fn = (0, queries_1.getFunctionById)(db, item.function_id);
22
+ if (!fn) {
23
+ (0, queries_1.updateAnalysisStatus)(db, item.id, 'failed');
24
+ result.failed++;
25
+ continue;
26
+ }
27
+ // Get file path for location
28
+ const file = db.prepare('SELECT path FROM files WHERE id = ?').get(fn.file_id);
29
+ const location = file ? `${file.path}:${fn.start_line}` : `unknown:${fn.start_line}`;
30
+ // Get calls
31
+ const callees = (0, queries_1.getCallees)(db, fn.id);
32
+ const callers = (0, queries_1.getCallersByName)(db, fn.name);
33
+ promptFunctions.push({
34
+ function_name: fn.name,
35
+ location,
36
+ signature: fn.signature,
37
+ code: fn.body,
38
+ calls: callees.map(c => c.callee_name),
39
+ called_by: callers.map(c => {
40
+ const callerFn = (0, queries_1.getFunctionById)(db, c.caller_function_id);
41
+ return callerFn?.name || 'unknown';
42
+ }),
43
+ });
44
+ functionMap.set(fn.name, { queueId: item.id, functionId: fn.id });
45
+ }
46
+ if (promptFunctions.length === 0)
47
+ return result;
48
+ const prompt = (0, prompt_1.buildBatchPrompt)(promptFunctions);
49
+ const promptHash = (0, prompt_1.hashPrompt)(prompt);
50
+ // Check cache for each function
51
+ const uncachedFunctions = [];
52
+ const cachedResults = [];
53
+ for (const pf of promptFunctions) {
54
+ const mapping = functionMap.get(pf.function_name);
55
+ const cached = (0, queries_1.getCachedResponse)(db, mapping.functionId, promptHash);
56
+ if (cached) {
57
+ try {
58
+ const parsed = JSON.parse(cached.response_json);
59
+ cachedResults.push(parsed);
60
+ (0, queries_1.updateAnalysisStatus)(db, mapping.queueId, 'done');
61
+ applySemanticResult(db, mapping.functionId, parsed);
62
+ result.cached++;
63
+ }
64
+ catch {
65
+ uncachedFunctions.push(pf);
66
+ }
67
+ }
68
+ else {
69
+ uncachedFunctions.push(pf);
70
+ }
71
+ }
72
+ // If everything was cached, done
73
+ if (uncachedFunctions.length === 0) {
74
+ return result;
75
+ }
76
+ // Build prompt for uncached functions only
77
+ const batchPrompt = (0, prompt_1.buildBatchPrompt)(uncachedFunctions);
78
+ const batchPromptHash = (0, prompt_1.hashPrompt)(batchPrompt);
79
+ // Call LLM
80
+ let responseText;
81
+ let inputTokens = 0;
82
+ let outputTokens = 0;
83
+ try {
84
+ const response = await client.messages.create({
85
+ model,
86
+ max_tokens: uncachedFunctions.length * 200,
87
+ messages: [{ role: 'user', content: batchPrompt }],
88
+ });
89
+ responseText = response.content
90
+ .filter(block => block.type === 'text')
91
+ .map(block => block.text)
92
+ .join('');
93
+ inputTokens = response.usage?.input_tokens ?? 0;
94
+ outputTokens = response.usage?.output_tokens ?? 0;
95
+ result.totalInputTokens += inputTokens;
96
+ result.totalOutputTokens += outputTokens;
97
+ result.totalCost += (0, tokens_1.estimateCost)(model, inputTokens, outputTokens);
98
+ }
99
+ catch (err) {
100
+ logger_1.logger.error(`LLM API call failed: ${err.message}`);
101
+ for (const pf of uncachedFunctions) {
102
+ const mapping = functionMap.get(pf.function_name);
103
+ if (mapping) {
104
+ (0, queries_1.updateAnalysisStatus)(db, mapping.queueId, 'failed');
105
+ result.failed++;
106
+ }
107
+ }
108
+ return result;
109
+ }
110
+ // Validate response
111
+ let validation = (0, validator_1.validateSemanticResponse)(responseText);
112
+ // Retry once on failure
113
+ if (!validation.valid && validation.results.length === 0) {
114
+ logger_1.logger.warn(`Validation failed, retrying. Errors: ${validation.errors.join('; ')}`);
115
+ try {
116
+ const retryResponse = await client.messages.create({
117
+ model,
118
+ max_tokens: uncachedFunctions.length * 200,
119
+ messages: [
120
+ { role: 'user', content: batchPrompt },
121
+ { role: 'assistant', content: responseText },
122
+ { role: 'user', content: `Your previous response had JSON errors: ${validation.errors.join('; ')}. Please respond with ONLY a valid JSON array.` },
123
+ ],
124
+ });
125
+ const retryText = retryResponse.content
126
+ .filter(block => block.type === 'text')
127
+ .map(block => block.text)
128
+ .join('');
129
+ result.totalInputTokens += retryResponse.usage?.input_tokens ?? 0;
130
+ result.totalOutputTokens += retryResponse.usage?.output_tokens ?? 0;
131
+ result.totalCost += (0, tokens_1.estimateCost)(model, retryResponse.usage?.input_tokens ?? 0, retryResponse.usage?.output_tokens ?? 0);
132
+ validation = (0, validator_1.validateSemanticResponse)(retryText);
133
+ if (validation.valid || validation.results.length > 0) {
134
+ responseText = retryText;
135
+ }
136
+ }
137
+ catch (retryErr) {
138
+ logger_1.logger.error(`Retry failed: ${retryErr.message}`);
139
+ }
140
+ }
141
+ // Apply results
142
+ for (const semanticResult of validation.results) {
143
+ const mapping = functionMap.get(semanticResult.function_name);
144
+ if (!mapping) {
145
+ logger_1.logger.warn(`No mapping found for function: ${semanticResult.function_name}`);
146
+ continue;
147
+ }
148
+ applySemanticResult(db, mapping.functionId, semanticResult);
149
+ (0, queries_1.updateAnalysisStatus)(db, mapping.queueId, 'done');
150
+ // Cache the result
151
+ (0, queries_1.insertCachedResponse)(db, mapping.functionId, batchPromptHash, model, inputTokens, outputTokens, result.totalCost, JSON.stringify(semanticResult));
152
+ result.analyzed++;
153
+ }
154
+ // Mark any unmatched as failed
155
+ for (const pf of uncachedFunctions) {
156
+ const mapping = functionMap.get(pf.function_name);
157
+ if (!mapping)
158
+ continue;
159
+ const matched = validation.results.some(r => r.function_name === pf.function_name);
160
+ if (!matched) {
161
+ (0, queries_1.updateAnalysisStatus)(db, mapping.queueId, 'failed');
162
+ result.failed++;
163
+ }
164
+ }
165
+ return result;
166
+ }
167
+ function applySemanticResult(db, functionId, result) {
168
+ (0, queries_1.updateSemanticFields)(db, functionId, {
169
+ purpose: result.purpose,
170
+ behavior_summary: result.behavior,
171
+ side_effects_json: JSON.stringify(result.side_effects),
172
+ domain: result.domain,
173
+ complexity: result.complexity,
174
+ });
175
+ }
176
+ function rebuildSearchIndex(db) {
177
+ (0, queries_1.rebuildFtsIndex)(db);
178
+ }
179
+ //# sourceMappingURL=analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../src/semantic/analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export interface CostEstimate {
2
+ totalFunctions: number;
3
+ batches: number;
4
+ estimatedInputTokens: number;
5
+ estimatedOutputTokens: number;
6
+ estimatedCost: number;
7
+ model: string;
8
+ }
9
+ export declare function estimateAnalysisCost(functionCount: number, batchSize: number, model: string): CostEstimate;
10
+ export declare function formatCostEstimate(estimate: CostEstimate): string;
11
+ //# sourceMappingURL=cost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../../src/semantic/cost.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,YAAY,CAoBd;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAOjE"}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.estimateAnalysisCost = estimateAnalysisCost;
4
+ exports.formatCostEstimate = formatCostEstimate;
5
+ const tokens_1 = require("../utils/tokens");
6
+ function estimateAnalysisCost(functionCount, batchSize, model) {
7
+ const batches = Math.ceil(functionCount / batchSize);
8
+ // ~400 input tokens per function + 200 overhead per batch
9
+ const inputTokensPerBatch = batchSize * 400 + 200;
10
+ const estimatedInputTokens = batches * inputTokensPerBatch;
11
+ // ~100 output tokens per function
12
+ const estimatedOutputTokens = functionCount * 100;
13
+ const estimatedCost = (0, tokens_1.estimateCost)(model, estimatedInputTokens, estimatedOutputTokens);
14
+ return {
15
+ totalFunctions: functionCount,
16
+ batches,
17
+ estimatedInputTokens,
18
+ estimatedOutputTokens,
19
+ estimatedCost,
20
+ model,
21
+ };
22
+ }
23
+ function formatCostEstimate(estimate) {
24
+ return [
25
+ `Functions to analyze: ${estimate.totalFunctions}`,
26
+ `Batches: ${estimate.batches}`,
27
+ `Estimated tokens: ~${(estimate.estimatedInputTokens + estimate.estimatedOutputTokens).toLocaleString()} total`,
28
+ `Estimated cost: $${estimate.estimatedCost.toFixed(4)} (using ${estimate.model})`,
29
+ ].join('\n');
30
+ }
31
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.js","sourceRoot":"","sources":["../../src/semantic/cost.ts"],"names":[],"mappings":";;AAWA,oDAwBC;AAED,gDAOC;AA5CD,4CAA+D;AAW/D,SAAgB,oBAAoB,CAClC,aAAqB,EACrB,SAAiB,EACjB,KAAa;IAEb,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;IAErD,0DAA0D;IAC1D,MAAM,mBAAmB,GAAG,SAAS,GAAG,GAAG,GAAG,GAAG,CAAC;IAClD,MAAM,oBAAoB,GAAG,OAAO,GAAG,mBAAmB,CAAC;IAE3D,kCAAkC;IAClC,MAAM,qBAAqB,GAAG,aAAa,GAAG,GAAG,CAAC;IAElD,MAAM,aAAa,GAAG,IAAA,qBAAY,EAAC,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,CAAC,CAAC;IAEvF,OAAO;QACL,cAAc,EAAE,aAAa;QAC7B,OAAO;QACP,oBAAoB;QACpB,qBAAqB;QACrB,aAAa;QACb,KAAK;KACN,CAAC;AACJ,CAAC;AAED,SAAgB,kBAAkB,CAAC,QAAsB;IACvD,OAAO;QACL,yBAAyB,QAAQ,CAAC,cAAc,EAAE;QAClD,YAAY,QAAQ,CAAC,OAAO,EAAE;QAC9B,sBAAsB,CAAC,QAAQ,CAAC,oBAAoB,GAAG,QAAQ,CAAC,qBAAqB,CAAC,CAAC,cAAc,EAAE,QAAQ;QAC/G,oBAAoB,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,QAAQ,CAAC,KAAK,GAAG;KAClF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface PromptFunction {
2
+ function_name: string;
3
+ location: string;
4
+ signature: string;
5
+ code: string;
6
+ calls: string[];
7
+ called_by: string[];
8
+ }
9
+ export declare function buildBatchPrompt(functions: PromptFunction[]): string;
10
+ export declare function hashPrompt(prompt: string): string;
11
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/semantic/prompt.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,MAAM,CA6BpE;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD"}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.buildBatchPrompt = buildBatchPrompt;
37
+ exports.hashPrompt = hashPrompt;
38
+ const crypto = __importStar(require("crypto"));
39
+ function buildBatchPrompt(functions) {
40
+ const functionsBlock = functions.map((fn, i) => `
41
+ Function ${i + 1}: ${fn.function_name}
42
+ Location: ${fn.location}
43
+ Signature: ${fn.signature}
44
+ Code:
45
+ \`\`\`typescript
46
+ ${fn.code}
47
+ \`\`\`
48
+ Context:
49
+ - Calls: ${fn.calls.length > 0 ? fn.calls.join(', ') : 'none'}
50
+ - Called by: ${fn.called_by.length > 0 ? fn.called_by.join(', ') : 'none'}
51
+ `).join('\n---\n');
52
+ return `Analyze the following TypeScript functions. For each function, extract structured metadata.
53
+
54
+ ${functionsBlock}
55
+
56
+ Respond ONLY with a JSON array, no markdown, no explanation:
57
+ [
58
+ {
59
+ "function_name": "exact_name_from_above",
60
+ "purpose": "One sentence describing what this function does",
61
+ "side_effects": ["list of side effects like DB writes, network calls, console output"],
62
+ "behavior": "2-3 sentence description of how the function works step by step",
63
+ "domain": "one of: authentication, database, validation, routing, middleware, utility, logging, session, crypto, ui, api, config, testing, other",
64
+ "complexity": "low | medium | high"
65
+ }
66
+ ]`;
67
+ }
68
+ function hashPrompt(prompt) {
69
+ return crypto.createHash('sha256').update(prompt).digest('hex');
70
+ }
71
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/semantic/prompt.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYA,4CA6BC;AAED,gCAEC;AA5CD,+CAAiC;AAWjC,SAAgB,gBAAgB,CAAC,SAA2B;IAC1D,MAAM,cAAc,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;WACvC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,aAAa;YACzB,EAAE,CAAC,QAAQ;aACV,EAAE,CAAC,SAAS;;;EAGvB,EAAE,CAAC,IAAI;;;WAGE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM;eAC9C,EAAE,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM;CACxE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAEjB,OAAO;;EAEP,cAAc;;;;;;;;;;;;EAYd,CAAC;AACH,CAAC;AAED,SAAgB,UAAU,CAAC,MAAc;IACvC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,15 @@
1
+ export interface SemanticResult {
2
+ function_name: string;
3
+ purpose: string;
4
+ side_effects: string[];
5
+ behavior: string;
6
+ domain: string;
7
+ complexity: string;
8
+ }
9
+ export interface ValidationResult {
10
+ valid: boolean;
11
+ results: SemanticResult[];
12
+ errors: string[];
13
+ }
14
+ export declare function validateSemanticResponse(responseText: string): ValidationResult;
15
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/semantic/validator.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG,gBAAgB,CAuF/E"}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateSemanticResponse = validateSemanticResponse;
4
+ const VALID_DOMAINS = new Set([
5
+ 'authentication', 'database', 'validation', 'routing', 'middleware',
6
+ 'utility', 'logging', 'session', 'crypto', 'ui', 'api', 'config',
7
+ 'testing', 'other',
8
+ ]);
9
+ const VALID_COMPLEXITY = new Set(['low', 'medium', 'high']);
10
+ function validateSemanticResponse(responseText) {
11
+ const errors = [];
12
+ // Try to extract JSON from the response
13
+ let parsed;
14
+ try {
15
+ // Handle cases where LLM wraps in markdown code blocks
16
+ const cleaned = responseText
17
+ .replace(/^```json?\s*/m, '')
18
+ .replace(/```\s*$/m, '')
19
+ .trim();
20
+ parsed = JSON.parse(cleaned);
21
+ }
22
+ catch (e) {
23
+ return { valid: false, results: [], errors: [`JSON parse error: ${e.message}`] };
24
+ }
25
+ if (!Array.isArray(parsed)) {
26
+ return { valid: false, results: [], errors: ['Response is not a JSON array'] };
27
+ }
28
+ const results = [];
29
+ const required = ['function_name', 'purpose', 'side_effects', 'behavior', 'domain', 'complexity'];
30
+ for (let i = 0; i < parsed.length; i++) {
31
+ const item = parsed[i];
32
+ // Check required fields
33
+ const missing = required.filter(f => !(f in item));
34
+ if (missing.length > 0) {
35
+ errors.push(`Item ${i}: missing fields: ${missing.join(', ')}`);
36
+ continue;
37
+ }
38
+ // Validate types
39
+ if (typeof item.function_name !== 'string' || !item.function_name.trim()) {
40
+ errors.push(`Item ${i}: function_name must be a non-empty string`);
41
+ continue;
42
+ }
43
+ if (typeof item.purpose !== 'string') {
44
+ errors.push(`Item ${i}: purpose must be a string`);
45
+ continue;
46
+ }
47
+ if (!Array.isArray(item.side_effects)) {
48
+ // Auto-fix: wrap in array if it's a string
49
+ if (typeof item.side_effects === 'string') {
50
+ item.side_effects = item.side_effects ? [item.side_effects] : [];
51
+ }
52
+ else {
53
+ errors.push(`Item ${i}: side_effects must be an array`);
54
+ continue;
55
+ }
56
+ }
57
+ if (typeof item.behavior !== 'string') {
58
+ errors.push(`Item ${i}: behavior must be a string`);
59
+ continue;
60
+ }
61
+ // Normalize domain
62
+ const domain = item.domain?.toLowerCase().trim() || 'other';
63
+ if (!VALID_DOMAINS.has(domain)) {
64
+ item.domain = 'other';
65
+ }
66
+ else {
67
+ item.domain = domain;
68
+ }
69
+ // Normalize complexity
70
+ const complexity = item.complexity?.toLowerCase().trim() || 'medium';
71
+ if (!VALID_COMPLEXITY.has(complexity)) {
72
+ item.complexity = 'medium';
73
+ }
74
+ else {
75
+ item.complexity = complexity;
76
+ }
77
+ results.push({
78
+ function_name: item.function_name.trim(),
79
+ purpose: sanitizeText(item.purpose),
80
+ side_effects: item.side_effects.map((s) => sanitizeText(String(s))),
81
+ behavior: sanitizeText(item.behavior),
82
+ domain: item.domain,
83
+ complexity: item.complexity,
84
+ });
85
+ }
86
+ return {
87
+ valid: errors.length === 0 && results.length > 0,
88
+ results,
89
+ errors,
90
+ };
91
+ }
92
+ function sanitizeText(text) {
93
+ return text.replace(/\s+/g, ' ').trim();
94
+ }
95
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/semantic/validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
2
+ export declare function setLogLevel(level: LogLevel): void;
3
+ export declare const logger: {
4
+ debug(message: string, data?: Record<string, unknown>): void;
5
+ info(message: string, data?: Record<string, unknown>): void;
6
+ warn(message: string, data?: Record<string, unknown>): void;
7
+ error(message: string, data?: Record<string, unknown>): void;
8
+ };
9
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAW3D,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAEjD;AAeD,eAAO,MAAM,MAAM;mBACF,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;kBAM9C,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;kBAM7C,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;mBAM5C,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAK7D,CAAC"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logger = void 0;
4
+ exports.setLogLevel = setLogLevel;
5
+ const LOG_LEVELS = {
6
+ debug: 0,
7
+ info: 1,
8
+ warn: 2,
9
+ error: 3,
10
+ };
11
+ let currentLevel = 'info';
12
+ function setLogLevel(level) {
13
+ currentLevel = level;
14
+ }
15
+ function shouldLog(level) {
16
+ return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
17
+ }
18
+ function formatMessage(level, message, data) {
19
+ const timestamp = new Date().toISOString();
20
+ const base = `[${timestamp}] [${level.toUpperCase()}] ${message}`;
21
+ if (data && Object.keys(data).length > 0) {
22
+ return `${base} ${JSON.stringify(data)}`;
23
+ }
24
+ return base;
25
+ }
26
+ exports.logger = {
27
+ debug(message, data) {
28
+ if (shouldLog('debug')) {
29
+ console.debug(formatMessage('debug', message, data));
30
+ }
31
+ },
32
+ info(message, data) {
33
+ if (shouldLog('info')) {
34
+ console.log(formatMessage('info', message, data));
35
+ }
36
+ },
37
+ warn(message, data) {
38
+ if (shouldLog('warn')) {
39
+ console.warn(formatMessage('warn', message, data));
40
+ }
41
+ },
42
+ error(message, data) {
43
+ if (shouldLog('error')) {
44
+ console.error(formatMessage('error', message, data));
45
+ }
46
+ },
47
+ };
48
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":";;;AAWA,kCAEC;AAXD,MAAM,UAAU,GAA6B;IAC3C,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CACT,CAAC;AAEF,IAAI,YAAY,GAAa,MAAM,CAAC;AAEpC,SAAgB,WAAW,CAAC,KAAe;IACzC,YAAY,GAAG,KAAK,CAAC;AACvB,CAAC;AAED,SAAS,SAAS,CAAC,KAAe;IAChC,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,aAAa,CAAC,KAAe,EAAE,OAAe,EAAE,IAA8B;IACrF,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAI,SAAS,MAAM,KAAK,CAAC,WAAW,EAAE,KAAK,OAAO,EAAE,CAAC;IAClE,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,OAAO,GAAG,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAEY,QAAA,MAAM,GAAG;IACpB,KAAK,CAAC,OAAe,EAAE,IAA8B;QACnD,IAAI,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,IAA8B;QAClD,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,IAA8B;QAClD,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAA8B;QACnD,IAAI,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function estimateTokens(text: string): number;
2
+ export declare function estimateCost(model: string, inputTokens: number, outputTokens: number): number;
3
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/utils/tokens.ts"],"names":[],"mappings":"AAGA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAQD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,CAKR"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ // Simple token estimation without external dependencies.
3
+ // Rough heuristic: ~4 characters per token for English/code.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.estimateTokens = estimateTokens;
6
+ exports.estimateCost = estimateCost;
7
+ function estimateTokens(text) {
8
+ return Math.ceil(text.length / 4);
9
+ }
10
+ // Pricing per million tokens (as of 2025)
11
+ const PRICING = {
12
+ 'claude-haiku-4-5-20251001': { input: 0.80, output: 4.00 },
13
+ 'claude-sonnet-4-5-20250929': { input: 3.00, output: 15.00 },
14
+ };
15
+ function estimateCost(model, inputTokens, outputTokens) {
16
+ const price = PRICING[model] ?? { input: 1.0, output: 5.0 };
17
+ const inputCost = (inputTokens / 1_000_000) * price.input;
18
+ const outputCost = (outputTokens / 1_000_000) * price.output;
19
+ return inputCost + outputCost;
20
+ }
21
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/utils/tokens.ts"],"names":[],"mappings":";AAAA,yDAAyD;AACzD,6DAA6D;;AAE7D,wCAEC;AAQD,oCASC;AAnBD,SAAgB,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,0CAA0C;AAC1C,MAAM,OAAO,GAAsD;IACjE,2BAA2B,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAC1D,4BAA4B,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE;CAC7D,CAAC;AAEF,SAAgB,YAAY,CAC1B,KAAa,EACb,WAAmB,EACnB,YAAoB;IAEpB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IAC5D,MAAM,SAAS,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1D,MAAM,UAAU,GAAG,CAAC,YAAY,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IAC7D,OAAO,SAAS,GAAG,UAAU,CAAC;AAChC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "structx",
3
+ "version": "1.0.0",
4
+ "main": "dist/cli.js",
5
+ "bin": {
6
+ "structx": "dist/cli.js"
7
+ },
8
+ "files": [
9
+ "dist",
10
+ "README.md"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc && node scripts/copy-assets.js",
14
+ "dev": "tsx src/cli.ts",
15
+ "test": "echo \"Error: no test specified\" && exit 1"
16
+ },
17
+ "keywords": [
18
+ "code-intelligence",
19
+ "typescript",
20
+ "ast",
21
+ "llm"
22
+ ],
23
+ "author": "",
24
+ "license": "ISC",
25
+ "description": "Graph-powered code intelligence CLI for TypeScript",
26
+ "dependencies": {
27
+ "@anthropic-ai/sdk": "^0.74.0",
28
+ "better-sqlite3": "^12.6.2",
29
+ "commander": "^14.0.3",
30
+ "dotenv": "^17.2.4",
31
+ "ts-morph": "^27.0.2"
32
+ },
33
+ "devDependencies": {
34
+ "@types/better-sqlite3": "^7.6.13",
35
+ "@types/node": "^25.2.3",
36
+ "tsx": "^4.21.0",
37
+ "typescript": "^5.9.3"
38
+ }
39
+ }