@xopcai/xopc 0.0.243 → 0.0.245

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 (202) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-CAah-_8h.js → activity-store-BlxqErph.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DDH4HgP7.js → agent-avatar-dicebear-DRQnogaU.js} +1 -1
  5. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-BDCfJZhh.js → agent-defaults-settings-panel-CpOxGbMD.js} +1 -1
  6. package/dist/gateway/static/root/assets/{agents-B0ZWgf-U.js → agents-flnXZLaT.js} +1 -1
  7. package/dist/gateway/static/root/assets/{api-B2tKxbcz.js → api-BbXzyQMj.js} +1 -1
  8. package/dist/gateway/static/root/assets/{app-management-settings-panel-Blfwszzn.js → app-management-settings-panel-CZl6n2xi.js} +1 -1
  9. package/dist/gateway/static/root/assets/{appearance-settings-C3V7Na75.js → appearance-settings-Bglp-pn6.js} +1 -1
  10. package/dist/gateway/static/root/assets/{apps-page-BiEks0-F.js → apps-page-CmsWarVB.js} +1 -1
  11. package/dist/gateway/static/root/assets/{archive-plugin-BmSx7wzY.js → archive-plugin-DD2SweEH.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-BS-S4LJ9.js → attachment-load-G0HenUmG.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-C7Y3L30D.js → automations-page-B78bFjH2.js} +1 -1
  14. package/dist/gateway/static/root/assets/{automations-workspace-A3zPkPuo.js → automations-workspace-BMQGmn50.js} +1 -1
  15. package/dist/gateway/static/root/assets/{binary-plugins-BM9B5kcm.js → binary-plugins-BbSQmXqn.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-BbnpkYP9.js → block-editor-DutTIH81.js} +1 -1
  17. package/dist/gateway/static/root/assets/{browser-settings-page-Dk4FQ7fY.js → browser-settings-page-CALiFKm4.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflow-inputs-CRnkgZHI.js → browser-workflow-inputs-BAAc151l.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-workflows-page-B9qGL-it.js → browser-workflows-page-DE5HPrHZ.js} +1 -1
  20. package/dist/gateway/static/root/assets/{capabilities-settings-panel--tR_El9e.js → capabilities-settings-panel-Dts7XtP3.js} +1 -1
  21. package/dist/gateway/static/root/assets/{channels-settings-D347vl_J.js → channels-settings-CWEd3wzh.js} +1 -1
  22. package/dist/gateway/static/root/assets/{channels-status-swr-DuY4MGxe.js → channels-status-swr-CCBCtLDg.js} +1 -1
  23. package/dist/gateway/static/root/assets/{chat-terminal-dock-DABPvwBT.js → chat-terminal-dock-Bp1fXQm1.js} +1 -1
  24. package/dist/gateway/static/root/assets/{connectors-page-B-tvJkRJ.js → connectors-page-CQ6wVNLm.js} +1 -1
  25. package/dist/gateway/static/root/assets/{cron-expression-D3bsKbNd.js → cron-expression-B8HA5IRb.js} +1 -1
  26. package/dist/gateway/static/root/assets/{date-picker-BsGM6Yty.js → date-picker-DD8b7oad.js} +1 -1
  27. package/dist/gateway/static/root/assets/{dependency-picker-Dj3g6YXZ.js → dependency-picker-BC9zwIyH.js} +1 -1
  28. package/dist/gateway/static/root/assets/{desktop-pet-C1QT0Sur.js → desktop-pet-DsrsPZTW.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-settings-r6kAOnfY.js → desktop-pet-settings-D7gp_HNA.js} +1 -1
  30. package/dist/gateway/static/root/assets/{extension-debug-page-DOkf7nh9.js → extension-debug-page-BoKbOX7x.js} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-page-Cq2IA4Ho.js → extension-page-BegL4FW8.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-settings-page-DQn4qjDZ.js → extension-settings-page-CjPqq57s.js} +1 -1
  33. package/dist/gateway/static/root/assets/{gateway-config-api-DM3poL22.js → gateway-config-api-DaG57o4X.js} +1 -1
  34. package/dist/gateway/static/root/assets/{gateway-config-swr-BC3pgb_P.js → gateway-config-swr-826dipyU.js} +1 -1
  35. package/dist/gateway/static/root/assets/{gateway-settings-DPgH1hnh.js → gateway-settings-DkJGpgm6.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-startup-retry-uMcSfLru.js → gateway-startup-retry-DyvcAIMm.js} +1 -1
  37. package/dist/gateway/static/root/assets/{heartbeat-settings-Bk80-E3b.js → heartbeat-settings-BLZ48kSU.js} +1 -1
  38. package/dist/gateway/static/root/assets/{home-page-DKo5JiMR.js → home-page-Dtw7Ipt1.js} +1 -1
  39. package/dist/gateway/static/root/assets/{image-generation-api-D1qlQA-A.js → image-generation-api-D7cyfks6.js} +1 -1
  40. package/dist/gateway/static/root/assets/{index-B0WJL9N1.js → index-DG5CfYat.js} +10 -10
  41. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BEwvd8ZU.js → keyboard-shortcuts-settings-D2Has7-N.js} +1 -1
  42. package/dist/gateway/static/root/assets/{local-app-workbench-page--eJ5rmNj.js → local-app-workbench-page-BWidWY93.js} +1 -1
  43. package/dist/gateway/static/root/assets/{local-apps-page-CgkY9E-r.js → local-apps-page-Bkekjoxf.js} +1 -1
  44. package/dist/gateway/static/root/assets/{locale-store-CMZljTJx.js → locale-store-CBoCuIMx.js} +1 -1
  45. package/dist/gateway/static/root/assets/{logs-page-Z49Td0J9.js → logs-page-C5zSSgvA.js} +1 -1
  46. package/dist/gateway/static/root/assets/{management-settings-Dv8NSJKt.js → management-settings-B8c62vRS.js} +1 -1
  47. package/dist/gateway/static/root/assets/{markdown-split-Cm0RBB-t.js → markdown-split-3kxTTGO7.js} +1 -1
  48. package/dist/gateway/static/root/assets/{markdown-view-PPCLt7fu.js → markdown-view-BXsHghJd.js} +1 -1
  49. package/dist/gateway/static/root/assets/{media-plugins-Bcr5sU1f.js → media-plugins-BW8J1nCG.js} +1 -1
  50. package/dist/gateway/static/root/assets/messages-BbdwoxVo.js +3 -0
  51. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-kKDiXofY.js → mobile-pairing-wizard-nwQ8iUcd.js} +1 -1
  52. package/dist/gateway/static/root/assets/models-hub-cache-88f4fzYS.js +1 -0
  53. package/dist/gateway/static/root/assets/{notes-page-CgsaRaGi.js → notes-page-DdybD0QM.js} +1 -1
  54. package/dist/gateway/static/root/assets/{notes-workbench-C1DEE09k.js → notes-workbench-IYfpy2Jx.js} +2 -2
  55. package/dist/gateway/static/root/assets/{oauth-api-4VeMbkTJ.js → oauth-api-BjSUDIgq.js} +1 -1
  56. package/dist/gateway/static/root/assets/{product-open-page-BU0HiZtv.js → product-open-page-CAJeUXeU.js} +1 -1
  57. package/dist/gateway/static/root/assets/{project-detail-page-isRapnp5.js → project-detail-page-4wjw-b7h.js} +1 -1
  58. package/dist/gateway/static/root/assets/{projects-page-zvsjg0mi.js → projects-page-CCMj9PeL.js} +1 -1
  59. package/dist/gateway/static/root/assets/{registry-api-CWOtPFrE.js → registry-api-BhGKnvLP.js} +1 -1
  60. package/dist/gateway/static/root/assets/{remote-access-hub-C9TGZ9Hc.js → remote-access-hub-DsBJqWIk.js} +1 -1
  61. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-2zm9edMA.js → runtime-tools-settings-panel-B4IDcqx0.js} +1 -1
  62. package/dist/gateway/static/root/assets/{schema-form-54A5gzkN.js → schema-form-DiGUUjO6.js} +1 -1
  63. package/dist/gateway/static/root/assets/{sessions-page-BP8RyiUn.js → sessions-page-BwGj0t-2.js} +1 -1
  64. package/dist/gateway/static/root/assets/settings-advanced-gate-BJCfUghk.js +1 -0
  65. package/dist/gateway/static/root/assets/{settings-page-DzDhoyxv.js → settings-page-CVQUsAhd.js} +1 -1
  66. package/dist/gateway/static/root/assets/{setup-status-panel-uDicHU1w.js → setup-status-panel-CQACRh1i.js} +1 -1
  67. package/dist/gateway/static/root/assets/{share-preview-page-lOmLCWFS.js → share-preview-page-DTP1dtuS.js} +1 -1
  68. package/dist/gateway/static/root/assets/{shares-settings-T4Yvouvv.js → shares-settings-D_YPh6Rw.js} +1 -1
  69. package/dist/gateway/static/root/assets/skill-reload-api-B43xlJlX.js +1 -0
  70. package/dist/gateway/static/root/assets/{skills-page-CnyNH3To.js → skills-page-Czpn7Y28.js} +1 -1
  71. package/dist/gateway/static/root/assets/{skills-page.utils-CgDtf2qs.js → skills-page.utils-d39rm3hb.js} +1 -1
  72. package/dist/gateway/static/root/assets/{system-settings-panel-C8yWfwtR.js → system-settings-panel-CXXySCSp.js} +1 -1
  73. package/dist/gateway/static/root/assets/{task-detail-page-Tzfjlbf3.js → task-detail-page-DHiOqQMx.js} +1 -1
  74. package/dist/gateway/static/root/assets/{theme-store-uxUwr10D.js → theme-store-hybK3oC9.js} +1 -1
  75. package/dist/gateway/static/root/assets/{tunnel-api-Bvg679no.js → tunnel-api-BiBGK7O2.js} +1 -1
  76. package/dist/gateway/static/root/assets/{use-autosave-D88VGoyG.js → use-autosave-DjpzpeIm.js} +1 -1
  77. package/dist/gateway/static/root/assets/{user-context-page-RijPtyfO.js → user-context-page-1XBRV5gX.js} +1 -1
  78. package/dist/gateway/static/root/assets/{voice-api-key-field-CBHLsMcc.js → voice-api-key-field-CUIPNmOc.js} +1 -1
  79. package/dist/gateway/static/root/assets/{voice-config-api-MqyI6cgq.js → voice-config-api-CBbiF1T3.js} +1 -1
  80. package/dist/gateway/static/root/assets/{work-discovery-overlay-GGe2TQ98.js → work-discovery-overlay-DVNxhb1x.js} +1 -1
  81. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-C0layUE9.js → workflow-run-setup-panel-HxxFQFY7.js} +1 -1
  82. package/dist/gateway/static/root/assets/{workflows-page-DQXIzBAc.js → workflows-page-BCgL7PRm.js} +1 -1
  83. package/dist/gateway/static/root/index.html +11 -11
  84. package/dist/package.js +1 -1
  85. package/dist/packages/gateway-contract/src/turn-outcome.js +3 -1
  86. package/dist/src/agent/agent-instance-gateway.d.ts +3 -1
  87. package/dist/src/agent/agent-manager.d.ts +2 -4
  88. package/dist/src/agent/agent-manager.js +24 -28
  89. package/dist/src/agent/background-review/coordinator.js +1 -1
  90. package/dist/src/agent/background-review/run-background-review.js +1 -1
  91. package/dist/src/agent/child-agent-factory.d.ts +10 -7
  92. package/dist/src/agent/child-agent-factory.js +112 -158
  93. package/dist/src/agent/coding/index.d.ts +1 -1
  94. package/dist/src/agent/coding/index.js +2 -2
  95. package/dist/src/agent/coding/repository-instructions.d.ts +12 -0
  96. package/dist/src/agent/coding/repository-instructions.js +76 -0
  97. package/dist/src/agent/coding/run-verification.d.ts +34 -0
  98. package/dist/src/agent/coding/run-verification.js +134 -0
  99. package/dist/src/agent/coding/verification-command.d.ts +3 -0
  100. package/dist/src/agent/coding/verification-command.js +50 -0
  101. package/dist/src/agent/coding/workspace-revision.d.ts +2 -0
  102. package/dist/src/agent/coding/workspace-revision.js +77 -0
  103. package/dist/src/agent/commands/command-isolation.d.ts +21 -0
  104. package/dist/src/agent/commands/command-isolation.js +71 -0
  105. package/dist/src/agent/commands/command-registry.d.ts +56 -0
  106. package/dist/src/agent/commands/command-registry.js +259 -0
  107. package/dist/src/agent/embedded/index.js +1 -1
  108. package/dist/src/agent/embedded/run-for-session.js +2 -1
  109. package/dist/src/agent/embedded/run-turn.js +88 -25
  110. package/dist/src/agent/embedded/session-tool-result-guard.js +2 -2
  111. package/dist/src/agent/embedded/subscribe-session.d.ts +2 -1
  112. package/dist/src/agent/embedded/subscribe-session.js +2 -1
  113. package/dist/src/agent/embedded/types.d.ts +3 -1
  114. package/dist/src/agent/embedded/xopc-tools-bridge.js +4 -1
  115. package/dist/src/agent/image/index.js +1 -1
  116. package/dist/src/agent/index.js +3 -3
  117. package/dist/src/agent/memory/user-context-coordinator.js +1 -1
  118. package/dist/src/agent/middleware/index.d.ts +0 -5
  119. package/dist/src/agent/middleware/index.js +1 -2
  120. package/dist/src/agent/orchestration/agent-event-handler.d.ts +0 -5
  121. package/dist/src/agent/orchestration/agent-event-handler.js +1 -96
  122. package/dist/src/agent/orchestration/agent-orchestrator.js +1 -1
  123. package/dist/src/agent/orchestration/agent-turn-policy.js +5 -5
  124. package/dist/src/agent/orchestration/index.d.ts +1 -1
  125. package/dist/src/agent/orchestration/index.js +2 -2
  126. package/dist/src/agent/orchestration/loop-guard.d.ts +4 -31
  127. package/dist/src/agent/orchestration/loop-guard.js +14 -99
  128. package/dist/src/agent/prompt/sections/tooling.js +2 -4
  129. package/dist/src/agent/sandbox/types.d.ts +2 -2
  130. package/dist/src/agent/sandbox/types.js +1 -1
  131. package/dist/src/agent/service/direct-turn-helpers.js +1 -1
  132. package/dist/src/agent/service/process-direct-streaming.js +1 -1
  133. package/dist/src/agent/service.d.ts +0 -2
  134. package/dist/src/agent/service.js +6 -23
  135. package/dist/src/agent/tasks/task-judge-service.d.ts +7 -0
  136. package/dist/src/agent/tasks/task-judge-service.js +24 -2
  137. package/dist/src/agent/tools/delegate-tool.d.ts +2 -1
  138. package/dist/src/agent/tools/delegate-tool.js +102 -124
  139. package/dist/src/agent/tools/exec-command.d.ts +8 -1
  140. package/dist/src/agent/tools/exec-command.js +77 -169
  141. package/dist/src/agent/tools/executor.js +9 -2
  142. package/dist/src/agent/tools/factory.js +50 -5
  143. package/dist/src/agent/tools/find.d.ts +10 -13
  144. package/dist/src/agent/tools/find.js +33 -80
  145. package/dist/src/agent/tools/grep.d.ts +14 -18
  146. package/dist/src/agent/tools/grep.js +56 -144
  147. package/dist/src/agent/tools/index.d.ts +0 -1
  148. package/dist/src/agent/tools/index.js +2 -3
  149. package/dist/src/agent/tools/language-diagnostics.d.ts +11 -0
  150. package/dist/src/agent/tools/language-diagnostics.js +62 -0
  151. package/dist/src/agent/tools/managed-job-tool.d.ts +2 -1
  152. package/dist/src/agent/tools/managed-job-tool.js +58 -118
  153. package/dist/src/agent/tools/read.js +24 -7
  154. package/dist/src/agent/tools/repository-search.d.ts +5 -0
  155. package/dist/src/agent/tools/repository-search.js +56 -0
  156. package/dist/src/agent/tools/review-workspace.d.ts +2 -0
  157. package/dist/src/agent/tools/review-workspace.js +103 -0
  158. package/dist/src/agent/tools/write.js +4 -4
  159. package/dist/src/agent/transcript/index.js +2 -2
  160. package/dist/src/agent/transcript/transcript-hygiene.js +2 -2
  161. package/dist/src/agent/workflow/subagent-runner.d.ts +0 -2
  162. package/dist/src/agent/workflow/subagent-runner.js +12 -31
  163. package/dist/src/agent-config/schema.d.ts +42 -0
  164. package/dist/src/agent-config/schema.js +5 -0
  165. package/dist/src/automations/draft/automation-draft-service.js +1 -1
  166. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  167. package/dist/src/config/schema.d.ts +28 -0
  168. package/dist/src/execution-environments/local-worktree-manager.d.ts +3 -1
  169. package/dist/src/execution-environments/local-worktree-manager.js +8 -3
  170. package/dist/src/execution-environments/session-environment-service.js +5 -3
  171. package/dist/src/extensions/update.js +1 -1
  172. package/dist/src/gateway/hono/lib/config-payload.d.ts +7 -0
  173. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  174. package/dist/src/gateway/hono/routes/connectors.js +23 -23
  175. package/dist/src/gateway/hono/routes/sessions.js +1 -1
  176. package/dist/src/gateway/media-access.js +1 -1
  177. package/dist/src/gateway/service/config-coordinator.js +1 -1
  178. package/dist/src/gateway/service/run-gateway-agent.js +4 -1
  179. package/dist/src/gateway/service.js +1 -1
  180. package/dist/src/gateway/session-reset-service.js +1 -1
  181. package/dist/src/gateway/workspace-ripgrep.d.ts +0 -6
  182. package/dist/src/gateway/workspace-ripgrep.js +2 -40
  183. package/dist/src/infra/ripgrep.d.ts +13 -0
  184. package/dist/src/infra/ripgrep.js +46 -0
  185. package/dist/src/infra/update-runner.js +1 -1
  186. package/dist/src/proactive/execution/agent-executor.js +1 -1
  187. package/dist/src/session/store.js +1 -1
  188. package/dist/src/session/turn-outcome-projector.js +26 -6
  189. package/dist/src/tasks/task-run-coordinator.d.ts +2 -2
  190. package/dist/src/tasks/task-run-coordinator.js +14 -12
  191. package/dist/src/tui/backends/embedded-backend.js +1 -1
  192. package/package.json +3 -3
  193. package/dist/gateway/static/root/assets/messages-CTSgFlE4.js +0 -3
  194. package/dist/gateway/static/root/assets/models-hub-cache-ZrbGRiGY.js +0 -1
  195. package/dist/gateway/static/root/assets/settings-advanced-gate-D4EMxWAZ.js +0 -1
  196. package/dist/gateway/static/root/assets/skill-reload-api-DVb7nrXz.js +0 -1
  197. package/dist/src/agent/coding/turn-diff-tracker.d.ts +0 -67
  198. package/dist/src/agent/coding/turn-diff-tracker.js +0 -231
  199. package/dist/src/agent/middleware/self-verify.d.ts +0 -136
  200. package/dist/src/agent/middleware/self-verify.js +0 -380
  201. package/dist/src/agent/tools/execute-code-tool.d.ts +0 -11
  202. package/dist/src/agent/tools/execute-code-tool.js +0 -208
@@ -1,161 +1,73 @@
1
- import { DEFAULT_MAX_BYTES, formatSize, truncateHead, truncateLine } from "./truncate.js";
1
+ import { evaluateFilePolicy } from "../sandbox/exec-policy.js";
2
2
  import { resolveToCwd } from "../../utils/helpers.js";
3
- import path from "path";
4
- import { existsSync, readFileSync, statSync } from "fs";
3
+ import { repositorySearch } from "./repository-search.js";
5
4
  import { Type } from "@sinclair/typebox";
6
- import { globSync } from "glob";
7
5
  //#region src/agent/tools/grep.ts
8
6
  const grepSchema = Type.Object({
9
- pattern: Type.String({ description: "Search pattern (regex or literal string)" }),
10
- path: Type.Optional(Type.String({ description: "Directory or file to search (default: current directory)" })),
11
- glob: Type.Optional(Type.String({ description: "Filter files by glob pattern, e.g. '*.ts'" })),
12
- ignoreCase: Type.Optional(Type.Boolean({ description: "Case-insensitive search (default: false)" })),
13
- literal: Type.Optional(Type.Boolean({ description: "Treat pattern as literal string instead of regex (default: false)" })),
14
- context: Type.Optional(Type.Number({ description: "Number of lines to show before and after each match (default: 0)" })),
15
- limit: Type.Optional(Type.Number({ description: "Maximum number of matches to return (default: 100)" }))
7
+ pattern: Type.String({ description: "Ripgrep regex, or literal text when literal=true" }),
8
+ path: Type.Optional(Type.String()),
9
+ glob: Type.Optional(Type.String()),
10
+ ignoreCase: Type.Optional(Type.Boolean()),
11
+ literal: Type.Optional(Type.Boolean()),
12
+ context: Type.Optional(Type.Integer({
13
+ minimum: 0,
14
+ maximum: 20
15
+ })),
16
+ limit: Type.Optional(Type.Integer({
17
+ minimum: 1,
18
+ maximum: 1e3
19
+ }))
16
20
  });
17
- const DEFAULT_LIMIT = 100;
18
- /**
19
- * Simple grep implementation using Node.js regex
20
- */
21
- function simpleGrep(content, pattern, options) {
22
- const matches = [];
23
- const lines = content.split("\n");
24
- const regexPattern = options.literal ? pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") : pattern;
25
- const flags = options.ignoreCase ? "i" : "";
26
- const regex = new RegExp(regexPattern, flags);
27
- for (let i = 0; i < lines.length; i++) if (regex.test(lines[i])) matches.push({
28
- lineNumber: i + 1,
29
- line: lines[i]
30
- });
31
- return matches;
32
- }
33
- /**
34
- * Grep tool - Search file contents for a pattern
35
- */
36
21
  function createGrepTool(cwd) {
37
22
  return {
38
23
  name: "grep",
39
- label: "🔍 grep",
40
- description: "Search file contents for a pattern (regex or literal).",
24
+ label: "Search",
41
25
  parameters: grepSchema,
26
+ description: "Search with ripgrep, respecting .gitignore and skipping binary files. Returns path:line content. Use a narrow path or glob; output is bounded.",
42
27
  supportsParallel: true,
43
28
  idempotent: true,
44
- execute: async (_toolCallId, params, signal) => {
45
- try {
46
- const p = params;
47
- const searchPath = resolveToCwd(p.path || ".", cwd);
48
- if (!existsSync(searchPath)) return {
49
- content: [{
50
- type: "text",
51
- text: `Error: Path not found: ${searchPath}`
52
- }],
53
- details: {}
54
- };
55
- const isDirectory = statSync(searchPath).isDirectory();
56
- const context = p.context || 0;
57
- const effectiveLimit = p.limit || DEFAULT_LIMIT;
58
- const files = [];
59
- if (isDirectory) {
60
- const filePaths = globSync(p.glob || "**/*", {
61
- cwd: searchPath,
62
- dot: true,
63
- ignore: ["**/node_modules/**", "**/.git/**"]
64
- });
65
- files.push(...filePaths.map((f) => path.join(searchPath, f)));
66
- } else files.push(searchPath);
67
- const matches = [];
68
- let matchCount = 0;
69
- let linesTruncated = false;
70
- for (const filePath of files) {
71
- if (signal?.aborted) return {
72
- content: [{
73
- type: "text",
74
- text: "Operation aborted"
75
- }],
76
- details: {}
77
- };
78
- try {
79
- if (!existsSync(filePath)) continue;
80
- const fileMatches = simpleGrep(readFileSync(filePath, "utf-8"), p.pattern, {
81
- ignoreCase: p.ignoreCase || false,
82
- literal: p.literal || false
83
- });
84
- for (const match of fileMatches) {
85
- if (matchCount >= effectiveLimit) break;
86
- matches.push({
87
- file: filePath,
88
- ...match
89
- });
90
- matchCount++;
91
- }
92
- } catch {}
93
- if (matchCount >= effectiveLimit) break;
94
- }
95
- if (matches.length === 0) return {
96
- content: [{
97
- type: "text",
98
- text: "No matches found"
99
- }],
100
- details: {}
101
- };
102
- const outputLines = [];
103
- const basePath = isDirectory ? searchPath : path.dirname(searchPath);
104
- for (const match of matches) {
105
- const relativePath = path.relative(basePath, match.file);
106
- const { text: truncatedLine, wasTruncated } = truncateLine(match.line);
107
- if (wasTruncated) linesTruncated = true;
108
- if (context > 0) try {
109
- const allLines = readFileSync(match.file, "utf-8").split("\n");
110
- const start = Math.max(1, match.lineNumber - context);
111
- const end = Math.min(allLines.length, match.lineNumber + context);
112
- for (let i = start; i <= end; i++) {
113
- const { text: truncatedContextLine } = truncateLine(allLines[i - 1] || "");
114
- if (i === match.lineNumber) outputLines.push(`${relativePath}:${i}: ${truncatedContextLine}`);
115
- else outputLines.push(`${relativePath}-${i}- ${truncatedContextLine}`);
116
- }
117
- } catch {
118
- outputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedLine}`);
119
- }
120
- else outputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedLine}`);
121
- }
122
- const truncation = truncateHead(outputLines.join("\n"), { maxLines: Number.MAX_SAFE_INTEGER });
123
- let output = truncation.content;
124
- const details = {};
125
- const notices = [];
126
- if (matches.length >= effectiveLimit) {
127
- notices.push(`${effectiveLimit} matches limit reached`);
128
- details.matchLimitReached = effectiveLimit;
129
- }
130
- if (truncation.truncated) {
131
- notices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);
132
- details.truncation = truncation;
133
- }
134
- if (linesTruncated) {
135
- notices.push(`Some lines truncated to 500 chars`);
136
- details.linesTruncated = true;
137
- }
138
- if (notices.length > 0) output += `\n\n[${notices.join(". ")}]`;
139
- return {
140
- content: [{
141
- type: "text",
142
- text: output
143
- }],
144
- details: Object.keys(details).length > 0 ? details : void 0
145
- };
146
- } catch (error) {
147
- return {
148
- content: [{
149
- type: "text",
150
- text: `Error during grep: ${error instanceof Error ? error.message : String(error)}`
151
- }],
152
- details: {}
153
- };
154
- }
29
+ async execute(_id, params, signal) {
30
+ const path = resolveToCwd(params.path || ".", cwd);
31
+ const policy = evaluateFilePolicy({
32
+ operation: "read",
33
+ path,
34
+ workspaceRoot: cwd
35
+ });
36
+ if (!policy.allowed) throw new Error(policy.reason);
37
+ const limit = Math.min(1e3, Math.max(1, params.limit ?? 100));
38
+ const result = await repositorySearch(cwd, [
39
+ "--line-number",
40
+ "--with-filename",
41
+ "--color",
42
+ "never",
43
+ "--max-columns",
44
+ "300",
45
+ "--max-columns-preview",
46
+ "--max-count",
47
+ String(limit),
48
+ "--context",
49
+ String(params.context ?? 0),
50
+ ...params.ignoreCase ? ["--ignore-case"] : [],
51
+ ...params.literal ? ["--fixed-strings"] : [],
52
+ ...params.glob ? ["--glob", params.glob] : [],
53
+ "-e",
54
+ params.pattern,
55
+ "--",
56
+ path
57
+ ], signal);
58
+ const lines = result.output.trimEnd().split("\n");
59
+ const outputLimit = limit * (1 + 2 * (params.context ?? 0));
60
+ const truncated = result.truncated || lines.length > outputLimit;
61
+ return {
62
+ content: [{
63
+ type: "text",
64
+ text: (result.output ? lines.slice(0, outputLimit).join("\n") : "No matches found") + (truncated ? "\n[Results truncated; narrow the path or pattern.]" : "")
65
+ }],
66
+ details: { truncated }
67
+ };
155
68
  }
156
69
  };
157
70
  }
158
- /** Default grep tool using process.cwd() */
159
71
  const grepTool = createGrepTool(process.cwd());
160
72
  //#endregion
161
73
  export { createGrepTool, grepTool };
@@ -25,7 +25,6 @@ export { createClarifyTool, type ClarifyRequestPayload, type GatewayClarifyReque
25
25
  export { BrowserManager, assertBrowserUrlAllowed } from '../../browser/index.js';
26
26
  export { createDelegateTool, DEFAULT_DELEGATE_TOOLS, DELEGATE_BLOCKED_TOOLS, } from './delegate-tool.js';
27
27
  export { createWorkflowTool, type WorkflowToolDeps, type WorkflowToolInput } from './workflow-tool.js';
28
- export { createExecuteCodeTool, buildSandboxToolMap, SANDBOX_ALLOWED_TOOLS, } from './execute-code-tool.js';
29
28
  export { createAutomationTool, type AutomationToolDeps } from './automation-tool.js';
30
29
  export { createBrowserRecipeTool } from './browser-recipe-tool.js';
31
30
  export { createXopcUseTool, type XopcUseToolDeps, type XopcUseToolInput } from './xopc-use-tool.js';
@@ -27,9 +27,9 @@ import { createClarifyTool } from "./clarify-tool.js";
27
27
  import { BrowserManager } from "../../browser/manager.js";
28
28
  import { assertBrowserUrlAllowed } from "../../browser/url-policy.js";
29
29
  import "../../browser/index.js";
30
+ import { resolveImageModelConfigForTool } from "../image/tool-model-config.js";
30
31
  import { DEFAULT_DELEGATE_TOOLS, DELEGATE_BLOCKED_TOOLS, createDelegateTool } from "./delegate-tool.js";
31
32
  import { createWorkflowTool } from "./workflow-tool.js";
32
- import { SANDBOX_ALLOWED_TOOLS, buildSandboxToolMap, createExecuteCodeTool } from "./execute-code-tool.js";
33
33
  import { createAutomationTool } from "./automation-tool.js";
34
34
  import { createBrowserRecipeTool } from "./browser-recipe-tool.js";
35
35
  import { createXopcUseTool } from "./xopc-use-tool.js";
@@ -40,7 +40,6 @@ import { createSkillInstallTool } from "./skill-install-tool.js";
40
40
  import { createToolManualTool } from "./tool-manual-tool.js";
41
41
  import { createDesktopPetTool } from "./desktop-pet-tool.js";
42
42
  import { createManagedJobTool } from "./managed-job-tool.js";
43
- import { resolveImageModelConfigForTool } from "../image/tool-model-config.js";
44
43
  import { createImageTool } from "./image-tool.js";
45
44
  import { createImageGenerateTool, resolveImageGenerationModelConfigForTool } from "./image-generate-tool.js";
46
- export { BrowserManager, DEFAULT_DELEGATE_TOOLS, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_TOOL_METADATA, DEFAULT_WEB_EXTRACT_MAX_LENGTH, DELEGATE_BLOCKED_TOOLS, GREP_MAX_LINE_LENGTH, MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT, SANDBOX_ALLOWED_TOOLS, TodoStore, ToolConcurrencyController, assertBrowserUrlAllowed, buildSandboxToolMap, createApplyPatchTool, createAutomationTool, createBrowserRecipeTool, createClarifyTool, createCreateShareTool, createDelegateTool, createDesktopPetTool, createDreamingTool, createExecCommandTool, createExecuteCodeTool, createFindTool, createGrepTool, createImageGenerateTool, createImageTool, createListDirTool, createManagedJobTool, createMemoryGetTool, createMemorySearchTool, createMessageTool, createPublishArtifactsTool, createReadFileTool, createReadMediaTool, createSendMediaTool, createSessionRecallTool, createSessionSearchTool, createSessionStatusTool, createSkillInstallTool, createSkillManageTool, createSkillViewTool, createSkillsListTool, createSkillsMarketplaceSearchTool, createTodoTool, createToolManualTool, createUpdatePlanTool, createWebExtractTool, createWebFetchTool, createWebSearchTool, createWorkflowTool, createWriteFileTool, createXopcUseTool, findTool, formatSize, fuzzyFindText, generateDiffString, getToolMetadata, grepTool, isShareToolAvailable, listDirTool, normalizeForFuzzyMatch, normalizeToLF, resolveImageGenerationModelConfigForTool, resolveImageModelConfigForTool, resolveToolLockMode, restoreLineEndings, stripBom, stripHtmlBoilerplate, truncateHead, truncateLine, truncateTail, writeFileTool };
45
+ export { BrowserManager, DEFAULT_DELEGATE_TOOLS, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_TOOL_METADATA, DEFAULT_WEB_EXTRACT_MAX_LENGTH, DELEGATE_BLOCKED_TOOLS, GREP_MAX_LINE_LENGTH, MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT, TodoStore, ToolConcurrencyController, assertBrowserUrlAllowed, createApplyPatchTool, createAutomationTool, createBrowserRecipeTool, createClarifyTool, createCreateShareTool, createDelegateTool, createDesktopPetTool, createDreamingTool, createExecCommandTool, createFindTool, createGrepTool, createImageGenerateTool, createImageTool, createListDirTool, createManagedJobTool, createMemoryGetTool, createMemorySearchTool, createMessageTool, createPublishArtifactsTool, createReadFileTool, createReadMediaTool, createSendMediaTool, createSessionRecallTool, createSessionSearchTool, createSessionStatusTool, createSkillInstallTool, createSkillManageTool, createSkillViewTool, createSkillsListTool, createSkillsMarketplaceSearchTool, createTodoTool, createToolManualTool, createUpdatePlanTool, createWebExtractTool, createWebFetchTool, createWebSearchTool, createWorkflowTool, createWriteFileTool, createXopcUseTool, findTool, formatSize, fuzzyFindText, generateDiffString, getToolMetadata, grepTool, isShareToolAvailable, listDirTool, normalizeForFuzzyMatch, normalizeToLF, resolveImageGenerationModelConfigForTool, resolveImageModelConfigForTool, resolveToolLockMode, restoreLineEndings, stripBom, stripHtmlBoilerplate, truncateHead, truncateLine, truncateTail, writeFileTool };
@@ -0,0 +1,11 @@
1
+ import type { AgentTool } from '@earendil-works/pi-agent-core';
2
+ import { type CreateExecCommandToolOptions } from './exec-command.js';
3
+ export interface LanguageDiagnostic {
4
+ file: string;
5
+ line: number;
6
+ column: number;
7
+ code: string;
8
+ message: string;
9
+ }
10
+ export declare function parseTypeScriptDiagnostics(output: string): LanguageDiagnostic[];
11
+ export declare function createLanguageDiagnosticsTool(workspace: string, options?: CreateExecCommandToolOptions): AgentTool;
@@ -0,0 +1,62 @@
1
+ import { createExecCommandTool } from "./exec-command.js";
2
+ import { relative, resolve, sep } from "node:path";
3
+ import { access } from "node:fs/promises";
4
+ import { Type } from "@sinclair/typebox";
5
+ //#region src/agent/tools/language-diagnostics.ts
6
+ function parseTypeScriptDiagnostics(output) {
7
+ return [...output.matchAll(/^(.+)\((\d+),(\d+)\): error (TS\d+): (.+)$/gm)].slice(0, 200).map((match) => ({
8
+ file: match[1],
9
+ line: Number(match[2]),
10
+ column: Number(match[3]),
11
+ code: match[4],
12
+ message: match[5]
13
+ }));
14
+ }
15
+ function quote(value) {
16
+ if (process.platform === "win32") {
17
+ if (/[%!"\r\n]/.test(value)) throw new Error("Unsupported character in diagnostic path");
18
+ return `"${value}"`;
19
+ }
20
+ return `'${value.replace(/'/g, `'\\''`)}'`;
21
+ }
22
+ function createLanguageDiagnosticsTool(workspace, options) {
23
+ const exec = createExecCommandTool(workspace, options);
24
+ return {
25
+ name: "language_diagnostics",
26
+ label: "TypeScript diagnostics",
27
+ description: "Run the repository-installed TypeScript compiler without emitting code. Returns compiler exit status, bounded file/line diagnostics, and a durable command log. Supports tsconfig projects; other languages use their normal check command.",
28
+ parameters: Type.Object({ project: Type.Optional(Type.String({ description: "tsconfig path relative to the workspace; defaults to tsconfig.json" })) }),
29
+ supportsParallel: false,
30
+ idempotent: false,
31
+ async execute(id, input, signal, onUpdate) {
32
+ const project = resolve(workspace, input.project ?? "tsconfig.json");
33
+ const projectRelative = relative(workspace, project);
34
+ if (projectRelative === ".." || projectRelative.startsWith(`..${sep}`)) throw new Error("Project must be inside the workspace");
35
+ await access(project);
36
+ let compiler;
37
+ try {
38
+ compiler = resolve(workspace, "node_modules/typescript/lib/tsc.js");
39
+ await access(compiler);
40
+ } catch {
41
+ throw new Error("This workspace has no installed TypeScript compiler. Install its declared dependencies first.");
42
+ }
43
+ const isolated = options?.getCommandIsolation?.()?.mode === "docker";
44
+ const compilerPath = isolated ? relative(workspace, compiler).split(sep).join("/") : compiler;
45
+ if (isolated && compilerPath.startsWith("../")) throw new Error("Container diagnostics require TypeScript installed inside the workspace.");
46
+ const result = await exec.execute(id, {
47
+ cmd: `${quote(isolated ? "node" : process.execPath)} ${quote(compilerPath)} --project ${quote(projectRelative)} --noEmit --pretty false`,
48
+ timeoutMs: 12e4
49
+ }, signal, onUpdate);
50
+ return {
51
+ ...result,
52
+ details: {
53
+ ...result.details,
54
+ diagnosticEngine: "typescript",
55
+ diagnostics: parseTypeScriptDiagnostics(String(result.details.aggregatedOutput ?? ""))
56
+ }
57
+ };
58
+ }
59
+ };
60
+ }
61
+ //#endregion
62
+ export { createLanguageDiagnosticsTool, parseTypeScriptDiagnostics };
@@ -1,2 +1,3 @@
1
1
  import type { AgentTool } from '@earendil-works/pi-agent-core';
2
- export declare function createManagedJobTool(workspace: string, getSessionKey: () => string | undefined, getSkillPassthroughEnvVarNames?: () => string[], prepareEnv?: (baseEnv: Record<string, string>, cwd: string) => Promise<Record<string, string>>): AgentTool;
2
+ import type { CommandIsolation } from '../commands/command-isolation.js';
3
+ export declare function createManagedJobTool(workspace: string, getSessionKey: () => string | undefined, getSkillPassthroughEnvVarNames?: () => string[], prepareEnv?: (baseEnv: Record<string, string>, cwd: string) => Promise<Record<string, string>>, getCommandIsolation?: () => CommandIsolation | undefined): AgentTool;
@@ -1,106 +1,12 @@
1
- import { resolveGlobalSingleton } from "../../utils/global-singleton.js";
1
+ import { commandRegistry, commandTimeout } from "../commands/command-registry.js";
2
2
  import { evaluateExecPolicy } from "../sandbox/exec-policy.js";
3
3
  import { resolve } from "node:path";
4
- import { spawn } from "node:child_process";
5
- import { randomUUID } from "node:crypto";
6
4
  import { Type } from "@sinclair/typebox";
7
5
  //#region src/agent/tools/managed-job-tool.ts
8
- const MANAGED_JOB_REGISTRY_KEY = Symbol.for("xopc.managedJobRegistry");
9
- const DEFAULT_MAX_RUNTIME_MS = 60 * 6e4;
10
- const MAX_RUNTIME_MS = 1440 * 6e4;
11
- const MAX_CAPTURE_CHARS = 2e5;
12
- var ManagedJobRegistry = class {
13
- jobs = /* @__PURE__ */ new Map();
14
- start(owner, command, cwd, env, maxRuntimeMs) {
15
- this.prune();
16
- const id = randomUUID();
17
- const child = spawn(command, [], {
18
- shell: true,
19
- cwd,
20
- env,
21
- detached: process.platform !== "win32"
22
- });
23
- const job = {
24
- id,
25
- owner,
26
- command,
27
- cwd,
28
- status: "running",
29
- process: child,
30
- pid: child.pid,
31
- createdAtMs: Date.now(),
32
- stdout: "",
33
- stderr: "",
34
- timeout: setTimeout(() => this.stop(job, "timed_out"), maxRuntimeMs)
35
- };
36
- job.timeout.unref?.();
37
- const append = (stream, value) => {
38
- const next = `${job[stream]}${String(value)}`;
39
- job[stream] = next.length > MAX_CAPTURE_CHARS ? next.slice(-MAX_CAPTURE_CHARS) : next;
40
- };
41
- child.stdout?.on("data", (value) => append("stdout", value));
42
- child.stderr?.on("data", (value) => append("stderr", value));
43
- child.on("error", (error) => append("stderr", `\n${error.message}`));
44
- child.on("close", (exitCode) => {
45
- if (job.status === "running") job.status = exitCode === 0 ? "succeeded" : "failed";
46
- job.exitCode = exitCode;
47
- job.endedAtMs = Date.now();
48
- clearTimeout(job.timeout);
49
- });
50
- this.jobs.set(id, job);
51
- return this.view(job);
52
- }
53
- get(owner, id) {
54
- const job = this.jobs.get(id);
55
- return job?.owner === owner ? this.view(job) : void 0;
56
- }
57
- list(owner) {
58
- return [...this.jobs.values()].filter((job) => job.owner === owner).toSorted((a, b) => b.createdAtMs - a.createdAtMs).slice(0, 50).map((job) => this.view(job));
59
- }
60
- cancel(owner, id) {
61
- const job = this.jobs.get(id);
62
- if (!job || job.owner !== owner) return void 0;
63
- if (job.status === "running") this.stop(job, "cancelled");
64
- return this.view(job);
65
- }
66
- stop(job, status) {
67
- if (job.status !== "running") return;
68
- job.status = status;
69
- job.endedAtMs = Date.now();
70
- clearTimeout(job.timeout);
71
- if (job.pid && process.platform !== "win32") try {
72
- process.kill(-job.pid, "SIGTERM");
73
- return;
74
- } catch {}
75
- job.process.kill("SIGTERM");
76
- }
77
- view(job) {
78
- const outputLength = job.stdout.length + job.stderr.length;
79
- return {
80
- id: job.id,
81
- command: job.command,
82
- cwd: job.cwd,
83
- status: job.status,
84
- pid: job.pid,
85
- createdAtMs: job.createdAtMs,
86
- endedAtMs: job.endedAtMs,
87
- exitCode: job.exitCode,
88
- stdout: job.stdout,
89
- stderr: job.stderr,
90
- durationMs: (job.endedAtMs ?? Date.now()) - job.createdAtMs,
91
- outputTruncated: outputLength >= MAX_CAPTURE_CHARS
92
- };
93
- }
94
- prune() {
95
- if (this.jobs.size < 500) return;
96
- const removable = [...this.jobs.values()].filter((job) => job.status !== "running").toSorted((a, b) => a.createdAtMs - b.createdAtMs).slice(0, Math.max(1, this.jobs.size - 400));
97
- for (const job of removable) this.jobs.delete(job.id);
98
- }
99
- };
100
6
  const ManagedJobSchema = Type.Union([
101
7
  Type.Object({
102
8
  action: Type.Literal("start"),
103
- command: Type.String(),
9
+ command: Type.String({ minLength: 1 }),
104
10
  cwd: Type.Optional(Type.String()),
105
11
  maxRuntimeMs: Type.Optional(Type.Number())
106
12
  }),
@@ -108,52 +14,86 @@ const ManagedJobSchema = Type.Union([
108
14
  action: Type.Literal("status"),
109
15
  jobId: Type.String()
110
16
  }),
17
+ Type.Object({
18
+ action: Type.Literal("wait"),
19
+ jobId: Type.String(),
20
+ waitMs: Type.Optional(Type.Number({
21
+ minimum: 0,
22
+ maximum: 6e4
23
+ }))
24
+ }),
25
+ Type.Object({
26
+ action: Type.Literal("stdin"),
27
+ jobId: Type.String(),
28
+ chars: Type.String({ maxLength: 65536 }),
29
+ end: Type.Optional(Type.Boolean())
30
+ }),
111
31
  Type.Object({ action: Type.Literal("list") }),
112
32
  Type.Object({
113
33
  action: Type.Literal("cancel"),
114
34
  jobId: Type.String()
115
35
  })
116
36
  ], { type: "object" });
117
- function registry() {
118
- return resolveGlobalSingleton(MANAGED_JOB_REGISTRY_KEY, () => new ManagedJobRegistry());
119
- }
120
37
  function result(value) {
121
38
  return {
122
39
  content: [{
123
40
  type: "text",
124
41
  text: JSON.stringify(value, null, 2)
125
42
  }],
126
- details: {}
43
+ details: Array.isArray(value) ? { jobs: value } : value
127
44
  };
128
45
  }
129
- function createManagedJobTool(workspace, getSessionKey, getSkillPassthroughEnvVarNames, prepareEnv) {
46
+ function createManagedJobTool(workspace, getSessionKey, getSkillPassthroughEnvVarNames, prepareEnv, getCommandIsolation) {
130
47
  return {
131
48
  name: "managed_job",
132
49
  label: "Managed Job",
133
- description: "Start and manage commands expected to outlive a single tool call. Start returns a jobId immediately; use status/list/cancel to observe or stop it.",
50
+ description: "Manage shell jobs, including jobs yielded by exec_command. Start returns an id; wait returns on completion or after at most 60s; stdin writes pipe input (not a terminal); status/list/cancel inspect or stop jobs. Completed output and logs survive restart. Interrupted jobs require inspection before restart.",
134
51
  parameters: ManagedJobSchema,
135
52
  supportsParallel: true,
136
53
  idempotent: false,
137
- async execute(_toolCallId, input) {
138
- const owner = getSessionKey() ?? "default";
139
- if (input.action === "list") return result(registry().list(owner));
140
- if (input.action === "status") return result(registry().get(owner, input.jobId) ?? { error: "Managed job not found" });
141
- if (input.action === "cancel") return result(registry().cancel(owner, input.jobId) ?? { error: "Managed job not found" });
142
- const command = String(input.command ?? "").trim();
143
- if (!command) return result({ error: "command is required" });
54
+ async execute(_toolCallId, input, signal) {
55
+ const owner = getSessionKey() ?? workspace;
56
+ const registry = commandRegistry();
57
+ if (input.action === "list") return result(registry.list(owner));
58
+ if (input.action !== "start") {
59
+ if (input.action === "stdin" && !registry.write(owner, input.jobId, input.chars, input.end)) return result({
60
+ status: "failed",
61
+ error: "Job is unavailable or stdin is closed"
62
+ });
63
+ return result((input.action === "wait" ? await registry.wait(owner, input.jobId, input.waitMs, signal) : input.action === "cancel" ? await registry.cancel(owner, input.jobId) : registry.get(owner, input.jobId)) ?? {
64
+ status: "failed",
65
+ error: "Managed job not found"
66
+ });
67
+ }
68
+ const command = input.command.trim();
69
+ if (!command) return result({
70
+ status: "failed",
71
+ error: "command is required"
72
+ });
144
73
  const policy = evaluateExecPolicy({
145
74
  command,
146
- cwd: input.cwd?.trim() ? resolve(workspace, input.cwd.trim()) : workspace,
75
+ cwd: resolve(workspace, input.cwd?.trim() || "."),
147
76
  allowedEnvVars: getSkillPassthroughEnvVarNames?.() ?? []
148
77
  });
149
- if (!policy.allowed) return result({ error: `Sandbox blocked command: ${policy.reason}` });
150
- const rawMax = Number(input.maxRuntimeMs ?? DEFAULT_MAX_RUNTIME_MS);
151
- const maxRuntimeMs = Math.min(MAX_RUNTIME_MS, Math.max(1e3, Number.isFinite(rawMax) ? rawMax : DEFAULT_MAX_RUNTIME_MS));
152
- const runtimeEnv = prepareEnv ? await prepareEnv(policy.sanitizedEnv, policy.effectiveCwd) : policy.sanitizedEnv;
153
- return result(registry().start(owner, command, policy.effectiveCwd, {
154
- ...runtimeEnv,
155
- COLUMNS: "200"
156
- }, maxRuntimeMs));
78
+ if (!policy.allowed) return result({
79
+ status: "blocked",
80
+ error: `Command blocked: ${policy.reason}`
81
+ });
82
+ const env = prepareEnv ? await prepareEnv(policy.sanitizedEnv, policy.effectiveCwd) : policy.sanitizedEnv;
83
+ return result(await registry.start({
84
+ owner,
85
+ command,
86
+ cwd: policy.effectiveCwd,
87
+ env: {
88
+ ...env,
89
+ COLUMNS: "200"
90
+ },
91
+ workspace,
92
+ isolation: getCommandIsolation?.(),
93
+ timeoutMs: commandTimeout(input.maxRuntimeMs, policy.timeoutMs),
94
+ snapshot: true,
95
+ signal
96
+ }));
157
97
  }
158
98
  };
159
99
  }
@@ -8,7 +8,15 @@ const MAX_FILE_SIZE = 10 * 1024 * 1024;
8
8
  const DEFAULT_MAX_LINES = 500;
9
9
  const ReadFileSchema = Type.Object({
10
10
  path: Type.String({ description: "File path to read" }),
11
- limit: Type.Optional(Type.Number({ description: "Max lines (default: 500)" }))
11
+ offset: Type.Optional(Type.Integer({
12
+ minimum: 1,
13
+ description: "First line to read, one-based (default: 1)"
14
+ })),
15
+ limit: Type.Optional(Type.Integer({
16
+ minimum: 1,
17
+ maximum: 2e3,
18
+ description: "Max lines (default: 500)"
19
+ }))
12
20
  });
13
21
  function createReadFileTool(workspace, options) {
14
22
  return {
@@ -31,7 +39,7 @@ async function executeReadFile(workspace, profileMarkdownRoot, params) {
31
39
  type: "text",
32
40
  text: `🚫 ${safety.message}`
33
41
  }],
34
- details: {}
42
+ details: { status: "failed" }
35
43
  };
36
44
  let normalized = resolvePathUnderWorkspace(params.path, workspace);
37
45
  let stats;
@@ -53,21 +61,30 @@ async function executeReadFile(workspace, profileMarkdownRoot, params) {
53
61
  type: "text",
54
62
  text: `🚫 File too large: ${formatSize(stats.size)}`
55
63
  }],
56
- details: {}
64
+ details: { status: "failed" }
57
65
  };
58
- const truncation = truncateHead(await readFile(normalized, "utf-8"), {
66
+ const content = await readFile(normalized, "utf-8");
67
+ const offset = Math.max(1, params.offset ?? 1);
68
+ const lines = content.split("\n");
69
+ if (offset > lines.length) throw new Error(`Offset ${offset} exceeds ${lines.length} lines`);
70
+ const truncation = truncateHead(lines.slice(offset - 1).join("\n"), {
59
71
  maxLines: params.limit || DEFAULT_MAX_LINES,
60
72
  maxBytes: DEFAULT_MAX_BYTES
61
73
  });
62
74
  let outputText = truncation.content;
63
75
  if (truncation.truncated) if (truncation.firstLineExceedsLimit) outputText = `(Line exceeds ${formatSize(DEFAULT_MAX_BYTES)})`;
64
- else outputText += `\n\n[${truncation.outputLines}/${truncation.totalLines} lines]`;
76
+ else outputText += `\n\n[Lines ${offset}-${offset + truncation.outputLines - 1} of ${lines.length}; continue with offset=${offset + truncation.outputLines}]`;
65
77
  return {
66
78
  content: [{
67
79
  type: "text",
68
80
  text: outputText
69
81
  }],
70
- details: {}
82
+ details: {
83
+ path: normalized,
84
+ offset,
85
+ totalLines: lines.length,
86
+ truncated: truncation.truncated
87
+ }
71
88
  };
72
89
  } catch (error) {
73
90
  return {
@@ -75,7 +92,7 @@ async function executeReadFile(workspace, profileMarkdownRoot, params) {
75
92
  type: "text",
76
93
  text: `Error: ${error instanceof Error ? error.message : String(error)}`
77
94
  }],
78
- details: {}
95
+ details: { status: "failed" }
79
96
  };
80
97
  }
81
98
  }
@@ -0,0 +1,5 @@
1
+ /** Bounded native search; unavailable tools and invalid regexes are explicit failures. */
2
+ export declare function repositorySearch(cwd: string, args: string[], signal?: AbortSignal): Promise<{
3
+ output: string;
4
+ truncated: boolean;
5
+ }>;