micro-models-agent 0.58.2 → 0.60.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 (233) hide show
  1. package/CHANGELOG.md +578 -556
  2. package/README.md +358 -358
  3. package/dist/certification/certifications.json +493 -493
  4. package/dist/i18n/en.json +732 -716
  5. package/dist/i18n/ru.json +732 -716
  6. package/dist/main.js +1243 -448
  7. package/dist/modules/browser/bridge-server.mjs +219 -219
  8. package/dist/skills/builtin/git.md +36 -36
  9. package/dist/skills/builtin/typescript.md +35 -35
  10. package/package.json +51 -51
  11. package/dist/cli/commands.js +0 -447
  12. package/dist/cli/completer.js +0 -167
  13. package/dist/cli/index.js +0 -2
  14. package/dist/cli/main.js +0 -153
  15. package/dist/cli/plugin-commands.js +0 -36
  16. package/dist/cli/repl-commands.js +0 -761
  17. package/dist/cli/repl.js +0 -702
  18. package/dist/cli/run-result.js +0 -33
  19. package/dist/cli/security-commands.js +0 -164
  20. package/dist/cli/setup.js +0 -237
  21. package/dist/config/config.js +0 -276
  22. package/dist/config/defaults.js +0 -141
  23. package/dist/config/domains.js +0 -179
  24. package/dist/config/experts.js +0 -15
  25. package/dist/config/index.js +0 -4
  26. package/dist/config/security.js +0 -213
  27. package/dist/config/types.js +0 -1
  28. package/dist/core/agent-moe.js +0 -102
  29. package/dist/core/agent.js +0 -1018
  30. package/dist/core/bootstrap.js +0 -481
  31. package/dist/core/crash-handler.js +0 -51
  32. package/dist/core/environment.js +0 -199
  33. package/dist/core/index.js +0 -2
  34. package/dist/core/prompt-builder.js +0 -76
  35. package/dist/core/session-logger.js +0 -251
  36. package/dist/core/types.js +0 -1
  37. package/dist/core/version.js +0 -26
  38. package/dist/core/workspace.js +0 -76
  39. package/dist/i18n/index.js +0 -46
  40. package/dist/index.js +0 -22
  41. package/dist/llm/image-utils.js +0 -143
  42. package/dist/llm/index.js +0 -4
  43. package/dist/llm/model-loader.js +0 -78
  44. package/dist/llm/openai-compat.js +0 -497
  45. package/dist/llm/orchestrator.js +0 -200
  46. package/dist/llm/provider.js +0 -10
  47. package/dist/llm/response.js +0 -39
  48. package/dist/llm/token-counter.js +0 -39
  49. package/dist/llm/types.js +0 -1
  50. package/dist/logger/app-logger.js +0 -189
  51. package/dist/logger/file-log.js +0 -151
  52. package/dist/logger/index.js +0 -1
  53. package/dist/migration/backup.js +0 -45
  54. package/dist/migration/detect.js +0 -50
  55. package/dist/migration/index.js +0 -2
  56. package/dist/modules/artifacts/store.js +0 -61
  57. package/dist/modules/browser/actions.js +0 -76
  58. package/dist/modules/browser/bridge-client.js +0 -199
  59. package/dist/modules/browser/bridge-path.js +0 -10
  60. package/dist/modules/browser/cookie-store.js +0 -24
  61. package/dist/modules/browser/driver.js +0 -136
  62. package/dist/modules/browser/index.js +0 -7
  63. package/dist/modules/browser/module.js +0 -29
  64. package/dist/modules/browser/session.js +0 -342
  65. package/dist/modules/browser/snapshot.js +0 -148
  66. package/dist/modules/browser/types.js +0 -12
  67. package/dist/modules/certification/cli.js +0 -213
  68. package/dist/modules/certification/fact-checker.js +0 -82
  69. package/dist/modules/certification/loader.js +0 -106
  70. package/dist/modules/certification/manifest.js +0 -58
  71. package/dist/modules/certification/runner.js +0 -245
  72. package/dist/modules/certification/scenarios.js +0 -407
  73. package/dist/modules/certification/types.js +0 -1
  74. package/dist/modules/context/chunk-query.js +0 -100
  75. package/dist/modules/context/fact-extractor.js +0 -168
  76. package/dist/modules/context/history.js +0 -15
  77. package/dist/modules/context/index.js +0 -1
  78. package/dist/modules/context/manager.js +0 -440
  79. package/dist/modules/execution/audit-runners.js +0 -206
  80. package/dist/modules/execution/auditor.js +0 -218
  81. package/dist/modules/execution/execution-plugin.js +0 -431
  82. package/dist/modules/execution/index.js +0 -8
  83. package/dist/modules/execution/module.js +0 -625
  84. package/dist/modules/execution/moe-executor.js +0 -304
  85. package/dist/modules/execution/plan-coverage.js +0 -68
  86. package/dist/modules/execution/plan-persister.js +0 -46
  87. package/dist/modules/execution/plan-store.js +0 -196
  88. package/dist/modules/execution/plan-tool.js +0 -677
  89. package/dist/modules/execution/plan-validator.js +0 -153
  90. package/dist/modules/execution/planner.js +0 -94
  91. package/dist/modules/execution/stuck-detector.js +0 -746
  92. package/dist/modules/execution/tracker.js +0 -69
  93. package/dist/modules/execution/types.js +0 -1
  94. package/dist/modules/execution/verifier.js +0 -235
  95. package/dist/modules/execution/windows-commands.js +0 -41
  96. package/dist/modules/hallucination/confidence.js +0 -66
  97. package/dist/modules/hallucination/consistency.js +0 -26
  98. package/dist/modules/hallucination/detector.js +0 -47
  99. package/dist/modules/hallucination/factual.js +0 -169
  100. package/dist/modules/hallucination/index.js +0 -5
  101. package/dist/modules/hallucination/js-identifiers.js +0 -262
  102. package/dist/modules/hallucination/llm-judge.js +0 -101
  103. package/dist/modules/index.js +0 -5
  104. package/dist/modules/indexer/cache.js +0 -40
  105. package/dist/modules/indexer/index.js +0 -3
  106. package/dist/modules/indexer/module.js +0 -246
  107. package/dist/modules/indexer/project-profile.js +0 -183
  108. package/dist/modules/indexer/walker.js +0 -101
  109. package/dist/modules/lsp/check-tool.js +0 -58
  110. package/dist/modules/lsp/client.js +0 -389
  111. package/dist/modules/lsp/command.js +0 -60
  112. package/dist/modules/lsp/config.js +0 -135
  113. package/dist/modules/lsp/index.js +0 -3
  114. package/dist/modules/lsp/module.js +0 -260
  115. package/dist/modules/lsp/probe.js +0 -86
  116. package/dist/modules/lsp/project-root.js +0 -32
  117. package/dist/modules/lsp/startup-check.js +0 -144
  118. package/dist/modules/lsp/types.js +0 -1
  119. package/dist/modules/mcp/client.js +0 -399
  120. package/dist/modules/mcp/index.js +0 -3
  121. package/dist/modules/mcp/module.js +0 -142
  122. package/dist/modules/mcp/registry.js +0 -15
  123. package/dist/modules/memory/index.js +0 -1
  124. package/dist/modules/memory/module.js +0 -96
  125. package/dist/modules/memory/search.js +0 -42
  126. package/dist/modules/memory/store.js +0 -69
  127. package/dist/modules/pipelines/engine.js +0 -60
  128. package/dist/modules/pipelines/index.js +0 -3
  129. package/dist/modules/pipelines/parser.js +0 -56
  130. package/dist/modules/pipelines/template.js +0 -14
  131. package/dist/modules/plugins/builtin/lint-on-write.js +0 -334
  132. package/dist/modules/plugins/builtin/notify.js +0 -9
  133. package/dist/modules/plugins/index.js +0 -1
  134. package/dist/modules/plugins/loader.js +0 -70
  135. package/dist/modules/plugins/manager.js +0 -261
  136. package/dist/modules/plugins/types.js +0 -1
  137. package/dist/modules/pricing/index.js +0 -61
  138. package/dist/modules/pricing/prices.js +0 -129
  139. package/dist/modules/processes/detect.js +0 -34
  140. package/dist/modules/processes/index.js +0 -2
  141. package/dist/modules/processes/registry.js +0 -327
  142. package/dist/modules/processes/runner.js +0 -23
  143. package/dist/modules/providers/create.js +0 -22
  144. package/dist/modules/providers/fallback.js +0 -79
  145. package/dist/modules/providers/health.js +0 -46
  146. package/dist/modules/providers/index.js +0 -5
  147. package/dist/modules/providers/manager.js +0 -161
  148. package/dist/modules/providers/presets.js +0 -128
  149. package/dist/modules/providers/registry.js +0 -22
  150. package/dist/modules/providers/types.js +0 -1
  151. package/dist/modules/registry.js +0 -48
  152. package/dist/modules/security/audit-log.js +0 -136
  153. package/dist/modules/security/audit-notifier.js +0 -292
  154. package/dist/modules/security/command-validator.js +0 -219
  155. package/dist/modules/security/content-scanner.js +0 -53
  156. package/dist/modules/security/data-sanitizer.js +0 -89
  157. package/dist/modules/security/encryption.js +0 -242
  158. package/dist/modules/security/index.js +0 -14
  159. package/dist/modules/security/network-validator.js +0 -88
  160. package/dist/modules/security/path-validator.js +0 -203
  161. package/dist/modules/security/rate-limiter.js +0 -119
  162. package/dist/modules/security/security-policies.js +0 -531
  163. package/dist/modules/security/session-encryption.js +0 -210
  164. package/dist/modules/security/session-isolation.js +0 -95
  165. package/dist/modules/session/index.js +0 -3
  166. package/dist/modules/session/manager.js +0 -172
  167. package/dist/modules/session/module.js +0 -24
  168. package/dist/modules/session/store.js +0 -222
  169. package/dist/modules/session/types.js +0 -1
  170. package/dist/modules/skills/index.js +0 -2
  171. package/dist/modules/skills/loader.js +0 -72
  172. package/dist/modules/skills/matcher.js +0 -27
  173. package/dist/modules/skills/module.js +0 -129
  174. package/dist/modules/types.js +0 -1
  175. package/dist/modules/updater/checker.js +0 -96
  176. package/dist/modules/updater/index.js +0 -2
  177. package/dist/modules/updater/module.js +0 -116
  178. package/dist/modules/user-profile/compressor.js +0 -16
  179. package/dist/modules/user-profile/index.js +0 -1
  180. package/dist/modules/user-profile/profile.js +0 -68
  181. package/dist/tools/approve.js +0 -33
  182. package/dist/tools/attach-image.js +0 -101
  183. package/dist/tools/bash.js +0 -519
  184. package/dist/tools/browser.js +0 -115
  185. package/dist/tools/chunk-query.js +0 -100
  186. package/dist/tools/create-dir.js +0 -56
  187. package/dist/tools/delete-file.js +0 -63
  188. package/dist/tools/download-file.js +0 -117
  189. package/dist/tools/edit-file.js +0 -80
  190. package/dist/tools/enable-tools.js +0 -59
  191. package/dist/tools/executor.js +0 -154
  192. package/dist/tools/file-info.js +0 -47
  193. package/dist/tools/filter-tools.js +0 -17
  194. package/dist/tools/glob-tool.js +0 -27
  195. package/dist/tools/grep-tool.js +0 -125
  196. package/dist/tools/hidden-tools-block.js +0 -37
  197. package/dist/tools/index.js +0 -78
  198. package/dist/tools/list-dir.js +0 -49
  199. package/dist/tools/load-skill.js +0 -43
  200. package/dist/tools/mcp-call.js +0 -69
  201. package/dist/tools/move-file.js +0 -86
  202. package/dist/tools/path-utils.js +0 -101
  203. package/dist/tools/pipeline-run.js +0 -145
  204. package/dist/tools/preview.js +0 -2
  205. package/dist/tools/process-kill.js +0 -40
  206. package/dist/tools/process-list.js +0 -37
  207. package/dist/tools/process-log.js +0 -54
  208. package/dist/tools/question.js +0 -141
  209. package/dist/tools/read-file.js +0 -179
  210. package/dist/tools/recall.js +0 -118
  211. package/dist/tools/registry.js +0 -47
  212. package/dist/tools/remember.js +0 -68
  213. package/dist/tools/scope-check.js +0 -32
  214. package/dist/tools/search-history.js +0 -85
  215. package/dist/tools/subagent.js +0 -196
  216. package/dist/tools/types.js +0 -1
  217. package/dist/tools/user-input.js +0 -123
  218. package/dist/tools/web-browse.js +0 -87
  219. package/dist/tools/web-fetch.js +0 -119
  220. package/dist/tools/web-search.js +0 -105
  221. package/dist/tools/write-file.js +0 -82
  222. package/dist/ui/box.js +0 -77
  223. package/dist/ui/colors.js +0 -4
  224. package/dist/ui/diff.js +0 -178
  225. package/dist/ui/index.js +0 -6
  226. package/dist/ui/line-editor.js +0 -822
  227. package/dist/ui/line-math.js +0 -73
  228. package/dist/ui/md-formatter.js +0 -212
  229. package/dist/ui/output.js +0 -13
  230. package/dist/ui/plan-view.js +0 -103
  231. package/dist/ui/renderer.js +0 -259
  232. package/dist/ui/spinner.js +0 -70
  233. package/dist/ui/table.js +0 -144
@@ -1,179 +0,0 @@
1
- import { readFileSync, existsSync, statSync, openSync, readSync, closeSync } from "fs";
2
- import { extname } from "path";
3
- import { t } from "../i18n/index";
4
- import { isPathInScope } from "../modules/security/path-validator";
5
- import { DEFAULT_SECURITY_CONFIG } from "../config/security";
6
- import { logSecurityBlock } from "../modules/security/audit-log";
7
- import { safeResolvePath } from "./path-utils";
8
- /**
9
- * Default lines per read_file call. Deliberately much larger than
10
- * MAX_PREVIEW_LINES (15): a 15-line default forces the model to issue 10-17
11
- * calls per file, which floods the context and drives compaction every 15
12
- * iterations (observed: 96 read_file calls, App.tsx read 23x, then 11
13
- * compactions in ~20 min that deleted the user's task mid-turn). 300 lines
14
- * covers typical component files in one call while still capping output.
15
- */
16
- const DEFAULT_LIMIT = 300;
17
- /**
18
- * Files larger than this are read through a bounded streaming path instead of
19
- * readFileSync (which loads the whole file into memory just to slice a few
20
- * hundred lines).
21
- */
22
- const LARGE_FILE_BYTES = 1024 * 1024;
23
- const STREAM_CHUNK = 256 * 1024;
24
- /**
25
- * Bounded line-slice read for large files: streams the file in chunks,
26
- * collects only the requested [offset, offset+limit) window, then counts the
27
- * remaining newlines raw (no decode) to produce the total. Memory stays
28
- * bounded regardless of file size.
29
- */
30
- function readLineSlice(path, offset, limit) {
31
- const fd = openSync(path, "r");
32
- try {
33
- const buf = Buffer.alloc(STREAM_CHUNK);
34
- let pos = 0;
35
- let carry = "";
36
- let lineNumber = 1;
37
- let total = 0;
38
- const collected = [];
39
- const endLine = offset + limit; // exclusive
40
- while (true) {
41
- const bytes = readSync(fd, buf, 0, STREAM_CHUNK, pos);
42
- if (bytes === 0)
43
- break;
44
- pos += bytes;
45
- const chunk = carry + buf.toString("utf-8", 0, bytes);
46
- const parts = chunk.split("\n");
47
- carry = parts.pop() ?? "";
48
- for (const line of parts) {
49
- total++;
50
- if (lineNumber >= offset && lineNumber < endLine)
51
- collected.push(line);
52
- lineNumber++;
53
- }
54
- if (lineNumber >= endLine && collected.length >= limit) {
55
- // Window complete — count remaining newlines without decoding.
56
- const rest = [];
57
- while (true) {
58
- const n = readSync(fd, buf, 0, STREAM_CHUNK, pos);
59
- if (n === 0)
60
- break;
61
- pos += n;
62
- rest.push(Buffer.from(buf.subarray(0, n)));
63
- }
64
- const tail = Buffer.concat([...rest, Buffer.from(carry, "utf-8")]);
65
- for (let i = 0; i < tail.length; i++)
66
- if (tail[i] === 0x0a)
67
- total++;
68
- total++; // last line has no trailing newline
69
- return { selected: collected.join("\n"), total };
70
- }
71
- }
72
- if (carry.length > 0 || total === 0) {
73
- total++;
74
- if (lineNumber >= offset && lineNumber < endLine)
75
- collected.push(carry);
76
- }
77
- return { selected: collected.join("\n"), total };
78
- }
79
- finally {
80
- closeSync(fd);
81
- }
82
- }
83
- export const readFileTool = {
84
- name: "read_file",
85
- icon: "👀",
86
- description: `Read a file from the filesystem. Reads up to ${DEFAULT_LIMIT} lines at a time by default; use offset to page through large files.`,
87
- tags: ["file", "code"],
88
- boundedOutput: true,
89
- parameters: {
90
- type: "object",
91
- properties: {
92
- path: { type: "string", description: "File path to read" },
93
- offset: {
94
- type: "number",
95
- description: `Starting line (1-indexed). Use offset=<next> from a truncated result to continue reading.`,
96
- },
97
- limit: {
98
- type: "number",
99
- description: `Number of lines to read (default ${DEFAULT_LIMIT})`,
100
- },
101
- },
102
- required: ["path"],
103
- },
104
- handler: async (ctx, args) => {
105
- const path = String(args.path);
106
- const resolved = safeResolvePath(ctx.baseDir, path);
107
- const securityPaths = ctx.config?.security?.paths || DEFAULT_SECURITY_CONFIG.paths;
108
- const scopeCheck = isPathInScope(ctx.baseDir, resolved, ctx.scope, securityPaths);
109
- if (!scopeCheck.allowed) {
110
- const pathStr = path;
111
- logSecurityBlock(ctx.sessionId || undefined, "file_read", scopeCheck.reason || "Path not allowed", pathStr);
112
- return {
113
- success: false,
114
- output: t("file.path_not_allowed", {
115
- path: `${path} — ${scopeCheck.reason}`,
116
- }),
117
- };
118
- }
119
- if (!existsSync(resolved)) {
120
- // For relative paths, tell the model WHERE the path resolved — the
121
- // "not found" alone is confusing (it cannot tell baseDir from cwd).
122
- const output = resolved !== path
123
- ? t("file.notfound_resolved", {
124
- path,
125
- resolved,
126
- })
127
- : t("file.notfound", { path });
128
- return { success: false, output };
129
- }
130
- const offset = args.offset || 1;
131
- const limit = args.limit || DEFAULT_LIMIT;
132
- let lines;
133
- let total;
134
- let selected;
135
- if (statSync(resolved).size > LARGE_FILE_BYTES) {
136
- const slice = readLineSlice(resolved, offset, limit);
137
- total = slice.total;
138
- selected = slice.selected;
139
- }
140
- else {
141
- const content = readFileSync(resolved, "utf-8");
142
- lines = content.split("\n");
143
- total = lines.length;
144
- const end = Math.min(offset - 1 + limit, total);
145
- selected = lines.slice(offset - 1, end).join("\n");
146
- }
147
- const end = Math.min(offset - 1 + limit, total);
148
- const ext = extname(resolved) || "(no extension)";
149
- const header = t("file.read_header", {
150
- path,
151
- ext,
152
- total: String(total),
153
- from: String(offset),
154
- to: String(end),
155
- });
156
- const truncated = end < total
157
- ? t("file.read_truncated", {
158
- remaining: String(total - end),
159
- next: String(end + 1),
160
- })
161
- : "";
162
- // Compact user-facing display: the tool header already shows the path,
163
- // so only a partial read needs extra info (the range within the file).
164
- // A full read adds nothing — keeps the card to two lines.
165
- const fullRead = offset === 1 && end >= total;
166
- const display = fullRead
167
- ? ""
168
- : t("file.read_range", {
169
- from: String(offset),
170
- to: String(end),
171
- total: String(total),
172
- });
173
- return {
174
- success: true,
175
- output: `${header}\n${selected}${truncated}`,
176
- display,
177
- };
178
- },
179
- };
@@ -1,118 +0,0 @@
1
- import { homedir } from "os";
2
- import { join } from "path";
3
- import { t } from "../i18n/index";
4
- import { MemoryStore } from "../modules/memory/store";
5
- const CATEGORIES = ["preferences", "conventions", "decisions", "errors", "facts"];
6
- export const recallTool = {
7
- name: "recall",
8
- icon: "💾",
9
- description: "Recall stored information from memory. Search across preferences, facts, conventions, decisions, errors.",
10
- tags: ["memory"],
11
- parameters: {
12
- type: "object",
13
- properties: {
14
- query: {
15
- type: "string",
16
- description: "Search query (full-text search across all memory)",
17
- },
18
- category: {
19
- type: "string",
20
- description: "Limit to specific category: preferences, conventions, decisions, errors, facts",
21
- enum: CATEGORIES,
22
- },
23
- },
24
- },
25
- handler: async (_ctx, args) => {
26
- const query = args.query ? String(args.query) : "";
27
- const category = args.category ? String(args.category) : "";
28
- const memoryDir = join(homedir(), ".mma", "memory");
29
- const store = new MemoryStore(memoryDir);
30
- try {
31
- // No query, no category → show everything
32
- if (!query && !category) {
33
- return { success: true, output: formatAll(store) };
34
- }
35
- // Category only → show that category
36
- if (!query && category) {
37
- return { success: true, output: formatCategory(store, category) };
38
- }
39
- // Query with optional category → search
40
- if (category) {
41
- const results = searchCategory(store, category, query);
42
- if (results.length === 0) {
43
- return { success: true, output: t("tool.recall.empty", { query }) };
44
- }
45
- return {
46
- success: true,
47
- output: t("tool.recall.search_results", { category, results: results.join("\n") }),
48
- };
49
- }
50
- // Query across all
51
- const results = store.search(query);
52
- if (results.length === 0) {
53
- return { success: true, output: t("tool.recall.empty", { query }) };
54
- }
55
- const formatted = results.map((r) => `[${r.file}] ${r.match}`).join("\n");
56
- return {
57
- success: true,
58
- output: t("tool.recall.search_results", { category: "all", results: formatted }),
59
- };
60
- }
61
- catch (err) {
62
- return { success: true, output: t("tool.memory_error", { error: String(err) }) };
63
- }
64
- },
65
- };
66
- function formatAll(store) {
67
- const parts = [];
68
- const prefs = store.getPreferences();
69
- if (Object.keys(prefs).length > 0) {
70
- parts.push("Preferences:");
71
- for (const [k, v] of Object.entries(prefs)) {
72
- parts.push(` ${k} = ${v}`);
73
- }
74
- }
75
- for (const cat of ["facts", "conventions", "decisions", "errors"]) {
76
- const content = store.read(cat);
77
- const entries = content.split("\n").filter((l) => l.startsWith("- "));
78
- if (entries.length > 0) {
79
- parts.push(`\n${cat.charAt(0).toUpperCase() + cat.slice(1)} (last 5):`);
80
- for (const e of entries.slice(-5)) {
81
- parts.push(` ${e}`);
82
- }
83
- }
84
- }
85
- return parts.length > 0 ? parts.join("\n") : t("tool.recall.no_memory");
86
- }
87
- function formatCategory(store, category) {
88
- if (category === "preferences") {
89
- const prefs = store.getPreferences();
90
- if (Object.keys(prefs).length === 0)
91
- return t("tool.recall.no_memory");
92
- const lines = ["Preferences:"];
93
- for (const [k, v] of Object.entries(prefs)) {
94
- lines.push(` ${k} = ${v}`);
95
- }
96
- return lines.join("\n");
97
- }
98
- const content = store.read(category);
99
- const entries = content.split("\n").filter((l) => l.startsWith("- "));
100
- if (entries.length === 0)
101
- return t("tool.recall.no_memory");
102
- return `${category.charAt(0).toUpperCase() + category.slice(1)} (${entries.length} entries):\n${entries.join("\n")}`;
103
- }
104
- function searchCategory(store, category, query) {
105
- if (category === "preferences") {
106
- const prefs = store.getPreferences();
107
- const lower = query.toLowerCase();
108
- return Object.entries(prefs)
109
- .filter(([k, v]) => k.toLowerCase().includes(lower) || v.toLowerCase().includes(lower))
110
- .map(([k, v]) => ` ${k} = ${v}`);
111
- }
112
- const content = store.read(category);
113
- const lower = query.toLowerCase();
114
- return content
115
- .split("\n")
116
- .filter((l) => l.startsWith("- ") && l.toLowerCase().includes(lower))
117
- .map((l) => ` ${l}`);
118
- }
@@ -1,47 +0,0 @@
1
- export class ToolRegistry {
2
- tools = new Map();
3
- register(tool) {
4
- if (this.tools.has(tool.name)) {
5
- throw new Error(`Tool already registered: ${tool.name}`);
6
- }
7
- this.tools.set(tool.name, tool);
8
- }
9
- get(name) {
10
- return this.tools.get(name);
11
- }
12
- has(name) {
13
- return this.tools.has(name);
14
- }
15
- list() {
16
- return Array.from(this.tools.keys()).sort();
17
- }
18
- getAll() {
19
- return Array.from(this.tools.values());
20
- }
21
- getByTags(tags) {
22
- return this.getAll().filter((t) => {
23
- if (!t.tags || t.tags.length === 0)
24
- return false;
25
- return tags.some((tag) => t.tags.includes(tag));
26
- });
27
- }
28
- /**
29
- * Tools to expose to the LLM. Always includes `alwaysOn` tools, then tools
30
- * matching the given tags. When no tags are given, returns every registered
31
- * tool (backward-compatible). Duplicates are impossible because the
32
- * alwaysOn + tagged sets are unioned by name.
33
- */
34
- getAllForLLM(tags) {
35
- const all = this.getAll();
36
- const tagSet = new Set(tags ?? []);
37
- const selected = tagSet.size === 0
38
- ? all
39
- : all.filter((t) => t.alwaysOn || (t.tags && t.tags.some((tag) => tagSet.has(tag))));
40
- return selected.map((t) => ({
41
- name: t.name,
42
- description: t.description,
43
- parameters: t.parameters,
44
- boundedOutput: t.boundedOutput,
45
- }));
46
- }
47
- }
@@ -1,68 +0,0 @@
1
- import { homedir } from "os";
2
- import { join } from "path";
3
- import { t } from "../i18n/index";
4
- import { MemoryStore } from "../modules/memory/store";
5
- const CATEGORIES = ["preferences", "conventions", "decisions", "errors", "facts"];
6
- export const rememberTool = {
7
- name: "remember",
8
- icon: "🧠",
9
- description: "Remember information across sessions. Use for user preferences, facts, conventions, decisions, or errors.",
10
- tags: ["memory"],
11
- parameters: {
12
- type: "object",
13
- properties: {
14
- category: {
15
- type: "string",
16
- description: "Memory category: preferences, conventions, decisions, errors, facts",
17
- enum: CATEGORIES,
18
- },
19
- key: {
20
- type: "string",
21
- description: 'Key name (required for preferences, e.g. "color", "language")',
22
- },
23
- value: {
24
- type: "string",
25
- description: "Value to store (required for preferences)",
26
- },
27
- entry: {
28
- type: "string",
29
- description: "Text entry to append (for conventions, decisions, errors, facts)",
30
- },
31
- },
32
- required: ["category"],
33
- },
34
- handler: async (_ctx, args) => {
35
- const category = String(args.category || "");
36
- if (!CATEGORIES.includes(category)) {
37
- return { success: false, output: t("tool.invalid_params") };
38
- }
39
- const memoryDir = join(homedir(), ".mma", "memory");
40
- const store = new MemoryStore(memoryDir);
41
- try {
42
- if (category === "preferences") {
43
- const key = String(args.key || "");
44
- const value = String(args.value || "");
45
- if (!key) {
46
- return { success: false, output: t("tool.remember.key_required") };
47
- }
48
- store.setPreference(key, value);
49
- return {
50
- success: true,
51
- output: t("tool.remember.preference", { key, value }),
52
- };
53
- }
54
- const entry = String(args.entry || "");
55
- if (!entry) {
56
- return { success: false, output: t("tool.remember.entry_required") };
57
- }
58
- store.append(category, entry);
59
- return {
60
- success: true,
61
- output: t("tool.remember.entry", { category, entry }),
62
- };
63
- }
64
- catch (err) {
65
- return { success: true, output: t("tool.memory_error", { error: String(err) }) };
66
- }
67
- },
68
- };
@@ -1,32 +0,0 @@
1
- import { resolve, normalize } from "path";
2
- import { isInsideDir, matchesScopeEntry } from "./path-utils";
3
- export function isPathInScope(baseDir, targetPath, scope) {
4
- const baseResolved = resolve(baseDir);
5
- const targetResolved = resolve(baseDir, normalize(targetPath));
6
- // Separator- and case-safe containment (sibling prefixes cannot pass).
7
- if (!isInsideDir(targetResolved, baseResolved)) {
8
- return { allowed: false, reason: "Path is outside the base working directory" };
9
- }
10
- if (!scope)
11
- return { allowed: true };
12
- const isRead = scope.read_only_files.some((f) => matchesScopeEntry(targetResolved, resolve(baseDir, f)));
13
- const isWrite = scope.allowed_files.some((f) => matchesScopeEntry(targetResolved, resolve(baseDir, f)));
14
- if (isWrite)
15
- return { allowed: true };
16
- if (isRead)
17
- return { allowed: true, reason: "Read-only file" };
18
- return { allowed: false, reason: "Path is not within the allowed scope for this sub-agent" };
19
- }
20
- export function isPathWritable(baseDir, targetPath, scope) {
21
- const baseResolved = resolve(baseDir);
22
- const targetResolved = resolve(baseDir, normalize(targetPath));
23
- if (!isInsideDir(targetResolved, baseResolved)) {
24
- return { allowed: false, reason: "Path is outside the base working directory" };
25
- }
26
- if (!scope)
27
- return { allowed: true };
28
- const isWrite = scope.allowed_files.some((f) => matchesScopeEntry(targetResolved, resolve(baseDir, f)));
29
- if (isWrite)
30
- return { allowed: true };
31
- return { allowed: false, reason: "Path is not within the writable scope for this sub-agent" };
32
- }
@@ -1,85 +0,0 @@
1
- import * as fs from "fs";
2
- import { join } from "path";
3
- import { homedir } from "os";
4
- import { t } from "../i18n/index";
5
- function searchFile(filePath, query, maxResults, results) {
6
- if (!fs.existsSync(filePath))
7
- return;
8
- const content = fs.readFileSync(filePath, "utf-8");
9
- for (const line of content.split("\n").filter(Boolean)) {
10
- if (line.toLowerCase().includes(query)) {
11
- try {
12
- const entry = JSON.parse(line);
13
- results.push(`[${filePath}] ${JSON.stringify(entry).slice(0, 200)}`);
14
- }
15
- catch {
16
- /* skip */
17
- }
18
- }
19
- if (results.length >= maxResults)
20
- break;
21
- }
22
- }
23
- export const searchHistoryTool = {
24
- name: "search_history",
25
- icon: "🕵️",
26
- description: "Search through session history for past interactions across all sessions.",
27
- tags: ["research"],
28
- parameters: {
29
- type: "object",
30
- properties: {
31
- query: { type: "string", description: "Search query" },
32
- maxResults: {
33
- type: "number",
34
- description: "Maximum results (default 5)",
35
- },
36
- sessionId: {
37
- type: "string",
38
- description: "Optional: limit search to a specific session",
39
- },
40
- },
41
- required: ["query"],
42
- },
43
- handler: async (_ctx, args) => {
44
- const query = String(args.query || "").toLowerCase();
45
- const maxResults = Number(args.maxResults) || 5;
46
- const sessionId = args.sessionId ? String(args.sessionId) : null;
47
- const sessionDir = join(homedir(), ".mma", "sessions");
48
- const results = [];
49
- try {
50
- if (!fs.existsSync(sessionDir)) {
51
- return {
52
- success: true,
53
- output: t("tool.no_sessions_dir", { dir: sessionDir }),
54
- };
55
- }
56
- const entries = fs.readdirSync(sessionDir, { withFileTypes: true });
57
- for (const entry of entries) {
58
- if (!entry.isDirectory())
59
- continue;
60
- if (sessionId && entry.name !== sessionId)
61
- continue;
62
- const historyFile = join(sessionDir, entry.name, "history.jsonl");
63
- searchFile(historyFile, query, maxResults, results);
64
- if (results.length >= maxResults)
65
- break;
66
- }
67
- if (results.length === 0) {
68
- return { success: true, output: t("tool.no_history", { query }) };
69
- }
70
- return {
71
- success: true,
72
- output: t("tool.history_results", {
73
- query,
74
- results: results.join("\n"),
75
- }),
76
- };
77
- }
78
- catch (err) {
79
- return {
80
- success: false,
81
- output: t("tool.history_error", { error: String(err) }),
82
- };
83
- }
84
- },
85
- };