micro-models-agent 0.23.0 → 0.24.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.
Files changed (171) hide show
  1. package/README.md +312 -312
  2. package/bin/mma.mjs +8 -8
  3. package/dist/main.js +8777 -864
  4. package/package.json +4 -3
  5. package/dist/cli/commands.js +0 -220
  6. package/dist/cli/completer.js +0 -168
  7. package/dist/cli/index.js +0 -2
  8. package/dist/cli/main.js +0 -113
  9. package/dist/cli/repl.js +0 -987
  10. package/dist/cli/security-commands.js +0 -166
  11. package/dist/cli/setup.js +0 -229
  12. package/dist/config/config.js +0 -186
  13. package/dist/config/defaults.js +0 -91
  14. package/dist/config/experts.js +0 -15
  15. package/dist/config/index.js +0 -3
  16. package/dist/config/security.js +0 -193
  17. package/dist/config/types.js +0 -1
  18. package/dist/core/agent-moe.js +0 -98
  19. package/dist/core/agent.js +0 -461
  20. package/dist/core/bootstrap.js +0 -321
  21. package/dist/core/index.js +0 -2
  22. package/dist/core/prompt-builder.js +0 -55
  23. package/dist/core/session-logger.js +0 -122
  24. package/dist/core/types.js +0 -1
  25. package/dist/i18n/en.json +0 -461
  26. package/dist/i18n/index.js +0 -43
  27. package/dist/i18n/ru.json +0 -461
  28. package/dist/index.js +0 -22
  29. package/dist/llm/image-utils.js +0 -144
  30. package/dist/llm/index.js +0 -4
  31. package/dist/llm/model-loader.js +0 -78
  32. package/dist/llm/openai-compat.js +0 -324
  33. package/dist/llm/orchestrator.js +0 -194
  34. package/dist/llm/provider.js +0 -10
  35. package/dist/llm/response.js +0 -39
  36. package/dist/llm/token-counter.js +0 -39
  37. package/dist/llm/types.js +0 -1
  38. package/dist/logger/app-logger.js +0 -76
  39. package/dist/logger/index.js +0 -1
  40. package/dist/migration/backup.js +0 -45
  41. package/dist/migration/detect.js +0 -50
  42. package/dist/migration/index.js +0 -2
  43. package/dist/modules/browser/actions.js +0 -46
  44. package/dist/modules/browser/cookie-store.js +0 -24
  45. package/dist/modules/browser/index.js +0 -5
  46. package/dist/modules/browser/module.js +0 -28
  47. package/dist/modules/browser/session.js +0 -287
  48. package/dist/modules/browser/snapshot.js +0 -114
  49. package/dist/modules/browser/types.js +0 -9
  50. package/dist/modules/context/history.js +0 -15
  51. package/dist/modules/context/index.js +0 -1
  52. package/dist/modules/context/manager.js +0 -240
  53. package/dist/modules/execution/auditor.js +0 -72
  54. package/dist/modules/execution/index.js +0 -6
  55. package/dist/modules/execution/module.js +0 -337
  56. package/dist/modules/execution/moe-executor.js +0 -209
  57. package/dist/modules/execution/plan-validator.js +0 -153
  58. package/dist/modules/execution/planner.js +0 -35
  59. package/dist/modules/execution/stuck-detector.js +0 -134
  60. package/dist/modules/execution/tracker.js +0 -53
  61. package/dist/modules/execution/types.js +0 -1
  62. package/dist/modules/execution/verifier.js +0 -149
  63. package/dist/modules/hallucination/confidence.js +0 -54
  64. package/dist/modules/hallucination/consistency.js +0 -60
  65. package/dist/modules/hallucination/detector.js +0 -41
  66. package/dist/modules/hallucination/factual.js +0 -170
  67. package/dist/modules/hallucination/index.js +0 -4
  68. package/dist/modules/index.js +0 -5
  69. package/dist/modules/indexer/cache.js +0 -38
  70. package/dist/modules/indexer/index.js +0 -3
  71. package/dist/modules/indexer/module.js +0 -192
  72. package/dist/modules/indexer/walker.js +0 -101
  73. package/dist/modules/mcp/client.js +0 -393
  74. package/dist/modules/mcp/index.js +0 -3
  75. package/dist/modules/mcp/module.js +0 -146
  76. package/dist/modules/mcp/registry.js +0 -15
  77. package/dist/modules/memory/index.js +0 -1
  78. package/dist/modules/memory/module.js +0 -48
  79. package/dist/modules/memory/search.js +0 -40
  80. package/dist/modules/memory/store.js +0 -65
  81. package/dist/modules/pipelines/engine.js +0 -60
  82. package/dist/modules/pipelines/index.js +0 -3
  83. package/dist/modules/pipelines/parser.js +0 -53
  84. package/dist/modules/pipelines/template.js +0 -14
  85. package/dist/modules/plugins/builtin/lint-on-write.js +0 -121
  86. package/dist/modules/plugins/builtin/notify.js +0 -8
  87. package/dist/modules/plugins/index.js +0 -1
  88. package/dist/modules/plugins/loader.js +0 -28
  89. package/dist/modules/plugins/manager.js +0 -161
  90. package/dist/modules/plugins/types.js +0 -1
  91. package/dist/modules/processes/detect.js +0 -34
  92. package/dist/modules/processes/index.js +0 -3
  93. package/dist/modules/processes/registry.js +0 -148
  94. package/dist/modules/processes/runner.js +0 -124
  95. package/dist/modules/registry.js +0 -45
  96. package/dist/modules/security/audit-log.js +0 -116
  97. package/dist/modules/security/audit-notifier.js +0 -292
  98. package/dist/modules/security/command-validator.js +0 -185
  99. package/dist/modules/security/content-scanner.js +0 -52
  100. package/dist/modules/security/data-sanitizer.js +0 -97
  101. package/dist/modules/security/encryption.js +0 -240
  102. package/dist/modules/security/index.js +0 -14
  103. package/dist/modules/security/network-validator.js +0 -79
  104. package/dist/modules/security/path-validator.js +0 -155
  105. package/dist/modules/security/rate-limiter.js +0 -119
  106. package/dist/modules/security/security-policies.js +0 -393
  107. package/dist/modules/security/session-encryption.js +0 -193
  108. package/dist/modules/security/session-isolation.js +0 -95
  109. package/dist/modules/session/index.js +0 -3
  110. package/dist/modules/session/manager.js +0 -167
  111. package/dist/modules/session/module.js +0 -24
  112. package/dist/modules/session/store.js +0 -174
  113. package/dist/modules/session/types.js +0 -1
  114. package/dist/modules/skills/index.js +0 -3
  115. package/dist/modules/skills/loader.js +0 -72
  116. package/dist/modules/skills/matcher.js +0 -27
  117. package/dist/modules/skills/module.js +0 -143
  118. package/dist/modules/types.js +0 -1
  119. package/dist/modules/updater/checker.js +0 -32
  120. package/dist/modules/updater/index.js +0 -1
  121. package/dist/modules/user-profile/compressor.js +0 -16
  122. package/dist/modules/user-profile/index.js +0 -1
  123. package/dist/modules/user-profile/profile.js +0 -68
  124. package/dist/skills/builtin/builtin/git.md +0 -36
  125. package/dist/skills/builtin/builtin/typescript.md +0 -35
  126. package/dist/tools/approve.js +0 -32
  127. package/dist/tools/attach-image.js +0 -89
  128. package/dist/tools/bash.js +0 -140
  129. package/dist/tools/browser.js +0 -97
  130. package/dist/tools/create-dir.js +0 -56
  131. package/dist/tools/delete-file.js +0 -63
  132. package/dist/tools/edit-file.js +0 -77
  133. package/dist/tools/executor.js +0 -95
  134. package/dist/tools/file-info.js +0 -45
  135. package/dist/tools/filter-tools.js +0 -10
  136. package/dist/tools/glob-tool.js +0 -26
  137. package/dist/tools/grep-tool.js +0 -64
  138. package/dist/tools/index.js +0 -52
  139. package/dist/tools/list-dir.js +0 -47
  140. package/dist/tools/load-skill.js +0 -48
  141. package/dist/tools/mcp-call.js +0 -68
  142. package/dist/tools/move-file.js +0 -84
  143. package/dist/tools/path-utils.js +0 -51
  144. package/dist/tools/pipeline-run.js +0 -144
  145. package/dist/tools/preview.js +0 -2
  146. package/dist/tools/process-kill.js +0 -29
  147. package/dist/tools/process-list.js +0 -38
  148. package/dist/tools/process-log.js +0 -41
  149. package/dist/tools/question.js +0 -142
  150. package/dist/tools/read-file.js +0 -73
  151. package/dist/tools/recall.js +0 -110
  152. package/dist/tools/registry.js +0 -36
  153. package/dist/tools/remember.js +0 -67
  154. package/dist/tools/scope-check.js +0 -30
  155. package/dist/tools/search-history.js +0 -64
  156. package/dist/tools/subagent.js +0 -142
  157. package/dist/tools/types.js +0 -1
  158. package/dist/tools/user-input.js +0 -123
  159. package/dist/tools/web-browse.js +0 -57
  160. package/dist/tools/web-fetch.js +0 -72
  161. package/dist/tools/web-search.js +0 -59
  162. package/dist/tools/write-file.js +0 -80
  163. package/dist/ui/box.js +0 -81
  164. package/dist/ui/colors.js +0 -4
  165. package/dist/ui/diff.js +0 -185
  166. package/dist/ui/index.js +0 -6
  167. package/dist/ui/md-formatter.js +0 -212
  168. package/dist/ui/output.js +0 -13
  169. package/dist/ui/renderer.js +0 -141
  170. package/dist/ui/spinner.js +0 -70
  171. package/dist/ui/table.js +0 -144
@@ -1,170 +0,0 @@
1
- import { t } from "../../i18n/index";
2
- import { existsSync } from "fs";
3
- import { join } from "path";
4
- const FILE_EXTENSIONS = new Set([
5
- "ts",
6
- "tsx",
7
- "js",
8
- "jsx",
9
- "mjs",
10
- "cjs",
11
- "mts",
12
- "cts",
13
- "json",
14
- "md",
15
- "yaml",
16
- "yml",
17
- "py",
18
- "rs",
19
- "go",
20
- "java",
21
- "c",
22
- "cpp",
23
- "h",
24
- "hpp",
25
- "html",
26
- "css",
27
- "scss",
28
- "less",
29
- "vue",
30
- "svelte",
31
- "sh",
32
- "bash",
33
- "zsh",
34
- "ps1",
35
- "bat",
36
- "cmd",
37
- "txt",
38
- "env",
39
- "env.local",
40
- "env.production",
41
- "gitignore",
42
- "dockerignore",
43
- "dockerfile",
44
- "makefile",
45
- "cmake",
46
- "toml",
47
- "lock",
48
- "config",
49
- "log",
50
- "xml",
51
- "sql",
52
- "graphql",
53
- "proto",
54
- "wasm",
55
- ]);
56
- const VERSION_PATTERN = /^\d+(\.\d+)*$/;
57
- const COMMON_WORDS = new Set([
58
- "node.js", "Node.js",
59
- "console.log", "console.error", "console.warn", "console.info",
60
- "Math.floor", "Math.ceil", "Math.round", "Math.max", "Math.min",
61
- "JSON.parse", "JSON.stringify",
62
- "Object.keys", "Object.values", "Object.entries",
63
- "Array.from", "Array.isArray",
64
- "Date.now", "Date.parse",
65
- "RegExp", "Promise",
66
- ]);
67
- export class FactualCheck {
68
- knownPaths = new Set();
69
- createdPaths = new Set();
70
- readFiles = new Set();
71
- baseDir = process.cwd();
72
- setBaseDir(dir) {
73
- this.baseDir = dir;
74
- }
75
- trackReadPath(path) {
76
- this.knownPaths.add(path);
77
- const base = path.split(/[/\\]/).pop();
78
- if (base && base !== path)
79
- this.knownPaths.add(base);
80
- // Track that this file was actually read by the agent
81
- this.readFiles.add(base || path);
82
- }
83
- trackCreatedPath(path) {
84
- this.knownPaths.add(path);
85
- const base = path.split(/[/\\]/).pop();
86
- if (base && base !== path)
87
- this.knownPaths.add(base);
88
- this.createdPaths.add(path);
89
- }
90
- trackDeletedPath(path) {
91
- this.knownPaths.add(path);
92
- const base = path.split(/[/\\]/).pop();
93
- if (base && base !== path)
94
- this.knownPaths.add(base);
95
- this.createdPaths.delete(path);
96
- }
97
- /**
98
- * Register file paths found in a document (e.g. structure.md, README).
99
- * Files mentioned in project documentation are not hallucinations.
100
- */
101
- trackDocumentContent(content) {
102
- // Match common path patterns in documentation
103
- const pathPatterns = /(?:^|\s)([\w\-./]+\.\w{1,10})(?:\s|$|[,;)])/gm;
104
- let match;
105
- while ((match = pathPatterns.exec(content)) !== null) {
106
- const file = match[1];
107
- if (file.includes('/') || file.includes('\\')) {
108
- this.knownPaths.add(file);
109
- }
110
- const base = file.split(/[/\\]/).pop();
111
- if (base)
112
- this.knownPaths.add(base);
113
- }
114
- }
115
- pathExistsOnDisk(path) {
116
- try {
117
- // Skip absolute paths — they're either system paths or outside the project.
118
- // On Windows, existsSync('/...') can hang on certain paths.
119
- if (path.startsWith("/") || path.startsWith("~") || /^[A-Za-z]:/.test(path)) {
120
- return false;
121
- }
122
- return existsSync(join(this.baseDir, path));
123
- }
124
- catch {
125
- return false;
126
- }
127
- }
128
- validate(response) {
129
- const pathRegex = /[\w\-./]+\.\w+/g;
130
- const mentionedPaths = response.match(pathRegex) || [];
131
- const unknownPaths = mentionedPaths.filter((p) => {
132
- if (this.knownPaths.has(p))
133
- return false;
134
- if (VERSION_PATTERN.test(p))
135
- return false;
136
- if (COMMON_WORDS.has(p))
137
- return false;
138
- // Skip absolute paths — agent responses use relative paths; absolute
139
- // paths are either system paths or URLs, and existsSync can hang on
140
- // Windows for root-relative paths like "/page.html".
141
- if (p.startsWith("/") || p.startsWith("~") || /^[A-Za-z]:/.test(p))
142
- return false;
143
- if (this.pathExistsOnDisk(p))
144
- return false;
145
- const ext = p.split(".").pop()?.toLowerCase() || "";
146
- if (!FILE_EXTENSIONS.has(ext))
147
- return false;
148
- const basename = p
149
- .split("/")
150
- .pop()
151
- ?.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
152
- if (basename) {
153
- const urlPattern = new RegExp(`(https?|file)://[^\\s]*${basename}`);
154
- if (urlPattern.test(response))
155
- return false;
156
- }
157
- return true;
158
- });
159
- if (unknownPaths.length > 0) {
160
- const uniquePaths = [...new Set(unknownPaths)];
161
- return {
162
- status: "warn",
163
- reason: t("hall.unknown_paths", {
164
- paths: uniquePaths.slice(0, 3).join(", "),
165
- }),
166
- };
167
- }
168
- return { status: "pass" };
169
- }
170
- }
@@ -1,4 +0,0 @@
1
- export { HallucinationDetector } from './detector';
2
- export { FactualCheck } from './factual';
3
- export { ConsistencyCheck } from './consistency';
4
- export { ConfidenceCheck } from './confidence';
@@ -1,5 +0,0 @@
1
- export { ModuleRegistry } from './registry';
2
- export { SkillsLoader, SkillsMatcher, SkillsModule } from './skills';
3
- export { PluginManager } from './plugins';
4
- export { PluginLoader } from './plugins/loader';
5
- export { MCPClient, MCPRegistry } from './mcp';
@@ -1,38 +0,0 @@
1
- import { readFileSync, writeFileSync, existsSync, mkdirSync, rmSync } from 'fs';
2
- import { join } from 'path';
3
- export class IndexCache {
4
- cachePath;
5
- cache = null;
6
- constructor(cacheDir) {
7
- this.cachePath = join(cacheDir, 'index-cache.json');
8
- }
9
- load() {
10
- if (this.cache)
11
- return this.cache;
12
- if (!existsSync(this.cachePath))
13
- return null;
14
- try {
15
- this.cache = JSON.parse(readFileSync(this.cachePath, 'utf-8'));
16
- return this.cache;
17
- }
18
- catch {
19
- return null;
20
- }
21
- }
22
- save(result) {
23
- this.cache = result;
24
- const dir = join(this.cachePath, '..');
25
- if (!existsSync(dir))
26
- mkdirSync(dir, { recursive: true });
27
- writeFileSync(this.cachePath, JSON.stringify(result), 'utf-8');
28
- }
29
- invalidate() {
30
- this.cache = null;
31
- if (existsSync(this.cachePath)) {
32
- try {
33
- rmSync(this.cachePath);
34
- }
35
- catch { /* ignore */ }
36
- }
37
- }
38
- }
@@ -1,3 +0,0 @@
1
- export { Indexer } from './walker';
2
- export { IndexCache } from './cache';
3
- export { IndexerModule } from './module';
@@ -1,192 +0,0 @@
1
- import { dirname } from 'path';
2
- import { Indexer } from './walker';
3
- import { IndexCache } from './cache';
4
- import { t } from '../../i18n/index';
5
- export class IndexerModule {
6
- name = 'indexer';
7
- indexer;
8
- cache;
9
- baseDir;
10
- index = null;
11
- rebuildTimeout = null;
12
- constructor(opts) {
13
- this.baseDir = opts.baseDir;
14
- this.indexer = new Indexer(opts.baseDir);
15
- this.cache = new IndexCache(opts.cacheDir);
16
- }
17
- async buildIndex() {
18
- if (this.index)
19
- return this.index;
20
- const cached = this.cache.load();
21
- if (cached) {
22
- this.index = cached;
23
- return cached;
24
- }
25
- try {
26
- const result = await this.indexer.walk();
27
- this.cache.save(result);
28
- this.index = result;
29
- return result;
30
- }
31
- catch {
32
- return null;
33
- }
34
- }
35
- async refresh() {
36
- this.cache.invalidate();
37
- this.index = null;
38
- return this.buildIndex();
39
- }
40
- find(query) {
41
- if (!this.index)
42
- return [];
43
- const q = query.toLowerCase();
44
- return this.index.files.filter((f) => {
45
- const path = f.path.toLowerCase();
46
- return path.includes(q) || f.exports.some((e) => e.toLowerCase().includes(q));
47
- });
48
- }
49
- watch() {
50
- this.unwatch();
51
- try {
52
- this.indexer.watch((_event, filename) => {
53
- if (!filename)
54
- return;
55
- if (this.rebuildTimeout)
56
- clearTimeout(this.rebuildTimeout);
57
- this.rebuildTimeout = setTimeout(() => {
58
- this.refresh().catch(() => { });
59
- }, 2000);
60
- });
61
- }
62
- catch {
63
- // Watching is best-effort; manual refresh still works.
64
- }
65
- }
66
- unwatch() {
67
- if (this.rebuildTimeout) {
68
- clearTimeout(this.rebuildTimeout);
69
- this.rebuildTimeout = null;
70
- }
71
- this.indexer.unwatch();
72
- }
73
- getSystemPromptBlock() {
74
- if (!this.index)
75
- return null;
76
- const content = this.formatMap(this.index);
77
- return {
78
- content,
79
- priority: 'normal',
80
- essential: false,
81
- estimatedTokens: this.estimateTokens(content),
82
- };
83
- }
84
- getToolDefinitions() {
85
- return [this.createProjectMapTool()];
86
- }
87
- getPlugin() {
88
- return {
89
- name: 'indexer',
90
- onSessionStart: () => {
91
- this.buildIndex().catch(() => { });
92
- this.watch();
93
- },
94
- onSessionEnd: () => {
95
- this.unwatch();
96
- },
97
- };
98
- }
99
- formatMap(result) {
100
- const summary = this.indexer.summarize(result);
101
- const dirCounts = this.getDirectoryCounts(result);
102
- const topDirs = Object.entries(dirCounts)
103
- .sort((a, b) => b[1] - a[1])
104
- .slice(0, 10)
105
- .map(([dir, count]) => `${dir} (${count})`)
106
- .join(', ') || '-';
107
- const fileLines = result.files.slice(0, 100).map((f) => {
108
- const path = f.path.replace(/\\/g, '/');
109
- const exports = f.exports.length > 0 ? `: ${f.exports.join(', ')}` : '';
110
- return `- ${path}${exports}`;
111
- });
112
- const more = result.files.length > 100
113
- ? `\n${t('indexer.and_more', { count: result.files.length - 100 })}`
114
- : '';
115
- return [
116
- `${t('indexer.map_header')} (${this.baseDir})`,
117
- summary,
118
- `${t('indexer.top_directories')}: ${topDirs}`,
119
- `${t('indexer.files')}:` + (fileLines.length > 0 ? '' : ' ' + t('indexer.empty')),
120
- ...fileLines,
121
- more,
122
- ].join('\n');
123
- }
124
- getDirectoryCounts(result) {
125
- const counts = {};
126
- for (const f of result.files) {
127
- const normalized = f.path.replace(/\\/g, '/');
128
- const dir = dirname(normalized);
129
- const key = dir === '.' ? '(root)' : dir;
130
- counts[key] = (counts[key] || 0) + 1;
131
- }
132
- return counts;
133
- }
134
- estimateTokens(content) {
135
- return Math.ceil(content.length / 4);
136
- }
137
- createProjectMapTool() {
138
- return {
139
- name: 'project_map',
140
- description: t('indexer.project_map_desc'),
141
- parameters: {
142
- type: 'object',
143
- properties: {
144
- action: {
145
- type: 'string',
146
- enum: ['summary', 'refresh', 'find'],
147
- description: t('indexer.project_map_action_desc'),
148
- },
149
- query: {
150
- type: 'string',
151
- description: t('indexer.project_map_query_desc'),
152
- },
153
- },
154
- required: ['action'],
155
- },
156
- handler: async (_ctx, args) => {
157
- const action = String(args.action || 'summary');
158
- if (action === 'refresh') {
159
- const result = await this.refresh();
160
- const summary = result ? this.indexer.summarize(result) : t('indexer.empty');
161
- return this.makeResult(t('indexer.refreshed', { summary }));
162
- }
163
- if (action === 'find') {
164
- const query = String(args.query || '').toLowerCase();
165
- if (!query)
166
- return { success: false, output: t('tool.invalid_params') };
167
- const matches = this.find(query);
168
- if (matches.length === 0) {
169
- return this.makeResult(t('indexer.no_matches', { query }));
170
- }
171
- const lines = matches.map((f) => {
172
- const path = f.path.replace(/\\/g, '/');
173
- const exports = f.exports.length > 0 ? `: ${f.exports.join(', ')}` : '';
174
- return `- ${path}${exports}`;
175
- }).join('\n');
176
- return this.makeResult(t('indexer.find_results', { count: matches.length, results: lines }));
177
- }
178
- if (!this.index) {
179
- await this.buildIndex();
180
- }
181
- if (!this.index) {
182
- return this.makeResult(t('indexer.not_indexed'));
183
- }
184
- const summary = this.indexer.summarize(this.index);
185
- return this.makeResult(t('indexer.summary', { summary }));
186
- },
187
- };
188
- }
189
- makeResult(output) {
190
- return { success: true, output, display: output };
191
- }
192
- }
@@ -1,101 +0,0 @@
1
- import { readdirSync, readFileSync, statSync, existsSync, watch } from 'fs';
2
- import { join, relative, extname } from 'path';
3
- const LANGUAGES = {
4
- '.ts': 'typescript',
5
- '.tsx': 'typescript-react',
6
- '.js': 'javascript',
7
- '.jsx': 'javascript-react',
8
- '.json': 'json',
9
- '.md': 'markdown',
10
- '.yaml': 'yaml',
11
- '.yml': 'yaml',
12
- '.py': 'python',
13
- '.rs': 'rust',
14
- '.go': 'go',
15
- };
16
- const IGNORE_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.mma', 'coverage']);
17
- export class Indexer {
18
- baseDir;
19
- MAX_FILES = 1000;
20
- watcher = null;
21
- constructor(baseDir) {
22
- this.baseDir = baseDir;
23
- }
24
- watch(callback) {
25
- this.watcher = watch(this.baseDir, { recursive: true }, (event, filename) => {
26
- if (filename && !Array.from(IGNORE_DIRS).some((dir) => filename.includes(dir))) {
27
- callback(event, filename);
28
- }
29
- });
30
- }
31
- unwatch() {
32
- if (this.watcher) {
33
- this.watcher.close();
34
- this.watcher = null;
35
- }
36
- }
37
- async walk() {
38
- const files = [];
39
- let totalSize = 0;
40
- let count = 0;
41
- const walkDir = (dir) => {
42
- if (!existsSync(dir))
43
- return;
44
- let entries;
45
- try {
46
- entries = readdirSync(dir);
47
- }
48
- catch {
49
- return;
50
- }
51
- for (const entry of entries) {
52
- if (count >= this.MAX_FILES)
53
- return;
54
- const fullPath = join(dir, entry);
55
- const relPath = relative(this.baseDir, fullPath);
56
- const stat = statSync(fullPath);
57
- if (stat.isDirectory()) {
58
- if (!IGNORE_DIRS.has(entry)) {
59
- walkDir(fullPath);
60
- }
61
- }
62
- else if (stat.isFile()) {
63
- const ext = extname(entry).toLowerCase();
64
- const language = LANGUAGES[ext];
65
- if (language) {
66
- const content = readFileSync(fullPath, 'utf-8');
67
- const exports = this.extractExports(content, language);
68
- files.push({ path: relPath, language, exports, size: stat.size });
69
- totalSize += stat.size;
70
- count++;
71
- }
72
- }
73
- }
74
- };
75
- walkDir(this.baseDir);
76
- return { files, totalSize };
77
- }
78
- extractExports(content, language) {
79
- if (language === 'typescript' || language === 'javascript') {
80
- const exports = [];
81
- const exportRegex = /export\s+(?:const|function|class|interface|type|enum|default\s+(?:class|function))\s+(\w+)/g;
82
- let match;
83
- while ((match = exportRegex.exec(content)) !== null) {
84
- exports.push(match[1]);
85
- }
86
- return exports;
87
- }
88
- return [];
89
- }
90
- summarize(result) {
91
- const byLang = {};
92
- for (const f of result.files) {
93
- byLang[f.language] = (byLang[f.language] || 0) + 1;
94
- }
95
- const langs = Object.entries(byLang)
96
- .sort((a, b) => b[1] - a[1])
97
- .map(([lang, count]) => `${lang}:${count}`)
98
- .join(', ');
99
- return `[Index: ${result.files.length} files, ${(result.totalSize / 1024).toFixed(1)}KB (${langs})]`;
100
- }
101
- }