codestrate 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -101
- package/dist/constants.d.ts +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +54 -4
- package/dist/constants.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +198 -119
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +0 -0
- package/dist/install.d.ts.map +0 -0
- package/dist/install.js +2 -2
- package/dist/install.js.map +1 -1
- package/dist/profiles.d.ts +28 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +89 -0
- package/dist/profiles.js.map +1 -0
- package/dist/schemas/index.d.ts +1441 -126
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +221 -10
- package/dist/schemas/index.js.map +1 -1
- package/dist/security/guard.d.ts +15 -2
- package/dist/security/guard.d.ts.map +1 -1
- package/dist/security/guard.js +42 -8
- package/dist/security/guard.js.map +1 -1
- package/dist/services/code-chunker.d.ts +50 -0
- package/dist/services/code-chunker.d.ts.map +1 -0
- package/dist/services/code-chunker.js +148 -0
- package/dist/services/code-chunker.js.map +1 -0
- package/dist/services/code-searcher.d.ts +6 -2
- package/dist/services/code-searcher.d.ts.map +1 -1
- package/dist/services/code-searcher.js +111 -17
- package/dist/services/code-searcher.js.map +1 -1
- package/dist/services/context-builder.d.ts +0 -11
- package/dist/services/context-builder.d.ts.map +1 -1
- package/dist/services/context-builder.js +74 -128
- package/dist/services/context-builder.js.map +1 -1
- package/dist/services/embedding-runtime.d.ts +41 -0
- package/dist/services/embedding-runtime.d.ts.map +1 -0
- package/dist/services/embedding-runtime.js +636 -0
- package/dist/services/embedding-runtime.js.map +1 -0
- package/dist/services/embedding.d.ts +79 -0
- package/dist/services/embedding.d.ts.map +1 -0
- package/dist/services/embedding.js +257 -0
- package/dist/services/embedding.js.map +1 -0
- package/dist/services/index-state.d.ts +74 -0
- package/dist/services/index-state.d.ts.map +1 -0
- package/dist/services/index-state.js +151 -0
- package/dist/services/index-state.js.map +1 -0
- package/dist/services/index-worker.d.ts +60 -0
- package/dist/services/index-worker.d.ts.map +1 -0
- package/dist/services/index-worker.js +182 -0
- package/dist/services/index-worker.js.map +1 -0
- package/dist/services/logger.d.ts +48 -0
- package/dist/services/logger.d.ts.map +1 -0
- package/dist/services/logger.js +106 -0
- package/dist/services/logger.js.map +1 -0
- package/dist/services/memory-store.d.ts +9 -7
- package/dist/services/memory-store.d.ts.map +1 -1
- package/dist/services/memory-store.js +93 -7
- package/dist/services/memory-store.js.map +1 -1
- package/dist/services/repository-parser.d.ts +0 -0
- package/dist/services/repository-parser.d.ts.map +0 -0
- package/dist/services/repository-parser.js +0 -0
- package/dist/services/repository-parser.js.map +0 -0
- package/dist/services/symbol-indexer.d.ts +0 -0
- package/dist/services/symbol-indexer.d.ts.map +1 -1
- package/dist/services/symbol-indexer.js +25 -13
- package/dist/services/symbol-indexer.js.map +1 -1
- package/dist/services/tree-sitter.d.ts +0 -0
- package/dist/services/tree-sitter.d.ts.map +0 -0
- package/dist/services/tree-sitter.js +0 -0
- package/dist/services/tree-sitter.js.map +0 -0
- package/dist/services/validation-runner.d.ts +0 -0
- package/dist/services/validation-runner.d.ts.map +1 -1
- package/dist/services/validation-runner.js +9 -9
- package/dist/services/validation-runner.js.map +1 -1
- package/dist/services/vector-indexer.d.ts +53 -0
- package/dist/services/vector-indexer.d.ts.map +1 -0
- package/dist/services/vector-indexer.js +230 -0
- package/dist/services/vector-indexer.js.map +1 -0
- package/dist/store/index.d.ts +0 -0
- package/dist/store/index.d.ts.map +0 -0
- package/dist/store/index.js +0 -0
- package/dist/store/index.js.map +0 -0
- package/dist/store/interface.d.ts +70 -1
- package/dist/store/interface.d.ts.map +1 -1
- package/dist/store/interface.js +0 -0
- package/dist/store/interface.js.map +0 -0
- package/dist/store/memory.d.ts +0 -0
- package/dist/store/memory.d.ts.map +0 -0
- package/dist/store/memory.js +0 -0
- package/dist/store/memory.js.map +0 -0
- package/dist/store/service.d.ts +49 -0
- package/dist/store/service.d.ts.map +1 -0
- package/dist/store/service.js +147 -0
- package/dist/store/service.js.map +1 -0
- package/dist/store/sqlite.d.ts +68 -3
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +708 -58
- package/dist/store/sqlite.js.map +1 -1
- package/dist/store/vector-store.d.ts +66 -0
- package/dist/store/vector-store.d.ts.map +1 -0
- package/dist/store/vector-store.js +330 -0
- package/dist/store/vector-store.js.map +1 -0
- package/dist/tools/analyze-impact.d.ts +0 -0
- package/dist/tools/analyze-impact.d.ts.map +1 -1
- package/dist/tools/analyze-impact.js +101 -39
- package/dist/tools/analyze-impact.js.map +1 -1
- package/dist/tools/deep-explore.d.ts +0 -0
- package/dist/tools/deep-explore.d.ts.map +1 -1
- package/dist/tools/deep-explore.js +18 -4
- package/dist/tools/deep-explore.js.map +1 -1
- package/dist/tools/detect-cycles.d.ts +3 -0
- package/dist/tools/detect-cycles.d.ts.map +1 -0
- package/dist/tools/detect-cycles.js +61 -0
- package/dist/tools/detect-cycles.js.map +1 -0
- package/dist/tools/detect-dead-code.d.ts +0 -0
- package/dist/tools/detect-dead-code.d.ts.map +1 -1
- package/dist/tools/detect-dead-code.js +1 -0
- package/dist/tools/detect-dead-code.js.map +1 -1
- package/dist/tools/explore.d.ts +13 -0
- package/dist/tools/explore.d.ts.map +1 -1
- package/dist/tools/explore.js +122 -88
- package/dist/tools/explore.js.map +1 -1
- package/dist/tools/get-context.d.ts +15 -0
- package/dist/tools/get-context.d.ts.map +1 -1
- package/dist/tools/get-context.js +66 -61
- package/dist/tools/get-context.js.map +1 -1
- package/dist/tools/graph-explain.d.ts +3 -0
- package/dist/tools/graph-explain.d.ts.map +1 -0
- package/dist/tools/graph-explain.js +140 -0
- package/dist/tools/graph-explain.js.map +1 -0
- package/dist/tools/graph-stats.d.ts +3 -0
- package/dist/tools/graph-stats.d.ts.map +1 -0
- package/dist/tools/graph-stats.js +73 -0
- package/dist/tools/graph-stats.js.map +1 -0
- package/dist/tools/inspect-symbol.d.ts +10 -0
- package/dist/tools/inspect-symbol.d.ts.map +1 -1
- package/dist/tools/inspect-symbol.js +112 -101
- package/dist/tools/inspect-symbol.js.map +1 -1
- package/dist/tools/ping.d.ts +0 -0
- package/dist/tools/ping.d.ts.map +1 -1
- package/dist/tools/ping.js +2 -3
- package/dist/tools/ping.js.map +1 -1
- package/dist/tools/profile.d.ts +9 -0
- package/dist/tools/profile.d.ts.map +1 -0
- package/dist/tools/profile.js +101 -0
- package/dist/tools/profile.js.map +1 -0
- package/dist/tools/query-graph.d.ts +3 -0
- package/dist/tools/query-graph.d.ts.map +1 -0
- package/dist/tools/query-graph.js +157 -0
- package/dist/tools/query-graph.js.map +1 -0
- package/dist/tools/recall-experience.d.ts +0 -0
- package/dist/tools/recall-experience.d.ts.map +1 -1
- package/dist/tools/recall-experience.js +5 -5
- package/dist/tools/recall-experience.js.map +1 -1
- package/dist/tools/record-experience.d.ts +0 -0
- package/dist/tools/record-experience.d.ts.map +1 -1
- package/dist/tools/record-experience.js +2 -5
- package/dist/tools/record-experience.js.map +1 -1
- package/dist/tools/reflect.d.ts +4 -0
- package/dist/tools/reflect.d.ts.map +1 -0
- package/dist/tools/reflect.js +99 -0
- package/dist/tools/reflect.js.map +1 -0
- package/dist/tools/register.d.ts +5 -2
- package/dist/tools/register.d.ts.map +1 -1
- package/dist/tools/register.js +31 -1
- package/dist/tools/register.js.map +1 -1
- package/dist/tools/reindex.d.ts +0 -0
- package/dist/tools/reindex.d.ts.map +1 -1
- package/dist/tools/reindex.js +102 -21
- package/dist/tools/reindex.js.map +1 -1
- package/dist/tools/repo-overview.d.ts +0 -0
- package/dist/tools/repo-overview.d.ts.map +1 -1
- package/dist/tools/repo-overview.js +8 -6
- package/dist/tools/repo-overview.js.map +1 -1
- package/dist/tools/run-validation.d.ts +0 -0
- package/dist/tools/run-validation.d.ts.map +1 -1
- package/dist/tools/run-validation.js +15 -1
- package/dist/tools/run-validation.js.map +1 -1
- package/dist/tools/search-code.d.ts +0 -0
- package/dist/tools/search-code.d.ts.map +1 -1
- package/dist/tools/search-code.js +11 -4
- package/dist/tools/search-code.js.map +1 -1
- package/dist/tools/search-history.d.ts +0 -0
- package/dist/tools/search-history.d.ts.map +0 -0
- package/dist/tools/search-history.js +0 -0
- package/dist/tools/search-history.js.map +0 -0
- package/dist/tools/session-heartbeat.d.ts +0 -0
- package/dist/tools/session-heartbeat.d.ts.map +1 -1
- package/dist/tools/session-heartbeat.js +1 -0
- package/dist/tools/session-heartbeat.js.map +1 -1
- package/dist/tools/session-status.d.ts +0 -0
- package/dist/tools/session-status.d.ts.map +1 -1
- package/dist/tools/session-status.js +1 -0
- package/dist/tools/session-status.js.map +1 -1
- package/dist/tools/status.d.ts +0 -0
- package/dist/tools/status.d.ts.map +1 -1
- package/dist/tools/status.js +87 -24
- package/dist/tools/status.js.map +1 -1
- package/dist/tools/trace-bfs.d.ts +13 -0
- package/dist/tools/trace-bfs.d.ts.map +1 -0
- package/dist/tools/trace-bfs.js +251 -0
- package/dist/tools/trace-bfs.js.map +1 -0
- package/dist/tools/trace-flow.d.ts +1 -1
- package/dist/tools/trace-flow.d.ts.map +1 -1
- package/dist/tools/trace-flow.js +113 -69
- package/dist/tools/trace-flow.js.map +1 -1
- package/dist/types.d.ts +75 -13
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -1
- package/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-go.wasm +0 -0
- package/grammars/tree-sitter-java.wasm +0 -0
- package/grammars/tree-sitter-javascript.wasm +0 -0
- package/grammars/tree-sitter-python.wasm +0 -0
- package/grammars/tree-sitter-rust.wasm +0 -0
- package/grammars/tree-sitter-tsx.wasm +0 -0
- package/grammars/tree-sitter-typescript.wasm +0 -0
- package/package.json +8 -6
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index Worker — content-hash based incremental indexing with atomic generation swap.
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* - Each index run produces an immutable "generation" stored in SQLite.
|
|
6
|
+
* - Files are hashed (SHA-256 of content) to detect changes.
|
|
7
|
+
* - Only changed files are re-parsed; unchanged entries carry forward.
|
|
8
|
+
* - Generation pointer is atomically swapped on success.
|
|
9
|
+
* - Supports cancellation via AbortSignal.
|
|
10
|
+
*
|
|
11
|
+
* This eliminates: full rebuilds on every index, blocking event loop,
|
|
12
|
+
* and mixed-state reads during indexing.
|
|
13
|
+
*/
|
|
14
|
+
import { createHash } from "crypto";
|
|
15
|
+
import { readFileSync } from "fs";
|
|
16
|
+
import { indexSymbols } from "./symbol-indexer.js";
|
|
17
|
+
import { getStore } from "../store/sqlite.js";
|
|
18
|
+
import { createLogger } from "./logger.js";
|
|
19
|
+
const log = createLogger("index-worker");
|
|
20
|
+
// ─── Content hashing ─────────────────────────────────────
|
|
21
|
+
/**
|
|
22
|
+
* Compute SHA-256 hash of a file's content.
|
|
23
|
+
* Returns hex string, or null if file unreadable.
|
|
24
|
+
*/
|
|
25
|
+
function fileHash(filePath) {
|
|
26
|
+
try {
|
|
27
|
+
const content = readFileSync(filePath);
|
|
28
|
+
return createHash("sha256").update(content).digest("hex");
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Compare current file hashes against stored hashes to determine
|
|
36
|
+
* which files need re-indexing.
|
|
37
|
+
*/
|
|
38
|
+
export function computeIndexPlan(allFiles) {
|
|
39
|
+
const store = getStore();
|
|
40
|
+
const previousHashes = {};
|
|
41
|
+
// Load previous generation metadata from SQLite
|
|
42
|
+
try {
|
|
43
|
+
const prev = store.getRepoFingerprint();
|
|
44
|
+
// Previous hashes stored in index_generation table
|
|
45
|
+
const hashRows = store.db?.prepare("SELECT file, content_hash FROM index_generation").all() ?? [];
|
|
46
|
+
for (const row of hashRows) {
|
|
47
|
+
previousHashes[row.file] = row.content_hash;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// No previous generation — full index
|
|
52
|
+
}
|
|
53
|
+
const currentFiles = new Set(allFiles.map(f => f.path));
|
|
54
|
+
const changed = [];
|
|
55
|
+
const removed = [];
|
|
56
|
+
const unchanged = [];
|
|
57
|
+
// Detect removed files
|
|
58
|
+
for (const prevFile of Object.keys(previousHashes)) {
|
|
59
|
+
if (!currentFiles.has(prevFile)) {
|
|
60
|
+
removed.push(prevFile);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Detect changed/unchanged
|
|
64
|
+
for (const file of allFiles) {
|
|
65
|
+
const prevHash = previousHashes[file.path];
|
|
66
|
+
if (!prevHash) {
|
|
67
|
+
changed.push(file.path);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const hash = fileHash(file.path);
|
|
71
|
+
if (hash === null) {
|
|
72
|
+
removed.push(file.path);
|
|
73
|
+
}
|
|
74
|
+
else if (hash !== prevHash) {
|
|
75
|
+
changed.push(file.path);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
unchanged.push(file.path);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return { changed, removed, unchanged };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Create a new index generation, atomically swapping the active pointer.
|
|
85
|
+
*
|
|
86
|
+
* Process:
|
|
87
|
+
* 1. Start SQLite transaction
|
|
88
|
+
* 2. Parse changed files
|
|
89
|
+
* 3. Remove stale entries
|
|
90
|
+
* 4. Insert new entries + carry-forward hashes
|
|
91
|
+
* 5. Update generation pointer
|
|
92
|
+
* 6. Commit
|
|
93
|
+
*/
|
|
94
|
+
export async function createGeneration(allFiles, plan, repoPath, commitSha, repoFingerprint, signal) {
|
|
95
|
+
if (signal?.aborted)
|
|
96
|
+
throw new DOMException("Index cancelled", "AbortError");
|
|
97
|
+
const store = getStore();
|
|
98
|
+
const startTime = Date.now();
|
|
99
|
+
log.info("Generating index", {
|
|
100
|
+
changed: plan.changed.length,
|
|
101
|
+
removed: plan.removed.length,
|
|
102
|
+
unchanged: plan.unchanged.length,
|
|
103
|
+
total: allFiles.length,
|
|
104
|
+
});
|
|
105
|
+
// Parse changed files (only parse what changed)
|
|
106
|
+
const filesToParse = allFiles.filter(f => plan.changed.includes(f.path) || plan.unchanged.includes(f.path));
|
|
107
|
+
if (signal?.aborted)
|
|
108
|
+
throw new DOMException("Index cancelled", "AbortError");
|
|
109
|
+
const { symbols, relations } = await indexSymbols({
|
|
110
|
+
repoPath,
|
|
111
|
+
files: allFiles,
|
|
112
|
+
commitSha,
|
|
113
|
+
repoFingerprint,
|
|
114
|
+
});
|
|
115
|
+
if (signal?.aborted)
|
|
116
|
+
throw new DOMException("Index cancelled", "AbortError");
|
|
117
|
+
// Atomic swap: write new generation, update pointer
|
|
118
|
+
store.db?.transaction(() => {
|
|
119
|
+
// Clear stale entries
|
|
120
|
+
for (const removedFile of plan.removed) {
|
|
121
|
+
store.removeSymbolsByFile(removedFile);
|
|
122
|
+
store.removeGraphForFile(removedFile);
|
|
123
|
+
}
|
|
124
|
+
// Re-insert changed file symbols
|
|
125
|
+
const changedSymbols = symbols.filter(s => plan.changed.includes(s.file));
|
|
126
|
+
if (changedSymbols.length > 0) {
|
|
127
|
+
// Remove and re-add for changed files
|
|
128
|
+
for (const file of plan.changed) {
|
|
129
|
+
store.removeSymbolsByFile(file);
|
|
130
|
+
store.removeGraphForFile(file);
|
|
131
|
+
}
|
|
132
|
+
store.addSymbols(changedSymbols);
|
|
133
|
+
}
|
|
134
|
+
// Insert relations (cleared and re-built only for changed file scope)
|
|
135
|
+
store.clearRelations();
|
|
136
|
+
store.addRelations(relations);
|
|
137
|
+
// Update graph
|
|
138
|
+
try {
|
|
139
|
+
store.populateGraph(symbols, relations);
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
log.warn("populateGraph failed (non-fatal)", { error: String(err) });
|
|
143
|
+
}
|
|
144
|
+
})();
|
|
145
|
+
// Compute and store content hashes for the next incremental check
|
|
146
|
+
const contentHashes = {};
|
|
147
|
+
for (const file of allFiles) {
|
|
148
|
+
if (plan.changed.includes(file.path) || plan.unchanged.includes(file.path)) {
|
|
149
|
+
const hash = fileHash(file.path);
|
|
150
|
+
if (hash)
|
|
151
|
+
contentHashes[file.path] = hash;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const generation = {
|
|
155
|
+
id: Date.now(),
|
|
156
|
+
timestamp: new Date().toISOString(),
|
|
157
|
+
fileCount: allFiles.length,
|
|
158
|
+
symbolCount: symbols.length,
|
|
159
|
+
relationCount: relations.length,
|
|
160
|
+
contentHashes,
|
|
161
|
+
};
|
|
162
|
+
const elapsed = Date.now() - startTime;
|
|
163
|
+
log.info("Index generation complete", {
|
|
164
|
+
id: generation.id,
|
|
165
|
+
symbols: generation.symbolCount,
|
|
166
|
+
relations: generation.relationCount,
|
|
167
|
+
elapsedMs: elapsed,
|
|
168
|
+
});
|
|
169
|
+
return generation;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Full re-index (no incremental).
|
|
173
|
+
*/
|
|
174
|
+
export async function fullReindex(allFiles, repoPath, commitSha, repoFingerprint, signal) {
|
|
175
|
+
const plan = {
|
|
176
|
+
changed: allFiles.map(f => f.path),
|
|
177
|
+
removed: [],
|
|
178
|
+
unchanged: [],
|
|
179
|
+
};
|
|
180
|
+
return createGeneration(allFiles, plan, repoPath, commitSha, repoFingerprint, signal);
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=index-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-worker.js","sourceRoot":"","sources":["../../src/services/index-worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured Logger — leveled, structured logging for observability.
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - Log levels (debug, info, warn, error)
|
|
6
|
+
* - Structured JSON output with timestamp, level, module, message
|
|
7
|
+
* - Optional OpenTelemetry-compatible span context
|
|
8
|
+
* - Off-by-default telemetry (privacy by default)
|
|
9
|
+
*/
|
|
10
|
+
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
11
|
+
export type LogMetadata = Record<string, unknown>;
|
|
12
|
+
export interface LogEntry {
|
|
13
|
+
timestamp: string;
|
|
14
|
+
level: LogLevel;
|
|
15
|
+
module: string;
|
|
16
|
+
message: string;
|
|
17
|
+
metadata?: LogMetadata;
|
|
18
|
+
/** OpenTelemetry span ID (when telemetry is enabled) */
|
|
19
|
+
spanId?: string;
|
|
20
|
+
/** OpenTelemetry trace ID (when telemetry is enabled) */
|
|
21
|
+
traceId?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Set the active log level.
|
|
25
|
+
*/
|
|
26
|
+
export declare function setLogLevel(level: LogLevel): void;
|
|
27
|
+
/**
|
|
28
|
+
* Enable or disable telemetry collection.
|
|
29
|
+
*/
|
|
30
|
+
export declare function setTelemetryEnabled(enabled: boolean): void;
|
|
31
|
+
/**
|
|
32
|
+
* Check if telemetry is enabled.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isTelemetryEnabled(): boolean;
|
|
35
|
+
export declare function debug(module: string, message: string, metadata?: LogMetadata): void;
|
|
36
|
+
export declare function info(module: string, message: string, metadata?: LogMetadata): void;
|
|
37
|
+
export declare function warn(module: string, message: string, metadata?: LogMetadata): void;
|
|
38
|
+
export declare function error(module: string, message: string, metadata?: LogMetadata): void;
|
|
39
|
+
/**
|
|
40
|
+
* Create a child logger with a fixed module prefix.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createLogger(module: string): {
|
|
43
|
+
debug: (msg: string, meta?: LogMetadata) => void;
|
|
44
|
+
info: (msg: string, meta?: LogMetadata) => void;
|
|
45
|
+
warn: (msg: string, meta?: LogMetadata) => void;
|
|
46
|
+
error: (msg: string, meta?: LogMetadata) => void;
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/services/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAwB3D,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAElD,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAEjD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AA0CD,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAEnF;AAED,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAElF;AAED,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAElF;AAED,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAEnF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM;iBAE1B,MAAM,SAAS,WAAW;gBAC3B,MAAM,SAAS,WAAW;gBAC1B,MAAM,SAAS,WAAW;iBACzB,MAAM,SAAS,WAAW;EAE1C"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured Logger — leveled, structured logging for observability.
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - Log levels (debug, info, warn, error)
|
|
6
|
+
* - Structured JSON output with timestamp, level, module, message
|
|
7
|
+
* - Optional OpenTelemetry-compatible span context
|
|
8
|
+
* - Off-by-default telemetry (privacy by default)
|
|
9
|
+
*/
|
|
10
|
+
const LOG_LEVELS = {
|
|
11
|
+
debug: 0,
|
|
12
|
+
info: 1,
|
|
13
|
+
warn: 2,
|
|
14
|
+
error: 3,
|
|
15
|
+
};
|
|
16
|
+
const LOG_LEVEL_NAMES = {
|
|
17
|
+
debug: "DBG",
|
|
18
|
+
info: "INF",
|
|
19
|
+
warn: "WRN",
|
|
20
|
+
error: "ERR",
|
|
21
|
+
};
|
|
22
|
+
let currentLevel = process.env.CI_MCP_LOG_LEVEL === "debug" ? "debug"
|
|
23
|
+
: process.env.CI_MCP_LOG_LEVEL === "info" ? "info"
|
|
24
|
+
: process.env.CI_MCP_LOG_LEVEL === "warn" ? "warn"
|
|
25
|
+
: process.env.CI_MCP_LOG_LEVEL === "error" ? "error"
|
|
26
|
+
: "info";
|
|
27
|
+
let telemetryEnabled = process.env.CI_MCP_TELEMETRY === "1";
|
|
28
|
+
/**
|
|
29
|
+
* Set the active log level.
|
|
30
|
+
*/
|
|
31
|
+
export function setLogLevel(level) {
|
|
32
|
+
currentLevel = level;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Enable or disable telemetry collection.
|
|
36
|
+
*/
|
|
37
|
+
export function setTelemetryEnabled(enabled) {
|
|
38
|
+
telemetryEnabled = enabled;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if telemetry is enabled.
|
|
42
|
+
*/
|
|
43
|
+
export function isTelemetryEnabled() {
|
|
44
|
+
return telemetryEnabled;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Format a log entry as structured JSON (for production parsing)
|
|
48
|
+
* or as human-readable text (for stderr).
|
|
49
|
+
*/
|
|
50
|
+
function formatEntry(entry, json) {
|
|
51
|
+
if (json) {
|
|
52
|
+
return JSON.stringify(entry);
|
|
53
|
+
}
|
|
54
|
+
const prefix = `[${entry.timestamp}] [${LOG_LEVEL_NAMES[entry.level]}] [${entry.module}]`;
|
|
55
|
+
const meta = entry.metadata ? ` ${JSON.stringify(entry.metadata)}` : "";
|
|
56
|
+
return `${prefix} ${entry.message}${meta}`;
|
|
57
|
+
}
|
|
58
|
+
function shouldLog(level) {
|
|
59
|
+
return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
|
|
60
|
+
}
|
|
61
|
+
function log(level, module, message, metadata) {
|
|
62
|
+
if (!shouldLog(level))
|
|
63
|
+
return;
|
|
64
|
+
const entry = {
|
|
65
|
+
timestamp: new Date().toISOString(),
|
|
66
|
+
level,
|
|
67
|
+
module,
|
|
68
|
+
message,
|
|
69
|
+
metadata,
|
|
70
|
+
};
|
|
71
|
+
const output = formatEntry(entry, false);
|
|
72
|
+
if (level === "error") {
|
|
73
|
+
console.error(output);
|
|
74
|
+
}
|
|
75
|
+
else if (level === "warn") {
|
|
76
|
+
console.warn(output);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
console.log(output);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// ─── Public API ──────────────────────────────────────────
|
|
83
|
+
export function debug(module, message, metadata) {
|
|
84
|
+
log("debug", module, message, metadata);
|
|
85
|
+
}
|
|
86
|
+
export function info(module, message, metadata) {
|
|
87
|
+
log("info", module, message, metadata);
|
|
88
|
+
}
|
|
89
|
+
export function warn(module, message, metadata) {
|
|
90
|
+
log("warn", module, message, metadata);
|
|
91
|
+
}
|
|
92
|
+
export function error(module, message, metadata) {
|
|
93
|
+
log("error", module, message, metadata);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create a child logger with a fixed module prefix.
|
|
97
|
+
*/
|
|
98
|
+
export function createLogger(module) {
|
|
99
|
+
return {
|
|
100
|
+
debug: (msg, meta) => debug(module, msg, meta),
|
|
101
|
+
info: (msg, meta) => info(module, msg, meta),
|
|
102
|
+
warn: (msg, meta) => warn(module, msg, meta),
|
|
103
|
+
error: (msg, meta) => error(module, msg, meta),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/services/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Memory Store Service — business logic for memory/experience management.
|
|
3
|
-
*
|
|
3
|
+
* Uses SQLite as single source of truth via store/service.ts.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { getAllExperiences, getAllMemories } from "../store/service.js";
|
|
6
6
|
import type { Experience, ExperienceEvidence, Memory, MemoryType } from "../types.js";
|
|
7
|
-
export {
|
|
8
|
-
/**
|
|
9
|
-
* Store a verified experience. Only accepts with complete evidence.
|
|
10
|
-
*/
|
|
7
|
+
export { getAllExperiences, getAllMemories };
|
|
11
8
|
export declare function storeExperience(input: {
|
|
12
9
|
task: string;
|
|
13
10
|
diagnosis: string;
|
|
@@ -25,7 +22,12 @@ export declare function storeExperience(input: {
|
|
|
25
22
|
export declare function storeKnowledge(type: MemoryType, content: string, symbols: string[], files: string[], commit: string | null, repo: string): Memory;
|
|
26
23
|
/**
|
|
27
24
|
* Hybrid recall combining experiences and memories.
|
|
25
|
+
* Falls back to list-based recall since SQLiteStore doesn't have
|
|
26
|
+
* semantic search yet.
|
|
28
27
|
*/
|
|
29
28
|
export declare function hybridRecall(query: string, repo?: string, topK?: number, types?: MemoryType[]): (Experience | Memory)[];
|
|
30
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Get a single experience by ID.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getExperience(id: string): Experience | undefined;
|
|
31
33
|
//# sourceMappingURL=memory-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../src/services/memory-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../src/services/memory-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EACL,iBAAiB,EACjB,cAAc,EAEf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAItF,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC;AA4B7C,wBAAgB,eAAe,CAC7B,KAAK,EAAE;IACL,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,EACD,QAAQ,EAAE,kBAAkB,EAC5B,eAAe,EAAE,MAAM,GACtB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAgCjC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EAAE,EACjB,KAAK,EAAE,MAAM,EAAE,EACf,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,IAAI,EAAE,MAAM,GACX,MAAM,CAeR;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,MAAM,EACb,IAAI,GAAE,MAAU,EAChB,KAAK,CAAC,EAAE,UAAU,EAAE,GACnB,CAAC,UAAU,GAAG,MAAM,CAAC,EAAE,CAuBzB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAEhE"}
|
|
@@ -1,27 +1,113 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Memory Store Service — business logic for memory/experience management.
|
|
3
|
-
*
|
|
3
|
+
* Uses SQLite as single source of truth via store/service.ts.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import { getStore } from "../store/sqlite.js";
|
|
6
|
+
import { loadConfig } from "../constants.js";
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import { getAllExperiences, getAllMemories, getExperience as serviceGetExperience, } from "../store/service.js";
|
|
10
|
+
// ─── Re-export SQLite-backed operations ────────────────
|
|
11
|
+
export { getAllExperiences, getAllMemories };
|
|
7
12
|
/**
|
|
8
13
|
* Store a verified experience. Only accepts with complete evidence.
|
|
9
14
|
*/
|
|
15
|
+
function updateSteeringFile(repoPath, experiences) {
|
|
16
|
+
const claudeMdPath = path.join(repoPath, "CLAUDE.md");
|
|
17
|
+
const cursorrulesPath = path.join(repoPath, ".cursorrules");
|
|
18
|
+
const targetPath = fs.existsSync(claudeMdPath) ? claudeMdPath : cursorrulesPath;
|
|
19
|
+
const rules = experiences.map(e => `- ${e.task}: ${e.solution.substring(0, 100)}`).join("\n");
|
|
20
|
+
const steeringContent = `# Coding Intelligence MCP — Steering Rules
|
|
21
|
+
|
|
22
|
+
**Core Workflow:**
|
|
23
|
+
1. Khởi động task bằng \`ci_get_context\` để lấy Canvas (Bản đồ Mermaid).
|
|
24
|
+
2. Dùng ID trên Canvas để drill-down chi tiết (Chỉ lật file khi cần thiết).
|
|
25
|
+
3. Gọi \`ci_run_validation\` sau mỗi lần sửa (Log lỗi dài sẽ tự động được offload, chỉ trả về error canvas).
|
|
26
|
+
4. Gọi \`ci_record_experience\` sau khi fix thành công (Lưu thành L1 Memory).
|
|
27
|
+
|
|
28
|
+
**Codebase SOPs (L3 Memory - Generated from past experiences):**
|
|
29
|
+
${rules}
|
|
30
|
+
`;
|
|
31
|
+
fs.writeFileSync(targetPath, steeringContent, "utf8");
|
|
32
|
+
}
|
|
10
33
|
export function storeExperience(input, evidence, repoFingerprint) {
|
|
11
|
-
|
|
34
|
+
// Compute quality from evidence
|
|
35
|
+
const quality = Math.min(1.0, (evidence.buildPassed ? 0.3 : 0) +
|
|
36
|
+
(evidence.testsPassed ? 0.3 : 0) +
|
|
37
|
+
(evidence.humanAccepted ? 0.2 : 0) +
|
|
38
|
+
(evidence.commitCreated ? 0.2 : 0)) || 0.5;
|
|
39
|
+
const exp = {
|
|
40
|
+
id: `exp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
41
|
+
type: "episodic",
|
|
42
|
+
task: input.task,
|
|
43
|
+
diagnosis: input.diagnosis,
|
|
44
|
+
solution: input.solution,
|
|
45
|
+
changedFiles: input.changedFiles,
|
|
46
|
+
commit: input.commit,
|
|
47
|
+
failedAttempts: input.failedAttempts,
|
|
48
|
+
validation: [],
|
|
49
|
+
evidence,
|
|
50
|
+
quality,
|
|
51
|
+
timestamp: new Date().toISOString(),
|
|
52
|
+
repo: repoFingerprint,
|
|
53
|
+
};
|
|
54
|
+
getStore().addExperience(exp);
|
|
55
|
+
const config = loadConfig();
|
|
56
|
+
const allExperiences = getAllExperiences(repoFingerprint) ?? [];
|
|
57
|
+
if (config.repoPath) {
|
|
58
|
+
updateSteeringFile(config.repoPath, allExperiences);
|
|
59
|
+
}
|
|
12
60
|
return { id: exp.id, quality: exp.quality };
|
|
13
61
|
}
|
|
14
62
|
/**
|
|
15
63
|
* Store unvalidated knowledge (semantic, procedural, negative).
|
|
16
64
|
*/
|
|
17
65
|
export function storeKnowledge(type, content, symbols, files, commit, repo) {
|
|
18
|
-
|
|
66
|
+
const mem = {
|
|
67
|
+
id: `mem-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
68
|
+
type,
|
|
69
|
+
content,
|
|
70
|
+
symbols,
|
|
71
|
+
files,
|
|
72
|
+
commit,
|
|
73
|
+
repo,
|
|
74
|
+
source: "manual",
|
|
75
|
+
quality: 0.5,
|
|
76
|
+
timestamp: new Date().toISOString(),
|
|
77
|
+
};
|
|
78
|
+
getStore().addMemory(mem);
|
|
79
|
+
return mem;
|
|
19
80
|
}
|
|
20
81
|
/**
|
|
21
82
|
* Hybrid recall combining experiences and memories.
|
|
83
|
+
* Falls back to list-based recall since SQLiteStore doesn't have
|
|
84
|
+
* semantic search yet.
|
|
22
85
|
*/
|
|
23
86
|
export function hybridRecall(query, repo, topK = 5, types) {
|
|
24
|
-
|
|
87
|
+
const allExperiences = getAllExperiences(repo) ?? [];
|
|
88
|
+
const allMemories = getAllMemories(repo) ?? [];
|
|
89
|
+
// Simple lexical scoring: count query term matches
|
|
90
|
+
const terms = query.toLowerCase().split(/\s+/);
|
|
91
|
+
function score(item) {
|
|
92
|
+
const text = [item.content, item.task, item.observation]
|
|
93
|
+
.filter(Boolean).join(" ").toLowerCase();
|
|
94
|
+
return terms.filter(t => text.includes(t)).length / terms.length;
|
|
95
|
+
}
|
|
96
|
+
const results = [
|
|
97
|
+
...allExperiences,
|
|
98
|
+
...allMemories,
|
|
99
|
+
]
|
|
100
|
+
.map(item => ({ item, score: score(item) }))
|
|
101
|
+
.filter(({ score }) => score > 0)
|
|
102
|
+
.sort((a, b) => b.score - a.score)
|
|
103
|
+
.slice(0, topK)
|
|
104
|
+
.map(({ item }) => item);
|
|
105
|
+
return results;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get a single experience by ID.
|
|
109
|
+
*/
|
|
110
|
+
export function getExperience(id) {
|
|
111
|
+
return serviceGetExperience(id);
|
|
25
112
|
}
|
|
26
|
-
export { getExperience } from "../store/memory.js";
|
|
27
113
|
//# sourceMappingURL=memory-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-store.js","sourceRoot":"","sources":["../../src/services/memory-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"memory-store.js","sourceRoot":"","sources":["../../src/services/memory-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,aAAa,IAAI,oBAAoB,GACtC,MAAM,qBAAqB,CAAC;AAG7B,0DAA0D;AAE1D,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC;AAE7C;;GAEG;AAEH,SAAS,kBAAkB,CAAC,QAAgB,EAAE,WAAyB;IACrE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACtD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IAE5D,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC;IAEhF,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE9F,MAAM,eAAe,GAAG;;;;;;;;;EASxB,KAAK;CACN,CAAC;IAEA,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC;AACxD,CAAC;AACD,MAAM,UAAU,eAAe,CAC7B,KAOC,EACD,QAA4B,EAC5B,eAAuB;IAEvB,gCAAgC;IAChC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAC1B,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CACnC,IAAI,GAAG,CAAC;IAET,MAAM,GAAG,GAAe;QACtB,EAAE,EAAE,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;QACjE,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,UAAU,EAAE,EAAE;QACd,QAAQ;QACR,OAAO;QACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,IAAI,EAAE,eAAe;KACtB,CAAC;IACF,QAAQ,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAE9B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,cAAc,GAAG,iBAAiB,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IAChE,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,kBAAkB,CAAC,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IACtD,CAAC;IACH,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAgB,EAChB,OAAe,EACf,OAAiB,EACjB,KAAe,EACf,MAAqB,EACrB,IAAY;IAEZ,MAAM,GAAG,GAAW;QAClB,EAAE,EAAE,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;QACjE,IAAI;QACJ,OAAO;QACP,OAAO;QACP,KAAK;QACL,MAAM;QACN,IAAI;QACJ,MAAM,EAAE,QAAQ;QAChB,OAAO,EAAE,GAAG;QACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,QAAQ,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC1B,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAa,EACb,IAAa,EACb,OAAe,CAAC,EAChB,KAAoB;IAEpB,MAAM,cAAc,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACrD,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAE/C,mDAAmD;IACnD,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/C,SAAS,KAAK,CAAC,IAA+D;QAC5E,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,EAAG,IAAY,CAAC,IAAI,EAAG,IAAY,CAAC,WAAW,CAAC;aACvE,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IACnE,CAAC;IAED,MAAM,OAAO,GAA4B;QACvC,GAAG,cAAc;QACjB,GAAG,WAAW;KACf;SACE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,IAAW,CAAC,EAAE,CAAC,CAAC;SAClD,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC;SAChC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;SACjC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;SACd,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAE3B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,OAAO,oBAAoB,CAAC,EAAE,CAAC,CAAC;AAClC,CAAC"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbol-indexer.d.ts","sourceRoot":"","sources":["../../src/services/symbol-indexer.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAc,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"symbol-indexer.d.ts","sourceRoot":"","sources":["../../src/services/symbol-indexer.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAc,cAAc,EAAE,MAAM,aAAa,CAAC;AAoB1E,UAAU,YAAY;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CACzB;AAwJD,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC;IAC9D,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,SAAS,EAAE,cAAc,EAAE,CAAC;CAC7B,CAAC,CA2ID"}
|