whale-code 6.4.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/README.md +95 -0
- package/bin/swag-agent.js +9 -0
- package/bin/swagmanager-mcp.js +321 -0
- package/dist/cli/app.d.ts +26 -0
- package/dist/cli/app.js +64 -0
- package/dist/cli/chat/AgentSelector.d.ts +14 -0
- package/dist/cli/chat/AgentSelector.js +14 -0
- package/dist/cli/chat/ChatApp.d.ts +9 -0
- package/dist/cli/chat/ChatApp.js +267 -0
- package/dist/cli/chat/ChatInput.d.ts +39 -0
- package/dist/cli/chat/ChatInput.js +509 -0
- package/dist/cli/chat/MarkdownText.d.ts +10 -0
- package/dist/cli/chat/MarkdownText.js +20 -0
- package/dist/cli/chat/MessageList.d.ts +37 -0
- package/dist/cli/chat/MessageList.js +80 -0
- package/dist/cli/chat/ModelSelector.d.ts +20 -0
- package/dist/cli/chat/ModelSelector.js +73 -0
- package/dist/cli/chat/RewindViewer.d.ts +26 -0
- package/dist/cli/chat/RewindViewer.js +185 -0
- package/dist/cli/chat/StoreSelector.d.ts +14 -0
- package/dist/cli/chat/StoreSelector.js +24 -0
- package/dist/cli/chat/StreamingText.d.ts +12 -0
- package/dist/cli/chat/StreamingText.js +12 -0
- package/dist/cli/chat/SubagentPanel.d.ts +45 -0
- package/dist/cli/chat/SubagentPanel.js +110 -0
- package/dist/cli/chat/TeamPanel.d.ts +21 -0
- package/dist/cli/chat/TeamPanel.js +42 -0
- package/dist/cli/chat/ToolIndicator.d.ts +25 -0
- package/dist/cli/chat/ToolIndicator.js +436 -0
- package/dist/cli/chat/hooks/useAgentLoop.d.ts +39 -0
- package/dist/cli/chat/hooks/useAgentLoop.js +382 -0
- package/dist/cli/chat/hooks/useSlashCommands.d.ts +37 -0
- package/dist/cli/chat/hooks/useSlashCommands.js +387 -0
- package/dist/cli/commands/config-cmd.d.ts +10 -0
- package/dist/cli/commands/config-cmd.js +99 -0
- package/dist/cli/commands/doctor.d.ts +14 -0
- package/dist/cli/commands/doctor.js +172 -0
- package/dist/cli/commands/init.d.ts +16 -0
- package/dist/cli/commands/init.js +278 -0
- package/dist/cli/commands/mcp.d.ts +12 -0
- package/dist/cli/commands/mcp.js +162 -0
- package/dist/cli/login/LoginApp.d.ts +7 -0
- package/dist/cli/login/LoginApp.js +157 -0
- package/dist/cli/print-mode.d.ts +31 -0
- package/dist/cli/print-mode.js +202 -0
- package/dist/cli/serve-mode.d.ts +37 -0
- package/dist/cli/serve-mode.js +636 -0
- package/dist/cli/services/agent-definitions.d.ts +25 -0
- package/dist/cli/services/agent-definitions.js +91 -0
- package/dist/cli/services/agent-events.d.ts +178 -0
- package/dist/cli/services/agent-events.js +175 -0
- package/dist/cli/services/agent-loop.d.ts +90 -0
- package/dist/cli/services/agent-loop.js +762 -0
- package/dist/cli/services/agent-worker-base.d.ts +97 -0
- package/dist/cli/services/agent-worker-base.js +220 -0
- package/dist/cli/services/auth-service.d.ts +30 -0
- package/dist/cli/services/auth-service.js +160 -0
- package/dist/cli/services/background-processes.d.ts +126 -0
- package/dist/cli/services/background-processes.js +318 -0
- package/dist/cli/services/browser-auth.d.ts +24 -0
- package/dist/cli/services/browser-auth.js +180 -0
- package/dist/cli/services/claude-md-loader.d.ts +16 -0
- package/dist/cli/services/claude-md-loader.js +58 -0
- package/dist/cli/services/config-store.d.ts +47 -0
- package/dist/cli/services/config-store.js +79 -0
- package/dist/cli/services/debug-log.d.ts +10 -0
- package/dist/cli/services/debug-log.js +52 -0
- package/dist/cli/services/error-logger.d.ts +58 -0
- package/dist/cli/services/error-logger.js +269 -0
- package/dist/cli/services/file-history.d.ts +21 -0
- package/dist/cli/services/file-history.js +83 -0
- package/dist/cli/services/format-server-response.d.ts +16 -0
- package/dist/cli/services/format-server-response.js +440 -0
- package/dist/cli/services/git-context.d.ts +11 -0
- package/dist/cli/services/git-context.js +66 -0
- package/dist/cli/services/hooks.d.ts +85 -0
- package/dist/cli/services/hooks.js +258 -0
- package/dist/cli/services/interactive-tools.d.ts +125 -0
- package/dist/cli/services/interactive-tools.js +260 -0
- package/dist/cli/services/keybinding-manager.d.ts +52 -0
- package/dist/cli/services/keybinding-manager.js +115 -0
- package/dist/cli/services/local-tools.d.ts +22 -0
- package/dist/cli/services/local-tools.js +697 -0
- package/dist/cli/services/lsp-manager.d.ts +18 -0
- package/dist/cli/services/lsp-manager.js +717 -0
- package/dist/cli/services/mcp-client.d.ts +48 -0
- package/dist/cli/services/mcp-client.js +157 -0
- package/dist/cli/services/memory-manager.d.ts +16 -0
- package/dist/cli/services/memory-manager.js +57 -0
- package/dist/cli/services/model-manager.d.ts +18 -0
- package/dist/cli/services/model-manager.js +71 -0
- package/dist/cli/services/model-router.d.ts +26 -0
- package/dist/cli/services/model-router.js +149 -0
- package/dist/cli/services/permission-modes.d.ts +13 -0
- package/dist/cli/services/permission-modes.js +43 -0
- package/dist/cli/services/rewind.d.ts +84 -0
- package/dist/cli/services/rewind.js +194 -0
- package/dist/cli/services/ripgrep.d.ts +28 -0
- package/dist/cli/services/ripgrep.js +138 -0
- package/dist/cli/services/sandbox.d.ts +29 -0
- package/dist/cli/services/sandbox.js +97 -0
- package/dist/cli/services/server-tools.d.ts +61 -0
- package/dist/cli/services/server-tools.js +543 -0
- package/dist/cli/services/session-persistence.d.ts +23 -0
- package/dist/cli/services/session-persistence.js +99 -0
- package/dist/cli/services/subagent-worker.d.ts +19 -0
- package/dist/cli/services/subagent-worker.js +41 -0
- package/dist/cli/services/subagent.d.ts +47 -0
- package/dist/cli/services/subagent.js +647 -0
- package/dist/cli/services/system-prompt.d.ts +7 -0
- package/dist/cli/services/system-prompt.js +198 -0
- package/dist/cli/services/team-lead.d.ts +73 -0
- package/dist/cli/services/team-lead.js +512 -0
- package/dist/cli/services/team-state.d.ts +77 -0
- package/dist/cli/services/team-state.js +398 -0
- package/dist/cli/services/teammate.d.ts +31 -0
- package/dist/cli/services/teammate.js +689 -0
- package/dist/cli/services/telemetry.d.ts +61 -0
- package/dist/cli/services/telemetry.js +209 -0
- package/dist/cli/services/tools/agent-tools.d.ts +14 -0
- package/dist/cli/services/tools/agent-tools.js +347 -0
- package/dist/cli/services/tools/file-ops.d.ts +15 -0
- package/dist/cli/services/tools/file-ops.js +487 -0
- package/dist/cli/services/tools/search-tools.d.ts +8 -0
- package/dist/cli/services/tools/search-tools.js +186 -0
- package/dist/cli/services/tools/shell-exec.d.ts +10 -0
- package/dist/cli/services/tools/shell-exec.js +168 -0
- package/dist/cli/services/tools/task-manager.d.ts +28 -0
- package/dist/cli/services/tools/task-manager.js +209 -0
- package/dist/cli/services/tools/web-tools.d.ts +11 -0
- package/dist/cli/services/tools/web-tools.js +395 -0
- package/dist/cli/setup/SetupApp.d.ts +9 -0
- package/dist/cli/setup/SetupApp.js +191 -0
- package/dist/cli/shared/MatrixIntro.d.ts +4 -0
- package/dist/cli/shared/MatrixIntro.js +83 -0
- package/dist/cli/shared/Theme.d.ts +74 -0
- package/dist/cli/shared/Theme.js +127 -0
- package/dist/cli/shared/WhaleBanner.d.ts +10 -0
- package/dist/cli/shared/WhaleBanner.js +12 -0
- package/dist/cli/shared/markdown.d.ts +21 -0
- package/dist/cli/shared/markdown.js +756 -0
- package/dist/cli/status/StatusApp.d.ts +4 -0
- package/dist/cli/status/StatusApp.js +105 -0
- package/dist/cli/stores/StoreApp.d.ts +7 -0
- package/dist/cli/stores/StoreApp.js +81 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +538 -0
- package/dist/local-agent/connection.d.ts +48 -0
- package/dist/local-agent/connection.js +332 -0
- package/dist/local-agent/discovery.d.ts +18 -0
- package/dist/local-agent/discovery.js +146 -0
- package/dist/local-agent/executor.d.ts +34 -0
- package/dist/local-agent/executor.js +241 -0
- package/dist/local-agent/index.d.ts +14 -0
- package/dist/local-agent/index.js +198 -0
- package/dist/node/adapters/base.d.ts +35 -0
- package/dist/node/adapters/base.js +10 -0
- package/dist/node/adapters/discord.d.ts +29 -0
- package/dist/node/adapters/discord.js +299 -0
- package/dist/node/adapters/email.d.ts +23 -0
- package/dist/node/adapters/email.js +218 -0
- package/dist/node/adapters/imessage.d.ts +17 -0
- package/dist/node/adapters/imessage.js +118 -0
- package/dist/node/adapters/slack.d.ts +26 -0
- package/dist/node/adapters/slack.js +259 -0
- package/dist/node/adapters/sms.d.ts +23 -0
- package/dist/node/adapters/sms.js +161 -0
- package/dist/node/adapters/telegram.d.ts +17 -0
- package/dist/node/adapters/telegram.js +101 -0
- package/dist/node/adapters/webchat.d.ts +27 -0
- package/dist/node/adapters/webchat.js +160 -0
- package/dist/node/adapters/whatsapp.d.ts +28 -0
- package/dist/node/adapters/whatsapp.js +230 -0
- package/dist/node/cli.d.ts +2 -0
- package/dist/node/cli.js +325 -0
- package/dist/node/config.d.ts +17 -0
- package/dist/node/config.js +31 -0
- package/dist/node/runtime.d.ts +50 -0
- package/dist/node/runtime.js +351 -0
- package/dist/server/handlers/__test-utils__/mock-supabase.d.ts +11 -0
- package/dist/server/handlers/__test-utils__/mock-supabase.js +393 -0
- package/dist/server/handlers/analytics.d.ts +17 -0
- package/dist/server/handlers/analytics.js +266 -0
- package/dist/server/handlers/api-keys.d.ts +6 -0
- package/dist/server/handlers/api-keys.js +221 -0
- package/dist/server/handlers/billing.d.ts +33 -0
- package/dist/server/handlers/billing.js +272 -0
- package/dist/server/handlers/browser.d.ts +10 -0
- package/dist/server/handlers/browser.js +517 -0
- package/dist/server/handlers/catalog.d.ts +99 -0
- package/dist/server/handlers/catalog.js +976 -0
- package/dist/server/handlers/comms.d.ts +254 -0
- package/dist/server/handlers/comms.js +588 -0
- package/dist/server/handlers/creations.d.ts +6 -0
- package/dist/server/handlers/creations.js +479 -0
- package/dist/server/handlers/crm.d.ts +89 -0
- package/dist/server/handlers/crm.js +538 -0
- package/dist/server/handlers/discovery.d.ts +6 -0
- package/dist/server/handlers/discovery.js +288 -0
- package/dist/server/handlers/embeddings.d.ts +92 -0
- package/dist/server/handlers/embeddings.js +197 -0
- package/dist/server/handlers/enrichment.d.ts +8 -0
- package/dist/server/handlers/enrichment.js +768 -0
- package/dist/server/handlers/image-gen.d.ts +6 -0
- package/dist/server/handlers/image-gen.js +409 -0
- package/dist/server/handlers/inventory.d.ts +319 -0
- package/dist/server/handlers/inventory.js +447 -0
- package/dist/server/handlers/kali.d.ts +10 -0
- package/dist/server/handlers/kali.js +210 -0
- package/dist/server/handlers/llm-providers.d.ts +6 -0
- package/dist/server/handlers/llm-providers.js +673 -0
- package/dist/server/handlers/local-agent.d.ts +6 -0
- package/dist/server/handlers/local-agent.js +118 -0
- package/dist/server/handlers/meta-ads.d.ts +111 -0
- package/dist/server/handlers/meta-ads.js +2279 -0
- package/dist/server/handlers/nodes.d.ts +33 -0
- package/dist/server/handlers/nodes.js +699 -0
- package/dist/server/handlers/operations.d.ts +138 -0
- package/dist/server/handlers/operations.js +131 -0
- package/dist/server/handlers/platform.d.ts +23 -0
- package/dist/server/handlers/platform.js +227 -0
- package/dist/server/handlers/supply-chain.d.ts +19 -0
- package/dist/server/handlers/supply-chain.js +327 -0
- package/dist/server/handlers/transcription.d.ts +17 -0
- package/dist/server/handlers/transcription.js +121 -0
- package/dist/server/handlers/video-gen.d.ts +6 -0
- package/dist/server/handlers/video-gen.js +466 -0
- package/dist/server/handlers/voice.d.ts +8 -0
- package/dist/server/handlers/voice.js +1146 -0
- package/dist/server/handlers/workflow-steps.d.ts +86 -0
- package/dist/server/handlers/workflow-steps.js +2349 -0
- package/dist/server/handlers/workflows.d.ts +7 -0
- package/dist/server/handlers/workflows.js +989 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +2427 -0
- package/dist/server/lib/batch-client.d.ts +80 -0
- package/dist/server/lib/batch-client.js +467 -0
- package/dist/server/lib/code-worker-pool.d.ts +31 -0
- package/dist/server/lib/code-worker-pool.js +224 -0
- package/dist/server/lib/code-worker.d.ts +1 -0
- package/dist/server/lib/code-worker.js +188 -0
- package/dist/server/lib/compaction-service.d.ts +32 -0
- package/dist/server/lib/compaction-service.js +162 -0
- package/dist/server/lib/logger.d.ts +19 -0
- package/dist/server/lib/logger.js +46 -0
- package/dist/server/lib/otel.d.ts +38 -0
- package/dist/server/lib/otel.js +126 -0
- package/dist/server/lib/pg-rate-limiter.d.ts +21 -0
- package/dist/server/lib/pg-rate-limiter.js +86 -0
- package/dist/server/lib/prompt-sanitizer.d.ts +37 -0
- package/dist/server/lib/prompt-sanitizer.js +177 -0
- package/dist/server/lib/provider-capabilities.d.ts +85 -0
- package/dist/server/lib/provider-capabilities.js +190 -0
- package/dist/server/lib/provider-failover.d.ts +74 -0
- package/dist/server/lib/provider-failover.js +210 -0
- package/dist/server/lib/rate-limiter.d.ts +39 -0
- package/dist/server/lib/rate-limiter.js +147 -0
- package/dist/server/lib/server-agent-loop.d.ts +107 -0
- package/dist/server/lib/server-agent-loop.js +667 -0
- package/dist/server/lib/server-subagent.d.ts +78 -0
- package/dist/server/lib/server-subagent.js +203 -0
- package/dist/server/lib/session-checkpoint.d.ts +51 -0
- package/dist/server/lib/session-checkpoint.js +145 -0
- package/dist/server/lib/ssrf-guard.d.ts +13 -0
- package/dist/server/lib/ssrf-guard.js +240 -0
- package/dist/server/lib/supabase-client.d.ts +7 -0
- package/dist/server/lib/supabase-client.js +78 -0
- package/dist/server/lib/template-resolver.d.ts +31 -0
- package/dist/server/lib/template-resolver.js +215 -0
- package/dist/server/lib/utils.d.ts +16 -0
- package/dist/server/lib/utils.js +147 -0
- package/dist/server/local-agent-gateway.d.ts +82 -0
- package/dist/server/local-agent-gateway.js +426 -0
- package/dist/server/providers/anthropic.d.ts +20 -0
- package/dist/server/providers/anthropic.js +199 -0
- package/dist/server/providers/bedrock.d.ts +20 -0
- package/dist/server/providers/bedrock.js +194 -0
- package/dist/server/providers/gemini.d.ts +24 -0
- package/dist/server/providers/gemini.js +486 -0
- package/dist/server/providers/openai.d.ts +24 -0
- package/dist/server/providers/openai.js +522 -0
- package/dist/server/providers/registry.d.ts +32 -0
- package/dist/server/providers/registry.js +58 -0
- package/dist/server/providers/shared.d.ts +32 -0
- package/dist/server/providers/shared.js +124 -0
- package/dist/server/providers/types.d.ts +92 -0
- package/dist/server/providers/types.js +12 -0
- package/dist/server/proxy-handlers.d.ts +6 -0
- package/dist/server/proxy-handlers.js +89 -0
- package/dist/server/tool-router.d.ts +149 -0
- package/dist/server/tool-router.js +803 -0
- package/dist/server/validation.d.ts +24 -0
- package/dist/server/validation.js +301 -0
- package/dist/server/worker.d.ts +19 -0
- package/dist/server/worker.js +201 -0
- package/dist/setup.d.ts +8 -0
- package/dist/setup.js +181 -0
- package/dist/shared/agent-core.d.ts +157 -0
- package/dist/shared/agent-core.js +534 -0
- package/dist/shared/anthropic-types.d.ts +105 -0
- package/dist/shared/anthropic-types.js +7 -0
- package/dist/shared/api-client.d.ts +90 -0
- package/dist/shared/api-client.js +379 -0
- package/dist/shared/constants.d.ts +33 -0
- package/dist/shared/constants.js +80 -0
- package/dist/shared/sse-parser.d.ts +26 -0
- package/dist/shared/sse-parser.js +259 -0
- package/dist/shared/tool-dispatch.d.ts +52 -0
- package/dist/shared/tool-dispatch.js +191 -0
- package/dist/shared/types.d.ts +72 -0
- package/dist/shared/types.js +7 -0
- package/dist/updater.d.ts +25 -0
- package/dist/updater.js +140 -0
- package/dist/webchat/widget.d.ts +0 -0
- package/dist/webchat/widget.js +397 -0
- package/package.json +95 -0
- package/src/cli/services/builtin-skills/commit.md +19 -0
- package/src/cli/services/builtin-skills/review-pr.md +21 -0
- package/src/cli/services/builtin-skills/review.md +18 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell Execution — run_command and background process tools
|
|
3
|
+
*
|
|
4
|
+
* Extracted from local-tools.ts for single-responsibility.
|
|
5
|
+
*/
|
|
6
|
+
import { ToolResult } from "../../../shared/types.js";
|
|
7
|
+
export declare function runCommand(input: Record<string, unknown>): Promise<ToolResult>;
|
|
8
|
+
export declare function bashOutput(input: Record<string, unknown>): ToolResult;
|
|
9
|
+
export declare function killShell(input: Record<string, unknown>): ToolResult;
|
|
10
|
+
export declare function listShellsFn(): ToolResult;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell Execution — run_command and background process tools
|
|
3
|
+
*
|
|
4
|
+
* Extracted from local-tools.ts for single-responsibility.
|
|
5
|
+
*/
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
import { spawn } from "child_process";
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import { spawnBackground, readProcessOutput, killProcess, listProcesses } from "../background-processes.js";
|
|
10
|
+
import { getGlobalEmitter } from "../agent-events.js";
|
|
11
|
+
import { sandboxCommand, cleanupSandbox } from "../sandbox.js";
|
|
12
|
+
import { debugLog } from "../debug-log.js";
|
|
13
|
+
function resolvePath(p) {
|
|
14
|
+
if (p.startsWith("~/"))
|
|
15
|
+
return join(homedir(), p.slice(2));
|
|
16
|
+
return p;
|
|
17
|
+
}
|
|
18
|
+
export async function runCommand(input) {
|
|
19
|
+
let command = input.command;
|
|
20
|
+
const cwd = input.working_directory ? resolvePath(input.working_directory) : undefined;
|
|
21
|
+
const timeout = Math.min(input.timeout || 30000, 300000);
|
|
22
|
+
const background = input.run_in_background;
|
|
23
|
+
const description = input.description;
|
|
24
|
+
debugLog("tools", `run_command: ${description || command.slice(0, 80)}`, { cwd, timeout, background });
|
|
25
|
+
// UX guardrail only — the sandbox (macOS) is the real security boundary.
|
|
26
|
+
// This catches obvious destructive commands before they reach the sandbox.
|
|
27
|
+
if (command.length > 10000) {
|
|
28
|
+
return { success: false, output: "Command too long (max 10000 chars)" };
|
|
29
|
+
}
|
|
30
|
+
const DANGEROUS_PATTERNS = [
|
|
31
|
+
/\brm\s+(-[a-z]*f[a-z]*\s+)?(-[a-z]*r[a-z]*\s+)?(\/|~)/i,
|
|
32
|
+
/\brm\s+(-[a-z]*r[a-z]*\s+)?(-[a-z]*f[a-z]*\s+)?(\/|~)/i,
|
|
33
|
+
/\bmkfs\b/i,
|
|
34
|
+
/\bdd\s+.*\bif=/i,
|
|
35
|
+
/>\s*\/dev\/sd/,
|
|
36
|
+
/:\(\)\s*\{.*\|.*&\s*\}\s*;/,
|
|
37
|
+
/\bchmod\s+(-[a-z]*R[a-z]*\s+)?777\s+\//i,
|
|
38
|
+
/\bchown\s+(-[a-z]*R[a-z]*\s+).*\//i,
|
|
39
|
+
/\bcurl\b.*\|\s*(ba)?sh\b/i,
|
|
40
|
+
/\bwget\b.*\|\s*(ba)?sh\b/i,
|
|
41
|
+
/\b(python|perl|ruby|node)\s+-e\s+.*\b(system|exec|spawn)\b/i,
|
|
42
|
+
/base64\s+(-d|--decode)\s*\|\s*(ba)?sh/i,
|
|
43
|
+
];
|
|
44
|
+
const command_lower = command.toLowerCase().replace(/\s+/g, " ");
|
|
45
|
+
if (DANGEROUS_PATTERNS.some((p) => p.test(command_lower))) {
|
|
46
|
+
return { success: false, output: "Command blocked for safety" };
|
|
47
|
+
}
|
|
48
|
+
// Apply sandbox wrapping (macOS only)
|
|
49
|
+
let sandboxProfilePath = null;
|
|
50
|
+
{
|
|
51
|
+
const effectiveCwd = cwd || process.cwd();
|
|
52
|
+
const sandboxResult = sandboxCommand(command, effectiveCwd);
|
|
53
|
+
command = sandboxResult.wrapped;
|
|
54
|
+
sandboxProfilePath = sandboxResult.profilePath;
|
|
55
|
+
}
|
|
56
|
+
// Background mode — spawn detached, validate, return with status
|
|
57
|
+
if (background) {
|
|
58
|
+
const result = await spawnBackground(command, { cwd, timeout: 600_000, description: input.description });
|
|
59
|
+
return { success: result.status === "running", output: result.message };
|
|
60
|
+
}
|
|
61
|
+
// Foreground async — spawn + stream output via events
|
|
62
|
+
return new Promise((resolve) => {
|
|
63
|
+
const stdout = [];
|
|
64
|
+
const stderr = [];
|
|
65
|
+
let killed = false;
|
|
66
|
+
const child = spawn(command, [], {
|
|
67
|
+
shell: true,
|
|
68
|
+
cwd,
|
|
69
|
+
env: { ...process.env, FORCE_COLOR: "0" },
|
|
70
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
71
|
+
});
|
|
72
|
+
const emitter = getGlobalEmitter();
|
|
73
|
+
child.stdout?.on("data", (data) => {
|
|
74
|
+
const text = data.toString();
|
|
75
|
+
stdout.push(text);
|
|
76
|
+
// Emit live output for UI streaming
|
|
77
|
+
for (const line of text.split("\n")) {
|
|
78
|
+
if (line.trim())
|
|
79
|
+
emitter.emitToolOutput("run_command", line);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
child.stderr?.on("data", (data) => {
|
|
83
|
+
const text = data.toString();
|
|
84
|
+
stderr.push(text);
|
|
85
|
+
for (const line of text.split("\n")) {
|
|
86
|
+
if (line.trim())
|
|
87
|
+
emitter.emitToolOutput("run_command", line);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// Timeout kill
|
|
91
|
+
const timer = setTimeout(() => {
|
|
92
|
+
if (!killed) {
|
|
93
|
+
killed = true;
|
|
94
|
+
child.kill("SIGTERM");
|
|
95
|
+
setTimeout(() => child.kill("SIGKILL"), 3000);
|
|
96
|
+
}
|
|
97
|
+
}, timeout);
|
|
98
|
+
child.on("exit", (code) => {
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
cleanupSandbox(sandboxProfilePath);
|
|
101
|
+
const output = stdout.join("") + (stderr.length > 0 ? "\n" + stderr.join("") : "");
|
|
102
|
+
if (killed) {
|
|
103
|
+
resolve({ success: false, output: `Command timed out after ${timeout}ms.\n${output}`.slice(0, 5000) });
|
|
104
|
+
}
|
|
105
|
+
else if (code === 0) {
|
|
106
|
+
let out = output || "(no output)";
|
|
107
|
+
if (out.length > 500_000) {
|
|
108
|
+
out = out.slice(0, 500_000) + `\n\n... (safety truncated — ${output.length.toLocaleString()} chars total)`;
|
|
109
|
+
}
|
|
110
|
+
resolve({ success: true, output: out });
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
resolve({ success: false, output: `Exit code ${code ?? "?"}:\n${output}`.slice(0, 5000) });
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
child.on("error", (err) => {
|
|
117
|
+
clearTimeout(timer);
|
|
118
|
+
cleanupSandbox(sandboxProfilePath);
|
|
119
|
+
resolve({ success: false, output: `Spawn error: ${err.message}` });
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
// Background tool handlers
|
|
124
|
+
export function bashOutput(input) {
|
|
125
|
+
const id = input.bash_id;
|
|
126
|
+
const filter = input.filter;
|
|
127
|
+
const result = readProcessOutput(id, { filter });
|
|
128
|
+
if ("error" in result)
|
|
129
|
+
return { success: false, output: result.error };
|
|
130
|
+
const statusIcon = result.status === "running" ? "\u25CF" : result.status === "completed" ? "\u2713" : "\u2715";
|
|
131
|
+
const statusColor = result.status === "running" ? "running" : result.status === "completed" ? "completed" : "failed";
|
|
132
|
+
const lines = [];
|
|
133
|
+
lines.push(`${statusIcon} Process ${id} — ${statusColor}`);
|
|
134
|
+
if (result.exitCode !== undefined)
|
|
135
|
+
lines.push(` Exit code: ${result.exitCode}`);
|
|
136
|
+
if (result.newOutput) {
|
|
137
|
+
lines.push(` Output:`);
|
|
138
|
+
lines.push(result.newOutput);
|
|
139
|
+
}
|
|
140
|
+
if (result.newErrors) {
|
|
141
|
+
lines.push(` Errors:`);
|
|
142
|
+
lines.push(result.newErrors);
|
|
143
|
+
}
|
|
144
|
+
if (!result.newOutput && !result.newErrors)
|
|
145
|
+
lines.push(" (no new output since last check)");
|
|
146
|
+
return { success: true, output: lines.join("\n") };
|
|
147
|
+
}
|
|
148
|
+
export function killShell(input) {
|
|
149
|
+
const id = (input.shell_id || input.bash_id);
|
|
150
|
+
const result = killProcess(id);
|
|
151
|
+
return { success: result.success, output: result.message };
|
|
152
|
+
}
|
|
153
|
+
export function listShellsFn() {
|
|
154
|
+
const procs = listProcesses();
|
|
155
|
+
if (procs.length === 0)
|
|
156
|
+
return { success: true, output: "No background processes." };
|
|
157
|
+
const lines = [`${procs.length} background process${procs.length !== 1 ? "es" : ""}:`, ""];
|
|
158
|
+
for (const p of procs) {
|
|
159
|
+
const icon = p.status === "running" ? "\u25CF" : p.status === "completed" ? "\u2713" : "\u2715";
|
|
160
|
+
lines.push(` ${icon} ${p.id} ${p.status} ${p.runtime}`);
|
|
161
|
+
lines.push(` ${p.command}`);
|
|
162
|
+
if (p.pid)
|
|
163
|
+
lines.push(` PID: ${p.pid}`);
|
|
164
|
+
lines.push(` stdout: ${p.outputLines} lines stderr: ${p.errorLines} lines`);
|
|
165
|
+
lines.push("");
|
|
166
|
+
}
|
|
167
|
+
return { success: true, output: lines.join("\n") };
|
|
168
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Manager — action-based CRUD task tracking with IDs and dependencies
|
|
3
|
+
*
|
|
4
|
+
* Extracted from local-tools.ts for single-responsibility.
|
|
5
|
+
* All consumers should import from local-tools.ts (re-export facade).
|
|
6
|
+
*/
|
|
7
|
+
interface TaskItem {
|
|
8
|
+
id: string;
|
|
9
|
+
subject: string;
|
|
10
|
+
description: string;
|
|
11
|
+
status: "pending" | "in_progress" | "completed";
|
|
12
|
+
activeForm?: string;
|
|
13
|
+
owner?: string;
|
|
14
|
+
metadata?: Record<string, unknown>;
|
|
15
|
+
blocks: string[];
|
|
16
|
+
blockedBy: string[];
|
|
17
|
+
createdAt: string;
|
|
18
|
+
}
|
|
19
|
+
import { ToolResult } from "../../../shared/types.js";
|
|
20
|
+
declare let taskState: TaskItem[];
|
|
21
|
+
export declare function tasksTool(input: Record<string, unknown>): ToolResult;
|
|
22
|
+
/** Load tasks from disk for a session */
|
|
23
|
+
export declare function loadTodos(sessionId: string): void;
|
|
24
|
+
/** Link tasks to a session for persistence */
|
|
25
|
+
export declare function setTodoSessionId(id: string): void;
|
|
26
|
+
/** Get current task state (for UI display) */
|
|
27
|
+
export declare function getTodoState(): typeof taskState;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Manager — action-based CRUD task tracking with IDs and dependencies
|
|
3
|
+
*
|
|
4
|
+
* Extracted from local-tools.ts for single-responsibility.
|
|
5
|
+
* All consumers should import from local-tools.ts (re-export facade).
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// STATE
|
|
12
|
+
// ============================================================================
|
|
13
|
+
let taskState = [];
|
|
14
|
+
let taskCounter = 0;
|
|
15
|
+
let todoSessionId = null;
|
|
16
|
+
const TODOS_DIR = join(homedir(), ".swagmanager", "todos");
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// TOOL IMPLEMENTATION
|
|
19
|
+
// ============================================================================
|
|
20
|
+
export function tasksTool(input) {
|
|
21
|
+
const action = input.action;
|
|
22
|
+
if (!action)
|
|
23
|
+
return { success: false, output: "action is required (create/update/list/get)" };
|
|
24
|
+
switch (action) {
|
|
25
|
+
case "create": {
|
|
26
|
+
const subject = input.subject;
|
|
27
|
+
const description = input.description;
|
|
28
|
+
if (!subject || !description)
|
|
29
|
+
return { success: false, output: "subject and description required for create" };
|
|
30
|
+
taskCounter++;
|
|
31
|
+
const task = {
|
|
32
|
+
id: String(taskCounter),
|
|
33
|
+
subject,
|
|
34
|
+
description,
|
|
35
|
+
status: "pending",
|
|
36
|
+
activeForm: input.activeForm,
|
|
37
|
+
owner: input.owner,
|
|
38
|
+
metadata: input.metadata,
|
|
39
|
+
blocks: [],
|
|
40
|
+
blockedBy: [],
|
|
41
|
+
createdAt: new Date().toISOString(),
|
|
42
|
+
};
|
|
43
|
+
taskState.push(task);
|
|
44
|
+
persistTasks();
|
|
45
|
+
return { success: true, output: `Created task #${task.id}: ${subject}` };
|
|
46
|
+
}
|
|
47
|
+
case "update": {
|
|
48
|
+
const taskId = input.taskId;
|
|
49
|
+
if (!taskId)
|
|
50
|
+
return { success: false, output: "taskId required for update" };
|
|
51
|
+
const task = taskState.find((t) => t.id === taskId);
|
|
52
|
+
if (!task)
|
|
53
|
+
return { success: false, output: `Task #${taskId} not found` };
|
|
54
|
+
const newStatus = input.status;
|
|
55
|
+
// Handle deletion
|
|
56
|
+
if (newStatus === "deleted") {
|
|
57
|
+
// Remove from other tasks' blocks/blockedBy
|
|
58
|
+
for (const t of taskState) {
|
|
59
|
+
t.blocks = t.blocks.filter((id) => id !== taskId);
|
|
60
|
+
t.blockedBy = t.blockedBy.filter((id) => id !== taskId);
|
|
61
|
+
}
|
|
62
|
+
taskState = taskState.filter((t) => t.id !== taskId);
|
|
63
|
+
persistTasks();
|
|
64
|
+
return { success: true, output: `Deleted task #${taskId}` };
|
|
65
|
+
}
|
|
66
|
+
if (newStatus && ["pending", "in_progress", "completed"].includes(newStatus)) {
|
|
67
|
+
task.status = newStatus;
|
|
68
|
+
}
|
|
69
|
+
if (input.subject_update)
|
|
70
|
+
task.subject = input.subject_update;
|
|
71
|
+
if (input.description !== undefined)
|
|
72
|
+
task.description = input.description;
|
|
73
|
+
if (input.activeForm !== undefined)
|
|
74
|
+
task.activeForm = input.activeForm;
|
|
75
|
+
if (input.owner !== undefined)
|
|
76
|
+
task.owner = input.owner;
|
|
77
|
+
if (input.metadata) {
|
|
78
|
+
task.metadata = { ...(task.metadata || {}), ...input.metadata };
|
|
79
|
+
// Remove null keys
|
|
80
|
+
for (const [k, v] of Object.entries(task.metadata)) {
|
|
81
|
+
if (v === null)
|
|
82
|
+
delete task.metadata[k];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Dependency management
|
|
86
|
+
const addBlocks = input.addBlocks;
|
|
87
|
+
const addBlockedBy = input.addBlockedBy;
|
|
88
|
+
if (addBlocks) {
|
|
89
|
+
for (const id of addBlocks) {
|
|
90
|
+
if (!task.blocks.includes(id))
|
|
91
|
+
task.blocks.push(id);
|
|
92
|
+
const target = taskState.find((t) => t.id === id);
|
|
93
|
+
if (target && !target.blockedBy.includes(taskId))
|
|
94
|
+
target.blockedBy.push(taskId);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (addBlockedBy) {
|
|
98
|
+
for (const id of addBlockedBy) {
|
|
99
|
+
if (!task.blockedBy.includes(id))
|
|
100
|
+
task.blockedBy.push(id);
|
|
101
|
+
const target = taskState.find((t) => t.id === id);
|
|
102
|
+
if (target && !target.blocks.includes(taskId))
|
|
103
|
+
target.blocks.push(taskId);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
persistTasks();
|
|
107
|
+
return { success: true, output: `Updated task #${taskId}: ${task.subject} [${task.status}]` };
|
|
108
|
+
}
|
|
109
|
+
case "list": {
|
|
110
|
+
if (taskState.length === 0)
|
|
111
|
+
return { success: true, output: "No tasks." };
|
|
112
|
+
const icon = { pending: "[ ]", in_progress: "[~]", completed: "[x]" };
|
|
113
|
+
const lines = taskState.map((t) => {
|
|
114
|
+
let line = `#${t.id}. ${icon[t.status] || "[ ]"} ${t.subject}`;
|
|
115
|
+
if (t.owner)
|
|
116
|
+
line += ` (${t.owner})`;
|
|
117
|
+
// Show only open blockers
|
|
118
|
+
const openBlockers = t.blockedBy.filter((id) => {
|
|
119
|
+
const blocker = taskState.find((b) => b.id === id);
|
|
120
|
+
return blocker && blocker.status !== "completed";
|
|
121
|
+
});
|
|
122
|
+
if (openBlockers.length > 0)
|
|
123
|
+
line += ` <- blocked by #${openBlockers.join(", #")}`;
|
|
124
|
+
return line;
|
|
125
|
+
});
|
|
126
|
+
const counts = {
|
|
127
|
+
pending: taskState.filter((t) => t.status === "pending").length,
|
|
128
|
+
in_progress: taskState.filter((t) => t.status === "in_progress").length,
|
|
129
|
+
completed: taskState.filter((t) => t.status === "completed").length,
|
|
130
|
+
};
|
|
131
|
+
return {
|
|
132
|
+
success: true,
|
|
133
|
+
output: `Tasks (${taskState.length}: ${counts.completed} done, ${counts.in_progress} active, ${counts.pending} pending):\n${lines.join("\n")}`,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
case "get": {
|
|
137
|
+
const taskId = input.taskId;
|
|
138
|
+
if (!taskId)
|
|
139
|
+
return { success: false, output: "taskId required for get" };
|
|
140
|
+
const task = taskState.find((t) => t.id === taskId);
|
|
141
|
+
if (!task)
|
|
142
|
+
return { success: false, output: `Task #${taskId} not found` };
|
|
143
|
+
const details = [
|
|
144
|
+
`# Task #${task.id}: ${task.subject}`,
|
|
145
|
+
`Status: ${task.status}`,
|
|
146
|
+
task.owner ? `Owner: ${task.owner}` : null,
|
|
147
|
+
task.activeForm ? `Active form: ${task.activeForm}` : null,
|
|
148
|
+
`Created: ${task.createdAt}`,
|
|
149
|
+
task.blocks.length ? `Blocks: #${task.blocks.join(", #")}` : null,
|
|
150
|
+
task.blockedBy.length ? `Blocked by: #${task.blockedBy.join(", #")}` : null,
|
|
151
|
+
task.metadata ? `Metadata: ${JSON.stringify(task.metadata)}` : null,
|
|
152
|
+
"",
|
|
153
|
+
task.description,
|
|
154
|
+
].filter(Boolean).join("\n");
|
|
155
|
+
return { success: true, output: details };
|
|
156
|
+
}
|
|
157
|
+
default:
|
|
158
|
+
return { success: false, output: `Unknown action: ${action}. Use create/update/list/get.` };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** Persist tasks to disk (fire-and-forget) */
|
|
162
|
+
function persistTasks() {
|
|
163
|
+
if (!todoSessionId)
|
|
164
|
+
return;
|
|
165
|
+
try {
|
|
166
|
+
if (!existsSync(TODOS_DIR))
|
|
167
|
+
mkdirSync(TODOS_DIR, { recursive: true });
|
|
168
|
+
writeFileSync(join(TODOS_DIR, `${todoSessionId}.json`), JSON.stringify({ tasks: taskState, counter: taskCounter }, null, 2), "utf-8");
|
|
169
|
+
}
|
|
170
|
+
catch { /* best effort */ }
|
|
171
|
+
}
|
|
172
|
+
/** Load tasks from disk for a session */
|
|
173
|
+
export function loadTodos(sessionId) {
|
|
174
|
+
const path = join(TODOS_DIR, `${sessionId}.json`);
|
|
175
|
+
if (!existsSync(path))
|
|
176
|
+
return;
|
|
177
|
+
try {
|
|
178
|
+
const raw = JSON.parse(readFileSync(path, "utf-8"));
|
|
179
|
+
// Support both old format (array) and new format ({tasks, counter})
|
|
180
|
+
if (Array.isArray(raw)) {
|
|
181
|
+
// Migrate old todo format
|
|
182
|
+
taskState = raw.map((t, i) => ({
|
|
183
|
+
id: t.id || String(i + 1),
|
|
184
|
+
subject: t.content || t.subject || "Untitled",
|
|
185
|
+
description: t.content || t.description || "",
|
|
186
|
+
status: t.status || "pending",
|
|
187
|
+
activeForm: t.activeForm,
|
|
188
|
+
blocks: t.blocks || [],
|
|
189
|
+
blockedBy: t.blockedBy || [],
|
|
190
|
+
createdAt: t.createdAt || new Date().toISOString(),
|
|
191
|
+
}));
|
|
192
|
+
taskCounter = taskState.length;
|
|
193
|
+
}
|
|
194
|
+
else if (raw.tasks) {
|
|
195
|
+
taskState = raw.tasks;
|
|
196
|
+
taskCounter = raw.counter || taskState.length;
|
|
197
|
+
}
|
|
198
|
+
todoSessionId = sessionId;
|
|
199
|
+
}
|
|
200
|
+
catch { /* skip corrupted */ }
|
|
201
|
+
}
|
|
202
|
+
/** Link tasks to a session for persistence */
|
|
203
|
+
export function setTodoSessionId(id) {
|
|
204
|
+
todoSessionId = id;
|
|
205
|
+
}
|
|
206
|
+
/** Get current task state (for UI display) */
|
|
207
|
+
export function getTodoState() {
|
|
208
|
+
return taskState;
|
|
209
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Tools — web_fetch and web_search implementations
|
|
3
|
+
*
|
|
4
|
+
* Extracted from local-tools.ts for single-responsibility.
|
|
5
|
+
*/
|
|
6
|
+
import { ToolResult } from "../../../shared/types.js";
|
|
7
|
+
export declare function isBlockedUrl(urlStr: string): boolean;
|
|
8
|
+
export declare function webFetch(input: Record<string, unknown>): Promise<ToolResult>;
|
|
9
|
+
/** Enhanced HTML -> readable text/markdown converter */
|
|
10
|
+
export declare function htmlToText(html: string): string;
|
|
11
|
+
export declare function webSearch(input: Record<string, unknown>): Promise<ToolResult>;
|