micro-models-agent 0.6.4 → 0.7.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 (472) hide show
  1. package/README.md +286 -436
  2. package/dist/main.js +11706 -0
  3. package/dist/skills/builtin/git.md +36 -0
  4. package/dist/skills/builtin/typescript.md +35 -0
  5. package/package.json +41 -47
  6. package/dist/agent/context.d.ts +0 -73
  7. package/dist/agent/context.d.ts.map +0 -1
  8. package/dist/agent/context.js +0 -262
  9. package/dist/agent/context.js.map +0 -1
  10. package/dist/agent/error-escalation.d.ts +0 -19
  11. package/dist/agent/error-escalation.d.ts.map +0 -1
  12. package/dist/agent/error-escalation.js +0 -168
  13. package/dist/agent/error-escalation.js.map +0 -1
  14. package/dist/agent/loop.d.ts +0 -46
  15. package/dist/agent/loop.d.ts.map +0 -1
  16. package/dist/agent/loop.js +0 -1043
  17. package/dist/agent/loop.js.map +0 -1
  18. package/dist/agent/memory.d.ts +0 -40
  19. package/dist/agent/memory.d.ts.map +0 -1
  20. package/dist/agent/memory.js +0 -231
  21. package/dist/agent/memory.js.map +0 -1
  22. package/dist/agent/modes/applier.d.ts +0 -43
  23. package/dist/agent/modes/applier.d.ts.map +0 -1
  24. package/dist/agent/modes/applier.js +0 -30
  25. package/dist/agent/modes/applier.js.map +0 -1
  26. package/dist/agent/modes/registry.d.ts +0 -35
  27. package/dist/agent/modes/registry.d.ts.map +0 -1
  28. package/dist/agent/modes/registry.js +0 -169
  29. package/dist/agent/modes/registry.js.map +0 -1
  30. package/dist/agent/modes/types.d.ts +0 -61
  31. package/dist/agent/modes/types.d.ts.map +0 -1
  32. package/dist/agent/modes/types.js +0 -13
  33. package/dist/agent/modes/types.js.map +0 -1
  34. package/dist/agent/react-loop.d.ts +0 -65
  35. package/dist/agent/react-loop.d.ts.map +0 -1
  36. package/dist/agent/react-loop.js +0 -101
  37. package/dist/agent/react-loop.js.map +0 -1
  38. package/dist/agent/system-prompt.d.ts +0 -26
  39. package/dist/agent/system-prompt.d.ts.map +0 -1
  40. package/dist/agent/system-prompt.js +0 -478
  41. package/dist/agent/system-prompt.js.map +0 -1
  42. package/dist/agent/tool-executor.d.ts +0 -36
  43. package/dist/agent/tool-executor.d.ts.map +0 -1
  44. package/dist/agent/tool-executor.js +0 -346
  45. package/dist/agent/tool-executor.js.map +0 -1
  46. package/dist/agent/user-profile.d.ts +0 -26
  47. package/dist/agent/user-profile.d.ts.map +0 -1
  48. package/dist/agent/user-profile.js +0 -169
  49. package/dist/agent/user-profile.js.map +0 -1
  50. package/dist/agent/write-enforcer.d.ts +0 -7
  51. package/dist/agent/write-enforcer.d.ts.map +0 -1
  52. package/dist/agent/write-enforcer.js +0 -8
  53. package/dist/agent/write-enforcer.js.map +0 -1
  54. package/dist/cli/config.d.ts +0 -13
  55. package/dist/cli/config.d.ts.map +0 -1
  56. package/dist/cli/config.js +0 -82
  57. package/dist/cli/config.js.map +0 -1
  58. package/dist/cli/model.d.ts +0 -13
  59. package/dist/cli/model.d.ts.map +0 -1
  60. package/dist/cli/model.js +0 -170
  61. package/dist/cli/model.js.map +0 -1
  62. package/dist/cli/provider.d.ts +0 -12
  63. package/dist/cli/provider.d.ts.map +0 -1
  64. package/dist/cli/provider.js +0 -90
  65. package/dist/cli/provider.js.map +0 -1
  66. package/dist/cli/update.d.ts +0 -12
  67. package/dist/cli/update.d.ts.map +0 -1
  68. package/dist/cli/update.js +0 -69
  69. package/dist/cli/update.js.map +0 -1
  70. package/dist/cli.d.ts +0 -3
  71. package/dist/cli.d.ts.map +0 -1
  72. package/dist/cli.js +0 -310
  73. package/dist/cli.js.map +0 -1
  74. package/dist/config/config.d.ts +0 -59
  75. package/dist/config/config.d.ts.map +0 -1
  76. package/dist/config/config.js +0 -232
  77. package/dist/config/config.js.map +0 -1
  78. package/dist/config/types.d.ts +0 -122
  79. package/dist/config/types.d.ts.map +0 -1
  80. package/dist/config/types.js +0 -13
  81. package/dist/config/types.js.map +0 -1
  82. package/dist/file-loader.d.ts +0 -20
  83. package/dist/file-loader.d.ts.map +0 -1
  84. package/dist/file-loader.js +0 -121
  85. package/dist/file-loader.js.map +0 -1
  86. package/dist/index.d.ts +0 -9
  87. package/dist/index.d.ts.map +0 -1
  88. package/dist/index.js +0 -11
  89. package/dist/index.js.map +0 -1
  90. package/dist/indexer/cache.d.ts +0 -34
  91. package/dist/indexer/cache.d.ts.map +0 -1
  92. package/dist/indexer/cache.js +0 -221
  93. package/dist/indexer/cache.js.map +0 -1
  94. package/dist/indexer/code-index.d.ts +0 -27
  95. package/dist/indexer/code-index.d.ts.map +0 -1
  96. package/dist/indexer/code-index.js +0 -219
  97. package/dist/indexer/code-index.js.map +0 -1
  98. package/dist/indexer/project-map.d.ts +0 -23
  99. package/dist/indexer/project-map.d.ts.map +0 -1
  100. package/dist/indexer/project-map.js +0 -264
  101. package/dist/indexer/project-map.js.map +0 -1
  102. package/dist/llm/lmstudio-native.d.ts +0 -10
  103. package/dist/llm/lmstudio-native.d.ts.map +0 -1
  104. package/dist/llm/lmstudio-native.js +0 -179
  105. package/dist/llm/lmstudio-native.js.map +0 -1
  106. package/dist/llm/openai-compat.d.ts +0 -11
  107. package/dist/llm/openai-compat.d.ts.map +0 -1
  108. package/dist/llm/openai-compat.js +0 -161
  109. package/dist/llm/openai-compat.js.map +0 -1
  110. package/dist/llm/provider.d.ts +0 -46
  111. package/dist/llm/provider.d.ts.map +0 -1
  112. package/dist/llm/provider.js +0 -13
  113. package/dist/llm/provider.js.map +0 -1
  114. package/dist/llm/token-counter.d.ts +0 -15
  115. package/dist/llm/token-counter.d.ts.map +0 -1
  116. package/dist/llm/token-counter.js +0 -51
  117. package/dist/llm/token-counter.js.map +0 -1
  118. package/dist/logger.d.ts +0 -24
  119. package/dist/logger.d.ts.map +0 -1
  120. package/dist/logger.js +0 -156
  121. package/dist/logger.js.map +0 -1
  122. package/dist/plugins/adapters/hooks-adapter.d.ts +0 -12
  123. package/dist/plugins/adapters/hooks-adapter.d.ts.map +0 -1
  124. package/dist/plugins/adapters/hooks-adapter.js +0 -23
  125. package/dist/plugins/adapters/hooks-adapter.js.map +0 -1
  126. package/dist/plugins/builtin/lint-on-write/index.d.ts +0 -12
  127. package/dist/plugins/builtin/lint-on-write/index.d.ts.map +0 -1
  128. package/dist/plugins/builtin/lint-on-write/index.js +0 -98
  129. package/dist/plugins/builtin/lint-on-write/index.js.map +0 -1
  130. package/dist/plugins/builtin/lint-on-write/index.ts +0 -97
  131. package/dist/plugins/builtin/lint-on-write/manifest.json +0 -13
  132. package/dist/plugins/builtin/notify/index.d.ts +0 -11
  133. package/dist/plugins/builtin/notify/index.d.ts.map +0 -1
  134. package/dist/plugins/builtin/notify/index.js +0 -102
  135. package/dist/plugins/builtin/notify/index.js.map +0 -1
  136. package/dist/plugins/builtin/notify/index.ts +0 -105
  137. package/dist/plugins/builtin/notify/manifest.json +0 -16
  138. package/dist/plugins/loader.d.ts +0 -18
  139. package/dist/plugins/loader.d.ts.map +0 -1
  140. package/dist/plugins/loader.js +0 -182
  141. package/dist/plugins/loader.js.map +0 -1
  142. package/dist/plugins/manager.d.ts +0 -55
  143. package/dist/plugins/manager.d.ts.map +0 -1
  144. package/dist/plugins/manager.js +0 -190
  145. package/dist/plugins/manager.js.map +0 -1
  146. package/dist/plugins/types.d.ts +0 -76
  147. package/dist/plugins/types.d.ts.map +0 -1
  148. package/dist/plugins/types.js +0 -8
  149. package/dist/plugins/types.js.map +0 -1
  150. package/dist/repl/commands.d.ts +0 -63
  151. package/dist/repl/commands.d.ts.map +0 -1
  152. package/dist/repl/commands.js +0 -1070
  153. package/dist/repl/commands.js.map +0 -1
  154. package/dist/repl/history.d.ts +0 -32
  155. package/dist/repl/history.d.ts.map +0 -1
  156. package/dist/repl/history.js +0 -40
  157. package/dist/repl/history.js.map +0 -1
  158. package/dist/repl/index.d.ts +0 -14
  159. package/dist/repl/index.d.ts.map +0 -1
  160. package/dist/repl/index.js +0 -235
  161. package/dist/repl/index.js.map +0 -1
  162. package/dist/session/store.d.ts +0 -46
  163. package/dist/session/store.d.ts.map +0 -1
  164. package/dist/session/store.js +0 -154
  165. package/dist/session/store.js.map +0 -1
  166. package/dist/setup-wizard.d.ts +0 -3
  167. package/dist/setup-wizard.d.ts.map +0 -1
  168. package/dist/setup-wizard.js +0 -410
  169. package/dist/setup-wizard.js.map +0 -1
  170. package/dist/skills/builtin/agent-test/SKILL.md +0 -68
  171. package/dist/skills/builtin/cli-expert/SKILL.md +0 -848
  172. package/dist/skills/builtin/code-review/SKILL.md +0 -424
  173. package/dist/skills/builtin/git-expert/SKILL.md +0 -522
  174. package/dist/skills/builtin/grill-me/SKILL.md +0 -46
  175. package/dist/skills/builtin/jest-testing-expert/SKILL.md +0 -957
  176. package/dist/skills/builtin/nodejs-expert/SKILL.md +0 -192
  177. package/dist/skills/builtin/systematic-debugging/SKILL.md +0 -296
  178. package/dist/skills/builtin/test-driven-development/SKILL.md +0 -371
  179. package/dist/skills/builtin/typescript-expert/SKILL.md +0 -429
  180. package/dist/skills/builtin/web-scraping/SKILL.md +0 -422
  181. package/dist/skills/loader.d.ts +0 -49
  182. package/dist/skills/loader.d.ts.map +0 -1
  183. package/dist/skills/loader.js +0 -401
  184. package/dist/skills/loader.js.map +0 -1
  185. package/dist/styling/engine.d.ts +0 -39
  186. package/dist/styling/engine.d.ts.map +0 -1
  187. package/dist/styling/engine.js +0 -122
  188. package/dist/styling/engine.js.map +0 -1
  189. package/dist/styling/index.d.ts +0 -15
  190. package/dist/styling/index.d.ts.map +0 -1
  191. package/dist/styling/index.js +0 -40
  192. package/dist/styling/index.js.map +0 -1
  193. package/dist/styling/loader.d.ts +0 -9
  194. package/dist/styling/loader.d.ts.map +0 -1
  195. package/dist/styling/loader.js +0 -169
  196. package/dist/styling/loader.js.map +0 -1
  197. package/dist/styling/types.d.ts +0 -64
  198. package/dist/styling/types.d.ts.map +0 -1
  199. package/dist/styling/types.js +0 -12
  200. package/dist/styling/types.js.map +0 -1
  201. package/dist/subagent/chat.d.ts +0 -19
  202. package/dist/subagent/chat.d.ts.map +0 -1
  203. package/dist/subagent/chat.js +0 -279
  204. package/dist/subagent/chat.js.map +0 -1
  205. package/dist/subagent/context.d.ts +0 -9
  206. package/dist/subagent/context.d.ts.map +0 -1
  207. package/dist/subagent/context.js +0 -75
  208. package/dist/subagent/context.js.map +0 -1
  209. package/dist/subagent/definition.d.ts +0 -7
  210. package/dist/subagent/definition.d.ts.map +0 -1
  211. package/dist/subagent/definition.js +0 -26
  212. package/dist/subagent/definition.js.map +0 -1
  213. package/dist/subagent/errors.d.ts +0 -24
  214. package/dist/subagent/errors.d.ts.map +0 -1
  215. package/dist/subagent/errors.js +0 -85
  216. package/dist/subagent/errors.js.map +0 -1
  217. package/dist/subagent/validation.d.ts +0 -17
  218. package/dist/subagent/validation.d.ts.map +0 -1
  219. package/dist/subagent/validation.js +0 -83
  220. package/dist/subagent/validation.js.map +0 -1
  221. package/dist/tools/adapters/bash-to-fs.d.ts +0 -20
  222. package/dist/tools/adapters/bash-to-fs.d.ts.map +0 -1
  223. package/dist/tools/adapters/bash-to-fs.js +0 -74
  224. package/dist/tools/adapters/bash-to-fs.js.map +0 -1
  225. package/dist/tools/adapters/content-sanitizer.d.ts +0 -13
  226. package/dist/tools/adapters/content-sanitizer.d.ts.map +0 -1
  227. package/dist/tools/adapters/content-sanitizer.js +0 -73
  228. package/dist/tools/adapters/content-sanitizer.js.map +0 -1
  229. package/dist/tools/adapters/grounding-fixer.d.ts +0 -15
  230. package/dist/tools/adapters/grounding-fixer.d.ts.map +0 -1
  231. package/dist/tools/adapters/grounding-fixer.js +0 -57
  232. package/dist/tools/adapters/grounding-fixer.js.map +0 -1
  233. package/dist/tools/adapters/index.d.ts +0 -6
  234. package/dist/tools/adapters/index.d.ts.map +0 -1
  235. package/dist/tools/adapters/index.js +0 -5
  236. package/dist/tools/adapters/index.js.map +0 -1
  237. package/dist/tools/adapters/pipeline.d.ts +0 -34
  238. package/dist/tools/adapters/pipeline.d.ts.map +0 -1
  239. package/dist/tools/adapters/pipeline.js +0 -58
  240. package/dist/tools/adapters/pipeline.js.map +0 -1
  241. package/dist/tools/adapters/types.d.ts +0 -46
  242. package/dist/tools/adapters/types.d.ts.map +0 -1
  243. package/dist/tools/adapters/types.js +0 -2
  244. package/dist/tools/adapters/types.js.map +0 -1
  245. package/dist/tools/approve.d.ts +0 -27
  246. package/dist/tools/approve.d.ts.map +0 -1
  247. package/dist/tools/approve.js +0 -45
  248. package/dist/tools/approve.js.map +0 -1
  249. package/dist/tools/bash.d.ts +0 -25
  250. package/dist/tools/bash.d.ts.map +0 -1
  251. package/dist/tools/bash.js +0 -292
  252. package/dist/tools/bash.js.map +0 -1
  253. package/dist/tools/fs/copy-file.d.ts +0 -13
  254. package/dist/tools/fs/copy-file.d.ts.map +0 -1
  255. package/dist/tools/fs/copy-file.js +0 -54
  256. package/dist/tools/fs/copy-file.js.map +0 -1
  257. package/dist/tools/fs/create-dir.d.ts +0 -13
  258. package/dist/tools/fs/create-dir.d.ts.map +0 -1
  259. package/dist/tools/fs/create-dir.js +0 -44
  260. package/dist/tools/fs/create-dir.js.map +0 -1
  261. package/dist/tools/fs/delete-file.d.ts +0 -13
  262. package/dist/tools/fs/delete-file.d.ts.map +0 -1
  263. package/dist/tools/fs/delete-file.js +0 -52
  264. package/dist/tools/fs/delete-file.js.map +0 -1
  265. package/dist/tools/fs/edit-file.d.ts +0 -15
  266. package/dist/tools/fs/edit-file.d.ts.map +0 -1
  267. package/dist/tools/fs/edit-file.js +0 -95
  268. package/dist/tools/fs/edit-file.js.map +0 -1
  269. package/dist/tools/fs/file-info.d.ts +0 -13
  270. package/dist/tools/fs/file-info.d.ts.map +0 -1
  271. package/dist/tools/fs/file-info.js +0 -50
  272. package/dist/tools/fs/file-info.js.map +0 -1
  273. package/dist/tools/fs/glob-search.d.ts +0 -13
  274. package/dist/tools/fs/glob-search.d.ts.map +0 -1
  275. package/dist/tools/fs/glob-search.js +0 -112
  276. package/dist/tools/fs/glob-search.js.map +0 -1
  277. package/dist/tools/fs/grep-search.d.ts +0 -14
  278. package/dist/tools/fs/grep-search.d.ts.map +0 -1
  279. package/dist/tools/fs/grep-search.js +0 -135
  280. package/dist/tools/fs/grep-search.js.map +0 -1
  281. package/dist/tools/fs/list-dir.d.ts +0 -13
  282. package/dist/tools/fs/list-dir.d.ts.map +0 -1
  283. package/dist/tools/fs/list-dir.js +0 -74
  284. package/dist/tools/fs/list-dir.js.map +0 -1
  285. package/dist/tools/fs/move-file.d.ts +0 -13
  286. package/dist/tools/fs/move-file.d.ts.map +0 -1
  287. package/dist/tools/fs/move-file.js +0 -54
  288. package/dist/tools/fs/move-file.js.map +0 -1
  289. package/dist/tools/fs/path-utils.d.ts +0 -51
  290. package/dist/tools/fs/path-utils.d.ts.map +0 -1
  291. package/dist/tools/fs/path-utils.js +0 -103
  292. package/dist/tools/fs/path-utils.js.map +0 -1
  293. package/dist/tools/fs/read-file.d.ts +0 -13
  294. package/dist/tools/fs/read-file.d.ts.map +0 -1
  295. package/dist/tools/fs/read-file.js +0 -64
  296. package/dist/tools/fs/read-file.js.map +0 -1
  297. package/dist/tools/fs/tree.d.ts +0 -13
  298. package/dist/tools/fs/tree.d.ts.map +0 -1
  299. package/dist/tools/fs/tree.js +0 -89
  300. package/dist/tools/fs/tree.js.map +0 -1
  301. package/dist/tools/fs/types.d.ts +0 -14
  302. package/dist/tools/fs/types.d.ts.map +0 -1
  303. package/dist/tools/fs/types.js +0 -11
  304. package/dist/tools/fs/types.js.map +0 -1
  305. package/dist/tools/fs/write-file.d.ts +0 -14
  306. package/dist/tools/fs/write-file.d.ts.map +0 -1
  307. package/dist/tools/fs/write-file.js +0 -83
  308. package/dist/tools/fs/write-file.js.map +0 -1
  309. package/dist/tools/hooks.d.ts +0 -44
  310. package/dist/tools/hooks.d.ts.map +0 -1
  311. package/dist/tools/hooks.js +0 -217
  312. package/dist/tools/hooks.js.map +0 -1
  313. package/dist/tools/id-gen.d.ts +0 -4
  314. package/dist/tools/id-gen.d.ts.map +0 -1
  315. package/dist/tools/id-gen.js +0 -12
  316. package/dist/tools/id-gen.js.map +0 -1
  317. package/dist/tools/mcp.d.ts +0 -36
  318. package/dist/tools/mcp.d.ts.map +0 -1
  319. package/dist/tools/mcp.js +0 -93
  320. package/dist/tools/mcp.js.map +0 -1
  321. package/dist/tools/native/approve.d.ts +0 -11
  322. package/dist/tools/native/approve.d.ts.map +0 -1
  323. package/dist/tools/native/approve.js +0 -39
  324. package/dist/tools/native/approve.js.map +0 -1
  325. package/dist/tools/native/plan.d.ts +0 -10
  326. package/dist/tools/native/plan.d.ts.map +0 -1
  327. package/dist/tools/native/plan.js +0 -115
  328. package/dist/tools/native/plan.js.map +0 -1
  329. package/dist/tools/native/project-map.d.ts +0 -15
  330. package/dist/tools/native/project-map.d.ts.map +0 -1
  331. package/dist/tools/native/project-map.js +0 -203
  332. package/dist/tools/native/project-map.js.map +0 -1
  333. package/dist/tools/native/question.d.ts +0 -11
  334. package/dist/tools/native/question.d.ts.map +0 -1
  335. package/dist/tools/native/question.js +0 -41
  336. package/dist/tools/native/question.js.map +0 -1
  337. package/dist/tools/native/scaffold.d.ts +0 -5
  338. package/dist/tools/native/scaffold.d.ts.map +0 -1
  339. package/dist/tools/native/scaffold.js +0 -246
  340. package/dist/tools/native/scaffold.js.map +0 -1
  341. package/dist/tools/native/theme.d.ts +0 -10
  342. package/dist/tools/native/theme.d.ts.map +0 -1
  343. package/dist/tools/native/theme.js +0 -101
  344. package/dist/tools/native/theme.js.map +0 -1
  345. package/dist/tools/native/todo.d.ts +0 -10
  346. package/dist/tools/native/todo.d.ts.map +0 -1
  347. package/dist/tools/native/todo.js +0 -58
  348. package/dist/tools/native/todo.js.map +0 -1
  349. package/dist/tools/native/user-profile.d.ts +0 -10
  350. package/dist/tools/native/user-profile.d.ts.map +0 -1
  351. package/dist/tools/native/user-profile.js +0 -58
  352. package/dist/tools/native/user-profile.js.map +0 -1
  353. package/dist/tools/parse-tool-call.d.ts +0 -11
  354. package/dist/tools/parse-tool-call.d.ts.map +0 -1
  355. package/dist/tools/parse-tool-call.js +0 -87
  356. package/dist/tools/parse-tool-call.js.map +0 -1
  357. package/dist/tools/plan.d.ts +0 -40
  358. package/dist/tools/plan.d.ts.map +0 -1
  359. package/dist/tools/plan.js +0 -143
  360. package/dist/tools/plan.js.map +0 -1
  361. package/dist/tools/question.d.ts +0 -33
  362. package/dist/tools/question.d.ts.map +0 -1
  363. package/dist/tools/question.js +0 -62
  364. package/dist/tools/question.js.map +0 -1
  365. package/dist/tools/registry.d.ts +0 -37
  366. package/dist/tools/registry.d.ts.map +0 -1
  367. package/dist/tools/registry.js +0 -97
  368. package/dist/tools/registry.js.map +0 -1
  369. package/dist/tools/sanitizer.d.ts +0 -30
  370. package/dist/tools/sanitizer.d.ts.map +0 -1
  371. package/dist/tools/sanitizer.js +0 -77
  372. package/dist/tools/sanitizer.js.map +0 -1
  373. package/dist/tools/subagent.d.ts +0 -39
  374. package/dist/tools/subagent.d.ts.map +0 -1
  375. package/dist/tools/subagent.js +0 -225
  376. package/dist/tools/subagent.js.map +0 -1
  377. package/dist/tools/syntax-check.d.ts +0 -32
  378. package/dist/tools/syntax-check.d.ts.map +0 -1
  379. package/dist/tools/syntax-check.js +0 -272
  380. package/dist/tools/syntax-check.js.map +0 -1
  381. package/dist/tools/todo.d.ts +0 -28
  382. package/dist/tools/todo.d.ts.map +0 -1
  383. package/dist/tools/todo.js +0 -125
  384. package/dist/tools/todo.js.map +0 -1
  385. package/dist/tools/types.d.ts +0 -51
  386. package/dist/tools/types.d.ts.map +0 -1
  387. package/dist/tools/types.js +0 -2
  388. package/dist/tools/types.js.map +0 -1
  389. package/dist/tools/web-browse.d.ts +0 -5
  390. package/dist/tools/web-browse.d.ts.map +0 -1
  391. package/dist/tools/web-browse.js +0 -757
  392. package/dist/tools/web-browse.js.map +0 -1
  393. package/dist/tools/web-fetch.d.ts +0 -19
  394. package/dist/tools/web-fetch.d.ts.map +0 -1
  395. package/dist/tools/web-fetch.js +0 -90
  396. package/dist/tools/web-fetch.js.map +0 -1
  397. package/dist/tools/web-search.d.ts +0 -19
  398. package/dist/tools/web-search.d.ts.map +0 -1
  399. package/dist/tools/web-search.js +0 -97
  400. package/dist/tools/web-search.js.map +0 -1
  401. package/dist/ui/components/status-bar.d.ts +0 -11
  402. package/dist/ui/components/status-bar.d.ts.map +0 -1
  403. package/dist/ui/components/status-bar.js +0 -20
  404. package/dist/ui/components/status-bar.js.map +0 -1
  405. package/dist/ui/index.d.ts +0 -8
  406. package/dist/ui/index.d.ts.map +0 -1
  407. package/dist/ui/index.js +0 -9
  408. package/dist/ui/index.js.map +0 -1
  409. package/dist/ui/ink/components/App.d.ts +0 -98
  410. package/dist/ui/ink/components/App.d.ts.map +0 -1
  411. package/dist/ui/ink/components/App.js +0 -212
  412. package/dist/ui/ink/components/App.js.map +0 -1
  413. package/dist/ui/ink/components/Conversation.d.ts +0 -20
  414. package/dist/ui/ink/components/Conversation.d.ts.map +0 -1
  415. package/dist/ui/ink/components/Conversation.js +0 -15
  416. package/dist/ui/ink/components/Conversation.js.map +0 -1
  417. package/dist/ui/ink/components/MessageBlock.d.ts +0 -27
  418. package/dist/ui/ink/components/MessageBlock.d.ts.map +0 -1
  419. package/dist/ui/ink/components/MessageBlock.js +0 -41
  420. package/dist/ui/ink/components/MessageBlock.js.map +0 -1
  421. package/dist/ui/ink/components/PromptInput.d.ts +0 -25
  422. package/dist/ui/ink/components/PromptInput.d.ts.map +0 -1
  423. package/dist/ui/ink/components/PromptInput.js +0 -167
  424. package/dist/ui/ink/components/PromptInput.js.map +0 -1
  425. package/dist/ui/ink/components/SelectInput.d.ts +0 -9
  426. package/dist/ui/ink/components/SelectInput.d.ts.map +0 -1
  427. package/dist/ui/ink/components/SelectInput.js +0 -30
  428. package/dist/ui/ink/components/SelectInput.js.map +0 -1
  429. package/dist/ui/ink/components/StatusBar.d.ts +0 -14
  430. package/dist/ui/ink/components/StatusBar.d.ts.map +0 -1
  431. package/dist/ui/ink/components/StatusBar.js +0 -20
  432. package/dist/ui/ink/components/StatusBar.js.map +0 -1
  433. package/dist/ui/ink/components/StreamBlock.d.ts +0 -8
  434. package/dist/ui/ink/components/StreamBlock.d.ts.map +0 -1
  435. package/dist/ui/ink/components/StreamBlock.js +0 -15
  436. package/dist/ui/ink/components/StreamBlock.js.map +0 -1
  437. package/dist/ui/ink/components/Tags.d.ts +0 -26
  438. package/dist/ui/ink/components/Tags.d.ts.map +0 -1
  439. package/dist/ui/ink/components/Tags.js +0 -37
  440. package/dist/ui/ink/components/Tags.js.map +0 -1
  441. package/dist/ui/ink/components/ToolCallBlock.d.ts +0 -31
  442. package/dist/ui/ink/components/ToolCallBlock.d.ts.map +0 -1
  443. package/dist/ui/ink/components/ToolCallBlock.js +0 -17
  444. package/dist/ui/ink/components/ToolCallBlock.js.map +0 -1
  445. package/dist/ui/ink/renderer.d.ts +0 -69
  446. package/dist/ui/ink/renderer.d.ts.map +0 -1
  447. package/dist/ui/ink/renderer.js +0 -142
  448. package/dist/ui/ink/renderer.js.map +0 -1
  449. package/dist/ui/ink/theme.d.ts +0 -28
  450. package/dist/ui/ink/theme.d.ts.map +0 -1
  451. package/dist/ui/ink/theme.js +0 -45
  452. package/dist/ui/ink/theme.js.map +0 -1
  453. package/dist/ui/md-formatter.d.ts +0 -16
  454. package/dist/ui/md-formatter.d.ts.map +0 -1
  455. package/dist/ui/md-formatter.js +0 -448
  456. package/dist/ui/md-formatter.js.map +0 -1
  457. package/dist/ui/readline-renderer.d.ts +0 -45
  458. package/dist/ui/readline-renderer.d.ts.map +0 -1
  459. package/dist/ui/readline-renderer.js +0 -181
  460. package/dist/ui/readline-renderer.js.map +0 -1
  461. package/dist/ui/renderer.d.ts +0 -66
  462. package/dist/ui/renderer.d.ts.map +0 -1
  463. package/dist/ui/renderer.js +0 -16
  464. package/dist/ui/renderer.js.map +0 -1
  465. package/dist/ui/subagent-renderer.d.ts +0 -58
  466. package/dist/ui/subagent-renderer.d.ts.map +0 -1
  467. package/dist/ui/subagent-renderer.js +0 -100
  468. package/dist/ui/subagent-renderer.js.map +0 -1
  469. package/dist/updater.d.ts +0 -15
  470. package/dist/updater.d.ts.map +0 -1
  471. package/dist/updater.js +0 -166
  472. package/dist/updater.js.map +0 -1
@@ -1,757 +0,0 @@
1
- import { logInfo, logError } from '../logger.js';
2
- /**
3
- * Интерактивный инструмент для работы с веб-страницами через headless-браузер.
4
- *
5
- * Поддерживает 9 actions: navigate, click, type, extract, screenshot,
6
- * scroll, wait, get_links, evaluate.
7
- *
8
- * Сессия браузера stateful: navigate открывает страницу,
9
- * последующие action'ы работают с ней.
10
- *
11
- * @module tools/web-browse
12
- */
13
- // ─── Browser Session ─────────────────────────────────────
14
- /** Тип для Playwright (ленивый импорт) */
15
- let playwrightModule = null;
16
- async function getPlaywright() {
17
- if (!playwrightModule) {
18
- playwrightModule = await import('playwright');
19
- }
20
- return playwrightModule;
21
- }
22
- const state = {
23
- browser: null,
24
- context: null,
25
- page: null,
26
- lastActivity: 0,
27
- };
28
- /** Таймаут неактивности (5 минут) */
29
- const IDLE_TIMEOUT_MS = 5 * 60 * 1000;
30
- /** Таймаут навигации */
31
- const NAV_TIMEOUT_MS = 30_000;
32
- /** Инициализация браузера (лениво) */
33
- async function ensureBrowser() {
34
- // Проверяем есть ли активная сессия
35
- if (state.page && !state.page.isClosed()) {
36
- state.lastActivity = Date.now();
37
- return state.page;
38
- }
39
- // Закрываем старые ресурсы
40
- await closeBrowser();
41
- const pw = await getPlaywright();
42
- state.browser = await pw.chromium.launch({
43
- headless: true,
44
- args: ['--no-sandbox', '--disable-gpu'],
45
- });
46
- state.context = await state.browser.newContext({
47
- userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
48
- viewport: { width: 1280, height: 720 },
49
- });
50
- state.page = await state.context.newPage();
51
- state.lastActivity = Date.now();
52
- logInfo('BROWSER', 'Headless browser launched');
53
- return state.page;
54
- }
55
- /** Закрытие браузера */
56
- async function closeBrowser() {
57
- try {
58
- if (state.page && !state.page.isClosed())
59
- await state.page.close();
60
- if (state.context)
61
- await state.context.close();
62
- if (state.browser)
63
- await state.browser.close();
64
- }
65
- catch (e) {
66
- logError('BROWSER', `close error: ${e.message}`);
67
- }
68
- state.browser = null;
69
- state.context = null;
70
- state.page = null;
71
- }
72
- /** Проверка и закрытие при простое */
73
- async function checkIdle() {
74
- if (state.page && Date.now() - state.lastActivity > IDLE_TIMEOUT_MS) {
75
- logInfo('BROWSER', 'Idle timeout, closing browser');
76
- await closeBrowser();
77
- }
78
- }
79
- // ─── Actions ─────────────────────────────────────────────
80
- /**
81
- * Универсальный scrape: navigate + auto-scroll + discover + извлечение данных.
82
- * Одним вызовом代替ует 4-шаговый паттерн (navigate → discover → evaluate → write_file).
83
- *
84
- * Алгоритм:
85
- * 1. Navigate (если страница не активна)
86
- * 2. Auto-scroll для lazy-контента
87
- * 3. Discover — найти элементы по паттерну классов
88
- * 4. Извлечь данные из каждого элемента (текст, ссылки, дочерние элементы)
89
- * 5. Вернуть структурированный JSON
90
- */
91
- async function actionScrape(page, args) {
92
- const url = String(args.url ?? '').trim();
93
- const pattern = String(args.pattern ?? 'product|card|item|goods|bike|velosiped').trim();
94
- const maxItems = Math.min(Number(args.maxItems) || 10, 50);
95
- const extractFields = String(args.fields ?? '').trim(); // e.g. "title,price,href"
96
- // Шаг 1: Navigate (если нет активной страницы или указан URL)
97
- if (url) {
98
- if (!url.startsWith('http://') && !url.startsWith('https://')) {
99
- return 'Error: URL must start with http:// or https://';
100
- }
101
- const navResult = await actionNavigate(page, args);
102
- if (navResult.text.startsWith('Error'))
103
- return navResult.text;
104
- }
105
- if (!page || page.isClosed()) {
106
- return 'Error: No active page. Provide a URL to navigate to.';
107
- }
108
- // Шаг 2: Auto-scroll (если не был сделан в navigate)
109
- try {
110
- const currentScroll = await page.evaluate(() => window.scrollY);
111
- if (currentScroll === 0) {
112
- // Navigate уже скроллил, но если мы здесь — скроллим ещё раз
113
- let prevCount = await page.evaluate(() => document.querySelectorAll('*').length);
114
- for (let i = 0; i < 5; i++) {
115
- await page.evaluate(() => window.scrollBy(0, window.innerHeight));
116
- await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => { });
117
- await page.waitForTimeout(1500);
118
- const newCount = await page.evaluate(() => document.querySelectorAll('*').length);
119
- if (newCount === prevCount)
120
- break;
121
- prevCount = newCount;
122
- }
123
- await page.evaluate(() => window.scrollTo(0, 0));
124
- await page.waitForTimeout(500);
125
- }
126
- }
127
- catch { /* ignore */ }
128
- // Шаг 3: Discover — найти элементы по паттерну
129
- const patternRegex = new RegExp(pattern, 'i');
130
- const scrapeResult = await page.evaluate(({ pat, max }) => {
131
- const regex = new RegExp(pat, 'i');
132
- // Собираем все элементы с классами
133
- const allElements = Array.from(document.querySelectorAll('*'));
134
- const candidates = [];
135
- for (const el of allElements) {
136
- if (!el.className || typeof el.className !== 'string')
137
- continue;
138
- const cls = el.className;
139
- // Считаем совпадения паттерна в классах
140
- const matches = cls.match(regex);
141
- if (!matches)
142
- continue;
143
- // Оценка: количество совпадений + длина текста (продукты обычно имеют текст)
144
- const text = (el.textContent ?? '').trim();
145
- const score = matches.length * 10 + Math.min(text.length / 10, 20);
146
- candidates.push({ el, score, className: cls });
147
- }
148
- // Сортируем по score, берём топ
149
- candidates.sort((a, b) => b.score - a.score);
150
- // Группируем похожие элементы (одинаковый тег + похожие классы)
151
- const groups = [];
152
- for (const c of candidates.slice(0, max * 3)) {
153
- const tag = c.el.tagName;
154
- const existing = groups.find(g => g.tag === tag && g.className === c.className);
155
- if (existing) {
156
- existing.count++;
157
- existing.elements.push(c.el);
158
- }
159
- else {
160
- groups.push({ tag, className: c.className, count: 1, elements: [c.el] });
161
- }
162
- }
163
- // Берём группу с наибольшим количеством элементов (это карточки товаров)
164
- groups.sort((a, b) => b.count - a.count);
165
- const bestGroup = groups[0];
166
- if (!bestGroup || bestGroup.count < 2) {
167
- // Нет подходящих групп — возвращаем все кандидаты как есть
168
- return {
169
- found: false,
170
- message: `No elements matching pattern "${pat}" found. Page classes: ${candidates.slice(0, 20).map(c => c.className).join(', ')}`,
171
- items: [],
172
- };
173
- }
174
- // Извлекаем данные из элементов лучшей группы
175
- const items = bestGroup.elements.slice(0, max).map(el => {
176
- const data = {};
177
- // Текст элемента
178
- const fullText = (el.textContent ?? '').trim().substring(0, 500);
179
- data.text = fullText;
180
- // Ссылки внутри элемента
181
- const links = Array.from(el.querySelectorAll('a[href]'))
182
- .filter((a) => a instanceof HTMLAnchorElement)
183
- .map(a => ({ text: (a.textContent ?? '').trim().substring(0, 100), href: a.href }));
184
- if (links.length > 0)
185
- data.links = JSON.stringify(links);
186
- // Изображения
187
- const imgs = Array.from(el.querySelectorAll('img[src]'))
188
- .map(img => img.src)
189
- .slice(0, 3);
190
- if (imgs.length > 0)
191
- data.images = JSON.stringify(imgs);
192
- // Дочерние элементы с有意义ными классами
193
- const children = Array.from(el.querySelectorAll('[class]'))
194
- .filter(c => c !== el && c.className && typeof c.className === 'string')
195
- .slice(0, 10)
196
- .map(c => ({
197
- tag: c.tagName,
198
- class: c.className.substring(0, 60),
199
- text: (c.textContent ?? '').trim().substring(0, 100),
200
- }));
201
- if (children.length > 0)
202
- data.children = JSON.stringify(children);
203
- return data;
204
- });
205
- return {
206
- found: true,
207
- groupTag: bestGroup.tag,
208
- groupClass: bestGroup.className,
209
- totalInGroup: bestGroup.count,
210
- items,
211
- };
212
- }, { pat: pattern, max: maxItems });
213
- if (!scrapeResult.found) {
214
- return `Scrape: ${scrapeResult.message}\n\nTry a different pattern or use discover to see page structure.`;
215
- }
216
- // Форматируем вывод
217
- let output = `Scrape results: ${scrapeResult.totalInGroup} items found (showing ${scrapeResult.items.length})\n`;
218
- output += `Selector: <${scrapeResult.groupTag} class="${scrapeResult.groupClass}">\n\n`;
219
- for (let i = 0; i < scrapeResult.items.length; i++) {
220
- const item = scrapeResult.items[i];
221
- output += `--- Item ${i + 1} ---\n`;
222
- if (item.text)
223
- output += `Text: ${item.text}\n`;
224
- if (item.links) {
225
- const links = JSON.parse(item.links);
226
- for (const link of links) {
227
- output += `Link: ${link.text} → ${link.href}\n`;
228
- }
229
- }
230
- if (item.images) {
231
- const imgs = JSON.parse(item.images);
232
- for (const img of imgs) {
233
- output += `Image: ${img}\n`;
234
- }
235
- }
236
- if (item.children) {
237
- const children = JSON.parse(item.children);
238
- for (const child of children) {
239
- output += ` <${child.tag} class="${child.class}"> ${child.text}\n`;
240
- }
241
- }
242
- output += '\n';
243
- }
244
- return output;
245
- }
246
- async function actionNavigate(page, args) {
247
- const url = String(args.url ?? '').trim();
248
- if (!url)
249
- return { text: 'Error: url is required for navigate', status: 0 };
250
- if (!url.startsWith('http://') && !url.startsWith('https://')) {
251
- return { text: 'Error: URL must start with http:// or https://', status: 0 };
252
- }
253
- const response = await page.goto(url, {
254
- waitUntil: 'domcontentloaded',
255
- timeout: NAV_TIMEOUT_MS,
256
- });
257
- // Ждём появления body
258
- await page.waitForSelector('body', { timeout: 5000 }).catch(() => { });
259
- // Ждём networkidle для AJAX-страниц (макс 8 сек)
260
- await page.waitForLoadState('networkidle', { timeout: 8000 }).catch(() => { });
261
- // Доп. ожидание для тяжёлых JS-страниц
262
- await page.waitForTimeout(2000);
263
- // Универсальный автоскролл: скроллим пока DOM стабилизируется
264
- // (нет новых элементов после скролла) или до лимита (8 скроллов).
265
- // Покрывает: lazy loading, infinite scroll, AJAX-каталоги.
266
- try {
267
- let prevCount = await page.evaluate(() => document.querySelectorAll('*').length);
268
- const maxScrolls = 8;
269
- let scrollsDone = 0;
270
- for (let i = 0; i < maxScrolls; i++) {
271
- // Скроллим вниз на высоту вьюпорта
272
- await page.evaluate(() => window.scrollBy(0, window.innerHeight));
273
- scrollsDone++;
274
- // Ждём загрузки контента (networkidle + фиксированная пауза)
275
- await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => { });
276
- await page.waitForTimeout(1500);
277
- // Проверяем стабилизацию DOM
278
- const newCount = await page.evaluate(() => document.querySelectorAll('*').length);
279
- if (newCount === prevCount) {
280
- // DOM стабилизировался — пробуем ещё раз для надёжности
281
- await page.evaluate(() => window.scrollBy(0, window.innerHeight));
282
- await page.waitForLoadState('networkidle', { timeout: 3000 }).catch(() => { });
283
- await page.waitForTimeout(1000);
284
- const finalCount = await page.evaluate(() => document.querySelectorAll('*').length);
285
- if (finalCount === prevCount)
286
- break; // Стабильно — выходим
287
- }
288
- prevCount = newCount;
289
- }
290
- // Вернуться наверх
291
- await page.evaluate(() => window.scrollTo(0, 0));
292
- await page.waitForTimeout(500);
293
- }
294
- catch { /* ignore — scroll is best-effort */ }
295
- const status = response?.status() ?? 0;
296
- const title = await page.title();
297
- const finalUrl = page.url();
298
- // Сводка страницы: текст + ссылки + классы
299
- let summary = '';
300
- try {
301
- const info = await page.evaluate(() => {
302
- // Текст страницы (первые 1500 символов для preview)
303
- const bodyText = (document.body?.innerText ?? '').trim().substring(0, 1500);
304
- // Ссылки (до 10)
305
- const allLinks = Array.from(document.querySelectorAll('a[href]'))
306
- .filter((a) => a instanceof HTMLAnchorElement)
307
- .filter(a => !a.href.startsWith('javascript:') && !a.href.startsWith('#'));
308
- const totalLinks = allLinks.length;
309
- const links = allLinks.slice(0, 10).map(a => ({
310
- text: (a.textContent ?? '').trim().substring(0, 60),
311
- href: a.href,
312
- parentClass: a.closest('div[class], li[class], article[class], section[class]')?.className?.substring(0, 40) ?? '',
313
- }));
314
- // Ключевые классы
315
- const classSet = new Set();
316
- for (const el of document.querySelectorAll('*')) {
317
- for (const cls of el.classList) {
318
- if (cls.length > 2 && cls.length < 50)
319
- classSet.add(cls);
320
- }
321
- }
322
- const classes = Array.from(classSet).sort();
323
- const totalElements = document.querySelectorAll('*').length;
324
- return { bodyText, links, totalLinks, classes, totalElements };
325
- });
326
- summary = `\n\nPage preview (${info.totalElements} elements, ${info.totalLinks} links):`;
327
- if (info.bodyText) {
328
- summary += `\nContent:\n${info.bodyText}`;
329
- if (info.bodyText.length >= 1500)
330
- summary += `\n... (content truncated)`;
331
- }
332
- if (info.links.length > 0) {
333
- summary += `\n\nLinks (${info.links.length} of ${info.totalLinks} shown):`;
334
- for (const link of info.links) {
335
- summary += `\n "${link.text || '(no text)'}" → ${link.href}`;
336
- if (link.parentClass)
337
- summary += ` [${link.parentClass}]`;
338
- }
339
- if (info.totalLinks > 10)
340
- summary += `\n ... and ${info.totalLinks - 10} more. Use get_links to see all.`;
341
- }
342
- if (info.classes.length > 0) {
343
- summary += `\nKey CSS classes: ${info.classes.slice(0, 15).join(', ')}${info.classes.length > 15 ? ` (+${info.classes.length - 15} more)` : ''}`;
344
- }
345
- summary += `\n\nSuggested next steps:`;
346
- summary += `\n - web_browse(action:"get_links") — all links on page`;
347
- summary += `\n - web_browse(action:"extract", selector:".content") — extract specific section`;
348
- summary += `\n - web_browse(action:"discover") — full page structure with CSS selectors`;
349
- summary += `\n - web_browse(action:"scrape", pattern:"...") — auto-scrape items from page`;
350
- }
351
- catch { /* ignore — summary is optional */ }
352
- return { text: `Navigated to: ${finalUrl}\nTitle: ${title}\nStatus: ${status}${summary}`, status };
353
- }
354
- async function actionClick(page, args) {
355
- const selector = String(args.selector ?? '').trim();
356
- if (!selector)
357
- return 'Error: selector is required for click';
358
- // Пробуем CSS-селектор, затем текст
359
- try {
360
- await page.click(selector, { timeout: 10_000 });
361
- }
362
- catch {
363
- // Если CSS-селектор не сработал, пробуем getByText
364
- try {
365
- await page.getByText(selector, { exact: false }).first().click({ timeout: 10_000 });
366
- }
367
- catch (e) {
368
- return `Error: could not click "${selector}": ${e.message}`;
369
- }
370
- }
371
- // Ждём стабилизации после клика
372
- await page.waitForLoadState('domcontentloaded').catch(() => { });
373
- return `Clicked: ${selector}`;
374
- }
375
- async function actionType(page, args) {
376
- const selector = String(args.selector ?? '').trim();
377
- const value = String(args.value ?? '');
378
- if (!selector)
379
- return 'Error: selector is required for type';
380
- try {
381
- await page.fill(selector, value, { timeout: 10_000 });
382
- }
383
- catch {
384
- // Fallback: кликаем и печатаем
385
- try {
386
- await page.click(selector, { timeout: 5_000 });
387
- await page.keyboard.type(value, { delay: 30 });
388
- }
389
- catch (e) {
390
- return `Error: could not type into "${selector}": ${e.message}`;
391
- }
392
- }
393
- return `Typed "${value}" into ${selector}`;
394
- }
395
- async function actionExtract(page, args) {
396
- const selector = String(args.selector ?? '').trim();
397
- const format = String(args.format ?? 'text');
398
- const maxChars = Number(args.maxChars) || 10_000;
399
- let content;
400
- if (selector) {
401
- // Извлечение из конкретного элемента
402
- try {
403
- if (format === 'html') {
404
- content = await page.innerHTML(selector, { timeout: 10_000 });
405
- }
406
- else {
407
- content = await page.textContent(selector, { timeout: 10_000 }) ?? '';
408
- }
409
- }
410
- catch (e) {
411
- return `Error: could not extract from "${selector}": ${e.message}. Hint: extract the full page first (no selector) to see the actual structure, then choose the right selector.`;
412
- }
413
- }
414
- else {
415
- // Извлечение всей страницы
416
- if (format === 'html') {
417
- content = await page.content();
418
- }
419
- else {
420
- content = await page.evaluate(() => document.body?.innerText ?? '');
421
- }
422
- }
423
- // Очистка
424
- content = content
425
- .replace(/\t/g, ' ')
426
- .replace(/[ ]{2,}/g, ' ')
427
- .replace(/\n{3,}/g, '\n\n')
428
- .trim();
429
- if (content.length > maxChars) {
430
- content = content.slice(0, maxChars) + `\n... (truncated, ${content.length} total chars)`;
431
- }
432
- return content || '(empty)';
433
- }
434
- async function actionScreenshot(page, args) {
435
- const selector = String(args.selector ?? '').trim();
436
- let buffer;
437
- if (selector) {
438
- try {
439
- const element = await page.$(selector);
440
- if (!element)
441
- return `Error: element "${selector}" not found`;
442
- buffer = await element.screenshot({ type: 'png' });
443
- }
444
- catch (e) {
445
- return `Error: screenshot of "${selector}" failed: ${e.message}`;
446
- }
447
- }
448
- else {
449
- buffer = await page.screenshot({ type: 'png', fullPage: false });
450
- }
451
- const base64 = buffer.toString('base64');
452
- const url = page.url();
453
- const title = await page.title();
454
- return `Screenshot of: ${url}\nTitle: ${title}\nSize: ${buffer.length} bytes\nFormat: PNG\n\nbase64:${base64}`;
455
- }
456
- async function actionScroll(page, args) {
457
- const direction = String(args.direction ?? 'down');
458
- const scrolled = await page.evaluate((dir) => {
459
- const amount = dir === 'up' ? -window.innerHeight : window.innerHeight;
460
- window.scrollBy(0, amount);
461
- return {
462
- scrollTop: window.scrollY,
463
- scrollHeight: document.documentElement.scrollHeight,
464
- clientHeight: window.innerHeight,
465
- };
466
- }, direction);
467
- const atTop = scrolled.scrollTop <= 0;
468
- const atBottom = scrolled.scrollTop + scrolled.clientHeight >= scrolled.scrollHeight - 10;
469
- let status = `Scrolled ${direction}. Position: ${scrolled.scrollTop}px`;
470
- if (atTop && direction === 'up')
471
- status += ' (at top)';
472
- if (atBottom && direction === 'down')
473
- status += ' (at bottom)';
474
- return status;
475
- }
476
- async function actionWait(page, args) {
477
- const selector = String(args.selector ?? '').trim();
478
- const condition = String(args.condition ?? '').trim();
479
- const timeout = Number(args.timeout) || 5000;
480
- if (condition) {
481
- try {
482
- await page.waitForFunction(condition, { timeout });
483
- return `Condition "${condition}" met`;
484
- }
485
- catch {
486
- return `Timeout: condition "${condition}" not met within ${timeout}ms`;
487
- }
488
- }
489
- else if (selector) {
490
- try {
491
- await page.waitForSelector(selector, { state: 'visible', timeout });
492
- return `Element "${selector}" appeared`;
493
- }
494
- catch {
495
- return `Timeout: element "${selector}" not found within ${timeout}ms. Hint: extract the full page first (no selector) to see the actual structure.`;
496
- }
497
- }
498
- else {
499
- await page.waitForTimeout(timeout);
500
- return `Waited ${timeout}ms`;
501
- }
502
- }
503
- async function actionDiscover(page, _args) {
504
- const result = await page.evaluate(() => {
505
- // Все уникальные CSS-классы на странице
506
- const allElements = document.querySelectorAll('*');
507
- const classSet = new Set();
508
- for (const el of allElements) {
509
- for (const cls of el.classList) {
510
- if (cls.length > 1 && cls.length < 60)
511
- classSet.add(cls);
512
- }
513
- }
514
- const classes = Array.from(classSet).sort();
515
- // Все ссылки (до 50)
516
- const links = Array.from(document.querySelectorAll('a[href]'))
517
- .filter((a) => a instanceof HTMLAnchorElement)
518
- .filter(a => !a.href.startsWith('javascript:') && !a.href.startsWith('#'))
519
- .slice(0, 50)
520
- .map(a => ({
521
- text: (a.textContent ?? '').trim().substring(0, 100),
522
- href: a.href,
523
- parentClass: a.closest('div[class], li[class], article[class], section[class]')?.className ?? '',
524
- }));
525
- return { classes, links };
526
- });
527
- let output = `=== DISCOVER: ${result.classes.length} unique classes, ${result.links.length} links ===\n\n`;
528
- if (result.links.length > 0) {
529
- output += '--- Links (first 20) ---\n';
530
- for (const link of result.links.slice(0, 20)) {
531
- output += ` "${link.text || '(no text)'}" → ${link.href}\n parent: ${link.parentClass}\n`;
532
- }
533
- }
534
- output += `\n--- All classes (${result.classes.length}) ---\n`;
535
- output += result.classes.join(', ');
536
- return output;
537
- }
538
- async function actionGetLinks(page, _args) {
539
- const links = await page.$$eval('a[href]', (anchors) => anchors.map((a) => ({
540
- text: (a.textContent ?? '').trim().slice(0, 100),
541
- href: a.getAttribute('href') ?? '',
542
- })).filter((l) => l.href && !l.href.startsWith('#') && !l.href.startsWith('javascript:')));
543
- if (links.length === 0)
544
- return 'No links found on page.';
545
- const maxLinks = 50;
546
- let output = `Found ${links.length} links:\n\n`;
547
- for (let i = 0; i < Math.min(links.length, maxLinks); i++) {
548
- const l = links[i];
549
- output += `${i + 1}. ${l.text || '(no text)'}\n ${l.href}\n`;
550
- }
551
- if (links.length > maxLinks) {
552
- output += `\n... and ${links.length - maxLinks} more`;
553
- }
554
- return output.trim();
555
- }
556
- async function actionEvaluate(page, args) {
557
- const code = String(args.value ?? args.code ?? '').trim();
558
- if (!code)
559
- return 'Error: value (JS code) is required for evaluate';
560
- try {
561
- // eval() в контексте страницы с IIFE-fallback для return-стейтментов.
562
- // Автоматически подменяет querySelectorAll чтобы возвращал Array (а не NodeList).
563
- // Это решает проблему "slice is not a function" для маленьких моделей.
564
- const result = await page.evaluate((script) => {
565
- // eslint-disable-next-line no-eval
566
- let raw;
567
- try {
568
- raw = eval(script);
569
- }
570
- catch (e) {
571
- if (e instanceof SyntaxError && /\breturn\b/.test(script)) {
572
- // Оборачиваем в IIFE чтобы return работал
573
- raw = eval('(function(){ ' + script + ' })()');
574
- }
575
- else if (e instanceof TypeError && /slice is not a function/i.test(e.message)) {
576
- // querySelectorAll вернул NodeList — подменяем querySelectorAll чтобы возвращал Array
577
- const wrapped = `
578
- (function(){
579
- var _origQSA = document.querySelectorAll.bind(document);
580
- document.querySelectorAll = function(s){ return Array.from(_origQSA(s)); };
581
- var _origQE = document.querySelector.bind(document);
582
- ${script}
583
- })()
584
- `;
585
- raw = eval(wrapped);
586
- }
587
- else {
588
- throw e;
589
- }
590
- }
591
- // Автоматически конвертируем NodeList/HTMLCollection в Array для JSON
592
- if (raw instanceof NodeList || raw instanceof HTMLCollection) {
593
- return Array.from(raw);
594
- }
595
- return raw;
596
- }, code);
597
- if (result === undefined)
598
- return '(undefined)';
599
- if (result === null)
600
- return '(null)';
601
- if (typeof result === 'object')
602
- return JSON.stringify(result, null, 2);
603
- return String(result);
604
- }
605
- catch (e) {
606
- const msg = e.message ?? String(e);
607
- // Подсказка при типичных ошибках
608
- if (msg.includes('slice is not a function')) {
609
- return `Error: ${msg}\nHint: querySelectorAll returns NodeList, not Array. Use Array.from():\n WRONG: document.querySelectorAll('.item').slice(0,5)\n RIGHT: Array.from(document.querySelectorAll('.item')).slice(0,5)\n RIGHT: [...document.querySelectorAll('.item')].slice(0,5)`;
610
- }
611
- if (msg.includes('SyntaxError') && msg.includes('return')) {
612
- return `Error: ${msg}\nHint: "return" works but code must be valid JS inside a function body. Check for syntax errors in your code.\n Example: return document.title\n Example: return Array.from(document.querySelectorAll('a')).map(a => a.href)`;
613
- }
614
- if (msg.includes('SyntaxError')) {
615
- return `Error: JS syntax error — ${msg}\nHint: check parentheses, quotes, and semicolons. evaluate runs JS in browser context.`;
616
- }
617
- // Ошибки "null/undefined" — скорее всего селектор не найден
618
- if (msg.includes('Cannot read propert') || msg.includes('is null') || msg.includes('is undefined')
619
- || msg.includes('null') || msg.includes('undefined')) {
620
- return `Error: ${msg}\nHint: A selector likely returned null. Use web_browse(action:"discover") to find real CSS selectors on this page, then retry with the correct selector.`;
621
- }
622
- return `Error: evaluate failed: ${msg}`;
623
- }
624
- }
625
- // ─── Tool Definition ─────────────────────────────────────
626
- export const webBrowseDefinition = {
627
- type: 'function',
628
- function: {
629
- name: 'web_browse',
630
- description: 'Interact with web pages using a headless browser. Navigate, click, type, scroll, extract text/HTML, take screenshots, and execute JavaScript on pages.',
631
- parameters: {
632
- type: 'object',
633
- properties: {
634
- action: {
635
- type: 'string',
636
- enum: ['navigate', 'click', 'type', 'extract', 'screenshot', 'scroll', 'wait', 'get_links', 'evaluate', 'discover', 'scrape', 'close'],
637
- description: 'Action to perform on the page',
638
- },
639
- url: { type: 'string', description: 'URL to navigate to (for navigate action)' },
640
- selector: { type: 'string', description: 'CSS selector or text to target an element' },
641
- value: { type: 'string', description: 'Value to type, or JS code to evaluate' },
642
- direction: { type: 'string', enum: ['up', 'down'], description: 'Scroll direction (default: down)' },
643
- format: { type: 'string', enum: ['text', 'html'], description: 'Extract format (default: text)' },
644
- maxChars: { type: 'number', description: 'Max characters to extract (default: 10000)' },
645
- timeout: { type: 'number', description: 'Timeout in ms for wait action (default: 5000)' },
646
- condition: { type: 'string', description: 'JS expression to wait for (e.g. "document.querySelectorAll(\\\'.item\\\').length > 0") — for wait action only' },
647
- pattern: { type: 'string', description: 'Regex pattern to match element classes (for scrape, default: "product|card|item|goods")' },
648
- maxItems: { type: 'number', description: 'Max items to scrape (default: 10, max: 50)' },
649
- fields: { type: 'string', description: 'Comma-separated fields to extract (for scrape, e.g. "title,price,href")' },
650
- },
651
- required: ['action'],
652
- },
653
- },
654
- };
655
- // ─── Handler ─────────────────────────────────────────────
656
- export const webBrowseHandler = {
657
- name: 'web_browse',
658
- definition: webBrowseDefinition,
659
- async execute(args) {
660
- const action = String(args.action ?? '').trim();
661
- if (!action) {
662
- return { stdout: '', stderr: 'action is required', exitCode: 1, truncated: false };
663
- }
664
- try {
665
- // Проверка простой сессии перед каждым action'ом
666
- await checkIdle();
667
- // Close action
668
- if (action === 'close') {
669
- await closeBrowser();
670
- return { stdout: 'Browser closed.', stderr: '', exitCode: 0, truncated: false };
671
- }
672
- // Navigate не требует существующей страницы
673
- if (action === 'navigate') {
674
- // Валидация URL до запуска браузера
675
- const url = String(args.url ?? '').trim();
676
- if (!url) {
677
- return { stdout: '', stderr: 'url is required for navigate', exitCode: 1, truncated: false };
678
- }
679
- if (!url.startsWith('http://') && !url.startsWith('https://')) {
680
- return { stdout: '', stderr: 'URL must start with http:// or https://', exitCode: 1, truncated: false };
681
- }
682
- const page = await ensureBrowser();
683
- const navResult = await actionNavigate(page, args);
684
- const isHttpError = navResult.status >= 400;
685
- return {
686
- stdout: navResult.text,
687
- stderr: isHttpError ? `HTTP ${navResult.status}` : '',
688
- exitCode: isHttpError ? 1 : 0,
689
- truncated: false,
690
- };
691
- }
692
- // Scrape тоже может навигировать сам (если указан URL)
693
- if (action === 'scrape') {
694
- const url = String(args.url ?? '').trim();
695
- if (url && !url.startsWith('http://') && !url.startsWith('https://')) {
696
- return { stdout: '', stderr: 'URL must start with http:// or https://', exitCode: 1, truncated: false };
697
- }
698
- const page = await ensureBrowser();
699
- const result = await actionScrape(page, args);
700
- const exitCode = result.startsWith('Error') ? 1 : 0;
701
- return { stdout: result, stderr: '', exitCode, truncated: false };
702
- }
703
- // Все остальные action'ы требуют активную страницу
704
- if (!state.page || state.page.isClosed()) {
705
- return {
706
- stdout: '',
707
- stderr: 'No active page. Use navigate action first.',
708
- exitCode: 1,
709
- truncated: false,
710
- };
711
- }
712
- let result;
713
- switch (action) {
714
- case 'click':
715
- result = await actionClick(state.page, args);
716
- break;
717
- case 'type':
718
- result = await actionType(state.page, args);
719
- break;
720
- case 'extract':
721
- result = await actionExtract(state.page, args);
722
- break;
723
- case 'screenshot':
724
- result = await actionScreenshot(state.page, args);
725
- break;
726
- case 'scroll':
727
- result = await actionScroll(state.page, args);
728
- break;
729
- case 'wait':
730
- result = await actionWait(state.page, args);
731
- break;
732
- case 'get_links':
733
- result = await actionGetLinks(state.page, args);
734
- break;
735
- case 'discover':
736
- result = await actionDiscover(state.page, args);
737
- break;
738
- case 'evaluate':
739
- result = await actionEvaluate(state.page, args);
740
- break;
741
- case 'scrape':
742
- result = await actionScrape(state.page, args);
743
- break;
744
- default:
745
- return { stdout: '', stderr: `Unknown action: ${action}`, exitCode: 1, truncated: false };
746
- }
747
- state.lastActivity = Date.now();
748
- const exitCode = result.startsWith('Error') || result.startsWith('Timeout') ? 1 : 0;
749
- return { stdout: result, stderr: '', exitCode, truncated: false };
750
- }
751
- catch (e) {
752
- logError('BROWSER', `${action} error: ${e.message}`);
753
- return { stdout: '', stderr: `Browser error: ${e.message}`, exitCode: 1, truncated: false };
754
- }
755
- },
756
- };
757
- //# sourceMappingURL=web-browse.js.map