@qlingzzy/qling 1.0.0 → 1.1.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 (254) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/README.en.md +82 -17
  3. package/README.md +15 -7
  4. package/dist/agent/main-loop.d.ts +120 -0
  5. package/dist/agent/main-loop.d.ts.map +1 -0
  6. package/dist/agent/main-loop.js +279 -0
  7. package/dist/agent/subtask-parallel.d.ts +29 -0
  8. package/dist/agent/subtask-parallel.d.ts.map +1 -0
  9. package/dist/agent/subtask-parallel.js +107 -0
  10. package/dist/agent/subtask.d.ts +13 -0
  11. package/dist/agent/subtask.d.ts.map +1 -1
  12. package/dist/agent/subtask.js +79 -24
  13. package/dist/agent/system-prompt.d.ts +39 -0
  14. package/dist/agent/system-prompt.d.ts.map +1 -0
  15. package/dist/agent/system-prompt.js +89 -0
  16. package/dist/agent/tool-orchestrator.d.ts +66 -0
  17. package/dist/agent/tool-orchestrator.d.ts.map +1 -0
  18. package/dist/agent/tool-orchestrator.js +355 -0
  19. package/dist/agent-loop.d.ts +29 -16
  20. package/dist/agent-loop.d.ts.map +1 -1
  21. package/dist/agent-loop.js +262 -807
  22. package/dist/agents/roles.d.ts +57 -0
  23. package/dist/agents/roles.d.ts.map +1 -0
  24. package/dist/agents/roles.js +198 -0
  25. package/dist/commands/agents.d.ts.map +1 -1
  26. package/dist/commands/agents.js +17 -3
  27. package/dist/commands/claude-style.d.ts.map +1 -1
  28. package/dist/commands/claude-style.js +19 -10
  29. package/dist/commands/help.d.ts.map +1 -1
  30. package/dist/commands/help.js +3 -2
  31. package/dist/commands/index.d.ts.map +1 -1
  32. package/dist/commands/index.js +6 -0
  33. package/dist/commands/mode.d.ts +16 -0
  34. package/dist/commands/mode.d.ts.map +1 -0
  35. package/dist/commands/mode.js +67 -0
  36. package/dist/commands/recover.d.ts +3 -0
  37. package/dist/commands/recover.d.ts.map +1 -0
  38. package/dist/commands/recover.js +69 -0
  39. package/dist/commands/runtime.d.ts +2 -0
  40. package/dist/commands/runtime.d.ts.map +1 -1
  41. package/dist/commands/runtime.js +2 -0
  42. package/dist/commands/trace.d.ts +3 -0
  43. package/dist/commands/trace.d.ts.map +1 -0
  44. package/dist/commands/trace.js +45 -0
  45. package/dist/commands/verify.js +2 -2
  46. package/dist/config-report.d.ts +0 -1
  47. package/dist/config-report.d.ts.map +1 -1
  48. package/dist/config-report.js +1 -2
  49. package/dist/config.d.ts +0 -1
  50. package/dist/config.d.ts.map +1 -1
  51. package/dist/config.js +0 -1
  52. package/dist/context-report.d.ts +13 -7
  53. package/dist/context-report.d.ts.map +1 -1
  54. package/dist/context-report.js +64 -61
  55. package/dist/context-tool-hygiene.d.ts +36 -0
  56. package/dist/context-tool-hygiene.d.ts.map +1 -0
  57. package/dist/context-tool-hygiene.js +125 -0
  58. package/dist/dashboard/client.d.ts +2 -0
  59. package/dist/dashboard/client.d.ts.map +1 -0
  60. package/dist/dashboard/client.js +305 -0
  61. package/dist/dashboard/model.d.ts +13 -0
  62. package/dist/dashboard/model.d.ts.map +1 -0
  63. package/dist/dashboard/model.js +112 -0
  64. package/dist/dashboard/page.d.ts +3 -0
  65. package/dist/dashboard/page.d.ts.map +1 -0
  66. package/dist/dashboard/page.js +204 -0
  67. package/dist/dashboard/types.d.ts +63 -0
  68. package/dist/dashboard/types.d.ts.map +1 -0
  69. package/dist/dashboard/types.js +1 -0
  70. package/dist/dashboard-server.d.ts +24 -4
  71. package/dist/dashboard-server.d.ts.map +1 -1
  72. package/dist/dashboard-server.js +397 -302
  73. package/dist/discovery-registry.d.ts +17 -3
  74. package/dist/discovery-registry.d.ts.map +1 -1
  75. package/dist/discovery-registry.js +78 -3
  76. package/dist/doctor.d.ts +8 -0
  77. package/dist/doctor.d.ts.map +1 -1
  78. package/dist/doctor.js +116 -0
  79. package/dist/eval/llm-tasks.d.ts +5 -0
  80. package/dist/eval/llm-tasks.d.ts.map +1 -0
  81. package/dist/eval/llm-tasks.js +125 -0
  82. package/dist/eval/repo-tasks.d.ts +12 -0
  83. package/dist/eval/repo-tasks.d.ts.map +1 -0
  84. package/dist/eval/repo-tasks.js +220 -0
  85. package/dist/eval/runner.d.ts +3 -1
  86. package/dist/eval/runner.d.ts.map +1 -1
  87. package/dist/eval/runner.js +23 -4
  88. package/dist/eval/tasks.d.ts.map +1 -1
  89. package/dist/eval/tasks.js +186 -0
  90. package/dist/eval/types.d.ts +8 -5
  91. package/dist/eval/types.d.ts.map +1 -1
  92. package/dist/execution/event-bus.d.ts +44 -0
  93. package/dist/execution/event-bus.d.ts.map +1 -0
  94. package/dist/execution/event-bus.js +76 -0
  95. package/dist/execution/failure-classifier.d.ts +11 -0
  96. package/dist/execution/failure-classifier.d.ts.map +1 -0
  97. package/dist/execution/failure-classifier.js +66 -0
  98. package/dist/execution/progress-detector.d.ts +3 -0
  99. package/dist/execution/progress-detector.d.ts.map +1 -0
  100. package/dist/execution/progress-detector.js +23 -0
  101. package/dist/execution/recovery-controller.d.ts +24 -0
  102. package/dist/execution/recovery-controller.d.ts.map +1 -0
  103. package/dist/execution/recovery-controller.js +114 -0
  104. package/dist/execution/recovery-messages.d.ts +24 -0
  105. package/dist/execution/recovery-messages.d.ts.map +1 -0
  106. package/dist/execution/recovery-messages.js +48 -0
  107. package/dist/execution/recovery-metrics.d.ts +16 -0
  108. package/dist/execution/recovery-metrics.d.ts.map +1 -0
  109. package/dist/execution/recovery-metrics.js +73 -0
  110. package/dist/execution/recovery-strategy-planner.d.ts +6 -0
  111. package/dist/execution/recovery-strategy-planner.d.ts.map +1 -0
  112. package/dist/execution/recovery-strategy-planner.js +24 -0
  113. package/dist/execution/run-trace-store.d.ts +29 -0
  114. package/dist/execution/run-trace-store.d.ts.map +1 -0
  115. package/dist/execution/run-trace-store.js +140 -0
  116. package/dist/execution/staged-verifier.d.ts +33 -0
  117. package/dist/execution/staged-verifier.d.ts.map +1 -0
  118. package/dist/execution/staged-verifier.js +39 -0
  119. package/dist/execution/types.d.ts +58 -0
  120. package/dist/execution/types.d.ts.map +1 -0
  121. package/dist/execution/types.js +1 -0
  122. package/dist/execution/verification-loop.d.ts +58 -0
  123. package/dist/execution/verification-loop.d.ts.map +1 -0
  124. package/dist/execution/verification-loop.js +195 -0
  125. package/dist/execution/verification-stages.d.ts +17 -0
  126. package/dist/execution/verification-stages.d.ts.map +1 -0
  127. package/dist/execution/verification-stages.js +102 -0
  128. package/dist/help-topics.d.ts.map +1 -1
  129. package/dist/help-topics.js +11 -0
  130. package/dist/index.js +0 -8
  131. package/dist/lsp/ts-service.d.ts +36 -0
  132. package/dist/lsp/ts-service.d.ts.map +1 -0
  133. package/dist/lsp/ts-service.js +291 -0
  134. package/dist/memory/lifecycle.d.ts +19 -0
  135. package/dist/memory/lifecycle.d.ts.map +1 -0
  136. package/dist/memory/lifecycle.js +53 -0
  137. package/dist/memory.d.ts +0 -16
  138. package/dist/memory.d.ts.map +1 -1
  139. package/dist/memory.js +0 -36
  140. package/dist/metrics/collector.d.ts +7 -0
  141. package/dist/metrics/collector.d.ts.map +1 -1
  142. package/dist/metrics/collector.js +60 -0
  143. package/dist/mission/manager.d.ts +1 -0
  144. package/dist/mission/manager.d.ts.map +1 -1
  145. package/dist/mission/manager.js +9 -0
  146. package/dist/mission/progress-notify.d.ts +39 -0
  147. package/dist/mission/progress-notify.d.ts.map +1 -0
  148. package/dist/mission/progress-notify.js +386 -0
  149. package/dist/pipeline/hooks.d.ts +1 -1
  150. package/dist/pipeline/hooks.d.ts.map +1 -1
  151. package/dist/pipeline/hooks.js +1 -0
  152. package/dist/pipeline/sections.d.ts +8 -4
  153. package/dist/pipeline/sections.d.ts.map +1 -1
  154. package/dist/pipeline/sections.js +70 -27
  155. package/dist/pipeline/verification.d.ts +1 -0
  156. package/dist/pipeline/verification.d.ts.map +1 -1
  157. package/dist/pipeline/verification.js +10 -7
  158. package/dist/providers/llm-client.d.ts +38 -0
  159. package/dist/providers/llm-client.d.ts.map +1 -0
  160. package/dist/providers/llm-client.js +105 -0
  161. package/dist/sdk.d.ts +1 -0
  162. package/dist/sdk.d.ts.map +1 -1
  163. package/dist/sdk.js +1 -0
  164. package/dist/session/durable-session-supervisor.d.ts.map +1 -1
  165. package/dist/session/durable-session-supervisor.js +13 -6
  166. package/dist/session/session-persistence.d.ts +29 -0
  167. package/dist/session/session-persistence.d.ts.map +1 -0
  168. package/dist/session/session-persistence.js +45 -0
  169. package/dist/session/session-scheduler.d.ts +8 -1
  170. package/dist/session/session-scheduler.d.ts.map +1 -1
  171. package/dist/session/session-scheduler.js +33 -4
  172. package/dist/session-task-report.d.ts +1 -0
  173. package/dist/session-task-report.d.ts.map +1 -1
  174. package/dist/session-task-report.js +2 -1
  175. package/dist/shortcuts.d.ts.map +1 -1
  176. package/dist/shortcuts.js +1 -0
  177. package/dist/skills/registry.d.ts.map +1 -1
  178. package/dist/skills/registry.js +10 -0
  179. package/dist/skills/security-scan.d.ts +15 -0
  180. package/dist/skills/security-scan.d.ts.map +1 -0
  181. package/dist/skills/security-scan.js +95 -0
  182. package/dist/skills/types.d.ts +2 -0
  183. package/dist/skills/types.d.ts.map +1 -1
  184. package/dist/statusline.d.ts +3 -3
  185. package/dist/statusline.d.ts.map +1 -1
  186. package/dist/statusline.js +9 -17
  187. package/dist/token-usage.d.ts +27 -0
  188. package/dist/token-usage.d.ts.map +1 -0
  189. package/dist/token-usage.js +107 -0
  190. package/dist/tools/bash.d.ts.map +1 -1
  191. package/dist/tools/bash.js +5 -3
  192. package/dist/tools/browser-act-session.d.ts +48 -0
  193. package/dist/tools/browser-act-session.d.ts.map +1 -0
  194. package/dist/tools/browser-act-session.js +168 -0
  195. package/dist/tools/browser-act.d.ts +14 -0
  196. package/dist/tools/browser-act.d.ts.map +1 -0
  197. package/dist/tools/browser-act.js +297 -0
  198. package/dist/tools/code-symbols.d.ts +35 -0
  199. package/dist/tools/code-symbols.d.ts.map +1 -0
  200. package/dist/tools/code-symbols.js +257 -0
  201. package/dist/tools/index.d.ts +4 -1
  202. package/dist/tools/index.d.ts.map +1 -1
  203. package/dist/tools/index.js +22 -2
  204. package/dist/tools/lsp.d.ts +13 -0
  205. package/dist/tools/lsp.d.ts.map +1 -0
  206. package/dist/tools/lsp.js +136 -0
  207. package/dist/tools/patch.d.ts +5 -0
  208. package/dist/tools/patch.d.ts.map +1 -1
  209. package/dist/tools/patch.js +25 -4
  210. package/dist/tools/search.d.ts +7 -0
  211. package/dist/tools/search.d.ts.map +1 -1
  212. package/dist/tools/search.js +20 -3
  213. package/dist/tools/skill.d.ts +2 -0
  214. package/dist/tools/skill.d.ts.map +1 -1
  215. package/dist/tools/skill.js +47 -14
  216. package/dist/tools/subtask.d.ts +3 -1
  217. package/dist/tools/subtask.d.ts.map +1 -1
  218. package/dist/tools/subtask.js +151 -56
  219. package/dist/tui/shell.d.ts +12 -0
  220. package/dist/tui/shell.d.ts.map +1 -1
  221. package/dist/tui/shell.js +36 -3
  222. package/dist/tui/streaming-repl.d.ts +1 -0
  223. package/dist/tui/streaming-repl.d.ts.map +1 -1
  224. package/dist/tui/streaming-repl.js +27 -4
  225. package/dist/tui/streaming-tui.d.ts +10 -0
  226. package/dist/tui/streaming-tui.d.ts.map +1 -1
  227. package/dist/tui/streaming-tui.js +70 -12
  228. package/dist/types.d.ts +0 -8
  229. package/dist/types.d.ts.map +1 -1
  230. package/dist/workflow-runtime.d.ts.map +1 -1
  231. package/dist/workflow-runtime.js +10 -2
  232. package/dist/workflow-types.d.ts +2 -0
  233. package/dist/workflow-types.d.ts.map +1 -1
  234. package/docs/install.md +29 -8
  235. package/docs/skills.md +56 -7
  236. package/docs/web-routing.md +83 -0
  237. package/package.json +18 -4
  238. package/scripts/dep-layers.mjs +275 -0
  239. package/scripts/eval-llm.mjs +27 -0
  240. package/scripts/eval-recovery.mjs +101 -0
  241. package/scripts/eval-tasks.mjs +20 -0
  242. package/scripts/validate-packaging.mjs +51 -0
  243. package/skills/examples/README.md +23 -0
  244. package/skills/examples/add-function/SKILL.md +31 -0
  245. package/skills/examples/fix-failing-test/SKILL.md +32 -0
  246. package/skills/examples/pr-summary/SKILL.md +34 -0
  247. package/skills/lifecycle-build/SKILL.md +22 -0
  248. package/skills/lifecycle-plan/SKILL.md +32 -0
  249. package/skills/lifecycle-review/SKILL.md +25 -0
  250. package/skills/lifecycle-ship/SKILL.md +22 -0
  251. package/skills/lifecycle-spec/SKILL.md +24 -0
  252. package/skills/lifecycle-test/SKILL.md +21 -0
  253. package/skills/opencli/SKILL.md +222 -0
  254. package/skills/qling.md +14 -3
@@ -0,0 +1,297 @@
1
+ // ============================================================
2
+ // Phase 3.3+ — browser_act:有限交互 + 跨步会话
3
+ // 启用:QLING_BROWSER_ACT=1
4
+ // 会话:session 参数(默认 default);open/close/status
5
+ // ============================================================
6
+ import { appendGuardAudit, checkUrlFetchPolicy } from "../guard.js";
7
+ import { guardConfigFromEnv } from "../config.js";
8
+ import { toolError, toolSuccess } from "./error-utils.js";
9
+ import { getBrowserSessionPool, normalizeSessionId, } from "./browser-act-session.js";
10
+ const ENABLED_VALUES = new Set(["1", "true", "on", "yes"]);
11
+ export function isBrowserActEnabled(env = process.env) {
12
+ const raw = String(env.QLING_BROWSER_ACT ?? "").trim().toLowerCase();
13
+ return ENABLED_VALUES.has(raw);
14
+ }
15
+ export const browserActTool = {
16
+ name: "browser_act",
17
+ description: "Interactive browser with cross-step sessions (open→goto→click→extract→close). DISABLED by default — QLING_BROWSER_ACT=1. Prefer opencli for social platforms.",
18
+ longDescription: `有限交互浏览器(Playwright)+ **跨步会话**。默认关闭。
19
+
20
+ **启用**: \`QLING_BROWSER_ACT=1\`
21
+
22
+ **会话**:
23
+ - \`session\` 名(默认 \`default\`)在进程内保活页面
24
+ - \`open\` — 打开会话(可选 url)
25
+ - \`close\` — 关闭会话
26
+ - \`status\` — 列出会话
27
+
28
+ **动作**:
29
+ - goto / click / type / wait_for / extract / press(在已有会话上操作)
30
+ - 无会话时:goto 会自动 open;click/type 等需先 open 或 goto
31
+
32
+ **不要用**: 抖音/小红书等 → opencli;只读文档 → browser_fetch
33
+
34
+ **安全**: 网络 Guard;Plan Mode 禁止;空闲默认 10min 回收(QLING_BROWSER_ACT_IDLE_TTL_MS)`,
35
+ parameters: {
36
+ type: "object",
37
+ properties: {
38
+ action: {
39
+ type: "string",
40
+ description: "open | close | status | goto | click | type | wait_for | extract | press",
41
+ },
42
+ session: {
43
+ type: "string",
44
+ description: "Session id (default: default). Keeps page across tool calls.",
45
+ },
46
+ url: { type: "string", description: "URL for open/goto (http/https)" },
47
+ selector: { type: "string", description: "CSS selector" },
48
+ text: { type: "string", description: "Text for type" },
49
+ key: { type: "string", description: "Key for press, e.g. Enter" },
50
+ timeout_ms: { type: "number", description: "Step timeout ms (default 15000)" },
51
+ },
52
+ required: ["action"],
53
+ },
54
+ scenes: ["web"],
55
+ priority: 5,
56
+ readOnly: false,
57
+ destructive: false,
58
+ concurrencySafe: false,
59
+ effortHint: "high",
60
+ };
61
+ function parseTimeout(raw) {
62
+ const n = Number(raw ?? 15_000);
63
+ if (!Number.isFinite(n) || n <= 0)
64
+ return 15_000;
65
+ return Math.min(120_000, Math.floor(n));
66
+ }
67
+ async function guardUrl(rawUrl) {
68
+ const guard = guardConfigFromEnv();
69
+ let target;
70
+ try {
71
+ target = new URL(rawUrl);
72
+ }
73
+ catch {
74
+ return toolError("BROWSER_ACT_INVALID_URL", `invalid url: ${rawUrl}`);
75
+ }
76
+ const decision = await checkUrlFetchPolicy(target, guard);
77
+ if (!decision.allowed) {
78
+ await appendGuardAudit(guard, {
79
+ tool: "browser_act",
80
+ action: "deny",
81
+ category: decision.category,
82
+ target: target.toString(),
83
+ reason: decision.reason,
84
+ });
85
+ return toolError("BROWSER_ACT_GUARD_BLOCKED", decision.reason ?? "guard denied browser_act", { category: "network" });
86
+ }
87
+ return null;
88
+ }
89
+ async function allowBrowserRequest(rawUrl) {
90
+ let target;
91
+ try {
92
+ target = new URL(rawUrl);
93
+ }
94
+ catch {
95
+ return false;
96
+ }
97
+ if (["about:", "data:", "blob:"].includes(target.protocol))
98
+ return true;
99
+ const guard = guardConfigFromEnv();
100
+ const decision = await checkUrlFetchPolicy(target, guard);
101
+ if (decision.allowed)
102
+ return true;
103
+ await appendGuardAudit(guard, {
104
+ tool: "browser_act",
105
+ action: "deny",
106
+ category: decision.category,
107
+ target: target.toString(),
108
+ reason: decision.reason,
109
+ });
110
+ return false;
111
+ }
112
+ export async function runBrowserAct(args) {
113
+ if (!isBrowserActEnabled()) {
114
+ return toolError("BROWSER_ACT_DISABLED", "browser_act 默认关闭。启用: QLING_BROWSER_ACT=1。平台数据请用 opencli;只读文档用 browser_fetch。见 docs/web-routing.md", { category: "permission" });
115
+ }
116
+ const action = String(args.action ?? "").trim().toLowerCase();
117
+ const allowed = [
118
+ "open",
119
+ "close",
120
+ "status",
121
+ "goto",
122
+ "click",
123
+ "type",
124
+ "wait_for",
125
+ "extract",
126
+ "press",
127
+ ];
128
+ if (!allowed.includes(action)) {
129
+ return toolError("BROWSER_ACT_INVALID_ACTION", `action must be one of: ${allowed.join(", ")}`);
130
+ }
131
+ const sessionId = normalizeSessionId(args.session);
132
+ const timeout = parseTimeout(args.timeout_ms);
133
+ const pool = getBrowserSessionPool();
134
+ const guard = guardConfigFromEnv();
135
+ const requestGuard = (url) => allowBrowserRequest(url);
136
+ let openedForAction = false;
137
+ try {
138
+ if (action === "status") {
139
+ await pool.sweepIdle();
140
+ const list = pool.list();
141
+ if (list.length === 0) {
142
+ return toolSuccess("browser_act sessions: (none)");
143
+ }
144
+ const lines = list.map((s) => `- ${s.id}: url=${s.lastUrl || "(blank)"} idle=${Math.round(s.idleMs / 1000)}s age=${Math.round(s.ageMs / 1000)}s`);
145
+ return toolSuccess(`browser_act sessions (${list.length}):\n${lines.join("\n")}`);
146
+ }
147
+ if (action === "close") {
148
+ const ok = await pool.close(sessionId);
149
+ return toolSuccess(ok ? `session closed: ${sessionId}` : `session not found: ${sessionId}`);
150
+ }
151
+ // open / goto / 交互动作需要会话
152
+ if (action === "open") {
153
+ if (args.url) {
154
+ const blocked = await guardUrl(String(args.url).trim());
155
+ if (blocked)
156
+ return blocked;
157
+ }
158
+ const existed = pool.has(sessionId);
159
+ const handle = await pool.open(sessionId, requestGuard);
160
+ openedForAction = !existed;
161
+ if (args.url) {
162
+ const rawUrl = String(args.url).trim();
163
+ await handle.page.goto(rawUrl, { waitUntil: "domcontentloaded", timeout });
164
+ pool.touch(sessionId, rawUrl);
165
+ const title = await handle.page.title();
166
+ return toolSuccess(`session open: ${sessionId}\ngoto: ${rawUrl}\ntitle: ${title}`);
167
+ }
168
+ return toolSuccess(`session open: ${sessionId}\nurl: (blank — use action=goto next)`);
169
+ }
170
+ // 需要 page 的动作
171
+ if (action === "goto" && !String(args.url ?? "").trim()) {
172
+ return toolError("BROWSER_ACT_MISSING_URL", "url is required for goto");
173
+ }
174
+ const navigationUrl = String(args.url ?? "").trim();
175
+ if (navigationUrl) {
176
+ const blocked = await guardUrl(navigationUrl);
177
+ if (blocked)
178
+ return blocked;
179
+ }
180
+ let handle = pool.get(sessionId);
181
+ if (!handle) {
182
+ if (action === "goto" || args.url) {
183
+ // 自动 open
184
+ handle = await pool.open(sessionId, requestGuard);
185
+ openedForAction = true;
186
+ }
187
+ else {
188
+ return toolError("BROWSER_ACT_NO_SESSION", `无会话 "${sessionId}"。请先 browser_act action=open 或 action=goto url=...(session 默认 default)`);
189
+ }
190
+ }
191
+ else {
192
+ handle = await pool.open(sessionId, requestGuard);
193
+ }
194
+ if (action === "goto" || (args.url && action !== "extract")) {
195
+ // extract 也可带 url 直接跳转
196
+ }
197
+ if (action === "goto") {
198
+ const rawUrl = navigationUrl;
199
+ await handle.page.goto(rawUrl, { waitUntil: "domcontentloaded", timeout });
200
+ pool.touch(sessionId, rawUrl);
201
+ const title = await handle.page.title();
202
+ await appendGuardAudit(guard, {
203
+ tool: "browser_act",
204
+ action: "allow",
205
+ category: "network",
206
+ target: rawUrl,
207
+ });
208
+ return toolSuccess(`goto ok\nsession: ${sessionId}\nurl: ${rawUrl}\ntitle: ${title}`);
209
+ }
210
+ // 可选:交互动作若带 url 则先导航
211
+ if (args.url && ["click", "type", "wait_for", "extract", "press"].includes(action)) {
212
+ const rawUrl = navigationUrl;
213
+ await handle.page.goto(rawUrl, { waitUntil: "domcontentloaded", timeout });
214
+ pool.touch(sessionId, rawUrl);
215
+ }
216
+ let output = "";
217
+ switch (action) {
218
+ case "click": {
219
+ const sel = String(args.selector ?? "").trim();
220
+ if (!sel) {
221
+ return toolError("BROWSER_ACT_MISSING_SELECTOR", "selector is required for click");
222
+ }
223
+ await handle.page.click(sel, { timeout });
224
+ pool.touch(sessionId);
225
+ output = `click ok\nsession: ${sessionId}\nselector: ${sel}`;
226
+ break;
227
+ }
228
+ case "type": {
229
+ const sel = String(args.selector ?? "").trim();
230
+ const text = String(args.text ?? "");
231
+ if (!sel) {
232
+ return toolError("BROWSER_ACT_MISSING_SELECTOR", "selector is required for type");
233
+ }
234
+ await handle.page.fill(sel, text, { timeout });
235
+ pool.touch(sessionId);
236
+ output = `type ok\nsession: ${sessionId}\nselector: ${sel}\nchars: ${text.length}`;
237
+ break;
238
+ }
239
+ case "wait_for": {
240
+ const sel = String(args.selector ?? "").trim();
241
+ if (!sel) {
242
+ return toolError("BROWSER_ACT_MISSING_SELECTOR", "selector is required for wait_for");
243
+ }
244
+ await handle.page.waitForSelector(sel, { timeout });
245
+ pool.touch(sessionId);
246
+ output = `wait_for ok\nsession: ${sessionId}\nselector: ${sel}`;
247
+ break;
248
+ }
249
+ case "extract": {
250
+ const sel = String(args.selector ?? "").trim();
251
+ let text;
252
+ if (sel) {
253
+ text = await handle.page.locator(sel).innerText({ timeout });
254
+ }
255
+ else {
256
+ text = await handle.page.evaluate(() => document.body?.innerText ?? "");
257
+ }
258
+ const cleaned = text.replace(/\n\s*\n/g, "\n\n").trim().slice(0, 12_000);
259
+ const title = await handle.page.title();
260
+ const url = handle.page.url();
261
+ pool.touch(sessionId, url);
262
+ output = `extract ok\nsession: ${sessionId}\ntitle: ${title}\nurl: ${url}\n\n${cleaned}`;
263
+ break;
264
+ }
265
+ case "press": {
266
+ const key = String(args.key ?? "").trim();
267
+ if (!key) {
268
+ return toolError("BROWSER_ACT_MISSING_KEY", "key is required for press");
269
+ }
270
+ const sel = String(args.selector ?? "").trim();
271
+ if (sel) {
272
+ await handle.page.focus(sel, { timeout });
273
+ }
274
+ await handle.page.keyboard.press(key);
275
+ pool.touch(sessionId);
276
+ output = `press ok\nsession: ${sessionId}\nkey: ${key}`;
277
+ break;
278
+ }
279
+ default:
280
+ return toolError("BROWSER_ACT_INVALID_ACTION", `unsupported action: ${action}`);
281
+ }
282
+ await appendGuardAudit(guard, {
283
+ tool: "browser_act",
284
+ action: "allow",
285
+ category: "network",
286
+ target: handle.lastUrl || sessionId,
287
+ });
288
+ return toolSuccess(output);
289
+ }
290
+ catch (err) {
291
+ if (openedForAction) {
292
+ await pool.close(sessionId).catch(() => false);
293
+ }
294
+ const msg = err instanceof Error ? err.message : String(err);
295
+ return toolError("BROWSER_ACT_FAILED", msg, { category: "network", retriable: true });
296
+ }
297
+ }
@@ -0,0 +1,35 @@
1
+ import type { ToolDefinition, ToolResult } from "../types.js";
2
+ export interface SymbolHit {
3
+ file: string;
4
+ name: string;
5
+ type: string;
6
+ line: number;
7
+ signature: string;
8
+ }
9
+ export declare const codeSymbolsTool: ToolDefinition;
10
+ /**
11
+ * 纯函数入口:便于单测。
12
+ */
13
+ export declare function searchCodeSymbols(options: {
14
+ workspaceDir: string;
15
+ query: string;
16
+ path?: string;
17
+ type?: string;
18
+ limit?: number;
19
+ regex?: boolean;
20
+ /** 内部/测试用遍历节点预算;工具默认 10,000。 */
21
+ maxNodes?: number;
22
+ }): Promise<{
23
+ hits: SymbolHit[];
24
+ scanned: number;
25
+ truncated: boolean;
26
+ error?: string;
27
+ }>;
28
+ export declare function runCodeSymbols(args: {
29
+ query?: string;
30
+ path?: string;
31
+ type?: string;
32
+ limit?: number;
33
+ regex?: boolean;
34
+ }): Promise<ToolResult>;
35
+ //# sourceMappingURL=code-symbols.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-symbols.d.ts","sourceRoot":"","sources":["../../src/tools/code-symbols.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA0C9D,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,eAAe,EAAE,cA8C7B,CAAC;AAuEF;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA0EtF;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC,UAAU,CAAC,CAuCtB"}
@@ -0,0 +1,257 @@
1
+ // ============================================================
2
+ // Phase 4.2 — code_symbols:工作区符号检索(轻量,非完整 LSP)
3
+ // ============================================================
4
+ import { readdir, readFile } from "fs/promises";
5
+ import { existsSync } from "fs";
6
+ import { join, relative, extname } from "path";
7
+ import { toolError, toolSuccess } from "./error-utils.js";
8
+ import { extractSymbols } from "../utils/symbol-extractor.js";
9
+ import { getRuntimeRootsFromEnv, isWithinAllowedRoots, resolveToolPath, } from "../runtime-paths.js";
10
+ const DEFAULT_IGNORES = new Set([
11
+ "node_modules",
12
+ ".git",
13
+ "dist",
14
+ "build",
15
+ "coverage",
16
+ "out",
17
+ "target",
18
+ ".qling",
19
+ ".idea",
20
+ ".vscode",
21
+ "bin",
22
+ "obj",
23
+ ]);
24
+ const CODE_EXTS = new Set([
25
+ ".ts",
26
+ ".tsx",
27
+ ".js",
28
+ ".jsx",
29
+ ".mjs",
30
+ ".cjs",
31
+ ".py",
32
+ ".go",
33
+ ".java",
34
+ ".rs",
35
+ ]);
36
+ const MAX_FILES_SCAN = 400;
37
+ const MAX_NODES_SCAN = 10_000;
38
+ const MAX_FILE_BYTES = 512 * 1024;
39
+ const MAX_HITS = 40;
40
+ export const codeSymbolsTool = {
41
+ name: "code_symbols",
42
+ description: "Search code symbols (functions/classes/types) in the workspace by name pattern. Lightweight regex-based — not a full LSP.",
43
+ longDescription: `在工作区内按名称模式检索代码符号(函数/类/接口/类型等)。
44
+
45
+ **基于** 静态行正则提取(与 /repomap 同源),**不是** 完整 LSP。
46
+ **只读**。适合:定位定义、浏览导出符号。
47
+
48
+ **参数**:
49
+ - query — 名称子串或正则(默认子串,不区分大小写)
50
+ - path — 扫描子目录(默认工作区)
51
+ - type — 可选过滤:function|class|interface|type|method|struct|variable
52
+ - limit — 最多返回条数(默认 30,最大 40)`,
53
+ parameters: {
54
+ type: "object",
55
+ properties: {
56
+ query: {
57
+ type: "string",
58
+ description: "Symbol name substring or regex",
59
+ },
60
+ path: {
61
+ type: "string",
62
+ description: "Directory to scan (default workspace)",
63
+ },
64
+ type: {
65
+ type: "string",
66
+ description: "Optional symbol type filter",
67
+ },
68
+ limit: {
69
+ type: "number",
70
+ description: "Max results (default 30)",
71
+ },
72
+ regex: {
73
+ type: "boolean",
74
+ description: "Treat query as regex (default false)",
75
+ },
76
+ },
77
+ required: ["query"],
78
+ },
79
+ scenes: ["code", "navigation"],
80
+ priority: 7,
81
+ readOnly: true,
82
+ destructive: false,
83
+ concurrencySafe: true,
84
+ effortHint: "low",
85
+ };
86
+ function compileMatcher(query, asRegex) {
87
+ const q = query.trim();
88
+ if (!q)
89
+ return { test: () => false, error: "empty query" };
90
+ if (asRegex) {
91
+ try {
92
+ const re = new RegExp(q, "i");
93
+ return { test: (name) => re.test(name) };
94
+ }
95
+ catch (err) {
96
+ return {
97
+ test: () => false,
98
+ error: err instanceof Error ? err.message : String(err),
99
+ };
100
+ }
101
+ }
102
+ const lower = q.toLowerCase();
103
+ return { test: (name) => name.toLowerCase().includes(lower) };
104
+ }
105
+ async function walkCodeFiles(root, onFile, options = {}) {
106
+ let scanned = 0;
107
+ let visitedNodes = 0;
108
+ let truncated = false;
109
+ const maxNodes = Math.max(1, Math.floor(options.maxNodes ?? MAX_NODES_SCAN));
110
+ const stack = [root];
111
+ while (stack.length > 0) {
112
+ if (scanned >= MAX_FILES_SCAN || visitedNodes >= maxNodes) {
113
+ truncated = true;
114
+ break;
115
+ }
116
+ const current = stack.pop();
117
+ let entries;
118
+ try {
119
+ entries = await readdir(current, { withFileTypes: true });
120
+ }
121
+ catch {
122
+ continue;
123
+ }
124
+ for (const entry of entries) {
125
+ visitedNodes++;
126
+ if (visitedNodes > maxNodes) {
127
+ truncated = true;
128
+ break;
129
+ }
130
+ const nameLower = entry.name.toLowerCase();
131
+ if (DEFAULT_IGNORES.has(nameLower))
132
+ continue;
133
+ const full = join(current, entry.name);
134
+ if (entry.isDirectory()) {
135
+ stack.push(full);
136
+ }
137
+ else if (entry.isFile()) {
138
+ const ext = extname(entry.name).toLowerCase();
139
+ if (!CODE_EXTS.has(ext))
140
+ continue;
141
+ scanned++;
142
+ await onFile(full);
143
+ if (scanned >= MAX_FILES_SCAN) {
144
+ truncated = true;
145
+ break;
146
+ }
147
+ }
148
+ }
149
+ }
150
+ return { scanned, truncated };
151
+ }
152
+ /**
153
+ * 纯函数入口:便于单测。
154
+ */
155
+ export async function searchCodeSymbols(options) {
156
+ const workspaceDir = options.workspaceDir || process.cwd();
157
+ const roots = getRuntimeRootsFromEnv({
158
+ ...process.env,
159
+ QLING_WORKSPACE_DIR: workspaceDir,
160
+ });
161
+ // 确保 roots 含 workspace
162
+ const rootsWithWs = {
163
+ ...roots,
164
+ workspaceDir: roots.workspaceDir ?? workspaceDir,
165
+ };
166
+ let scanRoot = workspaceDir;
167
+ if (options.path) {
168
+ const resolved = resolveToolPath(options.path, rootsWithWs);
169
+ if (!isWithinAllowedRoots(resolved, rootsWithWs)) {
170
+ return {
171
+ hits: [],
172
+ scanned: 0,
173
+ truncated: false,
174
+ error: `path outside allowed roots: ${options.path}`,
175
+ };
176
+ }
177
+ scanRoot = resolved;
178
+ }
179
+ if (!existsSync(scanRoot)) {
180
+ return {
181
+ hits: [],
182
+ scanned: 0,
183
+ truncated: false,
184
+ error: `path not found: ${scanRoot}`,
185
+ };
186
+ }
187
+ const matcher = compileMatcher(options.query, Boolean(options.regex));
188
+ if (matcher.error) {
189
+ return { hits: [], scanned: 0, truncated: false, error: matcher.error };
190
+ }
191
+ const typeFilter = options.type?.trim().toLowerCase() || "";
192
+ const limit = Math.min(MAX_HITS, Math.max(1, Number(options.limit) > 0 ? Math.floor(Number(options.limit)) : 30));
193
+ const hits = [];
194
+ const { scanned, truncated } = await walkCodeFiles(scanRoot, async (abs) => {
195
+ if (hits.length >= limit)
196
+ return;
197
+ let content;
198
+ try {
199
+ const buf = await readFile(abs);
200
+ if (buf.byteLength > MAX_FILE_BYTES)
201
+ return;
202
+ content = buf.toString("utf8");
203
+ }
204
+ catch {
205
+ return;
206
+ }
207
+ const ext = extname(abs);
208
+ const symbols = extractSymbols(content, ext);
209
+ const rel = relative(workspaceDir, abs).replace(/\\/g, "/");
210
+ for (const sym of symbols) {
211
+ if (hits.length >= limit)
212
+ break;
213
+ if (typeFilter && sym.type !== typeFilter)
214
+ continue;
215
+ if (!matcher.test(sym.name))
216
+ continue;
217
+ hits.push({
218
+ file: rel || abs,
219
+ name: sym.name,
220
+ type: sym.type,
221
+ line: sym.line,
222
+ signature: sym.signature.slice(0, 200),
223
+ });
224
+ }
225
+ }, { maxNodes: options.maxNodes });
226
+ return { hits, scanned, truncated };
227
+ }
228
+ export async function runCodeSymbols(args) {
229
+ const query = String(args.query ?? "").trim();
230
+ if (!query) {
231
+ return toolError("CODE_SYMBOLS_MISSING_QUERY", "query is required");
232
+ }
233
+ const roots = getRuntimeRootsFromEnv();
234
+ const result = await searchCodeSymbols({
235
+ workspaceDir: roots.workspaceDir ?? process.cwd(),
236
+ query,
237
+ path: args.path,
238
+ type: args.type,
239
+ limit: args.limit,
240
+ regex: args.regex,
241
+ });
242
+ if (result.error) {
243
+ return toolError("CODE_SYMBOLS_FAILED", result.error);
244
+ }
245
+ if (result.hits.length === 0) {
246
+ return toolSuccess(`code_symbols: 无匹配 query=${JSON.stringify(query)} scanned=${result.scanned}` +
247
+ (result.truncated ? " (scan truncated)" : ""));
248
+ }
249
+ const lines = result.hits.map((h) => `${h.file}:${h.line} [${h.type}] ${h.name} ${h.signature}`);
250
+ return toolSuccess([
251
+ `code_symbols: ${result.hits.length} hit(s) scanned=${result.scanned}` +
252
+ (result.truncated ? " truncated=true" : ""),
253
+ ...lines,
254
+ "",
255
+ "注: 基于静态提取,非完整 LSP。需要语义跳转可后续启用语言服务。",
256
+ ].join("\n"));
257
+ }
@@ -10,9 +10,12 @@ import { urlFetchTool } from "./url-fetch.js";
10
10
  import { subtaskTool } from "./subtask.js";
11
11
  import { visionAnalyzeTool } from "./vision-analyze.js";
12
12
  import { browserFetchTool } from "./browser-fetch.js";
13
+ import { browserActTool } from "./browser-act.js";
14
+ import { codeSymbolsTool } from "./code-symbols.js";
15
+ import { lspTool } from "./lsp.js";
13
16
  import { patchTool } from "./patch.js";
14
17
  import type { MCPRegistry } from "../mcp/registry.js";
15
- export { bashTool, readTool, writeTool, todoTool, skillTool, searchTool, plannerTool, urlFetchTool, subtaskTool, visionAnalyzeTool, browserFetchTool, patchTool };
18
+ export { bashTool, readTool, writeTool, todoTool, skillTool, searchTool, plannerTool, urlFetchTool, subtaskTool, visionAnalyzeTool, browserFetchTool, browserActTool, codeSymbolsTool, lspTool, patchTool, };
16
19
  export declare const ALL_TOOLS: ToolDefinition[];
17
20
  export declare function setMCPRegistry(registry: MCPRegistry): void;
18
21
  export declare function getMCPRegistry(): MCPRegistry | null;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAW,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAW,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAY,SAAS,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAW,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAY,SAAS,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAa,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAc,WAAW,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAe,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAc,WAAW,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAoB,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAmB,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAY,SAAS,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC;AAElK,eAAO,MAAM,SAAS,EAAE,cAAc,EAErC,CAAC;AAKF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAE1D;AAED,wBAAgB,cAAc,IAAI,WAAW,GAAG,IAAI,CAEnD;AAED,MAAM,WAAW,wBAAwB;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,iBAAiB,CAAC,EAAE,cAAc,EAAE,CAAC;CACtC;AAED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,cAAc,EAAE,CAU1F;AAmBD,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CA6BtE;AAED,wBAAsB,WAAW,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAE9E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAW,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAW,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAY,SAAS,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAW,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAY,SAAS,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAa,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAc,WAAW,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAe,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAc,WAAW,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAoB,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAmB,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAiB,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAkB,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAU,OAAO,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAY,SAAS,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,SAAS,EACT,UAAU,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,OAAO,EACP,SAAS,GACV,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,cAAc,EAgBrC,CAAC;AAKF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAE1D;AAED,wBAAgB,cAAc,IAAI,WAAW,GAAG,IAAI,CAEnD;AAED,MAAM,WAAW,wBAAwB;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,iBAAiB,CAAC,EAAE,cAAc,EAAE,CAAC;CACtC;AAED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,cAAc,EAAE,CAU1F;AAsBD,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CA6BtE;AAED,wBAAsB,WAAW,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAE9E"}
@@ -12,12 +12,29 @@ import { runUrlFetch, urlFetchTool } from "./url-fetch.js";
12
12
  import { runSubtask, subtaskTool } from "./subtask.js";
13
13
  import { runVisionAnalyze, visionAnalyzeTool } from "./vision-analyze.js";
14
14
  import { runBrowserFetch, browserFetchTool } from "./browser-fetch.js";
15
+ import { runBrowserAct, browserActTool } from "./browser-act.js";
16
+ import { runCodeSymbols, codeSymbolsTool } from "./code-symbols.js";
17
+ import { runLsp, lspTool } from "./lsp.js";
15
18
  import { runPatch, patchTool } from "./patch.js";
16
19
  import { toolError } from "./error-utils.js";
17
20
  import { isMCPTool, parseMCPToolName } from "../mcp/bridge.js";
18
- export { bashTool, readTool, writeTool, todoTool, skillTool, searchTool, plannerTool, urlFetchTool, subtaskTool, visionAnalyzeTool, browserFetchTool, patchTool };
21
+ export { bashTool, readTool, writeTool, todoTool, skillTool, searchTool, plannerTool, urlFetchTool, subtaskTool, visionAnalyzeTool, browserFetchTool, browserActTool, codeSymbolsTool, lspTool, patchTool, };
19
22
  export const ALL_TOOLS = [
20
- bashTool, readTool, writeTool, todoTool, skillTool, searchTool, plannerTool, urlFetchTool, subtaskTool, visionAnalyzeTool, browserFetchTool, patchTool
23
+ bashTool,
24
+ readTool,
25
+ writeTool,
26
+ todoTool,
27
+ skillTool,
28
+ searchTool,
29
+ plannerTool,
30
+ urlFetchTool,
31
+ subtaskTool,
32
+ visionAnalyzeTool,
33
+ browserFetchTool,
34
+ browserActTool,
35
+ codeSymbolsTool,
36
+ lspTool,
37
+ patchTool,
21
38
  ];
22
39
  // Runtime MCP registry reference
23
40
  let mcpRegistry = null;
@@ -49,6 +66,9 @@ const handlers = {
49
66
  subtask: runSubtask,
50
67
  vision_analyze: runVisionAnalyze,
51
68
  browser_fetch: runBrowserFetch,
69
+ browser_act: runBrowserAct,
70
+ code_symbols: runCodeSymbols,
71
+ lsp: runLsp,
52
72
  patch: runPatch,
53
73
  };
54
74
  export async function dispatch(toolCall) {
@@ -0,0 +1,13 @@
1
+ import type { ToolDefinition, ToolResult } from "../types.js";
2
+ import { isLspEnabled, resetTsServiceCache } from "../lsp/ts-service.js";
3
+ export { isLspEnabled, resetTsServiceCache };
4
+ export declare const lspTool: ToolDefinition;
5
+ export declare function clampLspLimit(raw: unknown, fallback: number): number;
6
+ export declare function runLsp(args: {
7
+ action?: string;
8
+ path?: string;
9
+ line?: number;
10
+ character?: number;
11
+ limit?: number;
12
+ }): Promise<ToolResult>;
13
+ //# sourceMappingURL=lsp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lsp.d.ts","sourceRoot":"","sources":["../../src/tools/lsp.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9D,OAAO,EAEL,YAAY,EAMZ,mBAAmB,EAEpB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAE7C,eAAO,MAAM,OAAO,EAAE,cA+CrB,CAAC;AAgBF,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIpE;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,UAAU,CAAC,CAoGtB"}