@cdoing/core 0.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.
- package/dist/agents/coordinator.d.ts +114 -0
- package/dist/agents/coordinator.d.ts.map +1 -0
- package/dist/agents/coordinator.js +158 -0
- package/dist/agents/coordinator.js.map +1 -0
- package/dist/context-providers/clipboard.d.ts +13 -0
- package/dist/context-providers/clipboard.d.ts.map +1 -0
- package/dist/context-providers/clipboard.js +53 -0
- package/dist/context-providers/clipboard.js.map +1 -0
- package/dist/context-providers/codebase.d.ts +46 -0
- package/dist/context-providers/codebase.d.ts.map +1 -0
- package/dist/context-providers/codebase.js +273 -0
- package/dist/context-providers/codebase.js.map +1 -0
- package/dist/context-providers/diff.d.ts +18 -0
- package/dist/context-providers/diff.d.ts.map +1 -0
- package/dist/context-providers/diff.js +63 -0
- package/dist/context-providers/diff.js.map +1 -0
- package/dist/context-providers/docs.d.ts +21 -0
- package/dist/context-providers/docs.d.ts.map +1 -0
- package/dist/context-providers/docs.js +180 -0
- package/dist/context-providers/docs.js.map +1 -0
- package/dist/context-providers/file-include.d.ts +13 -0
- package/dist/context-providers/file-include.d.ts.map +1 -0
- package/dist/context-providers/file-include.js +82 -0
- package/dist/context-providers/file-include.js.map +1 -0
- package/dist/context-providers/folder.d.ts +19 -0
- package/dist/context-providers/folder.d.ts.map +1 -0
- package/dist/context-providers/folder.js +130 -0
- package/dist/context-providers/folder.js.map +1 -0
- package/dist/context-providers/git.d.ts +19 -0
- package/dist/context-providers/git.d.ts.map +1 -0
- package/dist/context-providers/git.js +74 -0
- package/dist/context-providers/git.js.map +1 -0
- package/dist/context-providers/index.d.ts +26 -0
- package/dist/context-providers/index.d.ts.map +1 -0
- package/dist/context-providers/index.js +37 -0
- package/dist/context-providers/index.js.map +1 -0
- package/dist/context-providers/open-files.d.ts +25 -0
- package/dist/context-providers/open-files.d.ts.map +1 -0
- package/dist/context-providers/open-files.js +134 -0
- package/dist/context-providers/open-files.js.map +1 -0
- package/dist/context-providers/problems.d.ts +24 -0
- package/dist/context-providers/problems.d.ts.map +1 -0
- package/dist/context-providers/problems.js +97 -0
- package/dist/context-providers/problems.js.map +1 -0
- package/dist/context-providers/registry.d.ts +61 -0
- package/dist/context-providers/registry.d.ts.map +1 -0
- package/dist/context-providers/registry.js +92 -0
- package/dist/context-providers/registry.js.map +1 -0
- package/dist/context-providers/terminal.d.ts +25 -0
- package/dist/context-providers/terminal.d.ts.map +1 -0
- package/dist/context-providers/terminal.js +55 -0
- package/dist/context-providers/terminal.js.map +1 -0
- package/dist/context-providers/tree.d.ts +29 -0
- package/dist/context-providers/tree.d.ts.map +1 -0
- package/dist/context-providers/tree.js +172 -0
- package/dist/context-providers/tree.js.map +1 -0
- package/dist/context-providers/types.d.ts +72 -0
- package/dist/context-providers/types.d.ts.map +1 -0
- package/dist/context-providers/types.js +10 -0
- package/dist/context-providers/types.js.map +1 -0
- package/dist/context-providers/url.d.ts +27 -0
- package/dist/context-providers/url.d.ts.map +1 -0
- package/dist/context-providers/url.js +131 -0
- package/dist/context-providers/url.js.map +1 -0
- package/dist/effort/index.d.ts +78 -0
- package/dist/effort/index.d.ts.map +1 -0
- package/dist/effort/index.js +146 -0
- package/dist/effort/index.js.map +1 -0
- package/dist/hooks/index.d.ts +47 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +151 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +152 -0
- package/dist/index.js.map +1 -0
- package/dist/indexing/chunker.d.ts +25 -0
- package/dist/indexing/chunker.d.ts.map +1 -0
- package/dist/indexing/chunker.js +217 -0
- package/dist/indexing/chunker.js.map +1 -0
- package/dist/indexing/database.d.ts +49 -0
- package/dist/indexing/database.d.ts.map +1 -0
- package/dist/indexing/database.js +287 -0
- package/dist/indexing/database.js.map +1 -0
- package/dist/indexing/index.d.ts +9 -0
- package/dist/indexing/index.d.ts.map +1 -0
- package/dist/indexing/index.js +13 -0
- package/dist/indexing/index.js.map +1 -0
- package/dist/indexing/indexer.d.ts +63 -0
- package/dist/indexing/indexer.d.ts.map +1 -0
- package/dist/indexing/indexer.js +352 -0
- package/dist/indexing/indexer.js.map +1 -0
- package/dist/indexing/recent-edits-cache.d.ts +77 -0
- package/dist/indexing/recent-edits-cache.d.ts.map +1 -0
- package/dist/indexing/recent-edits-cache.js +123 -0
- package/dist/indexing/recent-edits-cache.js.map +1 -0
- package/dist/indexing/types.d.ts +39 -0
- package/dist/indexing/types.d.ts.map +1 -0
- package/dist/indexing/types.js +6 -0
- package/dist/indexing/types.js.map +1 -0
- package/dist/mcp/index.d.ts +33 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +37 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/manager.d.ts +123 -0
- package/dist/mcp/manager.d.ts.map +1 -0
- package/dist/mcp/manager.js +331 -0
- package/dist/mcp/manager.js.map +1 -0
- package/dist/oauth.d.ts +33 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +312 -0
- package/dist/oauth.js.map +1 -0
- package/dist/permissions/index.d.ts +216 -0
- package/dist/permissions/index.d.ts.map +1 -0
- package/dist/permissions/index.js +938 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/plan/index.d.ts +20 -0
- package/dist/plan/index.d.ts.map +1 -0
- package/dist/plan/index.js +24 -0
- package/dist/plan/index.js.map +1 -0
- package/dist/plan/manager.d.ts +101 -0
- package/dist/plan/manager.d.ts.map +1 -0
- package/dist/plan/manager.js +170 -0
- package/dist/plan/manager.js.map +1 -0
- package/dist/rules/index.d.ts +28 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +31 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/manager.d.ts +77 -0
- package/dist/rules/manager.d.ts.map +1 -0
- package/dist/rules/manager.js +279 -0
- package/dist/rules/manager.js.map +1 -0
- package/dist/rules/types.d.ts +34 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +9 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/sandbox/filesystem.d.ts +20 -0
- package/dist/sandbox/filesystem.d.ts.map +1 -0
- package/dist/sandbox/filesystem.js +141 -0
- package/dist/sandbox/filesystem.js.map +1 -0
- package/dist/sandbox/index.d.ts +4 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +8 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/manager.d.ts +47 -0
- package/dist/sandbox/manager.d.ts.map +1 -0
- package/dist/sandbox/manager.js +220 -0
- package/dist/sandbox/manager.js.map +1 -0
- package/dist/sandbox/network.d.ts +14 -0
- package/dist/sandbox/network.d.ts.map +1 -0
- package/dist/sandbox/network.js +87 -0
- package/dist/sandbox/network.js.map +1 -0
- package/dist/sandbox/types.d.ts +42 -0
- package/dist/sandbox/types.d.ts.map +1 -0
- package/dist/sandbox/types.js +25 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/tools/ast-edit.d.ts +57 -0
- package/dist/tools/ast-edit.d.ts.map +1 -0
- package/dist/tools/ast-edit.js +443 -0
- package/dist/tools/ast-edit.js.map +1 -0
- package/dist/tools/code-verify.d.ts +8 -0
- package/dist/tools/code-verify.d.ts.map +1 -0
- package/dist/tools/code-verify.js +159 -0
- package/dist/tools/code-verify.js.map +1 -0
- package/dist/tools/codebase-search.d.ts +17 -0
- package/dist/tools/codebase-search.d.ts.map +1 -0
- package/dist/tools/codebase-search.js +104 -0
- package/dist/tools/codebase-search.js.map +1 -0
- package/dist/tools/file-delete.d.ts +26 -0
- package/dist/tools/file-delete.d.ts.map +1 -0
- package/dist/tools/file-delete.js +179 -0
- package/dist/tools/file-delete.js.map +1 -0
- package/dist/tools/file-edit.d.ts +10 -0
- package/dist/tools/file-edit.d.ts.map +1 -0
- package/dist/tools/file-edit.js +138 -0
- package/dist/tools/file-edit.js.map +1 -0
- package/dist/tools/file-read.d.ts +12 -0
- package/dist/tools/file-read.d.ts.map +1 -0
- package/dist/tools/file-read.js +211 -0
- package/dist/tools/file-read.js.map +1 -0
- package/dist/tools/file-run.d.ts +10 -0
- package/dist/tools/file-run.d.ts.map +1 -0
- package/dist/tools/file-run.js +179 -0
- package/dist/tools/file-run.js.map +1 -0
- package/dist/tools/file-write.d.ts +10 -0
- package/dist/tools/file-write.d.ts.map +1 -0
- package/dist/tools/file-write.js +134 -0
- package/dist/tools/file-write.js.map +1 -0
- package/dist/tools/glob-search.d.ts +8 -0
- package/dist/tools/glob-search.d.ts.map +1 -0
- package/dist/tools/glob-search.js +108 -0
- package/dist/tools/glob-search.js.map +1 -0
- package/dist/tools/grep-search.d.ts +8 -0
- package/dist/tools/grep-search.d.ts.map +1 -0
- package/dist/tools/grep-search.js +139 -0
- package/dist/tools/grep-search.js.map +1 -0
- package/dist/tools/list-dir.d.ts +16 -0
- package/dist/tools/list-dir.d.ts.map +1 -0
- package/dist/tools/list-dir.js +183 -0
- package/dist/tools/list-dir.js.map +1 -0
- package/dist/tools/multi-edit.d.ts +16 -0
- package/dist/tools/multi-edit.d.ts.map +1 -0
- package/dist/tools/multi-edit.js +163 -0
- package/dist/tools/multi-edit.js.map +1 -0
- package/dist/tools/notebook-edit.d.ts +31 -0
- package/dist/tools/notebook-edit.d.ts.map +1 -0
- package/dist/tools/notebook-edit.js +321 -0
- package/dist/tools/notebook-edit.js.map +1 -0
- package/dist/tools/registry.d.ts +16 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +41 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/shell-exec.d.ts +12 -0
- package/dist/tools/shell-exec.d.ts.map +1 -0
- package/dist/tools/shell-exec.js +261 -0
- package/dist/tools/shell-exec.js.map +1 -0
- package/dist/tools/sub-agent-manager.d.ts +57 -0
- package/dist/tools/sub-agent-manager.d.ts.map +1 -0
- package/dist/tools/sub-agent-manager.js +153 -0
- package/dist/tools/sub-agent-manager.js.map +1 -0
- package/dist/tools/sub-agent-status.d.ts +12 -0
- package/dist/tools/sub-agent-status.d.ts.map +1 -0
- package/dist/tools/sub-agent-status.js +59 -0
- package/dist/tools/sub-agent-status.js.map +1 -0
- package/dist/tools/sub-agent-terminate.d.ts +12 -0
- package/dist/tools/sub-agent-terminate.d.ts.map +1 -0
- package/dist/tools/sub-agent-terminate.js +55 -0
- package/dist/tools/sub-agent-terminate.js.map +1 -0
- package/dist/tools/sub-agent.d.ts +34 -0
- package/dist/tools/sub-agent.d.ts.map +1 -0
- package/dist/tools/sub-agent.js +140 -0
- package/dist/tools/sub-agent.js.map +1 -0
- package/dist/tools/system-info.d.ts +24 -0
- package/dist/tools/system-info.d.ts.map +1 -0
- package/dist/tools/system-info.js +220 -0
- package/dist/tools/system-info.js.map +1 -0
- package/dist/tools/todo.d.ts +16 -0
- package/dist/tools/todo.d.ts.map +1 -0
- package/dist/tools/todo.js +144 -0
- package/dist/tools/todo.js.map +1 -0
- package/dist/tools/types.d.ts +20 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +3 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/view-diff.d.ts +11 -0
- package/dist/tools/view-diff.d.ts.map +1 -0
- package/dist/tools/view-diff.js +88 -0
- package/dist/tools/view-diff.js.map +1 -0
- package/dist/tools/view-repo-map.d.ts +18 -0
- package/dist/tools/view-repo-map.d.ts.map +1 -0
- package/dist/tools/view-repo-map.js +245 -0
- package/dist/tools/view-repo-map.js.map +1 -0
- package/dist/tools/web-fetch.d.ts +13 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +106 -0
- package/dist/tools/web-fetch.js.map +1 -0
- package/dist/tools/web-search.d.ts +10 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +106 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/utils/gitignore.d.ts +10 -0
- package/dist/utils/gitignore.d.ts.map +1 -0
- package/dist/utils/gitignore.js +104 -0
- package/dist/utils/gitignore.js.map +1 -0
- package/dist/utils/lazy-apply.d.ts +45 -0
- package/dist/utils/lazy-apply.d.ts.map +1 -0
- package/dist/utils/lazy-apply.js +164 -0
- package/dist/utils/lazy-apply.js.map +1 -0
- package/dist/utils/memory.d.ts +36 -0
- package/dist/utils/memory.d.ts.map +1 -0
- package/dist/utils/memory.js +136 -0
- package/dist/utils/memory.js.map +1 -0
- package/dist/utils/path-matching.d.ts +24 -0
- package/dist/utils/path-matching.d.ts.map +1 -0
- package/dist/utils/path-matching.js +116 -0
- package/dist/utils/path-matching.js.map +1 -0
- package/dist/utils/path-safety.d.ts +13 -0
- package/dist/utils/path-safety.d.ts.map +1 -0
- package/dist/utils/path-safety.js +54 -0
- package/dist/utils/path-safety.js.map +1 -0
- package/dist/utils/project-config.d.ts +18 -0
- package/dist/utils/project-config.d.ts.map +1 -0
- package/dist/utils/project-config.js +76 -0
- package/dist/utils/project-config.js.map +1 -0
- package/dist/utils/search-match.d.ts +63 -0
- package/dist/utils/search-match.d.ts.map +1 -0
- package/dist/utils/search-match.js +426 -0
- package/dist/utils/search-match.js.map +1 -0
- package/dist/utils/shell-paths.d.ts +17 -0
- package/dist/utils/shell-paths.d.ts.map +1 -0
- package/dist/utils/shell-paths.js +107 -0
- package/dist/utils/shell-paths.js.map +1 -0
- package/dist/utils/streaming-diff.d.ts +45 -0
- package/dist/utils/streaming-diff.d.ts.map +1 -0
- package/dist/utils/streaming-diff.js +230 -0
- package/dist/utils/streaming-diff.js.map +1 -0
- package/dist/utils/todo.d.ts +47 -0
- package/dist/utils/todo.d.ts.map +1 -0
- package/dist/utils/todo.js +102 -0
- package/dist/utils/todo.js.map +1 -0
- package/package.json +23 -0
- package/src/agents/coordinator.ts +240 -0
- package/src/context-providers/clipboard.ts +48 -0
- package/src/context-providers/codebase.ts +274 -0
- package/src/context-providers/diff.ts +66 -0
- package/src/context-providers/docs.ts +160 -0
- package/src/context-providers/file-include.ts +54 -0
- package/src/context-providers/folder.ts +106 -0
- package/src/context-providers/git.ts +72 -0
- package/src/context-providers/index.ts +26 -0
- package/src/context-providers/open-files.ts +113 -0
- package/src/context-providers/problems.ts +100 -0
- package/src/context-providers/registry.ts +99 -0
- package/src/context-providers/terminal.ts +58 -0
- package/src/context-providers/tree.ts +161 -0
- package/src/context-providers/types.ts +84 -0
- package/src/context-providers/url.ts +138 -0
- package/src/effort/index.ts +177 -0
- package/src/hooks/index.ts +148 -0
- package/src/index.ts +114 -0
- package/src/indexing/README.md +267 -0
- package/src/indexing/chunker.ts +206 -0
- package/src/indexing/database.ts +299 -0
- package/src/indexing/index.ts +15 -0
- package/src/indexing/indexer.ts +383 -0
- package/src/indexing/recent-edits-cache.ts +150 -0
- package/src/indexing/types.ts +44 -0
- package/src/mcp/index.ts +33 -0
- package/src/mcp/manager.ts +385 -0
- package/src/oauth.ts +330 -0
- package/src/permissions/index.ts +1011 -0
- package/src/plan/index.ts +20 -0
- package/src/plan/manager.ts +233 -0
- package/src/rules/index.ts +28 -0
- package/src/rules/manager.ts +276 -0
- package/src/rules/types.ts +40 -0
- package/src/sandbox/filesystem.ts +135 -0
- package/src/sandbox/index.ts +9 -0
- package/src/sandbox/manager.ts +213 -0
- package/src/sandbox/network.ts +101 -0
- package/src/sandbox/types.ts +63 -0
- package/src/tools/ast-edit.ts +493 -0
- package/src/tools/code-verify.ts +143 -0
- package/src/tools/codebase-search.ts +117 -0
- package/src/tools/file-delete.ts +155 -0
- package/src/tools/file-edit.ts +115 -0
- package/src/tools/file-read.ts +195 -0
- package/src/tools/file-run.ts +158 -0
- package/src/tools/file-write.ts +104 -0
- package/src/tools/glob-search.ts +80 -0
- package/src/tools/grep-search.ts +120 -0
- package/src/tools/list-dir.ts +172 -0
- package/src/tools/multi-edit.ts +138 -0
- package/src/tools/notebook-edit.ts +342 -0
- package/src/tools/registry.ts +43 -0
- package/src/tools/shell-exec.ts +251 -0
- package/src/tools/sub-agent-manager.ts +183 -0
- package/src/tools/sub-agent-status.ts +67 -0
- package/src/tools/sub-agent-terminate.ts +62 -0
- package/src/tools/sub-agent.ts +162 -0
- package/src/tools/system-info.ts +248 -0
- package/src/tools/todo.ts +149 -0
- package/src/tools/types.ts +21 -0
- package/src/tools/view-diff.ts +99 -0
- package/src/tools/view-repo-map.ts +249 -0
- package/src/tools/web-fetch.ts +118 -0
- package/src/tools/web-search.ts +129 -0
- package/src/utils/gitignore.ts +73 -0
- package/src/utils/lazy-apply.ts +189 -0
- package/src/utils/memory.ts +124 -0
- package/src/utils/path-matching.ts +84 -0
- package/src/utils/path-safety.ts +19 -0
- package/src/utils/project-config.ts +41 -0
- package/src/utils/search-match.ts +495 -0
- package/src/utils/shell-paths.ts +79 -0
- package/src/utils/streaming-diff.ts +260 -0
- package/src/utils/todo.ts +115 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { exec } from "child_process";
|
|
2
|
+
import * as os from "os";
|
|
3
|
+
import type { BaseTool, ToolDefinition, ToolResult } from "./types";
|
|
4
|
+
import type { SandboxManager } from "../sandbox";
|
|
5
|
+
import type { PermissionManager } from "../permissions";
|
|
6
|
+
import { extractShellPaths } from "../utils/shell-paths";
|
|
7
|
+
|
|
8
|
+
const IS_WINDOWS = os.platform() === "win32";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get the shell command and args for the current platform.
|
|
12
|
+
* - Windows: PowerShell (more capable than cmd.exe)
|
|
13
|
+
* - macOS: user's shell with login flag (loads .zshrc/.bashrc for PATH, nvm, pyenv, etc.)
|
|
14
|
+
* - Linux: user's shell with login flag
|
|
15
|
+
*/
|
|
16
|
+
function getShellCommand(command: string): { shell: string; args: string[] } {
|
|
17
|
+
if (IS_WINDOWS) {
|
|
18
|
+
return {
|
|
19
|
+
shell: "powershell.exe",
|
|
20
|
+
args: ["-NoLogo", "-ExecutionPolicy", "Bypass", "-Command", command],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const userShell = process.env.SHELL || (os.platform() === "darwin" ? "/bin/zsh" : "/bin/bash");
|
|
24
|
+
return { shell: userShell, args: ["-l", "-c", command] };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** For exec() — the shell to use */
|
|
28
|
+
const SHELL = IS_WINDOWS ? "powershell.exe" : process.env.SHELL || "/bin/sh";
|
|
29
|
+
|
|
30
|
+
/** Color-supporting environment variables */
|
|
31
|
+
const COLOR_ENV = {
|
|
32
|
+
FORCE_COLOR: "1",
|
|
33
|
+
COLORTERM: "truecolor",
|
|
34
|
+
TERM: "xterm-256color",
|
|
35
|
+
CLICOLOR: "1",
|
|
36
|
+
CLICOLOR_FORCE: "1",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** Absolute danger — always blocked regardless of permissions */
|
|
40
|
+
const ALWAYS_BLOCKED = [
|
|
41
|
+
// Unix — catastrophic filesystem destruction
|
|
42
|
+
"rm -rf /",
|
|
43
|
+
"rm -rf ~",
|
|
44
|
+
"rm -rf /*",
|
|
45
|
+
"rm -rf ~/*",
|
|
46
|
+
"rm -rf $HOME",
|
|
47
|
+
"mkfs",
|
|
48
|
+
"dd if=",
|
|
49
|
+
":(){", // fork bomb
|
|
50
|
+
// Windows — catastrophic filesystem destruction
|
|
51
|
+
"rd /s /q C:\\",
|
|
52
|
+
"del /f /s /q C:\\",
|
|
53
|
+
"format C:",
|
|
54
|
+
"rd /s /q %systemroot%",
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
/** Destructive patterns for elevated permission message */
|
|
58
|
+
const DESTRUCTIVE_PATTERNS = [
|
|
59
|
+
// File deletion (Unix)
|
|
60
|
+
/\brm\s/, /\brm$/, /\brmdir\s/, /\bunlink\s/, /\bshred\s/,
|
|
61
|
+
// File deletion (Windows)
|
|
62
|
+
/\bdel\s/, /\brd\s/, /\berase\s/,
|
|
63
|
+
// Git destructive operations
|
|
64
|
+
/\bgit\s+clean\b/,
|
|
65
|
+
/\bgit\s+reset\s+--hard\b/,
|
|
66
|
+
/\bgit\s+push\s+.*--force\b/, /\bgit\s+push\s+-f\b/,
|
|
67
|
+
/\bgit\s+checkout\s+--\s/, /\bgit\s+restore\s/,
|
|
68
|
+
/\bgit\s+branch\s+-[dD]\b/,
|
|
69
|
+
/\bgit\s+rebase\b/,
|
|
70
|
+
/\bgit\s+stash\s+drop\b/,
|
|
71
|
+
// Process killing
|
|
72
|
+
/\bkill\s+-9\b/, /\bkillall\b/, /\bpkill\b/,
|
|
73
|
+
// Permission changes
|
|
74
|
+
/\bchmod\s+777\b/, /\bchmod\s+-R\b/, /\bchown\s+-R\b/,
|
|
75
|
+
// Database destructive (SQL injection risk via shell)
|
|
76
|
+
/\bDROP\s+(TABLE|DATABASE)\b/i, /\bTRUNCATE\s+TABLE\b/i, /\bDELETE\s+FROM\b/i,
|
|
77
|
+
// Disk/system
|
|
78
|
+
/\bdd\s/, /\bmv\s+\//, /\bsudo\s/,
|
|
79
|
+
// Docker destructive
|
|
80
|
+
/\bdocker\s+(rm|rmi|system\s+prune)\b/,
|
|
81
|
+
// npm/package destructive
|
|
82
|
+
/\bnpm\s+unpublish\b/,
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
export class ShellExecTool implements BaseTool {
|
|
87
|
+
definition: ToolDefinition = {
|
|
88
|
+
name: "shell_exec",
|
|
89
|
+
description:
|
|
90
|
+
`Execute a shell command and return its output. Use for builds, tests, git commands, etc. Requires user permission before execution.
|
|
91
|
+
|
|
92
|
+
All file paths in commands are checked against permission rules:
|
|
93
|
+
- Read paths (cat, less, grep, etc.) are checked against Read deny rules.
|
|
94
|
+
- Write paths (cp, mv, redirect >, tee, etc.) are checked against Edit deny rules.
|
|
95
|
+
- Delete paths (rm, rmdir, unlink, etc.) are checked against Delete deny rules.
|
|
96
|
+
- Destructive commands are flagged as high-risk in the permission prompt.
|
|
97
|
+
|
|
98
|
+
Commands are also subject to sandbox restrictions.`,
|
|
99
|
+
inputSchema: {
|
|
100
|
+
type: "object",
|
|
101
|
+
properties: {
|
|
102
|
+
command: { type: "string", description: "The shell command to execute" },
|
|
103
|
+
timeout: { type: "number", description: "Timeout in ms. Default: 120000" },
|
|
104
|
+
background: {
|
|
105
|
+
type: "boolean",
|
|
106
|
+
description: "Run in background. Returns immediately with PID. Use for servers/watchers. Default: false.",
|
|
107
|
+
},
|
|
108
|
+
env_vars: {
|
|
109
|
+
type: "object",
|
|
110
|
+
description: "Environment variables to set (e.g., {\"PORT\": \"3001\", \"DEBUG\": \"app:*\"})",
|
|
111
|
+
additionalProperties: { type: "string" },
|
|
112
|
+
},
|
|
113
|
+
debug: {
|
|
114
|
+
type: "boolean",
|
|
115
|
+
description: "Enable debug/verbose mode. Sets DEBUG=*, NODE_DEBUG=*, RUST_BACKTRACE=1, PYTHONTRACEBACK=1. Default: false",
|
|
116
|
+
},
|
|
117
|
+
dangerouslyDisableSandbox: {
|
|
118
|
+
type: "boolean",
|
|
119
|
+
description: "Set to true to run this command outside the sandbox. Requires permission approval.",
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
required: ["command"],
|
|
123
|
+
},
|
|
124
|
+
requiresPermission: true,
|
|
125
|
+
permissionMessage: (input) => {
|
|
126
|
+
const cmd = String(input.command || "");
|
|
127
|
+
if (DESTRUCTIVE_PATTERNS.some((p) => p.test(cmd))) {
|
|
128
|
+
return `⚠ DESTRUCTIVE command: ${cmd}`;
|
|
129
|
+
}
|
|
130
|
+
return `Run command: ${cmd}`;
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
private workingDir: string;
|
|
135
|
+
private sandboxManager?: SandboxManager;
|
|
136
|
+
private permissionManager?: PermissionManager;
|
|
137
|
+
|
|
138
|
+
constructor(workingDir: string, sandboxManager?: SandboxManager, permissionManager?: PermissionManager) {
|
|
139
|
+
this.workingDir = workingDir;
|
|
140
|
+
this.sandboxManager = sandboxManager;
|
|
141
|
+
this.permissionManager = permissionManager;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async execute(input: Record<string, unknown>): Promise<ToolResult> {
|
|
145
|
+
const command = input.command as string;
|
|
146
|
+
const timeout = (input.timeout as number) || 120000;
|
|
147
|
+
const dangerouslyDisableSandbox = (input.dangerouslyDisableSandbox as boolean) || false;
|
|
148
|
+
|
|
149
|
+
// Always-blocked patterns (catastrophic destruction)
|
|
150
|
+
for (const pat of ALWAYS_BLOCKED) {
|
|
151
|
+
if (command.includes(pat))
|
|
152
|
+
return { success: false, output: "", error: `Blocked dangerous pattern: ${pat}` };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ── Permission-based path checks ────────────────────────────────────────
|
|
156
|
+
if (this.permissionManager) {
|
|
157
|
+
const paths = extractShellPaths(command, this.workingDir);
|
|
158
|
+
|
|
159
|
+
// Check read paths against Read deny rules
|
|
160
|
+
for (const p of paths.read) {
|
|
161
|
+
const result = this.permissionManager.checkPathPermission(p, "Read");
|
|
162
|
+
if (result === "deny") {
|
|
163
|
+
return { success: false, output: "", error: `Permission denied: read access to "${p}" is blocked by settings rules` };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check write paths against Edit deny rules
|
|
168
|
+
for (const p of paths.write) {
|
|
169
|
+
const result = this.permissionManager.checkPathPermission(p, "Edit");
|
|
170
|
+
if (result === "deny") {
|
|
171
|
+
return { success: false, output: "", error: `Permission denied: write access to "${p}" is blocked by settings rules` };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Check delete paths against Delete deny rules
|
|
176
|
+
for (const p of paths.delete) {
|
|
177
|
+
const result = this.permissionManager.checkPathPermission(p, "Delete");
|
|
178
|
+
if (result === "deny") {
|
|
179
|
+
return { success: false, output: "", error: `Permission denied: delete access to "${p}" is blocked by settings rules` };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ── Sandbox checks ──────────────────────────────────────────────────────
|
|
185
|
+
if (this.sandboxManager) {
|
|
186
|
+
const check = this.sandboxManager.checkShellCommand(command, dangerouslyDisableSandbox);
|
|
187
|
+
if (!check.allowed) {
|
|
188
|
+
return { success: false, output: "", error: check.reason || "Sandbox: command blocked" };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Build environment
|
|
193
|
+
const env = this.sandboxManager ? this.sandboxManager.getShellEnv() : { ...process.env };
|
|
194
|
+
|
|
195
|
+
// Merge user-provided env vars
|
|
196
|
+
const envVars = input.env_vars as Record<string, string> | undefined;
|
|
197
|
+
if (envVars && typeof envVars === "object") {
|
|
198
|
+
for (const [key, val] of Object.entries(envVars)) {
|
|
199
|
+
env[key] = String(val);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Debug mode
|
|
204
|
+
if (input.debug) {
|
|
205
|
+
env.DEBUG = env.DEBUG || "*";
|
|
206
|
+
env.NODE_DEBUG = env.NODE_DEBUG || "*";
|
|
207
|
+
env.RUST_BACKTRACE = env.RUST_BACKTRACE || "1";
|
|
208
|
+
env.PYTHONTRACEBACK = env.PYTHONTRACEBACK || "1";
|
|
209
|
+
env.PYTHONFAULTHANDLER = env.PYTHONFAULTHANDLER || "1";
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const background = (input.background as boolean) || false;
|
|
213
|
+
|
|
214
|
+
// Merge color env for better terminal output
|
|
215
|
+
Object.assign(env, COLOR_ENV);
|
|
216
|
+
|
|
217
|
+
// Background mode: spawn detached, return immediately with PID
|
|
218
|
+
if (background) {
|
|
219
|
+
const { spawn } = require("child_process") as typeof import("child_process");
|
|
220
|
+
const { shell, args } = getShellCommand(command);
|
|
221
|
+
const child = spawn(shell, args, {
|
|
222
|
+
cwd: this.workingDir,
|
|
223
|
+
env,
|
|
224
|
+
detached: !IS_WINDOWS,
|
|
225
|
+
stdio: "ignore",
|
|
226
|
+
});
|
|
227
|
+
child.unref();
|
|
228
|
+
return { success: true, output: `Started in background (PID: ${child.pid})` };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return new Promise((resolve) => {
|
|
232
|
+
exec(command, { cwd: this.workingDir, timeout, maxBuffer: 10 * 1024 * 1024, env, shell: SHELL },
|
|
233
|
+
(error, stdout, stderr) => {
|
|
234
|
+
const outputParts: string[] = [];
|
|
235
|
+
if (stdout) outputParts.push(stdout.trimEnd());
|
|
236
|
+
if (stderr) outputParts.push(`STDERR:\n${stderr.trimEnd()}`);
|
|
237
|
+
const output = outputParts.join("\n\n") || "(no output)";
|
|
238
|
+
|
|
239
|
+
if (error?.killed) {
|
|
240
|
+
return resolve({ success: false, output, error: `Timed out after ${timeout}ms` });
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (error) {
|
|
244
|
+
resolve({ success: false, output, error: `Exit code: ${error.code}` });
|
|
245
|
+
} else {
|
|
246
|
+
resolve({ success: true, output });
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubAgentManager — Tracks all spawned sub-agents.
|
|
3
|
+
*
|
|
4
|
+
* Provides lifecycle management: spawn with custom timeout,
|
|
5
|
+
* check status/output, and terminate running agents.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type SubAgentStatus = "running" | "completed" | "failed" | "terminated" | "timed_out";
|
|
9
|
+
|
|
10
|
+
export interface SubAgentEntry {
|
|
11
|
+
id: string;
|
|
12
|
+
task: string;
|
|
13
|
+
status: SubAgentStatus;
|
|
14
|
+
output: string;
|
|
15
|
+
error?: string;
|
|
16
|
+
startedAt: number;
|
|
17
|
+
finishedAt?: number;
|
|
18
|
+
/** AbortController to cancel a running agent */
|
|
19
|
+
abort?: AbortController;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class SubAgentManager {
|
|
23
|
+
private agents: Map<string, SubAgentEntry> = new Map();
|
|
24
|
+
private idCounter = 0;
|
|
25
|
+
|
|
26
|
+
/** Generate a unique agent ID */
|
|
27
|
+
private nextId(): string {
|
|
28
|
+
this.idCounter++;
|
|
29
|
+
return `agent_${this.idCounter}_${Date.now().toString(36)}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Spawn a sub-agent. Runs in background — returns the ID immediately.
|
|
34
|
+
* The caller provides runnerFn which actually executes the agent.
|
|
35
|
+
*/
|
|
36
|
+
spawn(
|
|
37
|
+
task: string,
|
|
38
|
+
runnerFn: (signal: AbortSignal) => Promise<string>,
|
|
39
|
+
timeoutMs?: number,
|
|
40
|
+
): string {
|
|
41
|
+
const id = this.nextId();
|
|
42
|
+
const abort = new AbortController();
|
|
43
|
+
|
|
44
|
+
const entry: SubAgentEntry = {
|
|
45
|
+
id,
|
|
46
|
+
task,
|
|
47
|
+
status: "running",
|
|
48
|
+
output: "",
|
|
49
|
+
startedAt: Date.now(),
|
|
50
|
+
abort,
|
|
51
|
+
};
|
|
52
|
+
this.agents.set(id, entry);
|
|
53
|
+
|
|
54
|
+
// Set up timeout if requested
|
|
55
|
+
let timeoutHandle: ReturnType<typeof setTimeout> | undefined;
|
|
56
|
+
if (timeoutMs && timeoutMs > 0) {
|
|
57
|
+
timeoutHandle = setTimeout(() => {
|
|
58
|
+
if (entry.status === "running") {
|
|
59
|
+
entry.status = "timed_out";
|
|
60
|
+
entry.error = `Timed out after ${timeoutMs}ms`;
|
|
61
|
+
entry.finishedAt = Date.now();
|
|
62
|
+
abort.abort();
|
|
63
|
+
}
|
|
64
|
+
}, timeoutMs);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Run the agent in background
|
|
68
|
+
runnerFn(abort.signal)
|
|
69
|
+
.then((result) => {
|
|
70
|
+
if (entry.status === "running") {
|
|
71
|
+
entry.status = "completed";
|
|
72
|
+
entry.output = result;
|
|
73
|
+
entry.finishedAt = Date.now();
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
.catch((err) => {
|
|
77
|
+
if (entry.status === "running") {
|
|
78
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
79
|
+
if (msg === "__cancelled__" || abort.signal.aborted) {
|
|
80
|
+
// Only set terminated if not already timed_out
|
|
81
|
+
if (entry.status === "running") {
|
|
82
|
+
entry.status = "terminated";
|
|
83
|
+
entry.error = "Terminated by user";
|
|
84
|
+
entry.finishedAt = Date.now();
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
entry.status = "failed";
|
|
88
|
+
entry.error = msg;
|
|
89
|
+
entry.finishedAt = Date.now();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
.finally(() => {
|
|
94
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
95
|
+
delete entry.abort; // clean up reference
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return id;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Spawn and wait — runs synchronously (blocks until done or timeout).
|
|
103
|
+
* Used when the LLM does NOT request background mode.
|
|
104
|
+
*/
|
|
105
|
+
async spawnAndWait(
|
|
106
|
+
task: string,
|
|
107
|
+
runnerFn: (signal: AbortSignal) => Promise<string>,
|
|
108
|
+
timeoutMs?: number,
|
|
109
|
+
): Promise<SubAgentEntry> {
|
|
110
|
+
const id = this.spawn(task, runnerFn, timeoutMs);
|
|
111
|
+
const entry = this.agents.get(id)!;
|
|
112
|
+
|
|
113
|
+
// Poll until done (the promise is already running)
|
|
114
|
+
await new Promise<void>((resolve) => {
|
|
115
|
+
const check = () => {
|
|
116
|
+
if (entry.status !== "running") {
|
|
117
|
+
resolve();
|
|
118
|
+
} else {
|
|
119
|
+
setTimeout(check, 50);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
check();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return entry;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Get a specific agent's info */
|
|
129
|
+
get(id: string): SubAgentEntry | undefined {
|
|
130
|
+
return this.agents.get(id);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Get status of a specific agent */
|
|
134
|
+
getStatus(id: string): { id: string; status: SubAgentStatus; task: string; output: string; error?: string; durationMs?: number } | null {
|
|
135
|
+
const entry = this.agents.get(id);
|
|
136
|
+
if (!entry) return null;
|
|
137
|
+
|
|
138
|
+
const durationMs = entry.finishedAt
|
|
139
|
+
? entry.finishedAt - entry.startedAt
|
|
140
|
+
: Date.now() - entry.startedAt;
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
id: entry.id,
|
|
144
|
+
status: entry.status,
|
|
145
|
+
task: entry.task,
|
|
146
|
+
output: entry.output,
|
|
147
|
+
error: entry.error,
|
|
148
|
+
durationMs,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** List all agents with their statuses */
|
|
153
|
+
listAll(): Array<{ id: string; task: string; status: SubAgentStatus; durationMs: number }> {
|
|
154
|
+
return Array.from(this.agents.values()).map((entry) => ({
|
|
155
|
+
id: entry.id,
|
|
156
|
+
task: entry.task,
|
|
157
|
+
status: entry.status,
|
|
158
|
+
durationMs: entry.finishedAt
|
|
159
|
+
? entry.finishedAt - entry.startedAt
|
|
160
|
+
: Date.now() - entry.startedAt,
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Terminate a running agent */
|
|
165
|
+
terminate(id: string): boolean {
|
|
166
|
+
const entry = this.agents.get(id);
|
|
167
|
+
if (!entry || entry.status !== "running") return false;
|
|
168
|
+
|
|
169
|
+
entry.status = "terminated";
|
|
170
|
+
entry.error = "Terminated by user";
|
|
171
|
+
entry.finishedAt = Date.now();
|
|
172
|
+
if (entry.abort) {
|
|
173
|
+
entry.abort.abort();
|
|
174
|
+
delete entry.abort;
|
|
175
|
+
}
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Check if any agents are still running */
|
|
180
|
+
hasRunning(): boolean {
|
|
181
|
+
return Array.from(this.agents.values()).some((e) => e.status === "running");
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sub-Agent Status Tool — check status and output of spawned sub-agents.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { BaseTool, ToolDefinition, ToolResult } from "./types";
|
|
6
|
+
import type { SubAgentManager } from "./sub-agent-manager";
|
|
7
|
+
|
|
8
|
+
export class SubAgentStatusTool implements BaseTool {
|
|
9
|
+
definition: ToolDefinition = {
|
|
10
|
+
name: "sub_agent_status",
|
|
11
|
+
description:
|
|
12
|
+
"Check the status and output of a background sub-agent by its ID, or list all sub-agents. Use this to poll for completion of background sub-agents.",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: {
|
|
16
|
+
agent_id: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description:
|
|
19
|
+
"The ID of the sub-agent to check. Omit to list all sub-agents.",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
required: [],
|
|
23
|
+
},
|
|
24
|
+
requiresPermission: false,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
private manager: SubAgentManager;
|
|
28
|
+
|
|
29
|
+
constructor(manager: SubAgentManager) {
|
|
30
|
+
this.manager = manager;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async execute(input: Record<string, unknown>): Promise<ToolResult> {
|
|
34
|
+
const agentId = input.agent_id as string | undefined;
|
|
35
|
+
|
|
36
|
+
if (agentId) {
|
|
37
|
+
// Get specific agent status
|
|
38
|
+
const status = this.manager.getStatus(agentId);
|
|
39
|
+
if (!status) {
|
|
40
|
+
return {
|
|
41
|
+
success: false,
|
|
42
|
+
output: "",
|
|
43
|
+
error: `No sub-agent found with ID "${agentId}". Use sub_agent_status without an agent_id to list all agents.`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
success: true,
|
|
49
|
+
output: JSON.stringify(status, null, 2),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// List all agents
|
|
54
|
+
const all = this.manager.listAll();
|
|
55
|
+
if (all.length === 0) {
|
|
56
|
+
return {
|
|
57
|
+
success: true,
|
|
58
|
+
output: "No sub-agents have been spawned yet.",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
success: true,
|
|
64
|
+
output: JSON.stringify(all, null, 2),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sub-Agent Terminate Tool — stop a running sub-agent.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { BaseTool, ToolDefinition, ToolResult } from "./types";
|
|
6
|
+
import type { SubAgentManager } from "./sub-agent-manager";
|
|
7
|
+
|
|
8
|
+
export class SubAgentTerminateTool implements BaseTool {
|
|
9
|
+
definition: ToolDefinition = {
|
|
10
|
+
name: "sub_agent_terminate",
|
|
11
|
+
description:
|
|
12
|
+
"Terminate a running sub-agent by its ID. Use this to stop a long-running or stuck background sub-agent.",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: {
|
|
16
|
+
agent_id: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "The ID of the sub-agent to terminate",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
required: ["agent_id"],
|
|
22
|
+
},
|
|
23
|
+
requiresPermission: false,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
private manager: SubAgentManager;
|
|
27
|
+
|
|
28
|
+
constructor(manager: SubAgentManager) {
|
|
29
|
+
this.manager = manager;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async execute(input: Record<string, unknown>): Promise<ToolResult> {
|
|
33
|
+
const agentId = input.agent_id as string;
|
|
34
|
+
|
|
35
|
+
if (!agentId) {
|
|
36
|
+
return { success: false, output: "", error: "agent_id is required" };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const terminated = this.manager.terminate(agentId);
|
|
40
|
+
|
|
41
|
+
if (!terminated) {
|
|
42
|
+
const status = this.manager.getStatus(agentId);
|
|
43
|
+
if (!status) {
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
output: "",
|
|
47
|
+
error: `No sub-agent found with ID "${agentId}".`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
output: "",
|
|
53
|
+
error: `Sub-agent "${agentId}" is not running (status: ${status.status}). Only running agents can be terminated.`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
success: true,
|
|
59
|
+
output: `Sub-agent "${agentId}" has been terminated.`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|