micro-models-agent 0.54.1 → 0.55.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 (232) hide show
  1. package/README.md +358 -358
  2. package/dist/certification/certifications.json +493 -493
  3. package/dist/main.js +489 -82
  4. package/dist/modules/browser/bridge-server.mjs +202 -202
  5. package/dist/skills/builtin/git.md +36 -36
  6. package/dist/skills/builtin/typescript.md +35 -35
  7. package/package.json +1 -1
  8. package/dist/cli/commands.js +0 -447
  9. package/dist/cli/completer.js +0 -167
  10. package/dist/cli/index.js +0 -2
  11. package/dist/cli/main.js +0 -153
  12. package/dist/cli/plugin-commands.js +0 -36
  13. package/dist/cli/repl-commands.js +0 -761
  14. package/dist/cli/repl.js +0 -702
  15. package/dist/cli/run-result.js +0 -33
  16. package/dist/cli/security-commands.js +0 -164
  17. package/dist/cli/setup.js +0 -237
  18. package/dist/config/config.js +0 -276
  19. package/dist/config/defaults.js +0 -141
  20. package/dist/config/domains.js +0 -179
  21. package/dist/config/experts.js +0 -15
  22. package/dist/config/index.js +0 -4
  23. package/dist/config/security.js +0 -213
  24. package/dist/config/types.js +0 -1
  25. package/dist/core/agent-moe.js +0 -102
  26. package/dist/core/agent.js +0 -1018
  27. package/dist/core/bootstrap.js +0 -481
  28. package/dist/core/crash-handler.js +0 -51
  29. package/dist/core/environment.js +0 -199
  30. package/dist/core/index.js +0 -2
  31. package/dist/core/prompt-builder.js +0 -76
  32. package/dist/core/session-logger.js +0 -251
  33. package/dist/core/types.js +0 -1
  34. package/dist/core/version.js +0 -26
  35. package/dist/core/workspace.js +0 -76
  36. package/dist/i18n/en.json +0 -679
  37. package/dist/i18n/index.js +0 -46
  38. package/dist/i18n/ru.json +0 -679
  39. package/dist/index.js +0 -22
  40. package/dist/llm/image-utils.js +0 -143
  41. package/dist/llm/index.js +0 -4
  42. package/dist/llm/model-loader.js +0 -78
  43. package/dist/llm/openai-compat.js +0 -497
  44. package/dist/llm/orchestrator.js +0 -200
  45. package/dist/llm/provider.js +0 -10
  46. package/dist/llm/response.js +0 -39
  47. package/dist/llm/token-counter.js +0 -39
  48. package/dist/llm/types.js +0 -1
  49. package/dist/logger/app-logger.js +0 -189
  50. package/dist/logger/file-log.js +0 -151
  51. package/dist/logger/index.js +0 -1
  52. package/dist/migration/backup.js +0 -45
  53. package/dist/migration/detect.js +0 -50
  54. package/dist/migration/index.js +0 -2
  55. package/dist/modules/artifacts/store.js +0 -61
  56. package/dist/modules/browser/actions.js +0 -76
  57. package/dist/modules/browser/bridge-client.js +0 -199
  58. package/dist/modules/browser/bridge-path.js +0 -10
  59. package/dist/modules/browser/cookie-store.js +0 -24
  60. package/dist/modules/browser/driver.js +0 -136
  61. package/dist/modules/browser/index.js +0 -7
  62. package/dist/modules/browser/module.js +0 -29
  63. package/dist/modules/browser/session.js +0 -342
  64. package/dist/modules/browser/snapshot.js +0 -148
  65. package/dist/modules/browser/types.js +0 -12
  66. package/dist/modules/certification/cli.js +0 -213
  67. package/dist/modules/certification/fact-checker.js +0 -82
  68. package/dist/modules/certification/loader.js +0 -106
  69. package/dist/modules/certification/manifest.js +0 -58
  70. package/dist/modules/certification/runner.js +0 -245
  71. package/dist/modules/certification/scenarios.js +0 -407
  72. package/dist/modules/certification/types.js +0 -1
  73. package/dist/modules/context/chunk-query.js +0 -100
  74. package/dist/modules/context/fact-extractor.js +0 -168
  75. package/dist/modules/context/history.js +0 -15
  76. package/dist/modules/context/index.js +0 -1
  77. package/dist/modules/context/manager.js +0 -440
  78. package/dist/modules/execution/audit-runners.js +0 -206
  79. package/dist/modules/execution/auditor.js +0 -218
  80. package/dist/modules/execution/execution-plugin.js +0 -431
  81. package/dist/modules/execution/index.js +0 -8
  82. package/dist/modules/execution/module.js +0 -625
  83. package/dist/modules/execution/moe-executor.js +0 -304
  84. package/dist/modules/execution/plan-coverage.js +0 -68
  85. package/dist/modules/execution/plan-persister.js +0 -46
  86. package/dist/modules/execution/plan-store.js +0 -196
  87. package/dist/modules/execution/plan-tool.js +0 -677
  88. package/dist/modules/execution/plan-validator.js +0 -153
  89. package/dist/modules/execution/planner.js +0 -94
  90. package/dist/modules/execution/stuck-detector.js +0 -746
  91. package/dist/modules/execution/tracker.js +0 -69
  92. package/dist/modules/execution/types.js +0 -1
  93. package/dist/modules/execution/verifier.js +0 -235
  94. package/dist/modules/execution/windows-commands.js +0 -41
  95. package/dist/modules/hallucination/confidence.js +0 -66
  96. package/dist/modules/hallucination/consistency.js +0 -26
  97. package/dist/modules/hallucination/detector.js +0 -47
  98. package/dist/modules/hallucination/factual.js +0 -169
  99. package/dist/modules/hallucination/index.js +0 -5
  100. package/dist/modules/hallucination/js-identifiers.js +0 -262
  101. package/dist/modules/hallucination/llm-judge.js +0 -101
  102. package/dist/modules/index.js +0 -5
  103. package/dist/modules/indexer/cache.js +0 -40
  104. package/dist/modules/indexer/index.js +0 -3
  105. package/dist/modules/indexer/module.js +0 -246
  106. package/dist/modules/indexer/project-profile.js +0 -183
  107. package/dist/modules/indexer/walker.js +0 -101
  108. package/dist/modules/lsp/check-tool.js +0 -58
  109. package/dist/modules/lsp/client.js +0 -389
  110. package/dist/modules/lsp/command.js +0 -60
  111. package/dist/modules/lsp/config.js +0 -135
  112. package/dist/modules/lsp/index.js +0 -3
  113. package/dist/modules/lsp/module.js +0 -260
  114. package/dist/modules/lsp/probe.js +0 -86
  115. package/dist/modules/lsp/project-root.js +0 -32
  116. package/dist/modules/lsp/startup-check.js +0 -144
  117. package/dist/modules/lsp/types.js +0 -1
  118. package/dist/modules/mcp/client.js +0 -399
  119. package/dist/modules/mcp/index.js +0 -3
  120. package/dist/modules/mcp/module.js +0 -142
  121. package/dist/modules/mcp/registry.js +0 -15
  122. package/dist/modules/memory/index.js +0 -1
  123. package/dist/modules/memory/module.js +0 -96
  124. package/dist/modules/memory/search.js +0 -42
  125. package/dist/modules/memory/store.js +0 -69
  126. package/dist/modules/pipelines/engine.js +0 -60
  127. package/dist/modules/pipelines/index.js +0 -3
  128. package/dist/modules/pipelines/parser.js +0 -56
  129. package/dist/modules/pipelines/template.js +0 -14
  130. package/dist/modules/plugins/builtin/lint-on-write.js +0 -334
  131. package/dist/modules/plugins/builtin/notify.js +0 -9
  132. package/dist/modules/plugins/index.js +0 -1
  133. package/dist/modules/plugins/loader.js +0 -70
  134. package/dist/modules/plugins/manager.js +0 -261
  135. package/dist/modules/plugins/types.js +0 -1
  136. package/dist/modules/pricing/index.js +0 -61
  137. package/dist/modules/pricing/prices.js +0 -129
  138. package/dist/modules/processes/detect.js +0 -34
  139. package/dist/modules/processes/index.js +0 -2
  140. package/dist/modules/processes/registry.js +0 -327
  141. package/dist/modules/processes/runner.js +0 -23
  142. package/dist/modules/providers/create.js +0 -22
  143. package/dist/modules/providers/fallback.js +0 -79
  144. package/dist/modules/providers/health.js +0 -46
  145. package/dist/modules/providers/index.js +0 -5
  146. package/dist/modules/providers/manager.js +0 -161
  147. package/dist/modules/providers/presets.js +0 -128
  148. package/dist/modules/providers/registry.js +0 -22
  149. package/dist/modules/providers/types.js +0 -1
  150. package/dist/modules/registry.js +0 -48
  151. package/dist/modules/security/audit-log.js +0 -136
  152. package/dist/modules/security/audit-notifier.js +0 -292
  153. package/dist/modules/security/command-validator.js +0 -219
  154. package/dist/modules/security/content-scanner.js +0 -53
  155. package/dist/modules/security/data-sanitizer.js +0 -89
  156. package/dist/modules/security/encryption.js +0 -242
  157. package/dist/modules/security/index.js +0 -14
  158. package/dist/modules/security/network-validator.js +0 -88
  159. package/dist/modules/security/path-validator.js +0 -203
  160. package/dist/modules/security/rate-limiter.js +0 -119
  161. package/dist/modules/security/security-policies.js +0 -531
  162. package/dist/modules/security/session-encryption.js +0 -210
  163. package/dist/modules/security/session-isolation.js +0 -95
  164. package/dist/modules/session/index.js +0 -3
  165. package/dist/modules/session/manager.js +0 -172
  166. package/dist/modules/session/module.js +0 -24
  167. package/dist/modules/session/store.js +0 -222
  168. package/dist/modules/session/types.js +0 -1
  169. package/dist/modules/skills/index.js +0 -2
  170. package/dist/modules/skills/loader.js +0 -72
  171. package/dist/modules/skills/matcher.js +0 -27
  172. package/dist/modules/skills/module.js +0 -129
  173. package/dist/modules/types.js +0 -1
  174. package/dist/modules/updater/checker.js +0 -96
  175. package/dist/modules/updater/index.js +0 -2
  176. package/dist/modules/updater/module.js +0 -116
  177. package/dist/modules/user-profile/compressor.js +0 -16
  178. package/dist/modules/user-profile/index.js +0 -1
  179. package/dist/modules/user-profile/profile.js +0 -68
  180. package/dist/tools/approve.js +0 -33
  181. package/dist/tools/attach-image.js +0 -101
  182. package/dist/tools/bash.js +0 -519
  183. package/dist/tools/browser.js +0 -115
  184. package/dist/tools/chunk-query.js +0 -100
  185. package/dist/tools/create-dir.js +0 -56
  186. package/dist/tools/delete-file.js +0 -63
  187. package/dist/tools/download-file.js +0 -117
  188. package/dist/tools/edit-file.js +0 -80
  189. package/dist/tools/enable-tools.js +0 -59
  190. package/dist/tools/executor.js +0 -154
  191. package/dist/tools/file-info.js +0 -47
  192. package/dist/tools/filter-tools.js +0 -17
  193. package/dist/tools/glob-tool.js +0 -27
  194. package/dist/tools/grep-tool.js +0 -125
  195. package/dist/tools/hidden-tools-block.js +0 -37
  196. package/dist/tools/index.js +0 -78
  197. package/dist/tools/list-dir.js +0 -49
  198. package/dist/tools/load-skill.js +0 -43
  199. package/dist/tools/mcp-call.js +0 -69
  200. package/dist/tools/move-file.js +0 -86
  201. package/dist/tools/path-utils.js +0 -101
  202. package/dist/tools/pipeline-run.js +0 -145
  203. package/dist/tools/preview.js +0 -2
  204. package/dist/tools/process-kill.js +0 -40
  205. package/dist/tools/process-list.js +0 -37
  206. package/dist/tools/process-log.js +0 -54
  207. package/dist/tools/question.js +0 -141
  208. package/dist/tools/read-file.js +0 -179
  209. package/dist/tools/recall.js +0 -118
  210. package/dist/tools/registry.js +0 -47
  211. package/dist/tools/remember.js +0 -68
  212. package/dist/tools/scope-check.js +0 -32
  213. package/dist/tools/search-history.js +0 -85
  214. package/dist/tools/subagent.js +0 -196
  215. package/dist/tools/types.js +0 -1
  216. package/dist/tools/user-input.js +0 -123
  217. package/dist/tools/web-browse.js +0 -87
  218. package/dist/tools/web-fetch.js +0 -119
  219. package/dist/tools/web-search.js +0 -105
  220. package/dist/tools/write-file.js +0 -82
  221. package/dist/ui/box.js +0 -77
  222. package/dist/ui/colors.js +0 -4
  223. package/dist/ui/diff.js +0 -178
  224. package/dist/ui/index.js +0 -6
  225. package/dist/ui/line-editor.js +0 -822
  226. package/dist/ui/line-math.js +0 -73
  227. package/dist/ui/md-formatter.js +0 -212
  228. package/dist/ui/output.js +0 -13
  229. package/dist/ui/plan-view.js +0 -103
  230. package/dist/ui/renderer.js +0 -259
  231. package/dist/ui/spinner.js +0 -70
  232. 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
- };