@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.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-CAah-_8h.js → activity-store-BlxqErph.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DDH4HgP7.js → agent-avatar-dicebear-DRQnogaU.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-BDCfJZhh.js → agent-defaults-settings-panel-CpOxGbMD.js} +1 -1
- package/dist/gateway/static/root/assets/{agents-B0ZWgf-U.js → agents-flnXZLaT.js} +1 -1
- package/dist/gateway/static/root/assets/{api-B2tKxbcz.js → api-BbXzyQMj.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-Blfwszzn.js → app-management-settings-panel-CZl6n2xi.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-C3V7Na75.js → appearance-settings-Bglp-pn6.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-BiEks0-F.js → apps-page-CmsWarVB.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-BmSx7wzY.js → archive-plugin-DD2SweEH.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-BS-S4LJ9.js → attachment-load-G0HenUmG.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-C7Y3L30D.js → automations-page-B78bFjH2.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-workspace-A3zPkPuo.js → automations-workspace-BMQGmn50.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-BM9B5kcm.js → binary-plugins-BbSQmXqn.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-BbnpkYP9.js → block-editor-DutTIH81.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-settings-page-Dk4FQ7fY.js → browser-settings-page-CALiFKm4.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-CRnkgZHI.js → browser-workflow-inputs-BAAc151l.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-B9qGL-it.js → browser-workflows-page-DE5HPrHZ.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-settings-panel--tR_El9e.js → capabilities-settings-panel-Dts7XtP3.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-D347vl_J.js → channels-settings-CWEd3wzh.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-DuY4MGxe.js → channels-status-swr-CCBCtLDg.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-DABPvwBT.js → chat-terminal-dock-Bp1fXQm1.js} +1 -1
- package/dist/gateway/static/root/assets/{connectors-page-B-tvJkRJ.js → connectors-page-CQ6wVNLm.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-expression-D3bsKbNd.js → cron-expression-B8HA5IRb.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-BsGM6Yty.js → date-picker-DD8b7oad.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-Dj3g6YXZ.js → dependency-picker-BC9zwIyH.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-C1QT0Sur.js → desktop-pet-DsrsPZTW.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-r6kAOnfY.js → desktop-pet-settings-D7gp_HNA.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DOkf7nh9.js → extension-debug-page-BoKbOX7x.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-Cq2IA4Ho.js → extension-page-BegL4FW8.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DQn4qjDZ.js → extension-settings-page-CjPqq57s.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-DM3poL22.js → gateway-config-api-DaG57o4X.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-BC3pgb_P.js → gateway-config-swr-826dipyU.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-DPgH1hnh.js → gateway-settings-DkJGpgm6.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-uMcSfLru.js → gateway-startup-retry-DyvcAIMm.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-Bk80-E3b.js → heartbeat-settings-BLZ48kSU.js} +1 -1
- package/dist/gateway/static/root/assets/{home-page-DKo5JiMR.js → home-page-Dtw7Ipt1.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-D1qlQA-A.js → image-generation-api-D7cyfks6.js} +1 -1
- package/dist/gateway/static/root/assets/{index-B0WJL9N1.js → index-DG5CfYat.js} +10 -10
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BEwvd8ZU.js → keyboard-shortcuts-settings-D2Has7-N.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page--eJ5rmNj.js → local-app-workbench-page-BWidWY93.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-CgkY9E-r.js → local-apps-page-Bkekjoxf.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-CMZljTJx.js → locale-store-CBoCuIMx.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-Z49Td0J9.js → logs-page-C5zSSgvA.js} +1 -1
- package/dist/gateway/static/root/assets/{management-settings-Dv8NSJKt.js → management-settings-B8c62vRS.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-Cm0RBB-t.js → markdown-split-3kxTTGO7.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-PPCLt7fu.js → markdown-view-BXsHghJd.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-Bcr5sU1f.js → media-plugins-BW8J1nCG.js} +1 -1
- package/dist/gateway/static/root/assets/messages-BbdwoxVo.js +3 -0
- package/dist/gateway/static/root/assets/{mobile-pairing-wizard-kKDiXofY.js → mobile-pairing-wizard-nwQ8iUcd.js} +1 -1
- package/dist/gateway/static/root/assets/models-hub-cache-88f4fzYS.js +1 -0
- package/dist/gateway/static/root/assets/{notes-page-CgsaRaGi.js → notes-page-DdybD0QM.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-workbench-C1DEE09k.js → notes-workbench-IYfpy2Jx.js} +2 -2
- package/dist/gateway/static/root/assets/{oauth-api-4VeMbkTJ.js → oauth-api-BjSUDIgq.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-BU0HiZtv.js → product-open-page-CAJeUXeU.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-isRapnp5.js → project-detail-page-4wjw-b7h.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-zvsjg0mi.js → projects-page-CCMj9PeL.js} +1 -1
- package/dist/gateway/static/root/assets/{registry-api-CWOtPFrE.js → registry-api-BhGKnvLP.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-C9TGZ9Hc.js → remote-access-hub-DsBJqWIk.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-2zm9edMA.js → runtime-tools-settings-panel-B4IDcqx0.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-54A5gzkN.js → schema-form-DiGUUjO6.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-BP8RyiUn.js → sessions-page-BwGj0t-2.js} +1 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-BJCfUghk.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-DzDhoyxv.js → settings-page-CVQUsAhd.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-uDicHU1w.js → setup-status-panel-CQACRh1i.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-lOmLCWFS.js → share-preview-page-DTP1dtuS.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-settings-T4Yvouvv.js → shares-settings-D_YPh6Rw.js} +1 -1
- package/dist/gateway/static/root/assets/skill-reload-api-B43xlJlX.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-CnyNH3To.js → skills-page-Czpn7Y28.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-CgDtf2qs.js → skills-page.utils-d39rm3hb.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-C8yWfwtR.js → system-settings-panel-CXXySCSp.js} +1 -1
- package/dist/gateway/static/root/assets/{task-detail-page-Tzfjlbf3.js → task-detail-page-DHiOqQMx.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-uxUwr10D.js → theme-store-hybK3oC9.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-Bvg679no.js → tunnel-api-BiBGK7O2.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-D88VGoyG.js → use-autosave-DjpzpeIm.js} +1 -1
- package/dist/gateway/static/root/assets/{user-context-page-RijPtyfO.js → user-context-page-1XBRV5gX.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-CBHLsMcc.js → voice-api-key-field-CUIPNmOc.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-MqyI6cgq.js → voice-config-api-CBbiF1T3.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-GGe2TQ98.js → work-discovery-overlay-DVNxhb1x.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-C0layUE9.js → workflow-run-setup-panel-HxxFQFY7.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-DQXIzBAc.js → workflows-page-BCgL7PRm.js} +1 -1
- package/dist/gateway/static/root/index.html +11 -11
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/turn-outcome.js +3 -1
- package/dist/src/agent/agent-instance-gateway.d.ts +3 -1
- package/dist/src/agent/agent-manager.d.ts +2 -4
- package/dist/src/agent/agent-manager.js +24 -28
- package/dist/src/agent/background-review/coordinator.js +1 -1
- package/dist/src/agent/background-review/run-background-review.js +1 -1
- package/dist/src/agent/child-agent-factory.d.ts +10 -7
- package/dist/src/agent/child-agent-factory.js +112 -158
- package/dist/src/agent/coding/index.d.ts +1 -1
- package/dist/src/agent/coding/index.js +2 -2
- package/dist/src/agent/coding/repository-instructions.d.ts +12 -0
- package/dist/src/agent/coding/repository-instructions.js +76 -0
- package/dist/src/agent/coding/run-verification.d.ts +34 -0
- package/dist/src/agent/coding/run-verification.js +134 -0
- package/dist/src/agent/coding/verification-command.d.ts +3 -0
- package/dist/src/agent/coding/verification-command.js +50 -0
- package/dist/src/agent/coding/workspace-revision.d.ts +2 -0
- package/dist/src/agent/coding/workspace-revision.js +77 -0
- package/dist/src/agent/commands/command-isolation.d.ts +21 -0
- package/dist/src/agent/commands/command-isolation.js +71 -0
- package/dist/src/agent/commands/command-registry.d.ts +56 -0
- package/dist/src/agent/commands/command-registry.js +259 -0
- package/dist/src/agent/embedded/index.js +1 -1
- package/dist/src/agent/embedded/run-for-session.js +2 -1
- package/dist/src/agent/embedded/run-turn.js +88 -25
- package/dist/src/agent/embedded/session-tool-result-guard.js +2 -2
- package/dist/src/agent/embedded/subscribe-session.d.ts +2 -1
- package/dist/src/agent/embedded/subscribe-session.js +2 -1
- package/dist/src/agent/embedded/types.d.ts +3 -1
- package/dist/src/agent/embedded/xopc-tools-bridge.js +4 -1
- package/dist/src/agent/image/index.js +1 -1
- package/dist/src/agent/index.js +3 -3
- package/dist/src/agent/memory/user-context-coordinator.js +1 -1
- package/dist/src/agent/middleware/index.d.ts +0 -5
- package/dist/src/agent/middleware/index.js +1 -2
- package/dist/src/agent/orchestration/agent-event-handler.d.ts +0 -5
- package/dist/src/agent/orchestration/agent-event-handler.js +1 -96
- package/dist/src/agent/orchestration/agent-orchestrator.js +1 -1
- package/dist/src/agent/orchestration/agent-turn-policy.js +5 -5
- package/dist/src/agent/orchestration/index.d.ts +1 -1
- package/dist/src/agent/orchestration/index.js +2 -2
- package/dist/src/agent/orchestration/loop-guard.d.ts +4 -31
- package/dist/src/agent/orchestration/loop-guard.js +14 -99
- package/dist/src/agent/prompt/sections/tooling.js +2 -4
- package/dist/src/agent/sandbox/types.d.ts +2 -2
- package/dist/src/agent/sandbox/types.js +1 -1
- package/dist/src/agent/service/direct-turn-helpers.js +1 -1
- package/dist/src/agent/service/process-direct-streaming.js +1 -1
- package/dist/src/agent/service.d.ts +0 -2
- package/dist/src/agent/service.js +6 -23
- package/dist/src/agent/tasks/task-judge-service.d.ts +7 -0
- package/dist/src/agent/tasks/task-judge-service.js +24 -2
- package/dist/src/agent/tools/delegate-tool.d.ts +2 -1
- package/dist/src/agent/tools/delegate-tool.js +102 -124
- package/dist/src/agent/tools/exec-command.d.ts +8 -1
- package/dist/src/agent/tools/exec-command.js +77 -169
- package/dist/src/agent/tools/executor.js +9 -2
- package/dist/src/agent/tools/factory.js +50 -5
- package/dist/src/agent/tools/find.d.ts +10 -13
- package/dist/src/agent/tools/find.js +33 -80
- package/dist/src/agent/tools/grep.d.ts +14 -18
- package/dist/src/agent/tools/grep.js +56 -144
- package/dist/src/agent/tools/index.d.ts +0 -1
- package/dist/src/agent/tools/index.js +2 -3
- package/dist/src/agent/tools/language-diagnostics.d.ts +11 -0
- package/dist/src/agent/tools/language-diagnostics.js +62 -0
- package/dist/src/agent/tools/managed-job-tool.d.ts +2 -1
- package/dist/src/agent/tools/managed-job-tool.js +58 -118
- package/dist/src/agent/tools/read.js +24 -7
- package/dist/src/agent/tools/repository-search.d.ts +5 -0
- package/dist/src/agent/tools/repository-search.js +56 -0
- package/dist/src/agent/tools/review-workspace.d.ts +2 -0
- package/dist/src/agent/tools/review-workspace.js +103 -0
- package/dist/src/agent/tools/write.js +4 -4
- package/dist/src/agent/transcript/index.js +2 -2
- package/dist/src/agent/transcript/transcript-hygiene.js +2 -2
- package/dist/src/agent/workflow/subagent-runner.d.ts +0 -2
- package/dist/src/agent/workflow/subagent-runner.js +12 -31
- package/dist/src/agent-config/schema.d.ts +42 -0
- package/dist/src/agent-config/schema.js +5 -0
- package/dist/src/automations/draft/automation-draft-service.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/config/schema.d.ts +28 -0
- package/dist/src/execution-environments/local-worktree-manager.d.ts +3 -1
- package/dist/src/execution-environments/local-worktree-manager.js +8 -3
- package/dist/src/execution-environments/session-environment-service.js +5 -3
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +7 -0
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/connectors.js +23 -23
- package/dist/src/gateway/hono/routes/sessions.js +1 -1
- package/dist/src/gateway/media-access.js +1 -1
- package/dist/src/gateway/service/config-coordinator.js +1 -1
- package/dist/src/gateway/service/run-gateway-agent.js +4 -1
- package/dist/src/gateway/service.js +1 -1
- package/dist/src/gateway/session-reset-service.js +1 -1
- package/dist/src/gateway/workspace-ripgrep.d.ts +0 -6
- package/dist/src/gateway/workspace-ripgrep.js +2 -40
- package/dist/src/infra/ripgrep.d.ts +13 -0
- package/dist/src/infra/ripgrep.js +46 -0
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/proactive/execution/agent-executor.js +1 -1
- package/dist/src/session/store.js +1 -1
- package/dist/src/session/turn-outcome-projector.js +26 -6
- package/dist/src/tasks/task-run-coordinator.d.ts +2 -2
- package/dist/src/tasks/task-run-coordinator.js +14 -12
- package/dist/src/tui/backends/embedded-backend.js +1 -1
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/messages-CTSgFlE4.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-cache-ZrbGRiGY.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-D4EMxWAZ.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DVb7nrXz.js +0 -1
- package/dist/src/agent/coding/turn-diff-tracker.d.ts +0 -67
- package/dist/src/agent/coding/turn-diff-tracker.js +0 -231
- package/dist/src/agent/middleware/self-verify.d.ts +0 -136
- package/dist/src/agent/middleware/self-verify.js +0 -380
- package/dist/src/agent/tools/execute-code-tool.d.ts +0 -11
- package/dist/src/agent/tools/execute-code-tool.js +0 -208
|
@@ -1,161 +1,73 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { evaluateFilePolicy } from "../sandbox/exec-policy.js";
|
|
2
2
|
import { resolveToCwd } from "../../utils/helpers.js";
|
|
3
|
-
import
|
|
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: "
|
|
10
|
-
path: Type.Optional(Type.String(
|
|
11
|
-
glob: Type.Optional(Type.String(
|
|
12
|
-
ignoreCase: Type.Optional(Type.Boolean(
|
|
13
|
-
literal: Type.Optional(Type.Boolean(
|
|
14
|
-
context: Type.Optional(Type.
|
|
15
|
-
|
|
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: "
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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,
|
|
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
|
-
|
|
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 {
|
|
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: "
|
|
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() ??
|
|
139
|
-
|
|
140
|
-
if (input.action === "
|
|
141
|
-
if (input.action
|
|
142
|
-
|
|
143
|
-
|
|
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:
|
|
75
|
+
cwd: resolve(workspace, input.cwd?.trim() || "."),
|
|
147
76
|
allowedEnvVars: getSkillPassthroughEnvVarNames?.() ?? []
|
|
148
77
|
});
|
|
149
|
-
if (!policy.allowed) return result({
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
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
|
|
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}
|
|
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
|
}
|