micro-models-agent 0.43.3 → 0.45.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 (188) hide show
  1. package/README.md +312 -312
  2. package/bin/mma.mjs +41 -41
  3. package/dist/main.js +333 -66
  4. package/dist/skills/builtin/git.md +36 -36
  5. package/dist/skills/builtin/typescript.md +35 -35
  6. package/package.json +1 -1
  7. package/dist/cli/commands.js +0 -333
  8. package/dist/cli/completer.js +0 -168
  9. package/dist/cli/index.js +0 -2
  10. package/dist/cli/main.js +0 -140
  11. package/dist/cli/repl-commands.js +0 -633
  12. package/dist/cli/repl.js +0 -486
  13. package/dist/cli/security-commands.js +0 -166
  14. package/dist/cli/setup.js +0 -249
  15. package/dist/config/config.js +0 -202
  16. package/dist/config/defaults.js +0 -100
  17. package/dist/config/experts.js +0 -15
  18. package/dist/config/index.js +0 -3
  19. package/dist/config/security.js +0 -200
  20. package/dist/config/types.js +0 -1
  21. package/dist/core/agent-moe.js +0 -110
  22. package/dist/core/agent.js +0 -695
  23. package/dist/core/bootstrap.js +0 -337
  24. package/dist/core/index.js +0 -2
  25. package/dist/core/prompt-builder.js +0 -55
  26. package/dist/core/session-logger.js +0 -155
  27. package/dist/core/types.js +0 -1
  28. package/dist/core/workspace.js +0 -76
  29. package/dist/i18n/en.json +0 -525
  30. package/dist/i18n/index.js +0 -46
  31. package/dist/i18n/ru.json +0 -525
  32. package/dist/index.js +0 -22
  33. package/dist/llm/image-utils.js +0 -144
  34. package/dist/llm/index.js +0 -4
  35. package/dist/llm/model-loader.js +0 -78
  36. package/dist/llm/openai-compat.js +0 -353
  37. package/dist/llm/orchestrator.js +0 -194
  38. package/dist/llm/provider.js +0 -10
  39. package/dist/llm/response.js +0 -39
  40. package/dist/llm/token-counter.js +0 -39
  41. package/dist/llm/types.js +0 -1
  42. package/dist/logger/app-logger.js +0 -143
  43. package/dist/logger/file-log.js +0 -151
  44. package/dist/logger/index.js +0 -1
  45. package/dist/migration/backup.js +0 -45
  46. package/dist/migration/detect.js +0 -50
  47. package/dist/migration/index.js +0 -2
  48. package/dist/modules/browser/actions.js +0 -46
  49. package/dist/modules/browser/cookie-store.js +0 -24
  50. package/dist/modules/browser/index.js +0 -5
  51. package/dist/modules/browser/module.js +0 -28
  52. package/dist/modules/browser/session.js +0 -335
  53. package/dist/modules/browser/snapshot.js +0 -114
  54. package/dist/modules/browser/types.js +0 -9
  55. package/dist/modules/certification/cli.js +0 -176
  56. package/dist/modules/certification/fact-checker.js +0 -84
  57. package/dist/modules/certification/loader.js +0 -111
  58. package/dist/modules/certification/manifest.js +0 -50
  59. package/dist/modules/certification/runner.js +0 -162
  60. package/dist/modules/certification/scenarios.js +0 -124
  61. package/dist/modules/certification/types.js +0 -1
  62. package/dist/modules/context/index.js +0 -1
  63. package/dist/modules/context/manager.js +0 -349
  64. package/dist/modules/execution/auditor.js +0 -66
  65. package/dist/modules/execution/index.js +0 -8
  66. package/dist/modules/execution/module.js +0 -779
  67. package/dist/modules/execution/moe-executor.js +0 -266
  68. package/dist/modules/execution/plan-coverage.js +0 -68
  69. package/dist/modules/execution/plan-persister.js +0 -46
  70. package/dist/modules/execution/plan-store.js +0 -159
  71. package/dist/modules/execution/plan-validator.js +0 -153
  72. package/dist/modules/execution/planner.js +0 -85
  73. package/dist/modules/execution/stuck-detector.js +0 -347
  74. package/dist/modules/execution/tracker.js +0 -67
  75. package/dist/modules/execution/types.js +0 -1
  76. package/dist/modules/execution/verifier.js +0 -178
  77. package/dist/modules/hallucination/confidence.js +0 -59
  78. package/dist/modules/hallucination/consistency.js +0 -26
  79. package/dist/modules/hallucination/detector.js +0 -46
  80. package/dist/modules/hallucination/factual.js +0 -190
  81. package/dist/modules/hallucination/index.js +0 -5
  82. package/dist/modules/hallucination/js-identifiers.js +0 -72
  83. package/dist/modules/hallucination/llm-judge.js +0 -103
  84. package/dist/modules/index.js +0 -5
  85. package/dist/modules/indexer/cache.js +0 -38
  86. package/dist/modules/indexer/index.js +0 -3
  87. package/dist/modules/indexer/module.js +0 -192
  88. package/dist/modules/indexer/walker.js +0 -101
  89. package/dist/modules/lsp/client.js +0 -235
  90. package/dist/modules/lsp/config.js +0 -81
  91. package/dist/modules/lsp/index.js +0 -3
  92. package/dist/modules/lsp/module.js +0 -68
  93. package/dist/modules/lsp/types.js +0 -1
  94. package/dist/modules/mcp/client.js +0 -399
  95. package/dist/modules/mcp/index.js +0 -3
  96. package/dist/modules/mcp/module.js +0 -146
  97. package/dist/modules/mcp/registry.js +0 -15
  98. package/dist/modules/memory/index.js +0 -1
  99. package/dist/modules/memory/module.js +0 -48
  100. package/dist/modules/memory/search.js +0 -40
  101. package/dist/modules/memory/store.js +0 -69
  102. package/dist/modules/pipelines/engine.js +0 -60
  103. package/dist/modules/pipelines/index.js +0 -3
  104. package/dist/modules/pipelines/parser.js +0 -53
  105. package/dist/modules/pipelines/template.js +0 -14
  106. package/dist/modules/plugins/builtin/lint-on-write.js +0 -226
  107. package/dist/modules/plugins/builtin/notify.js +0 -8
  108. package/dist/modules/plugins/index.js +0 -1
  109. package/dist/modules/plugins/loader.js +0 -28
  110. package/dist/modules/plugins/manager.js +0 -161
  111. package/dist/modules/plugins/types.js +0 -1
  112. package/dist/modules/processes/index.js +0 -2
  113. package/dist/modules/processes/registry.js +0 -238
  114. package/dist/modules/processes/runner.js +0 -23
  115. package/dist/modules/registry.js +0 -45
  116. package/dist/modules/security/audit-log.js +0 -136
  117. package/dist/modules/security/audit-notifier.js +0 -292
  118. package/dist/modules/security/command-validator.js +0 -211
  119. package/dist/modules/security/content-scanner.js +0 -53
  120. package/dist/modules/security/data-sanitizer.js +0 -97
  121. package/dist/modules/security/encryption.js +0 -240
  122. package/dist/modules/security/index.js +0 -14
  123. package/dist/modules/security/network-validator.js +0 -79
  124. package/dist/modules/security/path-validator.js +0 -209
  125. package/dist/modules/security/rate-limiter.js +0 -119
  126. package/dist/modules/security/security-policies.js +0 -547
  127. package/dist/modules/security/session-encryption.js +0 -210
  128. package/dist/modules/security/session-isolation.js +0 -95
  129. package/dist/modules/session/index.js +0 -3
  130. package/dist/modules/session/manager.js +0 -172
  131. package/dist/modules/session/module.js +0 -24
  132. package/dist/modules/session/store.js +0 -228
  133. package/dist/modules/session/types.js +0 -1
  134. package/dist/modules/skills/index.js +0 -2
  135. package/dist/modules/skills/loader.js +0 -72
  136. package/dist/modules/skills/module.js +0 -130
  137. package/dist/modules/types.js +0 -1
  138. package/dist/modules/updater/checker.js +0 -32
  139. package/dist/modules/updater/index.js +0 -1
  140. package/dist/modules/user-profile/compressor.js +0 -16
  141. package/dist/modules/user-profile/index.js +0 -1
  142. package/dist/modules/user-profile/profile.js +0 -68
  143. package/dist/tools/approve.js +0 -32
  144. package/dist/tools/attach-image.js +0 -89
  145. package/dist/tools/bash.js +0 -337
  146. package/dist/tools/browser.js +0 -97
  147. package/dist/tools/create-dir.js +0 -55
  148. package/dist/tools/delete-file.js +0 -62
  149. package/dist/tools/edit-file.js +0 -79
  150. package/dist/tools/executor.js +0 -145
  151. package/dist/tools/file-info.js +0 -45
  152. package/dist/tools/filter-tools.js +0 -10
  153. package/dist/tools/glob-tool.js +0 -26
  154. package/dist/tools/grep-tool.js +0 -86
  155. package/dist/tools/index.js +0 -67
  156. package/dist/tools/list-dir.js +0 -47
  157. package/dist/tools/load-skill.js +0 -44
  158. package/dist/tools/mcp-call.js +0 -68
  159. package/dist/tools/move-file.js +0 -85
  160. package/dist/tools/path-utils.js +0 -51
  161. package/dist/tools/pipeline-run.js +0 -144
  162. package/dist/tools/preview.js +0 -2
  163. package/dist/tools/process-kill.js +0 -29
  164. package/dist/tools/process-list.js +0 -38
  165. package/dist/tools/process-log.js +0 -41
  166. package/dist/tools/question.js +0 -142
  167. package/dist/tools/read-file.js +0 -83
  168. package/dist/tools/recall.js +0 -110
  169. package/dist/tools/registry.js +0 -36
  170. package/dist/tools/remember.js +0 -67
  171. package/dist/tools/scope-check.js +0 -30
  172. package/dist/tools/search-history.js +0 -84
  173. package/dist/tools/subagent.js +0 -151
  174. package/dist/tools/types.js +0 -1
  175. package/dist/tools/user-input.js +0 -123
  176. package/dist/tools/web-browse.js +0 -86
  177. package/dist/tools/web-fetch.js +0 -98
  178. package/dist/tools/web-search.js +0 -78
  179. package/dist/tools/write-file.js +0 -83
  180. package/dist/ui/box.js +0 -81
  181. package/dist/ui/colors.js +0 -4
  182. package/dist/ui/diff.js +0 -178
  183. package/dist/ui/index.js +0 -6
  184. package/dist/ui/md-formatter.js +0 -212
  185. package/dist/ui/output.js +0 -13
  186. package/dist/ui/renderer.js +0 -204
  187. package/dist/ui/spinner.js +0 -70
  188. package/dist/ui/table.js +0 -144
@@ -1,46 +0,0 @@
1
- export function buildClickScript(elementIndex) {
2
- return `
3
- const el = document.querySelector('[data-browser-index="${elementIndex}"]');
4
- if (!el) throw new Error('Element not found: ${elementIndex}');
5
- el.click();
6
- `;
7
- }
8
- export function buildTypeScript(elementIndex, text) {
9
- const escaped = JSON.stringify(text);
10
- return `
11
- const el = document.querySelector('[data-browser-index="${elementIndex}"]');
12
- if (!el) throw new Error('Element not found: ${elementIndex}');
13
- const text = JSON.parse(${JSON.stringify(escaped)});
14
- el.focus();
15
- el.value = text;
16
- el.dispatchEvent(new Event('input', { bubbles: true }));
17
- el.dispatchEvent(new Event('change', { bubbles: true }));
18
- `;
19
- }
20
- export function buildScrollScript(direction) {
21
- switch (direction) {
22
- case 'down':
23
- return `window.scrollBy({ top: 600, behavior: 'smooth' })`;
24
- case 'up':
25
- return `window.scrollBy({ top: -600, behavior: 'smooth' })`;
26
- case 'top':
27
- return `window.scrollTo({ top: 0, behavior: 'smooth' })`;
28
- case 'bottom':
29
- return `window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' })`;
30
- }
31
- }
32
- export function buildWaitScript(timeoutMs) {
33
- return `await new Promise(r => setTimeout(r, ${timeoutMs}))`;
34
- }
35
- export function buildIndexInjectionScript() {
36
- return `
37
- const selectors = 'a[href], button, input, textarea, select, [role="button"], [role="link"], [role="textbox"], [role="checkbox"], [role="radio"], [contenteditable="true"]';
38
- const elements = document.querySelectorAll(selectors);
39
- let idx = 1;
40
- elements.forEach(el => {
41
- const style = window.getComputedStyle(el);
42
- if (style.display === 'none' || style.visibility === 'hidden') return;
43
- el.setAttribute('data-browser-index', String(idx++));
44
- });
45
- `;
46
- }
@@ -1,24 +0,0 @@
1
- import { readFile, writeFile, mkdir } from 'fs/promises';
2
- import { join } from 'path';
3
- export class CookieStore {
4
- filePath;
5
- constructor(cookieDir) {
6
- this.filePath = join(cookieDir, 'cookies.json');
7
- }
8
- async save(cookies) {
9
- await mkdir(join(this.filePath, '..'), { recursive: true });
10
- await writeFile(this.filePath, JSON.stringify(cookies, null, 2), 'utf-8');
11
- }
12
- async load() {
13
- try {
14
- const data = await readFile(this.filePath, 'utf-8');
15
- return JSON.parse(data);
16
- }
17
- catch {
18
- return [];
19
- }
20
- }
21
- async clear() {
22
- await this.save([]);
23
- }
24
- }
@@ -1,5 +0,0 @@
1
- export { BrowserModule } from './module';
2
- export { BrowserSession, BrowserActionTracker } from './session';
3
- export { CookieStore } from './cookie-store';
4
- export { extractInteractiveElements, formatSnapshot } from './snapshot';
5
- export { DEFAULT_BROWSER_CONFIG } from './types';
@@ -1,28 +0,0 @@
1
- import { createBrowserTool, closeBrowserSession } from '../../tools/browser';
2
- export class BrowserModule {
3
- name = 'browser';
4
- getSystemPromptBlock() {
5
- return {
6
- content: [
7
- 'You have a headless browser tool. Use it to navigate websites, click links, fill forms, and read page content.',
8
- 'Workflow: open(url) → read snapshot → click/type on element numbers → read updated snapshot.',
9
- 'Always start with "open" action. Use element numbers from snapshot for click/type targets.',
10
- 'Use "screenshot" action only if the model supports vision. Otherwise rely on the text snapshot.',
11
- ].join('\n'),
12
- priority: 'normal',
13
- essential: false,
14
- estimatedTokens: 80,
15
- };
16
- }
17
- getToolDefinitions() {
18
- return [createBrowserTool()];
19
- }
20
- getPlugin() {
21
- return {
22
- name: 'browser',
23
- onSessionEnd: () => {
24
- closeBrowserSession();
25
- },
26
- };
27
- }
28
- }
@@ -1,335 +0,0 @@
1
- import { chromium, } from "playwright";
2
- import { extractInteractiveElements, formatSnapshot } from "./snapshot";
3
- import { buildClickScript, buildTypeScript, buildScrollScript, buildIndexInjectionScript, } from "./actions";
4
- import { CookieStore } from "./cookie-store";
5
- import { t } from "../../i18n/index";
6
- export class BrowserActionTracker {
7
- history = [];
8
- threshold;
9
- constructor(threshold = 3) {
10
- this.threshold = threshold;
11
- }
12
- record(action, args, url) {
13
- this.history.push({ action, args, url });
14
- if (this.history.length < this.threshold)
15
- return null;
16
- const recent = this.history.slice(-this.threshold);
17
- const allSame = recent.every((h) => h.action === recent[0].action &&
18
- h.url === recent[0].url &&
19
- JSON.stringify(h.args) === JSON.stringify(recent[0].args));
20
- if (allSame) {
21
- return t("browser.repeated_action", {
22
- action,
23
- threshold: this.threshold,
24
- });
25
- }
26
- return null;
27
- }
28
- reset() {
29
- this.history = [];
30
- }
31
- }
32
- export class BrowserSession {
33
- browser = null;
34
- context = null;
35
- page = null;
36
- config;
37
- cookieStore;
38
- state = {
39
- isOpen: false,
40
- url: null,
41
- title: null,
42
- elementCount: 0,
43
- };
44
- actionTracker = new BrowserActionTracker(3);
45
- constructor(config) {
46
- this.config = config;
47
- this.cookieStore = new CookieStore(config.cookieDir);
48
- }
49
- getState() {
50
- return { ...this.state };
51
- }
52
- async execute(action, args) {
53
- try {
54
- let result;
55
- switch (action) {
56
- case "open":
57
- result = await this.open(String(args.url || ""));
58
- break;
59
- case "click":
60
- result = await this.click(Number(args.target));
61
- break;
62
- case "type":
63
- result = await this.type(Number(args.target), String(args.text || ""));
64
- break;
65
- case "scroll":
66
- result = await this.scroll(String(args.direction || "down"));
67
- break;
68
- case "back":
69
- result = await this.back();
70
- break;
71
- case "forward":
72
- result = await this.forward();
73
- break;
74
- case "screenshot":
75
- result = await this.screenshot();
76
- break;
77
- case "snapshot":
78
- result = await this.snapshot();
79
- break;
80
- case "close":
81
- result = await this.close();
82
- break;
83
- case "wait":
84
- result = await this.wait(Number(args.ms || 1000));
85
- break;
86
- default:
87
- return {
88
- success: false,
89
- output: t("browser.unknown_action", { action }),
90
- };
91
- }
92
- if (action !== "open") {
93
- const warning = this.actionTracker.record(action, args, this.page?.url() || "");
94
- if (warning && result.success) {
95
- result.output = result.output + "\n\n⚠️ " + warning;
96
- }
97
- }
98
- return result;
99
- }
100
- catch (err) {
101
- return {
102
- success: false,
103
- output: t("browser.error", { message: err.message }),
104
- };
105
- }
106
- }
107
- async ensurePage() {
108
- if (!this.page) {
109
- return { success: false, output: t("browser.no_page") };
110
- }
111
- return null;
112
- }
113
- async launch() {
114
- if (this.browser)
115
- return;
116
- this.browser = await chromium.launch({ headless: this.config.headless });
117
- this.context = await this.browser.newContext({
118
- viewport: {
119
- width: this.config.viewportWidth,
120
- height: this.config.viewportHeight,
121
- },
122
- });
123
- const savedCookies = await this.cookieStore.load();
124
- if (savedCookies.length > 0) {
125
- await this.context.addCookies(savedCookies.map((c) => ({
126
- ...c,
127
- sameSite: c.sameSite,
128
- })));
129
- }
130
- this.page = await this.context.newPage();
131
- this.page.setDefaultTimeout(this.config.navigationTimeout);
132
- }
133
- async saveCookies() {
134
- if (!this.context)
135
- return;
136
- const cookies = await this.context.cookies();
137
- await this.cookieStore.save(cookies);
138
- }
139
- async takeSnapshot() {
140
- if (!this.page)
141
- return "No page open.";
142
- await this.page.evaluate(buildIndexInjectionScript());
143
- const html = await this.page.content();
144
- const url = this.page.url();
145
- const title = await this.page.title();
146
- const allElements = extractInteractiveElements(html, this.config.maxElements + 5);
147
- const truncated = allElements.length > this.config.maxElements;
148
- const elements = allElements.slice(0, this.config.maxElements);
149
- this.state = {
150
- isOpen: true,
151
- url,
152
- title,
153
- elementCount: elements.length,
154
- };
155
- return formatSnapshot({ url, title, elements, truncated });
156
- }
157
- async open(url) {
158
- if (!url)
159
- return { success: false, output: t("browser.url_required") };
160
- if (!url.startsWith("http://") &&
161
- !url.startsWith("https://") &&
162
- !url.startsWith("file://")) {
163
- const isLocalhost = /^(localhost|127\.0\.0\.1|0\.0\.0\.0)(:\d+)?$/i.test(url);
164
- url = isLocalhost ? "http://" + url : "https://" + url;
165
- }
166
- await this.launch();
167
- if (!this.page)
168
- return { success: false, output: t("browser.create_page_failed") };
169
- this.actionTracker.reset();
170
- try {
171
- await this.page.goto(url, {
172
- waitUntil: "domcontentloaded",
173
- timeout: this.config.navigationTimeout,
174
- });
175
- }
176
- catch (err) {
177
- return {
178
- success: false,
179
- output: t("browser.nav_failed", { message: err.message }),
180
- };
181
- }
182
- const snapshot = await this.takeSnapshot();
183
- await this.saveCookies();
184
- return { success: true, output: snapshot };
185
- }
186
- async click(target) {
187
- const err = await this.ensurePage();
188
- if (err)
189
- return err;
190
- if (!this.page)
191
- return { success: false, output: "No page" };
192
- if (!target || target < 1) {
193
- return { success: false, output: t("browser.invalid_target") };
194
- }
195
- try {
196
- const script = buildClickScript(target);
197
- await this.page.evaluate(script);
198
- await this.page
199
- .waitForLoadState("domcontentloaded", { timeout: 5000 })
200
- .catch(() => { });
201
- await new Promise((r) => setTimeout(r, 500));
202
- const snapshot = await this.takeSnapshot();
203
- await this.saveCookies();
204
- return { success: true, output: snapshot };
205
- }
206
- catch (err) {
207
- return {
208
- success: false,
209
- output: t("browser.click_failed", { message: err.message }),
210
- };
211
- }
212
- }
213
- async type(target, text) {
214
- const err = await this.ensurePage();
215
- if (err)
216
- return err;
217
- if (!this.page)
218
- return { success: false, output: "No page" };
219
- if (!target || target < 1) {
220
- return { success: false, output: t("browser.invalid_target_short") };
221
- }
222
- if (!text) {
223
- return { success: false, output: t("browser.text_required") };
224
- }
225
- try {
226
- const script = buildTypeScript(target, text);
227
- await this.page.evaluate(script);
228
- const snapshot = await this.takeSnapshot();
229
- return { success: true, output: snapshot };
230
- }
231
- catch (err) {
232
- return {
233
- success: false,
234
- output: t("browser.type_failed", { message: err.message }),
235
- };
236
- }
237
- }
238
- async scroll(direction) {
239
- const err = await this.ensurePage();
240
- if (err)
241
- return err;
242
- if (!this.page)
243
- return { success: false, output: "No page" };
244
- const dir = direction;
245
- if (!["up", "down", "top", "bottom"].includes(dir)) {
246
- return { success: false, output: t("browser.direction_invalid") };
247
- }
248
- try {
249
- await this.page.evaluate(buildScrollScript(dir));
250
- await new Promise((r) => setTimeout(r, 300));
251
- const snapshot = await this.takeSnapshot();
252
- return { success: true, output: snapshot };
253
- }
254
- catch (err) {
255
- return {
256
- success: false,
257
- output: t("browser.scroll_failed", { message: err.message }),
258
- };
259
- }
260
- }
261
- async back() {
262
- const err = await this.ensurePage();
263
- if (err)
264
- return err;
265
- if (!this.page)
266
- return { success: false, output: "No page" };
267
- await this.page
268
- .goBack({
269
- waitUntil: "domcontentloaded",
270
- timeout: this.config.navigationTimeout,
271
- })
272
- .catch(() => { });
273
- await new Promise((r) => setTimeout(r, 300));
274
- const snapshot = await this.takeSnapshot();
275
- return { success: true, output: snapshot };
276
- }
277
- async forward() {
278
- const err = await this.ensurePage();
279
- if (err)
280
- return err;
281
- if (!this.page)
282
- return { success: false, output: "No page" };
283
- await this.page
284
- .goForward({
285
- waitUntil: "domcontentloaded",
286
- timeout: this.config.navigationTimeout,
287
- })
288
- .catch(() => { });
289
- await new Promise((r) => setTimeout(r, 300));
290
- const snapshot = await this.takeSnapshot();
291
- return { success: true, output: snapshot };
292
- }
293
- async screenshot() {
294
- const err = await this.ensurePage();
295
- if (err)
296
- return err;
297
- if (!this.page)
298
- return { success: false, output: "No page" };
299
- const buffer = await this.page.screenshot({ type: "png", fullPage: false });
300
- const snapshot = await this.takeSnapshot();
301
- return { success: true, output: snapshot, screenshot: buffer };
302
- }
303
- async snapshot() {
304
- const err = await this.ensurePage();
305
- if (err)
306
- return err;
307
- const snap = await this.takeSnapshot();
308
- return { success: true, output: snap };
309
- }
310
- async wait(ms) {
311
- const err = await this.ensurePage();
312
- if (err)
313
- return err;
314
- await new Promise((r) => setTimeout(r, Math.min(ms, 10000)));
315
- const snapshot = await this.takeSnapshot();
316
- return { success: true, output: snapshot };
317
- }
318
- async close() {
319
- await this.saveCookies();
320
- if (this.page) {
321
- await this.page.close().catch(() => { });
322
- this.page = null;
323
- }
324
- if (this.context) {
325
- await this.context.close().catch(() => { });
326
- this.context = null;
327
- }
328
- if (this.browser) {
329
- await this.browser.close().catch(() => { });
330
- this.browser = null;
331
- }
332
- this.state = { isOpen: false, url: null, title: null, elementCount: 0 };
333
- return { success: true, output: t("browser.closed") };
334
- }
335
- }
@@ -1,114 +0,0 @@
1
- import { t } from '../../i18n/index';
2
- function inferRole(tag, type) {
3
- const t = tag.toLowerCase();
4
- if (t === 'a')
5
- return 'link';
6
- if (t === 'button')
7
- return 'button';
8
- if (t === 'input') {
9
- const inputType = type?.toLowerCase();
10
- if (inputType === 'submit' || inputType === 'button')
11
- return 'button';
12
- if (inputType === 'checkbox')
13
- return 'checkbox';
14
- if (inputType === 'radio')
15
- return 'radio';
16
- return 'textbox';
17
- }
18
- if (t === 'textarea')
19
- return 'textbox';
20
- if (t === 'select')
21
- return 'combobox';
22
- return 'widget';
23
- }
24
- function getName(tag, attrs, html, matchIndex) {
25
- const fromAttr = (attrs['aria-label'] ||
26
- attrs['placeholder'] ||
27
- attrs['title'] ||
28
- attrs['alt'] ||
29
- attrs['value'] ||
30
- attrs['name'] ||
31
- '');
32
- if (fromAttr)
33
- return fromAttr;
34
- const afterTag = html.slice(matchIndex);
35
- const closeIdx = afterTag.indexOf('>');
36
- if (closeIdx === -1)
37
- return '';
38
- const afterOpen = afterTag.slice(closeIdx + 1);
39
- const endTag = `</${tag}>`;
40
- const endIdx = afterOpen.indexOf(endTag);
41
- if (endIdx === -1)
42
- return '';
43
- const text = afterOpen.slice(0, endIdx).replace(/<[^>]+>/g, '').trim();
44
- return text.slice(0, 50);
45
- }
46
- export function extractInteractiveElements(html, maxElements = 30) {
47
- const elements = [];
48
- const tagRegex = /<(a|button|input|textarea|select|div|span)([^>]*)>/gi;
49
- let match;
50
- while ((match = tagRegex.exec(html)) !== null) {
51
- if (elements.length >= maxElements)
52
- break;
53
- const tag = match[1].toLowerCase();
54
- const attrStr = match[2];
55
- const attrs = {};
56
- const attrRegex = /(\w[\w-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|(\S+)))?/g;
57
- let attrMatch;
58
- while ((attrMatch = attrRegex.exec(attrStr)) !== null) {
59
- attrs[attrMatch[1].toLowerCase()] = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? '';
60
- }
61
- if (attrs['style']?.includes('display:none') || attrs['style']?.includes('display: none'))
62
- continue;
63
- if (attrs['hidden'] !== undefined)
64
- continue;
65
- if (attrs['aria-hidden'] === 'true')
66
- continue;
67
- if (tag === 'input' && attrs['type'] === 'hidden')
68
- continue;
69
- const role = attrs['role'] || inferRole(tag, attrs['type']);
70
- const isInteractive = [
71
- 'a', 'button', 'input', 'textarea', 'select',
72
- ].includes(tag) || attrs['role'] !== undefined;
73
- if (!isInteractive)
74
- continue;
75
- if (tag === 'a' && !attrs['href'])
76
- continue;
77
- const name = getName(tag, attrs, html, match.index);
78
- elements.push({
79
- index: elements.length + 1,
80
- tag,
81
- role,
82
- name,
83
- value: attrs['value'],
84
- href: attrs['href'],
85
- visible: true,
86
- });
87
- }
88
- return elements;
89
- }
90
- export function formatSnapshot(snapshot) {
91
- const lines = [];
92
- lines.push(`Page: "${snapshot.title}"`);
93
- lines.push(`URL: ${snapshot.url}`);
94
- lines.push('');
95
- if (snapshot.elements.length === 0 && !snapshot.truncated) {
96
- lines.push(t('browser.no_elements'));
97
- return lines.join('\n');
98
- }
99
- for (const el of snapshot.elements) {
100
- let line = `[${el.index}] ${el.role}`;
101
- if (el.name)
102
- line += ` "${el.name}"`;
103
- if (el.href)
104
- line += ` → ${el.href}`;
105
- if (el.value)
106
- line += ` = "${el.value}"`;
107
- lines.push(line);
108
- }
109
- if (snapshot.truncated) {
110
- lines.push('');
111
- lines.push(t('browser.more_elements'));
112
- }
113
- return lines.join('\n');
114
- }
@@ -1,9 +0,0 @@
1
- export const DEFAULT_BROWSER_CONFIG = {
2
- headless: true,
3
- maxElements: 30,
4
- screenshotMaxWidth: 1280,
5
- cookieDir: '',
6
- viewportWidth: 1280,
7
- viewportHeight: 720,
8
- navigationTimeout: 15000,
9
- };