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,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Telemetry — fire-and-forget span logging to audit_logs
|
|
3
|
+
*
|
|
4
|
+
* Session-scoped conversationId + auto-incrementing turnNumber.
|
|
5
|
+
* Uses same column schema as executor.ts telemetry (trace_id, span_id, etc).
|
|
6
|
+
* Never blocks or crashes the chat.
|
|
7
|
+
*/
|
|
8
|
+
export interface ExecutionContext {
|
|
9
|
+
source: string;
|
|
10
|
+
userId?: string;
|
|
11
|
+
userEmail?: string;
|
|
12
|
+
traceId?: string;
|
|
13
|
+
spanId?: string;
|
|
14
|
+
parentSpanId?: string;
|
|
15
|
+
traceFlags?: number;
|
|
16
|
+
requestId?: string;
|
|
17
|
+
parentId?: string;
|
|
18
|
+
rowId?: string;
|
|
19
|
+
serviceName?: string;
|
|
20
|
+
serviceVersion?: string;
|
|
21
|
+
agentId?: string;
|
|
22
|
+
agentName?: string;
|
|
23
|
+
conversationId?: string;
|
|
24
|
+
turnNumber?: number;
|
|
25
|
+
model?: string;
|
|
26
|
+
inputTokens?: number;
|
|
27
|
+
outputTokens?: number;
|
|
28
|
+
totalCost?: number;
|
|
29
|
+
costBefore?: number;
|
|
30
|
+
turnCost?: number;
|
|
31
|
+
iteration?: number;
|
|
32
|
+
toolType?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Set the conversation ID (used by worker threads to share parent's conversation)
|
|
36
|
+
*/
|
|
37
|
+
export declare function setConversationId(id: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* Get the current conversation ID
|
|
40
|
+
*/
|
|
41
|
+
export declare function getConversationId(): string;
|
|
42
|
+
/**
|
|
43
|
+
* Initialize the telemetry client with a specific auth token.
|
|
44
|
+
* Used by worker threads that receive the token from the parent.
|
|
45
|
+
*/
|
|
46
|
+
export declare function initializeTelemetryClient(authToken: string): void;
|
|
47
|
+
export declare function generateTraceId(): string;
|
|
48
|
+
export declare function generateSpanId(): string;
|
|
49
|
+
export declare function nextTurn(): number;
|
|
50
|
+
export declare function createTurnContext(overrides?: Partial<ExecutionContext>): ExecutionContext;
|
|
51
|
+
export declare function getTurnNumber(): number;
|
|
52
|
+
export interface SpanOptions {
|
|
53
|
+
action: string;
|
|
54
|
+
severity?: "info" | "warn" | "error";
|
|
55
|
+
durationMs: number;
|
|
56
|
+
context: ExecutionContext;
|
|
57
|
+
storeId?: string;
|
|
58
|
+
error?: string;
|
|
59
|
+
details?: Record<string, unknown>;
|
|
60
|
+
}
|
|
61
|
+
export declare function logSpan(opts: SpanOptions): void;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Telemetry — fire-and-forget span logging to audit_logs
|
|
3
|
+
*
|
|
4
|
+
* Session-scoped conversationId + auto-incrementing turnNumber.
|
|
5
|
+
* Uses same column schema as executor.ts telemetry (trace_id, span_id, etc).
|
|
6
|
+
* Never blocks or crashes the chat.
|
|
7
|
+
*/
|
|
8
|
+
import { createClient } from "@supabase/supabase-js";
|
|
9
|
+
import { createRequire } from "module";
|
|
10
|
+
import { resolveConfig, loadConfig } from "./config-store.js";
|
|
11
|
+
import { getValidToken, createAuthenticatedClient } from "./auth-service.js";
|
|
12
|
+
import { captureError } from "./error-logger.js";
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
const PKG_VERSION = require("../../../package.json").version;
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// SESSION STATE
|
|
17
|
+
// ============================================================================
|
|
18
|
+
let conversationId = crypto.randomUUID();
|
|
19
|
+
let turnNumber = 0;
|
|
20
|
+
/**
|
|
21
|
+
* Set the conversation ID (used by worker threads to share parent's conversation)
|
|
22
|
+
*/
|
|
23
|
+
export function setConversationId(id) {
|
|
24
|
+
conversationId = id;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get the current conversation ID
|
|
28
|
+
*/
|
|
29
|
+
export function getConversationId() {
|
|
30
|
+
return conversationId;
|
|
31
|
+
}
|
|
32
|
+
let supabaseClient = null;
|
|
33
|
+
/**
|
|
34
|
+
* Initialize the telemetry client with a specific auth token.
|
|
35
|
+
* Used by worker threads that receive the token from the parent.
|
|
36
|
+
*/
|
|
37
|
+
export function initializeTelemetryClient(authToken) {
|
|
38
|
+
if (supabaseClient)
|
|
39
|
+
return; // Already initialized
|
|
40
|
+
supabaseClient = createAuthenticatedClient(authToken);
|
|
41
|
+
if (process.env.DEBUG_TELEMETRY) {
|
|
42
|
+
process.stderr.write(`[telemetry] initialized client with provided auth token\n`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// ============================================================================
|
|
46
|
+
// W3C TRACE CONTEXT GENERATORS
|
|
47
|
+
// ============================================================================
|
|
48
|
+
export function generateTraceId() {
|
|
49
|
+
// Use proper UUID format so it's compatible with Postgres uuid columns
|
|
50
|
+
return crypto.randomUUID();
|
|
51
|
+
}
|
|
52
|
+
export function generateSpanId() {
|
|
53
|
+
const bytes = new Uint8Array(8);
|
|
54
|
+
crypto.getRandomValues(bytes);
|
|
55
|
+
return Array.from(bytes).map(b => b.toString(16).padStart(2, "0")).join("");
|
|
56
|
+
}
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// SUPABASE CLIENT (lazy init)
|
|
59
|
+
// ============================================================================
|
|
60
|
+
async function getClient() {
|
|
61
|
+
if (supabaseClient)
|
|
62
|
+
return supabaseClient;
|
|
63
|
+
const config = resolveConfig();
|
|
64
|
+
// Prefer service role key
|
|
65
|
+
if (config.supabaseUrl && config.supabaseKey) {
|
|
66
|
+
supabaseClient = createClient(config.supabaseUrl, config.supabaseKey, {
|
|
67
|
+
auth: { persistSession: false, autoRefreshToken: false },
|
|
68
|
+
});
|
|
69
|
+
if (process.env.DEBUG_TELEMETRY) {
|
|
70
|
+
process.stderr.write(`[telemetry] using service role key\n`);
|
|
71
|
+
}
|
|
72
|
+
return supabaseClient;
|
|
73
|
+
}
|
|
74
|
+
// Fallback: user JWT
|
|
75
|
+
const token = await getValidToken();
|
|
76
|
+
if (token) {
|
|
77
|
+
supabaseClient = createAuthenticatedClient(token);
|
|
78
|
+
if (process.env.DEBUG_TELEMETRY) {
|
|
79
|
+
process.stderr.write(`[telemetry] using user JWT token\n`);
|
|
80
|
+
}
|
|
81
|
+
return supabaseClient;
|
|
82
|
+
}
|
|
83
|
+
if (process.env.DEBUG_TELEMETRY) {
|
|
84
|
+
process.stderr.write(`[telemetry] NO CLIENT - no service key and no valid token\n`);
|
|
85
|
+
process.stderr.write(`[telemetry] config.supabaseUrl: ${config.supabaseUrl}\n`);
|
|
86
|
+
process.stderr.write(`[telemetry] config.supabaseKey: ${config.supabaseKey ? 'set' : 'not set'}\n`);
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// TURN CONTEXT
|
|
92
|
+
// ============================================================================
|
|
93
|
+
export function nextTurn() {
|
|
94
|
+
return ++turnNumber;
|
|
95
|
+
}
|
|
96
|
+
export function createTurnContext(overrides) {
|
|
97
|
+
// Get user info from config
|
|
98
|
+
const { user_id, email } = loadConfig();
|
|
99
|
+
return {
|
|
100
|
+
source: "whale_cli",
|
|
101
|
+
serviceName: "whale-code",
|
|
102
|
+
serviceVersion: PKG_VERSION,
|
|
103
|
+
conversationId,
|
|
104
|
+
turnNumber,
|
|
105
|
+
traceId: generateTraceId(),
|
|
106
|
+
spanId: generateSpanId(),
|
|
107
|
+
traceFlags: 1,
|
|
108
|
+
userId: user_id,
|
|
109
|
+
userEmail: email,
|
|
110
|
+
...overrides,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export function getTurnNumber() {
|
|
114
|
+
return turnNumber;
|
|
115
|
+
}
|
|
116
|
+
export function logSpan(opts) {
|
|
117
|
+
// Fire-and-forget — don't await, log errors in debug mode
|
|
118
|
+
_logSpan(opts).catch((err) => {
|
|
119
|
+
if (process.env.DEBUG_TELEMETRY) {
|
|
120
|
+
process.stderr.write(`[telemetry error] ${opts.action}: ${err.message}\n`);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
async function _logSpan(opts) {
|
|
125
|
+
if (process.env.DEBUG_TELEMETRY) {
|
|
126
|
+
process.stderr.write(`[telemetry] _logSpan called for ${opts.action}\n`);
|
|
127
|
+
}
|
|
128
|
+
const client = await getClient();
|
|
129
|
+
if (!client) {
|
|
130
|
+
if (process.env.DEBUG_TELEMETRY) {
|
|
131
|
+
process.stderr.write(`[telemetry] no client for ${opts.action}\n`);
|
|
132
|
+
}
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const now = new Date();
|
|
136
|
+
const startTime = new Date(now.getTime() - opts.durationMs);
|
|
137
|
+
const ctx = opts.context;
|
|
138
|
+
// Debug: log team-related spans (only when DEBUG_TELEMETRY is set)
|
|
139
|
+
if (process.env.DEBUG_TELEMETRY && (opts.action.startsWith("team.") || opts.details?.parent_conversation_id)) {
|
|
140
|
+
process.stderr.write(`[telemetry:team] action=${opts.action}\n`);
|
|
141
|
+
process.stderr.write(`[telemetry:team] conversation_id=${ctx.conversationId}\n`);
|
|
142
|
+
process.stderr.write(`[telemetry:team] parent_conversation_id=${opts.details?.parent_conversation_id}\n`);
|
|
143
|
+
}
|
|
144
|
+
const row = {
|
|
145
|
+
action: opts.action,
|
|
146
|
+
severity: opts.severity || (opts.error ? "error" : "info"),
|
|
147
|
+
store_id: opts.storeId || resolveConfig().storeId || null,
|
|
148
|
+
user_id: ctx.userId || null,
|
|
149
|
+
user_email: ctx.userEmail || null,
|
|
150
|
+
resource_type: "cli_span",
|
|
151
|
+
resource_id: opts.action,
|
|
152
|
+
request_id: ctx.traceId,
|
|
153
|
+
parent_id: ctx.parentId || null,
|
|
154
|
+
duration_ms: opts.durationMs,
|
|
155
|
+
error_message: opts.error || null,
|
|
156
|
+
// OTEL columns
|
|
157
|
+
trace_id: ctx.traceId,
|
|
158
|
+
span_id: ctx.spanId,
|
|
159
|
+
trace_flags: ctx.traceFlags ?? 1,
|
|
160
|
+
span_kind: "INTERNAL",
|
|
161
|
+
service_name: ctx.serviceName || "whale-code",
|
|
162
|
+
service_version: ctx.serviceVersion || PKG_VERSION,
|
|
163
|
+
status_code: opts.error ? "ERROR" : "OK",
|
|
164
|
+
start_time: startTime.toISOString(),
|
|
165
|
+
end_time: now.toISOString(),
|
|
166
|
+
// AI telemetry — use ?? to handle 0 correctly
|
|
167
|
+
model: ctx.model || null,
|
|
168
|
+
input_tokens: ctx.inputTokens ?? null,
|
|
169
|
+
output_tokens: ctx.outputTokens ?? null,
|
|
170
|
+
total_cost: ctx.totalCost ?? null,
|
|
171
|
+
turn_number: ctx.turnNumber ?? null,
|
|
172
|
+
conversation_id: ctx.conversationId || null,
|
|
173
|
+
details: {
|
|
174
|
+
source: ctx.source || "whale_cli",
|
|
175
|
+
conversation_id: ctx.conversationId || conversationId,
|
|
176
|
+
turn_number: ctx.turnNumber ?? turnNumber,
|
|
177
|
+
parent_span_id: ctx.parentSpanId || null,
|
|
178
|
+
...opts.details,
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
// Allow caller to control row ID so children can reference it via parent_id
|
|
182
|
+
if (ctx.rowId)
|
|
183
|
+
row.id = ctx.rowId;
|
|
184
|
+
const { error } = await client.from("audit_logs").insert(row);
|
|
185
|
+
if (error) {
|
|
186
|
+
if (process.env.DEBUG_TELEMETRY) {
|
|
187
|
+
process.stderr.write(`[telemetry db error] ${opts.action}: ${error.message}\n`);
|
|
188
|
+
process.stderr.write(`[telemetry db error] code: ${error.code}\n`);
|
|
189
|
+
process.stderr.write(`[telemetry db error] hint: ${error.hint}\n`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
else if (opts.details?.is_teammate && process.env.DEBUG_TELEMETRY) {
|
|
193
|
+
process.stderr.write(`[telemetry] teammate span logged: ${opts.action}\n`);
|
|
194
|
+
}
|
|
195
|
+
// Bridge errors to the error logging system
|
|
196
|
+
if (opts.error) {
|
|
197
|
+
captureError({
|
|
198
|
+
errorType: opts.action,
|
|
199
|
+
errorMessage: opts.error,
|
|
200
|
+
severity: "error",
|
|
201
|
+
traceId: ctx.traceId,
|
|
202
|
+
spanId: ctx.spanId,
|
|
203
|
+
storeId: opts.storeId || resolveConfig().storeId,
|
|
204
|
+
userId: ctx.userId,
|
|
205
|
+
userEmail: ctx.userEmail,
|
|
206
|
+
tags: { action: opts.action },
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Tools — task, team_create, task_output, task_stop, config, ask_user, lsp, skill
|
|
3
|
+
*
|
|
4
|
+
* Extracted from local-tools.ts for single-responsibility.
|
|
5
|
+
*/
|
|
6
|
+
import { ToolResult } from "../../../shared/types.js";
|
|
7
|
+
export declare function configTool(input: Record<string, unknown>): ToolResult;
|
|
8
|
+
export declare function askUser(input: Record<string, unknown>): ToolResult;
|
|
9
|
+
export declare function lspTool(input: Record<string, unknown>): Promise<ToolResult>;
|
|
10
|
+
export declare function skillTool(input: Record<string, unknown>): ToolResult;
|
|
11
|
+
export declare function taskTool(input: Record<string, unknown>): Promise<ToolResult>;
|
|
12
|
+
export declare function taskOutput(input: Record<string, unknown>): Promise<ToolResult>;
|
|
13
|
+
export declare function taskStop(input: Record<string, unknown>): ToolResult;
|
|
14
|
+
export declare function teamCreateTool(input: Record<string, unknown>): Promise<ToolResult>;
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Tools — task, team_create, task_output, task_stop, config, ask_user, lsp, skill
|
|
3
|
+
*
|
|
4
|
+
* Extracted from local-tools.ts for single-responsibility.
|
|
5
|
+
*/
|
|
6
|
+
import { readFileSync, existsSync } from "fs";
|
|
7
|
+
import { dirname, join } from "path";
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import { runSubagent, runSubagentBackground, } from "../subagent.js";
|
|
10
|
+
import { createTurnContext, getTurnNumber, } from "../telemetry.js";
|
|
11
|
+
import { runAgentTeam, } from "../team-lead.js";
|
|
12
|
+
import { readAgentOutput, stopBackgroundAgent } from "../background-processes.js";
|
|
13
|
+
import { readProcessOutput, killProcess } from "../background-processes.js";
|
|
14
|
+
import { getGlobalEmitter } from "../agent-events.js";
|
|
15
|
+
import { executeLSP } from "../lsp-manager.js";
|
|
16
|
+
import { debugLog } from "../debug-log.js";
|
|
17
|
+
import { setPermissionMode, getPermissionMode } from "../permission-modes.js";
|
|
18
|
+
import { getModel, setModel } from "../model-manager.js";
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// CONFIG TOOL
|
|
21
|
+
// ============================================================================
|
|
22
|
+
export function configTool(input) {
|
|
23
|
+
const setting = input.setting;
|
|
24
|
+
const value = input.value;
|
|
25
|
+
switch (setting) {
|
|
26
|
+
case "model": {
|
|
27
|
+
if (!value)
|
|
28
|
+
return { success: true, output: `Current model: ${getModel()}` };
|
|
29
|
+
const result = setModel(value);
|
|
30
|
+
if (!result.success) {
|
|
31
|
+
return { success: false, output: result.error || `Unknown model: ${value}` };
|
|
32
|
+
}
|
|
33
|
+
return { success: true, output: `Model set to: ${result.model}` };
|
|
34
|
+
}
|
|
35
|
+
case "mode":
|
|
36
|
+
case "permission_mode": {
|
|
37
|
+
if (!value)
|
|
38
|
+
return { success: true, output: `Current mode: ${getPermissionMode()}` };
|
|
39
|
+
if (!["default", "plan", "yolo"].includes(value)) {
|
|
40
|
+
return { success: false, output: `Invalid mode: ${value}. Use: default, plan, yolo` };
|
|
41
|
+
}
|
|
42
|
+
const result = setPermissionMode(value);
|
|
43
|
+
return { success: result.success, output: result.message };
|
|
44
|
+
}
|
|
45
|
+
case "memory": {
|
|
46
|
+
if (!value) {
|
|
47
|
+
const memPath = join(homedir(), ".swagmanager", "memory", "MEMORY.md");
|
|
48
|
+
if (!existsSync(memPath))
|
|
49
|
+
return { success: true, output: "No memory file found." };
|
|
50
|
+
const content = readFileSync(memPath, "utf-8");
|
|
51
|
+
return { success: true, output: `Memory (${content.length} chars):\n${content.slice(0, 20_000)}` };
|
|
52
|
+
}
|
|
53
|
+
return { success: false, output: "Use read_file/write_file to edit memory directly." };
|
|
54
|
+
}
|
|
55
|
+
default:
|
|
56
|
+
return { success: false, output: `Unknown setting: ${setting}. Available: model, mode, memory` };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// ASK USER
|
|
61
|
+
// ============================================================================
|
|
62
|
+
export function askUser(input) {
|
|
63
|
+
const question = input.question;
|
|
64
|
+
const options = input.options;
|
|
65
|
+
if (!question)
|
|
66
|
+
return { success: false, output: "question is required" };
|
|
67
|
+
if (!options || options.length < 2)
|
|
68
|
+
return { success: false, output: "at least 2 options required" };
|
|
69
|
+
// Emit the question via the global event emitter for the UI to render
|
|
70
|
+
const emitter = getGlobalEmitter();
|
|
71
|
+
if (emitter) {
|
|
72
|
+
emitter.emit("ask_user", { question, options });
|
|
73
|
+
}
|
|
74
|
+
// Format question as text for the model to see in the response
|
|
75
|
+
const optionLines = options.map((o, i) => ` ${i + 1}. **${o.label}** — ${o.description}`).join("\n");
|
|
76
|
+
return {
|
|
77
|
+
success: true,
|
|
78
|
+
output: `Question presented to user:\n${question}\n\nOptions:\n${optionLines}\n\n(Waiting for user response...)`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// LSP TOOL
|
|
83
|
+
// ============================================================================
|
|
84
|
+
export async function lspTool(input) {
|
|
85
|
+
const operation = input.operation;
|
|
86
|
+
if (!operation)
|
|
87
|
+
return { success: false, output: "operation is required" };
|
|
88
|
+
return await executeLSP(operation, input);
|
|
89
|
+
}
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// SKILL TOOL
|
|
92
|
+
// ============================================================================
|
|
93
|
+
export function skillTool(input) {
|
|
94
|
+
const skillName = input.skill;
|
|
95
|
+
if (!skillName)
|
|
96
|
+
return { success: false, output: "skill name is required" };
|
|
97
|
+
const args = (input.args || "").split(/\s+/).filter(Boolean);
|
|
98
|
+
// Resolution order:
|
|
99
|
+
// 1. .whale/commands/{skill}.md (project-local)
|
|
100
|
+
// 2. ~/.swagmanager/commands/{skill}.md (user global)
|
|
101
|
+
// 3. Built-in skills bundled with package
|
|
102
|
+
const localPath = join(process.cwd(), ".whale", "commands", `${skillName}.md`);
|
|
103
|
+
const globalPath = join(homedir(), ".swagmanager", "commands", `${skillName}.md`);
|
|
104
|
+
// Built-in skills: check both dist/ and src/ locations
|
|
105
|
+
const thisFileDir = dirname(new URL(import.meta.url).pathname);
|
|
106
|
+
const builtinPaths = [
|
|
107
|
+
join(thisFileDir, "..", "builtin-skills", `${skillName}.md`), // dist/cli/services/tools/../builtin-skills/
|
|
108
|
+
join(thisFileDir, "..", "..", "..", "..", "src", "cli", "services", "builtin-skills", `${skillName}.md`), // src/ from dist/
|
|
109
|
+
];
|
|
110
|
+
let template = null;
|
|
111
|
+
let source = "";
|
|
112
|
+
// Check local -> global -> builtin (multiple paths)
|
|
113
|
+
const candidates = [
|
|
114
|
+
[localPath, "local"],
|
|
115
|
+
[globalPath, "global"],
|
|
116
|
+
...builtinPaths.map(p => [p, "builtin"]),
|
|
117
|
+
];
|
|
118
|
+
for (const [path, src] of candidates) {
|
|
119
|
+
if (existsSync(path)) {
|
|
120
|
+
try {
|
|
121
|
+
let content = readFileSync(path, "utf-8");
|
|
122
|
+
// Strip frontmatter
|
|
123
|
+
if (content.startsWith("---")) {
|
|
124
|
+
const endIdx = content.indexOf("---", 3);
|
|
125
|
+
if (endIdx !== -1) {
|
|
126
|
+
content = content.slice(endIdx + 3).trim();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
template = content;
|
|
130
|
+
source = src;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
catch { /* skip */ }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (!template) {
|
|
137
|
+
return {
|
|
138
|
+
success: false,
|
|
139
|
+
output: `Skill not found: ${skillName}. Available locations:\n .whale/commands/${skillName}.md\n ~/.swagmanager/commands/${skillName}.md\n\nBuilt-in skills: commit, review, review-pr`,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
// Expand arguments ($1, $2, $ARGS)
|
|
143
|
+
let expanded = template;
|
|
144
|
+
for (let i = 0; i < args.length; i++) {
|
|
145
|
+
expanded = expanded.replace(new RegExp(`\\$${i + 1}`, "g"), args[i]);
|
|
146
|
+
}
|
|
147
|
+
expanded = expanded.replace(/\$ARGS/g, args.join(" "));
|
|
148
|
+
expanded = expanded.replace(/\$\d+/g, ""); // Clean up unused
|
|
149
|
+
return {
|
|
150
|
+
success: true,
|
|
151
|
+
output: `[Skill: ${skillName} (${source})]\n\n${expanded.trim()}`,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// ============================================================================
|
|
155
|
+
// TASK TOOL — subagent execution
|
|
156
|
+
// ============================================================================
|
|
157
|
+
/** Create parent trace context for subagent hierarchy */
|
|
158
|
+
function getParentTraceContext() {
|
|
159
|
+
const ctx = createTurnContext();
|
|
160
|
+
return {
|
|
161
|
+
traceId: ctx.traceId,
|
|
162
|
+
spanId: ctx.spanId,
|
|
163
|
+
conversationId: ctx.conversationId,
|
|
164
|
+
turnNumber: getTurnNumber(),
|
|
165
|
+
userId: ctx.userId,
|
|
166
|
+
userEmail: ctx.userEmail,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
export async function taskTool(input) {
|
|
170
|
+
const prompt = input.prompt;
|
|
171
|
+
const subagent_type = input.subagent_type;
|
|
172
|
+
const model = input.model || "haiku";
|
|
173
|
+
const runInBackground = input.run_in_background;
|
|
174
|
+
const maxTurns = input.max_turns;
|
|
175
|
+
const agentName = input.name;
|
|
176
|
+
const teamName = input.team_name;
|
|
177
|
+
const mode = input.mode;
|
|
178
|
+
if (!prompt)
|
|
179
|
+
return { success: false, output: "prompt is required" };
|
|
180
|
+
if (!subagent_type)
|
|
181
|
+
return { success: false, output: "subagent_type is required" };
|
|
182
|
+
// Apply permission mode for subagent if specified
|
|
183
|
+
if (mode) {
|
|
184
|
+
setPermissionMode(mode);
|
|
185
|
+
// Note: mode resets are handled by subagent isolation
|
|
186
|
+
}
|
|
187
|
+
debugLog("tools", `task: ${agentName || subagent_type}`, { model, maxTurns, teamName, mode });
|
|
188
|
+
try {
|
|
189
|
+
// Background mode: start agent, return output file path immediately
|
|
190
|
+
if (runInBackground) {
|
|
191
|
+
const { agentId, outputFile } = await runSubagentBackground({
|
|
192
|
+
prompt,
|
|
193
|
+
subagent_type,
|
|
194
|
+
model,
|
|
195
|
+
max_turns: maxTurns,
|
|
196
|
+
name: agentName,
|
|
197
|
+
run_in_background: true,
|
|
198
|
+
parentTraceContext: getParentTraceContext(),
|
|
199
|
+
});
|
|
200
|
+
return {
|
|
201
|
+
success: true,
|
|
202
|
+
output: `Background agent started.\n agent_id: ${agentId}\n output_file: ${outputFile}\n\nUse task_output with task_id="${agentId}" to check progress.`,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
// Foreground mode: run agent synchronously
|
|
206
|
+
const result = await runSubagent({
|
|
207
|
+
prompt,
|
|
208
|
+
subagent_type,
|
|
209
|
+
model,
|
|
210
|
+
max_turns: maxTurns,
|
|
211
|
+
name: agentName,
|
|
212
|
+
parentTraceContext: getParentTraceContext(),
|
|
213
|
+
});
|
|
214
|
+
return {
|
|
215
|
+
success: result.success,
|
|
216
|
+
output: result.output,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
return {
|
|
221
|
+
success: false,
|
|
222
|
+
output: `Task failed: ${err.message || err}`,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// ============================================================================
|
|
227
|
+
// TASK OUTPUT / TASK STOP
|
|
228
|
+
// ============================================================================
|
|
229
|
+
export async function taskOutput(input) {
|
|
230
|
+
const taskId = input.task_id;
|
|
231
|
+
const block = input.block ?? true;
|
|
232
|
+
const timeout = Math.min(input.timeout || 30000, 120000);
|
|
233
|
+
if (!taskId)
|
|
234
|
+
return { success: false, output: "task_id is required" };
|
|
235
|
+
// Check if it's a background agent (agent-xxx prefix)
|
|
236
|
+
if (taskId.startsWith("agent-")) {
|
|
237
|
+
const agentResult = readAgentOutput(taskId);
|
|
238
|
+
if (!agentResult)
|
|
239
|
+
return { success: false, output: `Agent not found: ${taskId}. Use list_shells to see available tasks.` };
|
|
240
|
+
// If blocking and still running, poll until done or timeout
|
|
241
|
+
if (block && agentResult.status === "running") {
|
|
242
|
+
const start = Date.now();
|
|
243
|
+
while (Date.now() - start < timeout) {
|
|
244
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
245
|
+
const updated = readAgentOutput(taskId);
|
|
246
|
+
if (updated && updated.status !== "running") {
|
|
247
|
+
return { success: true, output: `[${updated.status}]\n${updated.output}` };
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const final = readAgentOutput(taskId);
|
|
251
|
+
return { success: true, output: `[${final?.status || "running"} — timed out waiting]\n${final?.output || ""}` };
|
|
252
|
+
}
|
|
253
|
+
return { success: true, output: `[${agentResult.status}]\n${agentResult.output}` };
|
|
254
|
+
}
|
|
255
|
+
// Fall back to shell process output (bash_output behavior)
|
|
256
|
+
const result = readProcessOutput(taskId, {});
|
|
257
|
+
if ("error" in result)
|
|
258
|
+
return { success: false, output: result.error };
|
|
259
|
+
const statusIcon = result.status === "running" ? "\u25CF" : result.status === "completed" ? "\u2713" : "\u2715";
|
|
260
|
+
const lines = [];
|
|
261
|
+
lines.push(`${statusIcon} Task ${taskId} — ${result.status}`);
|
|
262
|
+
if (result.exitCode !== undefined)
|
|
263
|
+
lines.push(` Exit code: ${result.exitCode}`);
|
|
264
|
+
if (result.newOutput) {
|
|
265
|
+
lines.push(` Output:`);
|
|
266
|
+
lines.push(result.newOutput);
|
|
267
|
+
}
|
|
268
|
+
if (result.newErrors) {
|
|
269
|
+
lines.push(` Errors:`);
|
|
270
|
+
lines.push(result.newErrors);
|
|
271
|
+
}
|
|
272
|
+
if (!result.newOutput && !result.newErrors)
|
|
273
|
+
lines.push(" (no new output since last check)");
|
|
274
|
+
return { success: true, output: lines.join("\n") };
|
|
275
|
+
}
|
|
276
|
+
export function taskStop(input) {
|
|
277
|
+
const taskId = input.task_id;
|
|
278
|
+
if (!taskId)
|
|
279
|
+
return { success: false, output: "task_id is required" };
|
|
280
|
+
// Check if it's a background agent
|
|
281
|
+
if (taskId.startsWith("agent-")) {
|
|
282
|
+
const result = stopBackgroundAgent(taskId);
|
|
283
|
+
return { success: result.success, output: result.message };
|
|
284
|
+
}
|
|
285
|
+
// Fall back to shell kill
|
|
286
|
+
const result = killProcess(taskId);
|
|
287
|
+
return { success: result.success, output: result.message };
|
|
288
|
+
}
|
|
289
|
+
// ============================================================================
|
|
290
|
+
// TEAM CREATE
|
|
291
|
+
// ============================================================================
|
|
292
|
+
export async function teamCreateTool(input) {
|
|
293
|
+
const name = input.name;
|
|
294
|
+
const teammateCount = input.teammate_count;
|
|
295
|
+
const model = input.model || "sonnet";
|
|
296
|
+
const tasksInput = input.tasks;
|
|
297
|
+
if (!name)
|
|
298
|
+
return { success: false, output: "name is required" };
|
|
299
|
+
if (!teammateCount || teammateCount < 1) {
|
|
300
|
+
return { success: false, output: "teammate_count must be at least 1" };
|
|
301
|
+
}
|
|
302
|
+
if (!tasksInput || tasksInput.length === 0) {
|
|
303
|
+
return { success: false, output: "tasks array is required and must not be empty" };
|
|
304
|
+
}
|
|
305
|
+
// Validate task count vs teammate count
|
|
306
|
+
if (tasksInput.length < teammateCount) {
|
|
307
|
+
return {
|
|
308
|
+
success: false,
|
|
309
|
+
output: `Not enough tasks (${tasksInput.length}) for ${teammateCount} teammates. Add more tasks or reduce teammates.`,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
const config = {
|
|
313
|
+
name,
|
|
314
|
+
teammateCount,
|
|
315
|
+
model,
|
|
316
|
+
tasks: tasksInput,
|
|
317
|
+
};
|
|
318
|
+
try {
|
|
319
|
+
const result = await runAgentTeam(config);
|
|
320
|
+
// Build summary output
|
|
321
|
+
const lines = [
|
|
322
|
+
`## Team: ${name}`,
|
|
323
|
+
`Status: ${result.success ? "SUCCESS" : "PARTIAL"}`,
|
|
324
|
+
`Duration: ${(result.durationMs / 1000).toFixed(1)}s`,
|
|
325
|
+
`Tokens: ${result.tokensUsed.input} in, ${result.tokensUsed.output} out`,
|
|
326
|
+
"",
|
|
327
|
+
"### Task Results",
|
|
328
|
+
];
|
|
329
|
+
for (const task of result.taskResults) {
|
|
330
|
+
const icon = task.status === "completed" ? "[done]" : "[fail]";
|
|
331
|
+
lines.push(`${icon} ${task.description}`);
|
|
332
|
+
if (task.result) {
|
|
333
|
+
lines.push(` ${task.result.slice(0, 200)}${task.result.length > 200 ? "..." : ""}`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return {
|
|
337
|
+
success: result.success,
|
|
338
|
+
output: lines.join("\n"),
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
catch (err) {
|
|
342
|
+
return {
|
|
343
|
+
success: false,
|
|
344
|
+
output: `Team failed: ${err.message || err}`,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Operations — read, write, edit, multi-edit, notebook, list, search
|
|
3
|
+
*
|
|
4
|
+
* Extracted from local-tools.ts for single-responsibility.
|
|
5
|
+
*/
|
|
6
|
+
import { ToolResult } from "../../../shared/types.js";
|
|
7
|
+
export declare function resolvePath(p: string): string;
|
|
8
|
+
export declare function readFile(input: Record<string, unknown>): Promise<ToolResult>;
|
|
9
|
+
export declare function writeFile(input: Record<string, unknown>): ToolResult;
|
|
10
|
+
export declare function editFile(input: Record<string, unknown>): ToolResult;
|
|
11
|
+
export declare function multiEdit(input: Record<string, unknown>): ToolResult;
|
|
12
|
+
export declare function notebookEdit(input: Record<string, unknown>): ToolResult;
|
|
13
|
+
export declare function listDirectory(input: Record<string, unknown>): ToolResult;
|
|
14
|
+
export declare function searchFiles(input: Record<string, unknown>): ToolResult;
|
|
15
|
+
export declare function searchContent(input: Record<string, unknown>): ToolResult;
|