@a13xu/lucid 1.1.0 → 1.9.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 (56) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +221 -99
  3. package/build/config.d.ts +37 -0
  4. package/build/config.js +45 -0
  5. package/build/database.d.ts +54 -0
  6. package/build/database.js +175 -62
  7. package/build/guardian/checklist.js +66 -66
  8. package/build/guardian/coding-analyzer.d.ts +11 -0
  9. package/build/guardian/coding-analyzer.js +393 -0
  10. package/build/guardian/coding-rules.d.ts +1 -0
  11. package/build/guardian/coding-rules.js +97 -0
  12. package/build/index.js +241 -2
  13. package/build/indexer/ast.d.ts +9 -0
  14. package/build/indexer/ast.js +158 -0
  15. package/build/indexer/file.d.ts +15 -0
  16. package/build/indexer/file.js +100 -0
  17. package/build/indexer/project.d.ts +8 -0
  18. package/build/indexer/project.js +320 -0
  19. package/build/memory/experience.d.ts +11 -0
  20. package/build/memory/experience.js +85 -0
  21. package/build/retrieval/context.d.ts +29 -0
  22. package/build/retrieval/context.js +219 -0
  23. package/build/retrieval/qdrant.d.ts +16 -0
  24. package/build/retrieval/qdrant.js +135 -0
  25. package/build/retrieval/tfidf.d.ts +14 -0
  26. package/build/retrieval/tfidf.js +64 -0
  27. package/build/security/alerts.d.ts +44 -0
  28. package/build/security/alerts.js +228 -0
  29. package/build/security/env.d.ts +24 -0
  30. package/build/security/env.js +85 -0
  31. package/build/security/guard.d.ts +35 -0
  32. package/build/security/guard.js +133 -0
  33. package/build/security/ratelimit.d.ts +34 -0
  34. package/build/security/ratelimit.js +105 -0
  35. package/build/security/smtp.d.ts +26 -0
  36. package/build/security/smtp.js +125 -0
  37. package/build/security/ssrf.d.ts +18 -0
  38. package/build/security/ssrf.js +109 -0
  39. package/build/security/waf.d.ts +33 -0
  40. package/build/security/waf.js +174 -0
  41. package/build/store/content.d.ts +3 -0
  42. package/build/store/content.js +11 -0
  43. package/build/tools/coding-guard.d.ts +24 -0
  44. package/build/tools/coding-guard.js +82 -0
  45. package/build/tools/context.d.ts +39 -0
  46. package/build/tools/context.js +105 -0
  47. package/build/tools/grep.d.ts +17 -0
  48. package/build/tools/grep.js +65 -0
  49. package/build/tools/init.d.ts +51 -0
  50. package/build/tools/init.js +212 -0
  51. package/build/tools/remember.d.ts +4 -4
  52. package/build/tools/reward.d.ts +29 -0
  53. package/build/tools/reward.js +154 -0
  54. package/build/tools/sync.d.ts +18 -0
  55. package/build/tools/sync.js +76 -0
  56. package/package.json +55 -48
package/build/database.js CHANGED
@@ -30,85 +30,198 @@ export function initDatabase() {
30
30
  return db;
31
31
  }
32
32
  function createSchema(db) {
33
- db.exec(`
34
- CREATE TABLE IF NOT EXISTS entities (
35
- id INTEGER PRIMARY KEY,
36
- name TEXT NOT NULL UNIQUE COLLATE NOCASE,
37
- type TEXT NOT NULL,
38
- observations TEXT NOT NULL DEFAULT '[]',
39
- created_at INTEGER DEFAULT (unixepoch()),
40
- updated_at INTEGER DEFAULT (unixepoch())
41
- );
42
-
43
- CREATE TABLE IF NOT EXISTS relations (
44
- id INTEGER PRIMARY KEY,
45
- from_entity INTEGER NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
46
- to_entity INTEGER NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
47
- relation_type TEXT NOT NULL,
48
- created_at INTEGER DEFAULT (unixepoch()),
49
- UNIQUE(from_entity, to_entity, relation_type)
50
- );
51
-
52
- CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
53
- name,
54
- type,
55
- observations,
56
- content='entities',
57
- content_rowid='id',
58
- tokenize='porter unicode61'
59
- );
60
-
61
- CREATE TRIGGER IF NOT EXISTS entities_ai AFTER INSERT ON entities BEGIN
62
- INSERT INTO entities_fts(rowid, name, type, observations)
63
- VALUES (new.id, new.name, new.type, new.observations);
64
- END;
65
-
66
- CREATE TRIGGER IF NOT EXISTS entities_au AFTER UPDATE ON entities BEGIN
67
- INSERT INTO entities_fts(entities_fts, rowid, name, type, observations)
68
- VALUES('delete', old.id, old.name, old.type, old.observations);
69
- INSERT INTO entities_fts(rowid, name, type, observations)
70
- VALUES (new.id, new.name, new.type, new.observations);
71
- END;
72
-
73
- CREATE TRIGGER IF NOT EXISTS entities_ad AFTER DELETE ON entities BEGIN
74
- INSERT INTO entities_fts(entities_fts, rowid, name, type, observations)
75
- VALUES('delete', old.id, old.name, old.type, old.observations);
76
- END;
77
-
78
- CREATE INDEX IF NOT EXISTS idx_relations_from ON relations(from_entity);
79
- CREATE INDEX IF NOT EXISTS idx_relations_to ON relations(to_entity);
80
- CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(type);
33
+ db.exec(`
34
+ CREATE TABLE IF NOT EXISTS entities (
35
+ id INTEGER PRIMARY KEY,
36
+ name TEXT NOT NULL UNIQUE COLLATE NOCASE,
37
+ type TEXT NOT NULL,
38
+ observations TEXT NOT NULL DEFAULT '[]',
39
+ created_at INTEGER DEFAULT (unixepoch()),
40
+ updated_at INTEGER DEFAULT (unixepoch())
41
+ );
42
+
43
+ CREATE TABLE IF NOT EXISTS relations (
44
+ id INTEGER PRIMARY KEY,
45
+ from_entity INTEGER NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
46
+ to_entity INTEGER NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
47
+ relation_type TEXT NOT NULL,
48
+ created_at INTEGER DEFAULT (unixepoch()),
49
+ UNIQUE(from_entity, to_entity, relation_type)
50
+ );
51
+
52
+ CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
53
+ name,
54
+ type,
55
+ observations,
56
+ content='entities',
57
+ content_rowid='id',
58
+ tokenize='porter unicode61'
59
+ );
60
+
61
+ CREATE TRIGGER IF NOT EXISTS entities_ai AFTER INSERT ON entities BEGIN
62
+ INSERT INTO entities_fts(rowid, name, type, observations)
63
+ VALUES (new.id, new.name, new.type, new.observations);
64
+ END;
65
+
66
+ CREATE TRIGGER IF NOT EXISTS entities_au AFTER UPDATE ON entities BEGIN
67
+ INSERT INTO entities_fts(entities_fts, rowid, name, type, observations)
68
+ VALUES('delete', old.id, old.name, old.type, old.observations);
69
+ INSERT INTO entities_fts(rowid, name, type, observations)
70
+ VALUES (new.id, new.name, new.type, new.observations);
71
+ END;
72
+
73
+ CREATE TRIGGER IF NOT EXISTS entities_ad AFTER DELETE ON entities BEGIN
74
+ INSERT INTO entities_fts(entities_fts, rowid, name, type, observations)
75
+ VALUES('delete', old.id, old.name, old.type, old.observations);
76
+ END;
77
+
78
+ CREATE INDEX IF NOT EXISTS idx_relations_from ON relations(from_entity);
79
+ CREATE INDEX IF NOT EXISTS idx_relations_to ON relations(to_entity);
80
+ CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(type);
81
+
82
+ -- Conținut sursă comprimat (zlib deflate nivel 9)
83
+ CREATE TABLE IF NOT EXISTS file_contents (
84
+ id INTEGER PRIMARY KEY,
85
+ filepath TEXT NOT NULL UNIQUE,
86
+ content BLOB NOT NULL,
87
+ content_hash TEXT NOT NULL,
88
+ original_size INTEGER NOT NULL,
89
+ compressed_size INTEGER NOT NULL,
90
+ language TEXT NOT NULL DEFAULT 'generic',
91
+ indexed_at INTEGER DEFAULT (unixepoch())
92
+ );
93
+ CREATE INDEX IF NOT EXISTS idx_fc_filepath ON file_contents(filepath);
94
+ CREATE INDEX IF NOT EXISTS idx_fc_hash ON file_contents(content_hash);
95
+ CREATE INDEX IF NOT EXISTS idx_fc_indexed ON file_contents(indexed_at);
96
+
97
+ -- Diffs între versiuni consecutive (pentru get_recent)
98
+ CREATE TABLE IF NOT EXISTS file_diffs (
99
+ filepath TEXT PRIMARY KEY,
100
+ prev_hash TEXT NOT NULL,
101
+ diff_text TEXT NOT NULL,
102
+ changed_at INTEGER DEFAULT (unixepoch())
103
+ );
104
+ CREATE INDEX IF NOT EXISTS idx_fd_changed ON file_diffs(changed_at);
105
+
106
+ -- Experiences: logged get_context calls for RL reward system
107
+ CREATE TABLE IF NOT EXISTS experiences (
108
+ id INTEGER PRIMARY KEY,
109
+ query TEXT NOT NULL,
110
+ query_terms TEXT NOT NULL DEFAULT '',
111
+ context_fps TEXT NOT NULL DEFAULT '[]',
112
+ strategy TEXT NOT NULL DEFAULT 'tfidf',
113
+ reward REAL NOT NULL DEFAULT 0.0,
114
+ feedback TEXT,
115
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
116
+ rewarded_at INTEGER
117
+ );
118
+
119
+ CREATE VIRTUAL TABLE IF NOT EXISTS experiences_fts USING fts5(
120
+ query,
121
+ feedback,
122
+ content='experiences',
123
+ content_rowid='id',
124
+ tokenize='porter unicode61'
125
+ );
126
+
127
+ CREATE TRIGGER IF NOT EXISTS experiences_ai AFTER INSERT ON experiences BEGIN
128
+ INSERT INTO experiences_fts(rowid, query, feedback)
129
+ VALUES (new.id, new.query, COALESCE(new.feedback, ''));
130
+ END;
131
+
132
+ CREATE TRIGGER IF NOT EXISTS experiences_au AFTER UPDATE ON experiences BEGIN
133
+ INSERT INTO experiences_fts(experiences_fts, rowid, query, feedback)
134
+ VALUES('delete', old.id, old.query, COALESCE(old.feedback, ''));
135
+ INSERT INTO experiences_fts(rowid, query, feedback)
136
+ VALUES (new.id, new.query, COALESCE(new.feedback, ''));
137
+ END;
138
+
139
+ -- Denormalized reward cache per file (updated on every reward/penalize/implicit)
140
+ CREATE TABLE IF NOT EXISTS file_rewards (
141
+ filepath TEXT PRIMARY KEY,
142
+ total_reward REAL NOT NULL DEFAULT 0.0,
143
+ use_count INTEGER NOT NULL DEFAULT 0,
144
+ last_rewarded INTEGER
145
+ );
81
146
  `);
82
147
  }
83
148
  export function prepareStatements(db) {
84
149
  return {
150
+ // file_contents
151
+ getFileByPath: db.prepare("SELECT * FROM file_contents WHERE filepath = ?"),
152
+ upsertFile: db.prepare(`INSERT INTO file_contents (filepath, content, content_hash, original_size, compressed_size, language)
153
+ VALUES (?, ?, ?, ?, ?, ?)
154
+ ON CONFLICT(filepath) DO UPDATE SET
155
+ content = excluded.content,
156
+ content_hash = excluded.content_hash,
157
+ original_size = excluded.original_size,
158
+ compressed_size = excluded.compressed_size,
159
+ language = excluded.language,
160
+ indexed_at = unixepoch()`),
161
+ getAllFiles: db.prepare("SELECT filepath, content, language, content_hash, indexed_at FROM file_contents"),
162
+ getRecentFiles: db.prepare("SELECT filepath, language, indexed_at FROM file_contents WHERE indexed_at >= ? ORDER BY indexed_at DESC"),
163
+ deleteFile: db.prepare("DELETE FROM file_contents WHERE filepath = ?"),
164
+ upsertDiff: db.prepare(`INSERT INTO file_diffs (filepath, prev_hash, diff_text)
165
+ VALUES (?, ?, ?)
166
+ ON CONFLICT(filepath) DO UPDATE SET
167
+ prev_hash = excluded.prev_hash,
168
+ diff_text = excluded.diff_text,
169
+ changed_at = unixepoch()`),
170
+ getDiff: db.prepare("SELECT * FROM file_diffs WHERE filepath = ?"),
171
+ getRecentDiffs: db.prepare("SELECT * FROM file_diffs WHERE changed_at >= ? ORDER BY changed_at DESC"),
172
+ fileStorageStats: db.prepare("SELECT COUNT(*) as count, SUM(original_size) as total_original, SUM(compressed_size) as total_compressed FROM file_contents"),
173
+ // entities
85
174
  getEntityByName: db.prepare("SELECT * FROM entities WHERE name = ? COLLATE NOCASE"),
86
175
  insertEntity: db.prepare("INSERT INTO entities (name, type, observations) VALUES (?, ?, ?)"),
87
176
  // SQL: SET observations = ?, WHERE id = ? → 2 params
88
177
  updateEntity: db.prepare("UPDATE entities SET observations = ?, updated_at = unixepoch() WHERE id = ?"),
89
178
  deleteEntity: db.prepare("DELETE FROM entities WHERE name = ? COLLATE NOCASE"),
90
179
  getAllEntities: db.prepare("SELECT * FROM entities ORDER BY updated_at DESC"),
91
- getRelationsForEntity: db.prepare(`SELECT r.*, ef.name AS from_name, et.name AS to_name
92
- FROM relations r
93
- JOIN entities ef ON r.from_entity = ef.id
94
- JOIN entities et ON r.to_entity = et.id
180
+ getRelationsForEntity: db.prepare(`SELECT r.*, ef.name AS from_name, et.name AS to_name
181
+ FROM relations r
182
+ JOIN entities ef ON r.from_entity = ef.id
183
+ JOIN entities et ON r.to_entity = et.id
95
184
  WHERE r.from_entity = ? OR r.to_entity = ?`),
96
185
  insertRelation: db.prepare("INSERT OR IGNORE INTO relations (from_entity, to_entity, relation_type) VALUES (?, ?, ?)"),
97
- searchFTS: db.prepare(`SELECT e.* FROM entities_fts
98
- JOIN entities e ON entities_fts.rowid = e.id
99
- WHERE entities_fts MATCH ?
100
- ORDER BY rank
186
+ searchFTS: db.prepare(`SELECT e.* FROM entities_fts
187
+ JOIN entities e ON entities_fts.rowid = e.id
188
+ WHERE entities_fts MATCH ?
189
+ ORDER BY rank
101
190
  LIMIT 20`),
102
- searchLike: db.prepare(`SELECT * FROM entities
103
- WHERE name LIKE ? OR type LIKE ? OR observations LIKE ?
104
- ORDER BY updated_at DESC
191
+ searchLike: db.prepare(`SELECT * FROM entities
192
+ WHERE name LIKE ? OR type LIKE ? OR observations LIKE ?
193
+ ORDER BY updated_at DESC
105
194
  LIMIT 20`),
106
195
  countEntities: db.prepare("SELECT COUNT(*) as count FROM entities"),
107
196
  countRelations: db.prepare("SELECT COUNT(*) as count FROM relations"),
108
197
  getWalMode: db.prepare("PRAGMA journal_mode"),
109
- getAllRelations: db.prepare(`SELECT r.*, ef.name AS from_name, et.name AS to_name
110
- FROM relations r
111
- JOIN entities ef ON r.from_entity = ef.id
198
+ getAllRelations: db.prepare(`SELECT r.*, ef.name AS from_name, et.name AS to_name
199
+ FROM relations r
200
+ JOIN entities ef ON r.from_entity = ef.id
112
201
  JOIN entities et ON r.to_entity = et.id`),
202
+ // experiences
203
+ insertExperience: db.prepare(`INSERT INTO experiences (query, query_terms, context_fps, strategy)
204
+ VALUES (?, ?, ?, ?)`),
205
+ updateExperienceReward: db.prepare(`UPDATE experiences SET
206
+ reward = reward + ?,
207
+ rewarded_at = unixepoch(),
208
+ feedback = COALESCE(?, feedback)
209
+ WHERE id = ?`),
210
+ getExperienceById: db.prepare("SELECT * FROM experiences WHERE id = ?"),
211
+ getTopExperiences: db.prepare("SELECT * FROM experiences ORDER BY reward DESC LIMIT ?"),
212
+ searchExperiencesFTS: db.prepare(`SELECT e.* FROM experiences_fts
213
+ JOIN experiences e ON experiences_fts.rowid = e.id
214
+ WHERE experiences_fts MATCH ?
215
+ ORDER BY rank
216
+ LIMIT ?`),
217
+ // file_rewards
218
+ upsertFileReward: db.prepare(`INSERT INTO file_rewards (filepath, total_reward, use_count, last_rewarded)
219
+ VALUES (?, ?, 1, unixepoch())
220
+ ON CONFLICT(filepath) DO UPDATE SET
221
+ total_reward = total_reward + excluded.total_reward,
222
+ use_count = use_count + 1,
223
+ last_rewarded = unixepoch()`),
224
+ getFileRewards: db.prepare("SELECT * FROM file_rewards"),
225
+ getTopFileRewards: db.prepare("SELECT * FROM file_rewards WHERE total_reward > 0 ORDER BY total_reward DESC LIMIT ?"),
113
226
  };
114
227
  }
@@ -1,67 +1,67 @@
1
- export const CHECKLIST = `# Logic Guardian — Validation Checklist (5 passes)
2
-
3
- ## Pass 1: Logic Trace
4
- Trace through the code with CONCRETE values:
5
- - Happy path → real values, write each variable state
6
- - Empty/zero → null, 0, "", []
7
- - Boundary → first element, last element, max int, single char
8
- - Error case → network down, file missing, permission denied
9
-
10
- STOP if any trace produces unexpected output. Fix before continuing.
11
-
12
- ## Pass 2: Contract Verification
13
- - [ ] Preconditions: what must be true BEFORE this runs? Is it checked?
14
- - [ ] Postconditions: what must be true AFTER? Can you prove it?
15
- - [ ] Invariants: what must ALWAYS be true? Does the code maintain it?
16
- - [ ] Return type: does EVERY code path return the expected type?
17
- - [ ] Side effects: are all side effects intentional?
18
-
19
- ## Pass 3: Stupid Mistakes Checklist
20
-
21
- ### Off-by-one
22
- - [ ] < vs <= — verify with boundary values
23
- - [ ] Array indices — last is length - 1
24
- - [ ] Loop iterations — exactly N times?
25
-
26
- ### Null/Undefined Propagation
27
- - [ ] Every .property access — can the object be null?
28
- - [ ] Every array index — can the array be empty?
29
- - [ ] Every map lookup — can the key be missing?
30
-
31
- ### Type Confusion
32
- - [ ] String vs Number comparisons
33
- - [ ] Integer vs Float division
34
- - [ ] Boolean coercion edge cases
35
-
36
- ### Logic Inversions (THE #1 LLM drift pattern)
37
- - [ ] if/else — is the condition testing what you THINK?
38
- - [ ] Early returns — does the guard return the RIGHT value?
39
- - [ ] filter/find/some — keeping the RIGHT elements?
40
- - [ ] Error handling — catching and re-throwing correctly?
41
-
42
- ### State & Mutation
43
- - [ ] Mutating shared object when you should copy?
44
- - [ ] Async state read after it might have changed?
45
-
46
- ### Copy-Paste Drift
47
- - [ ] ALL variable names updated in copied blocks?
48
- - [ ] Conditions changed, not just variable names?
49
-
50
- ## Pass 4: Integration Sanity
51
- - [ ] Breaks existing callers?
52
- - [ ] Imports/exports correct?
53
- - [ ] If async, all callers awaiting it?
54
- - [ ] If type changed, all usages updated?
55
-
56
- ## Pass 5: Explain It Test
57
- In ONE sentence: what does this code do?
58
- If you can't explain it, or the sentence doesn't match the code → something is wrong.
59
-
60
- ## Anti-Drift Triggers
61
- STOP if you find yourself thinking:
62
- - "This is similar to..." → You're pattern-matching. TRACE THE LOGIC.
63
- - "This should work because the other one does" → VERIFY INDEPENDENTLY.
64
- - "I'll just copy and change the names" → CHECK EVERY DIFFERENCE.
65
- - "The error handling is probably fine" → TRACE THE ERROR PATH.
66
- - "This is standard boilerplate" → Verify it fits this context.
1
+ export const CHECKLIST = `# Logic Guardian — Validation Checklist (5 passes)
2
+
3
+ ## Pass 1: Logic Trace
4
+ Trace through the code with CONCRETE values:
5
+ - Happy path → real values, write each variable state
6
+ - Empty/zero → null, 0, "", []
7
+ - Boundary → first element, last element, max int, single char
8
+ - Error case → network down, file missing, permission denied
9
+
10
+ STOP if any trace produces unexpected output. Fix before continuing.
11
+
12
+ ## Pass 2: Contract Verification
13
+ - [ ] Preconditions: what must be true BEFORE this runs? Is it checked?
14
+ - [ ] Postconditions: what must be true AFTER? Can you prove it?
15
+ - [ ] Invariants: what must ALWAYS be true? Does the code maintain it?
16
+ - [ ] Return type: does EVERY code path return the expected type?
17
+ - [ ] Side effects: are all side effects intentional?
18
+
19
+ ## Pass 3: Stupid Mistakes Checklist
20
+
21
+ ### Off-by-one
22
+ - [ ] < vs <= — verify with boundary values
23
+ - [ ] Array indices — last is length - 1
24
+ - [ ] Loop iterations — exactly N times?
25
+
26
+ ### Null/Undefined Propagation
27
+ - [ ] Every .property access — can the object be null?
28
+ - [ ] Every array index — can the array be empty?
29
+ - [ ] Every map lookup — can the key be missing?
30
+
31
+ ### Type Confusion
32
+ - [ ] String vs Number comparisons
33
+ - [ ] Integer vs Float division
34
+ - [ ] Boolean coercion edge cases
35
+
36
+ ### Logic Inversions (THE #1 LLM drift pattern)
37
+ - [ ] if/else — is the condition testing what you THINK?
38
+ - [ ] Early returns — does the guard return the RIGHT value?
39
+ - [ ] filter/find/some — keeping the RIGHT elements?
40
+ - [ ] Error handling — catching and re-throwing correctly?
41
+
42
+ ### State & Mutation
43
+ - [ ] Mutating shared object when you should copy?
44
+ - [ ] Async state read after it might have changed?
45
+
46
+ ### Copy-Paste Drift
47
+ - [ ] ALL variable names updated in copied blocks?
48
+ - [ ] Conditions changed, not just variable names?
49
+
50
+ ## Pass 4: Integration Sanity
51
+ - [ ] Breaks existing callers?
52
+ - [ ] Imports/exports correct?
53
+ - [ ] If async, all callers awaiting it?
54
+ - [ ] If type changed, all usages updated?
55
+
56
+ ## Pass 5: Explain It Test
57
+ In ONE sentence: what does this code do?
58
+ If you can't explain it, or the sentence doesn't match the code → something is wrong.
59
+
60
+ ## Anti-Drift Triggers
61
+ STOP if you find yourself thinking:
62
+ - "This is similar to..." → You're pattern-matching. TRACE THE LOGIC.
63
+ - "This should work because the other one does" → VERIFY INDEPENDENTLY.
64
+ - "I'll just copy and change the names" → CHECK EVERY DIFFERENCE.
65
+ - "The error handling is probably fine" → TRACE THE ERROR PATH.
66
+ - "This is standard boilerplate" → Verify it fits this context.
67
67
  `;
@@ -0,0 +1,11 @@
1
+ export type QualitySeverity = "high" | "medium" | "low";
2
+ export interface QualityIssue {
3
+ file: string;
4
+ line: number;
5
+ severity: QualitySeverity;
6
+ ruleId: string;
7
+ message: string;
8
+ suggestion: string;
9
+ }
10
+ export declare function analyzeCodeQuality(filepath: string, source: string, lang?: string): QualityIssue[];
11
+ export declare function formatQualityReport(filepath: string, issues: QualityIssue[]): string;