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,512 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team Lead — Coordinator for Agent Teams
|
|
3
|
+
*
|
|
4
|
+
* Following Anthropic's official patterns:
|
|
5
|
+
* - Spawns and manages teammates
|
|
6
|
+
* - Creates and assigns tasks
|
|
7
|
+
* - Monitors progress
|
|
8
|
+
* - Synthesizes results
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from "events";
|
|
11
|
+
import { createTeam, loadTeam, saveTeam, addTeammate, addTask, getTeamProgress, setTeamStatus, sendMessage, getUnreadMessages, markMessagesRead, failTask, updateTeammate, } from "./team-state.js";
|
|
12
|
+
import { spawnTeammate } from "./teammate.js";
|
|
13
|
+
import { logSpan, generateTraceId, generateSpanId, getConversationId } from "./telemetry.js";
|
|
14
|
+
import { resolveConfig } from "./config-store.js";
|
|
15
|
+
import { getGlobalEmitter } from "./agent-events.js";
|
|
16
|
+
import { getModelShortName } from "./agent-loop.js";
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// TEAM LEAD CLASS
|
|
19
|
+
// ============================================================================
|
|
20
|
+
const TEAM_TIMEOUT_MS = 5 * 60 * 1000; // 5 min total
|
|
21
|
+
const WORKER_STALL_MS = 2 * 60 * 1000; // 2 min no messages
|
|
22
|
+
export class TeamLead extends EventEmitter {
|
|
23
|
+
teamId = null;
|
|
24
|
+
workers = new Map();
|
|
25
|
+
lastMessageTime = new Map();
|
|
26
|
+
teamTimer = null;
|
|
27
|
+
stallInterval = null;
|
|
28
|
+
resolveTeam = null;
|
|
29
|
+
traceId;
|
|
30
|
+
spanId;
|
|
31
|
+
startTime = 0;
|
|
32
|
+
constructor() {
|
|
33
|
+
super();
|
|
34
|
+
this.traceId = generateTraceId();
|
|
35
|
+
this.spanId = generateSpanId();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Generate meaningful teammate names from task descriptions
|
|
39
|
+
* Extracts key action words to create role-based names
|
|
40
|
+
*/
|
|
41
|
+
generateTeammateNames(tasks, count) {
|
|
42
|
+
const roles = [
|
|
43
|
+
"Researcher", "Analyst", "Writer", "Reviewer",
|
|
44
|
+
"Coordinator", "Specialist", "Explorer", "Synthesizer"
|
|
45
|
+
];
|
|
46
|
+
// Extract keywords from task descriptions
|
|
47
|
+
const names = [];
|
|
48
|
+
const usedRoles = new Set();
|
|
49
|
+
for (let i = 0; i < count; i++) {
|
|
50
|
+
if (i < tasks.length) {
|
|
51
|
+
const desc = tasks[i].description.toLowerCase();
|
|
52
|
+
// Match task keywords to roles
|
|
53
|
+
let role;
|
|
54
|
+
if (desc.includes("research") || desc.includes("search") || desc.includes("find")) {
|
|
55
|
+
role = "Researcher";
|
|
56
|
+
}
|
|
57
|
+
else if (desc.includes("analyze") || desc.includes("analysis") || desc.includes("review")) {
|
|
58
|
+
role = "Analyst";
|
|
59
|
+
}
|
|
60
|
+
else if (desc.includes("write") || desc.includes("create") || desc.includes("draft")) {
|
|
61
|
+
role = "Writer";
|
|
62
|
+
}
|
|
63
|
+
else if (desc.includes("compile") || desc.includes("combine") || desc.includes("synthesize")) {
|
|
64
|
+
role = "Synthesizer";
|
|
65
|
+
}
|
|
66
|
+
else if (desc.includes("explore") || desc.includes("investigate")) {
|
|
67
|
+
role = "Explorer";
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Use a generic role
|
|
71
|
+
role = roles[i % roles.length];
|
|
72
|
+
}
|
|
73
|
+
// Avoid duplicate names by adding number if needed
|
|
74
|
+
if (usedRoles.has(role)) {
|
|
75
|
+
let suffix = 2;
|
|
76
|
+
while (usedRoles.has(`${role} ${suffix}`))
|
|
77
|
+
suffix++;
|
|
78
|
+
role = `${role} ${suffix}`;
|
|
79
|
+
}
|
|
80
|
+
usedRoles.add(role);
|
|
81
|
+
names.push(role);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
// More teammates than tasks - use generic names
|
|
85
|
+
names.push(roles[i % roles.length]);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return names;
|
|
89
|
+
}
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// TEAM CREATION
|
|
92
|
+
// ============================================================================
|
|
93
|
+
async createTeam(config) {
|
|
94
|
+
this.startTime = Date.now();
|
|
95
|
+
// Create team
|
|
96
|
+
const team = createTeam(config.name, "lead");
|
|
97
|
+
this.teamId = team.id;
|
|
98
|
+
this.emit("team_created", { teamId: team.id, name: config.name });
|
|
99
|
+
// Emit to global emitter for UI
|
|
100
|
+
const emitter = getGlobalEmitter();
|
|
101
|
+
emitter.emitTeamStart(team.id, config.name, config.teammateCount, config.tasks.length);
|
|
102
|
+
// Log team creation
|
|
103
|
+
logSpan({
|
|
104
|
+
action: "team.create",
|
|
105
|
+
durationMs: 0,
|
|
106
|
+
context: {
|
|
107
|
+
traceId: this.traceId,
|
|
108
|
+
spanId: this.spanId,
|
|
109
|
+
conversationId: getConversationId(),
|
|
110
|
+
source: "claude_code",
|
|
111
|
+
serviceName: "whale-cli",
|
|
112
|
+
serviceVersion: "2.1.0",
|
|
113
|
+
},
|
|
114
|
+
storeId: resolveConfig().storeId || undefined,
|
|
115
|
+
details: {
|
|
116
|
+
// Team identification (for blackops detection)
|
|
117
|
+
is_team: true,
|
|
118
|
+
is_team_coordinator: true,
|
|
119
|
+
team_id: team.id,
|
|
120
|
+
team_name: config.name,
|
|
121
|
+
teammate_count: config.teammateCount,
|
|
122
|
+
task_count: config.tasks.length,
|
|
123
|
+
model: config.model || getModelShortName(),
|
|
124
|
+
// Display metadata
|
|
125
|
+
display_name: `Team: ${config.name}`,
|
|
126
|
+
display_icon: "person.3.fill",
|
|
127
|
+
display_color: "#10B981",
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
// Create tasks
|
|
131
|
+
const taskIdMap = new Map(); // description -> id
|
|
132
|
+
for (const taskConfig of config.tasks) {
|
|
133
|
+
const task = await addTask(team.id, {
|
|
134
|
+
description: taskConfig.description,
|
|
135
|
+
files: taskConfig.files,
|
|
136
|
+
model: taskConfig.model,
|
|
137
|
+
});
|
|
138
|
+
if (task) {
|
|
139
|
+
taskIdMap.set(taskConfig.description, task.id);
|
|
140
|
+
this.emit("task_created", { taskId: task.id, description: taskConfig.description });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Set up dependencies (now that we have IDs)
|
|
144
|
+
const freshTeam = loadTeam(team.id);
|
|
145
|
+
for (const taskConfig of config.tasks) {
|
|
146
|
+
if (taskConfig.dependencies?.length) {
|
|
147
|
+
const task = freshTeam.tasks.find(t => t.description === taskConfig.description);
|
|
148
|
+
if (task) {
|
|
149
|
+
task.dependencies = taskConfig.dependencies
|
|
150
|
+
.map(dep => taskIdMap.get(dep))
|
|
151
|
+
.filter(Boolean);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
saveTeam(freshTeam);
|
|
156
|
+
// Create teammates with meaningful names
|
|
157
|
+
const model = config.model || getModelShortName();
|
|
158
|
+
// Generate teammate names from tasks if not provided
|
|
159
|
+
const teammateNames = config.teammateNames || this.generateTeammateNames(config.tasks, config.teammateCount);
|
|
160
|
+
for (let i = 0; i < config.teammateCount; i++) {
|
|
161
|
+
const name = teammateNames[i] || `Agent ${i + 1}`;
|
|
162
|
+
const id = `teammate-${i + 1}-${Date.now()}`;
|
|
163
|
+
await addTeammate(team.id, {
|
|
164
|
+
id,
|
|
165
|
+
name,
|
|
166
|
+
model,
|
|
167
|
+
status: "idle",
|
|
168
|
+
});
|
|
169
|
+
this.emit("teammate_created", { teammateId: id, name });
|
|
170
|
+
}
|
|
171
|
+
return team.id;
|
|
172
|
+
}
|
|
173
|
+
// ============================================================================
|
|
174
|
+
// TEAM EXECUTION
|
|
175
|
+
// ============================================================================
|
|
176
|
+
async runTeam() {
|
|
177
|
+
if (!this.teamId) {
|
|
178
|
+
throw new Error("No team created. Call createTeam first.");
|
|
179
|
+
}
|
|
180
|
+
const team = loadTeam(this.teamId);
|
|
181
|
+
const cwd = process.cwd();
|
|
182
|
+
this.emit("team_started", { teamId: this.teamId, teammateCount: team.teammates.length });
|
|
183
|
+
// Spawn worker threads for each teammate
|
|
184
|
+
const parentConversationId = getConversationId();
|
|
185
|
+
for (const teammate of team.teammates) {
|
|
186
|
+
const worker = await spawnTeammate(this.teamId, teammate.id, teammate.name, teammate.model, cwd, parentConversationId, team.name);
|
|
187
|
+
this.lastMessageTime.set(teammate.id, Date.now());
|
|
188
|
+
// Handle messages from worker
|
|
189
|
+
worker.on("message", (msg) => {
|
|
190
|
+
this.lastMessageTime.set(msg.teammateId, Date.now());
|
|
191
|
+
this.handleTeammateMessage(msg);
|
|
192
|
+
});
|
|
193
|
+
worker.on("error", (err) => {
|
|
194
|
+
this.emit("teammate_error", { teammateId: teammate.id, error: err.message });
|
|
195
|
+
// Fail any in-progress task when worker crashes
|
|
196
|
+
this.handleTeammateFailure(teammate.id, err.message);
|
|
197
|
+
});
|
|
198
|
+
worker.on("exit", (code) => {
|
|
199
|
+
if (code !== 0) {
|
|
200
|
+
this.emit("teammate_exit", { teammateId: teammate.id, code });
|
|
201
|
+
// Fail any in-progress task on non-zero exit
|
|
202
|
+
this.handleTeammateFailure(teammate.id, `Worker exited with code ${code}`);
|
|
203
|
+
}
|
|
204
|
+
this.workers.delete(teammate.id);
|
|
205
|
+
this.checkCompletion();
|
|
206
|
+
});
|
|
207
|
+
this.workers.set(teammate.id, worker);
|
|
208
|
+
}
|
|
209
|
+
// Wait for all workers to complete — with timeout and stall detection
|
|
210
|
+
return new Promise((resolve) => {
|
|
211
|
+
this.resolveTeam = resolve;
|
|
212
|
+
const cleanup = () => {
|
|
213
|
+
if (this.teamTimer) {
|
|
214
|
+
clearTimeout(this.teamTimer);
|
|
215
|
+
this.teamTimer = null;
|
|
216
|
+
}
|
|
217
|
+
if (this.stallInterval) {
|
|
218
|
+
clearInterval(this.stallInterval);
|
|
219
|
+
this.stallInterval = null;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
const forceComplete = (reason) => {
|
|
223
|
+
cleanup();
|
|
224
|
+
this.resolveTeam = null; // Prevent double-resolve from checkCompletion
|
|
225
|
+
// Terminate all remaining workers
|
|
226
|
+
for (const [id, worker] of this.workers) {
|
|
227
|
+
this.emit("teammate_timeout", { teammateId: id, reason });
|
|
228
|
+
this.handleTeammateFailure(id, `Terminated: ${reason}`);
|
|
229
|
+
worker.terminate();
|
|
230
|
+
}
|
|
231
|
+
this.workers.clear();
|
|
232
|
+
if (this.teamId)
|
|
233
|
+
setTeamStatus(this.teamId, "completed");
|
|
234
|
+
resolve(this.buildResult());
|
|
235
|
+
};
|
|
236
|
+
// Global team timeout
|
|
237
|
+
this.teamTimer = setTimeout(() => {
|
|
238
|
+
if (this.workers.size > 0) {
|
|
239
|
+
forceComplete(`Team timeout after ${TEAM_TIMEOUT_MS / 1000}s`);
|
|
240
|
+
}
|
|
241
|
+
}, TEAM_TIMEOUT_MS);
|
|
242
|
+
// Stall detection — check every 15s for stalled workers
|
|
243
|
+
this.stallInterval = setInterval(() => {
|
|
244
|
+
if (this.workers.size === 0) {
|
|
245
|
+
cleanup();
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const now = Date.now();
|
|
249
|
+
for (const [id, worker] of this.workers) {
|
|
250
|
+
const lastMsg = this.lastMessageTime.get(id) || 0;
|
|
251
|
+
if (now - lastMsg > WORKER_STALL_MS) {
|
|
252
|
+
this.emit("teammate_timeout", { teammateId: id, reason: "stall" });
|
|
253
|
+
this.handleTeammateFailure(id, `Worker stalled (no messages for ${WORKER_STALL_MS / 1000}s)`);
|
|
254
|
+
worker.terminate();
|
|
255
|
+
this.workers.delete(id);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}, 15_000);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
// ============================================================================
|
|
262
|
+
// MESSAGE HANDLING
|
|
263
|
+
// ============================================================================
|
|
264
|
+
handleTeammateMessage(msg) {
|
|
265
|
+
const emitter = getGlobalEmitter();
|
|
266
|
+
const team = this.teamId ? loadTeam(this.teamId) : null;
|
|
267
|
+
const teammate = team?.teammates.find(t => t.id === msg.teammateId);
|
|
268
|
+
const teammateName = teammate?.name || msg.teammateId;
|
|
269
|
+
switch (msg.type) {
|
|
270
|
+
case "progress":
|
|
271
|
+
this.emit("teammate_progress", {
|
|
272
|
+
teammateId: msg.teammateId,
|
|
273
|
+
taskId: msg.taskId,
|
|
274
|
+
content: msg.content,
|
|
275
|
+
});
|
|
276
|
+
// Emit to global emitter for UI
|
|
277
|
+
if (this.teamId) {
|
|
278
|
+
emitter.emitTeamProgress(this.teamId, msg.teammateId, teammateName, msg.content, msg.taskId);
|
|
279
|
+
}
|
|
280
|
+
break;
|
|
281
|
+
case "task_started":
|
|
282
|
+
this.emit("task_started", {
|
|
283
|
+
teammateId: msg.teammateId,
|
|
284
|
+
taskId: msg.taskId,
|
|
285
|
+
content: msg.content,
|
|
286
|
+
});
|
|
287
|
+
// Emit to global emitter for UI
|
|
288
|
+
if (this.teamId && msg.taskId) {
|
|
289
|
+
emitter.emitTeamTask(this.teamId, msg.teammateId, msg.taskId, msg.content, "started");
|
|
290
|
+
}
|
|
291
|
+
break;
|
|
292
|
+
case "task_completed":
|
|
293
|
+
this.emit("task_completed", {
|
|
294
|
+
teammateId: msg.teammateId,
|
|
295
|
+
taskId: msg.taskId,
|
|
296
|
+
content: msg.content,
|
|
297
|
+
});
|
|
298
|
+
// Emit to global emitter for UI
|
|
299
|
+
if (this.teamId && msg.taskId) {
|
|
300
|
+
emitter.emitTeamTask(this.teamId, msg.teammateId, msg.taskId, msg.content, "completed", msg.content);
|
|
301
|
+
}
|
|
302
|
+
break;
|
|
303
|
+
case "message_sent":
|
|
304
|
+
this.emit("message_sent", {
|
|
305
|
+
teammateId: msg.teammateId,
|
|
306
|
+
content: msg.content,
|
|
307
|
+
});
|
|
308
|
+
break;
|
|
309
|
+
case "done": {
|
|
310
|
+
this.emit("teammate_done", {
|
|
311
|
+
teammateId: msg.teammateId,
|
|
312
|
+
content: msg.content,
|
|
313
|
+
tokensUsed: msg.tokensUsed,
|
|
314
|
+
});
|
|
315
|
+
// Emit UI event so TeamPanel shows "done" (overrides any prior "failed" from task errors)
|
|
316
|
+
const teammateName = this.teamId
|
|
317
|
+
? loadTeam(this.teamId)?.teammates.find(t => t.id === msg.teammateId)?.name
|
|
318
|
+
: undefined;
|
|
319
|
+
emitter.emitTeamProgress(this.teamId, msg.teammateId, teammateName || msg.teammateId, "done");
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
case "error":
|
|
323
|
+
this.emit("teammate_error", {
|
|
324
|
+
teammateId: msg.teammateId,
|
|
325
|
+
content: msg.content,
|
|
326
|
+
});
|
|
327
|
+
// Fail any in-progress task when teammate reports error
|
|
328
|
+
this.handleTeammateFailure(msg.teammateId, msg.content);
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// ============================================================================
|
|
333
|
+
// FAILURE HANDLING
|
|
334
|
+
// ============================================================================
|
|
335
|
+
async handleTeammateFailure(teammateId, errorMessage) {
|
|
336
|
+
if (!this.teamId)
|
|
337
|
+
return;
|
|
338
|
+
const team = loadTeam(this.teamId);
|
|
339
|
+
if (!team)
|
|
340
|
+
return;
|
|
341
|
+
const teammate = team.teammates.find(t => t.id === teammateId);
|
|
342
|
+
if (!teammate)
|
|
343
|
+
return;
|
|
344
|
+
// Find and fail the task this teammate was working on
|
|
345
|
+
const inProgressTask = team.tasks.find(t => t.status === "in_progress" && t.assignedTo === teammateId);
|
|
346
|
+
if (inProgressTask) {
|
|
347
|
+
await failTask(this.teamId, inProgressTask.id, errorMessage);
|
|
348
|
+
this.emit("task_failed", {
|
|
349
|
+
teammateId,
|
|
350
|
+
taskId: inProgressTask.id,
|
|
351
|
+
error: errorMessage,
|
|
352
|
+
});
|
|
353
|
+
// Emit to global emitter for UI
|
|
354
|
+
const emitter = getGlobalEmitter();
|
|
355
|
+
emitter.emitTeamTask(this.teamId, teammateId, inProgressTask.id, inProgressTask.description, "failed", errorMessage);
|
|
356
|
+
}
|
|
357
|
+
// Update teammate status (use "done" since "error" isn't a valid status)
|
|
358
|
+
await updateTeammate(this.teamId, teammateId, {
|
|
359
|
+
status: "done",
|
|
360
|
+
currentTask: undefined,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
// ============================================================================
|
|
364
|
+
// COMPLETION
|
|
365
|
+
// ============================================================================
|
|
366
|
+
checkCompletion() {
|
|
367
|
+
if (this.workers.size === 0 && this.teamId) {
|
|
368
|
+
// Clean up timers
|
|
369
|
+
if (this.teamTimer) {
|
|
370
|
+
clearTimeout(this.teamTimer);
|
|
371
|
+
this.teamTimer = null;
|
|
372
|
+
}
|
|
373
|
+
if (this.stallInterval) {
|
|
374
|
+
clearInterval(this.stallInterval);
|
|
375
|
+
this.stallInterval = null;
|
|
376
|
+
}
|
|
377
|
+
setTeamStatus(this.teamId, "completed");
|
|
378
|
+
this.emit("team_completed", { teamId: this.teamId });
|
|
379
|
+
// Resolve the runTeam() promise
|
|
380
|
+
if (this.resolveTeam) {
|
|
381
|
+
this.resolveTeam(this.buildResult());
|
|
382
|
+
this.resolveTeam = null;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
buildResult() {
|
|
387
|
+
if (!this.teamId) {
|
|
388
|
+
return {
|
|
389
|
+
success: false,
|
|
390
|
+
teamId: "",
|
|
391
|
+
summary: "No team created",
|
|
392
|
+
taskResults: [],
|
|
393
|
+
tokensUsed: { input: 0, output: 0 },
|
|
394
|
+
durationMs: Date.now() - this.startTime,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
const team = loadTeam(this.teamId);
|
|
398
|
+
const progress = getTeamProgress(team);
|
|
399
|
+
// Calculate total tokens
|
|
400
|
+
let totalIn = 0;
|
|
401
|
+
let totalOut = 0;
|
|
402
|
+
for (const teammate of team.teammates) {
|
|
403
|
+
totalIn += teammate.tokensUsed.input;
|
|
404
|
+
totalOut += teammate.tokensUsed.output;
|
|
405
|
+
}
|
|
406
|
+
// Build task results
|
|
407
|
+
const taskResults = team.tasks.map(t => ({
|
|
408
|
+
description: t.description,
|
|
409
|
+
result: t.result || t.error || "Not completed",
|
|
410
|
+
status: t.status === "completed" ? "completed" : "failed",
|
|
411
|
+
}));
|
|
412
|
+
const durationMs = Date.now() - this.startTime;
|
|
413
|
+
const success = progress.blocked === 0 && progress.completed === progress.total;
|
|
414
|
+
// Log team completion
|
|
415
|
+
logSpan({
|
|
416
|
+
action: "team.complete",
|
|
417
|
+
durationMs,
|
|
418
|
+
context: {
|
|
419
|
+
traceId: this.traceId,
|
|
420
|
+
spanId: generateSpanId(),
|
|
421
|
+
parentSpanId: this.spanId,
|
|
422
|
+
source: "claude_code",
|
|
423
|
+
serviceName: "whale-cli",
|
|
424
|
+
serviceVersion: "2.1.0",
|
|
425
|
+
inputTokens: totalIn,
|
|
426
|
+
outputTokens: totalOut,
|
|
427
|
+
},
|
|
428
|
+
storeId: resolveConfig().storeId || undefined,
|
|
429
|
+
details: {
|
|
430
|
+
// Team identification (for blackops detection)
|
|
431
|
+
is_team: true,
|
|
432
|
+
is_team_coordinator: true,
|
|
433
|
+
team_id: this.teamId,
|
|
434
|
+
team_name: team.name,
|
|
435
|
+
// Metrics
|
|
436
|
+
tasks_total: progress.total,
|
|
437
|
+
tasks_completed: progress.completed,
|
|
438
|
+
tasks_failed: progress.blocked,
|
|
439
|
+
teammates: team.teammates.length,
|
|
440
|
+
percent_complete: progress.percentComplete,
|
|
441
|
+
// Display metadata
|
|
442
|
+
display_name: `Team Complete: ${team.name}`,
|
|
443
|
+
display_icon: "checkmark.circle.fill",
|
|
444
|
+
display_color: success ? "#10B981" : "#EF4444",
|
|
445
|
+
},
|
|
446
|
+
});
|
|
447
|
+
// Emit team done to global emitter for UI
|
|
448
|
+
const emitter = getGlobalEmitter();
|
|
449
|
+
emitter.emitTeamDone(this.teamId, success, `${progress.completed}/${progress.total} tasks completed`, progress.completed, progress.total, { input: totalIn, output: totalOut }, durationMs);
|
|
450
|
+
return {
|
|
451
|
+
success,
|
|
452
|
+
teamId: this.teamId,
|
|
453
|
+
summary: `${progress.completed}/${progress.total} tasks completed (${progress.percentComplete}%)`,
|
|
454
|
+
taskResults,
|
|
455
|
+
tokensUsed: { input: totalIn, output: totalOut },
|
|
456
|
+
durationMs,
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
// ============================================================================
|
|
460
|
+
// CONTROL METHODS
|
|
461
|
+
// ============================================================================
|
|
462
|
+
async sendToTeammate(teammateId, message) {
|
|
463
|
+
if (!this.teamId)
|
|
464
|
+
return false;
|
|
465
|
+
const result = await sendMessage(this.teamId, "lead", teammateId, message);
|
|
466
|
+
return !!result;
|
|
467
|
+
}
|
|
468
|
+
async broadcast(message) {
|
|
469
|
+
if (!this.teamId)
|
|
470
|
+
return false;
|
|
471
|
+
const result = await sendMessage(this.teamId, "lead", "all", message);
|
|
472
|
+
return !!result;
|
|
473
|
+
}
|
|
474
|
+
async getMessages() {
|
|
475
|
+
if (!this.teamId)
|
|
476
|
+
return [];
|
|
477
|
+
const messages = await getUnreadMessages(this.teamId, "lead");
|
|
478
|
+
if (messages.length > 0) {
|
|
479
|
+
await markMessagesRead(this.teamId, messages.map(m => m.id));
|
|
480
|
+
}
|
|
481
|
+
return messages.map(m => ({ from: m.from, content: m.content }));
|
|
482
|
+
}
|
|
483
|
+
getProgress() {
|
|
484
|
+
if (!this.teamId)
|
|
485
|
+
return null;
|
|
486
|
+
const team = loadTeam(this.teamId);
|
|
487
|
+
if (!team)
|
|
488
|
+
return null;
|
|
489
|
+
return getTeamProgress(team);
|
|
490
|
+
}
|
|
491
|
+
stop() {
|
|
492
|
+
// Terminate all workers
|
|
493
|
+
for (const [id, worker] of this.workers) {
|
|
494
|
+
worker.terminate();
|
|
495
|
+
this.emit("teammate_stopped", { teammateId: id });
|
|
496
|
+
}
|
|
497
|
+
this.workers.clear();
|
|
498
|
+
if (this.teamId) {
|
|
499
|
+
setTeamStatus(this.teamId, "failed");
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
// ============================================================================
|
|
504
|
+
// CONVENIENCE FUNCTION
|
|
505
|
+
// ============================================================================
|
|
506
|
+
export async function runAgentTeam(config) {
|
|
507
|
+
const lead = new TeamLead();
|
|
508
|
+
// Events are handled via global emitter -> ChatApp UI
|
|
509
|
+
// No stderr writes here to avoid interfering with Ink rendering
|
|
510
|
+
await lead.createTeam(config);
|
|
511
|
+
return lead.runTeam();
|
|
512
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team State — Shared state management for Agent Teams
|
|
3
|
+
*
|
|
4
|
+
* Following Anthropic's official patterns:
|
|
5
|
+
* - Shared task list with status tracking
|
|
6
|
+
* - File-based locking to prevent conflicts
|
|
7
|
+
* - Inter-agent message queue
|
|
8
|
+
* - Dependencies between tasks
|
|
9
|
+
*/
|
|
10
|
+
export type TaskStatus = "pending" | "in_progress" | "completed" | "blocked";
|
|
11
|
+
export interface TeamTask {
|
|
12
|
+
id: string;
|
|
13
|
+
description: string;
|
|
14
|
+
status: TaskStatus;
|
|
15
|
+
assignedTo?: string;
|
|
16
|
+
dependencies?: string[];
|
|
17
|
+
files?: string[];
|
|
18
|
+
result?: string;
|
|
19
|
+
error?: string;
|
|
20
|
+
model?: string;
|
|
21
|
+
createdAt: string;
|
|
22
|
+
updatedAt: string;
|
|
23
|
+
}
|
|
24
|
+
export interface TeamMessage {
|
|
25
|
+
id: string;
|
|
26
|
+
from: string;
|
|
27
|
+
to: string;
|
|
28
|
+
content: string;
|
|
29
|
+
timestamp: string;
|
|
30
|
+
read: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface TeammateInfo {
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
model: string;
|
|
36
|
+
status: "idle" | "working" | "waiting" | "done";
|
|
37
|
+
currentTask?: string;
|
|
38
|
+
tokensUsed: {
|
|
39
|
+
input: number;
|
|
40
|
+
output: number;
|
|
41
|
+
};
|
|
42
|
+
startedAt: string;
|
|
43
|
+
}
|
|
44
|
+
export interface TeamState {
|
|
45
|
+
id: string;
|
|
46
|
+
name: string;
|
|
47
|
+
leadId: string;
|
|
48
|
+
teammates: TeammateInfo[];
|
|
49
|
+
tasks: TeamTask[];
|
|
50
|
+
messages: TeamMessage[];
|
|
51
|
+
createdAt: string;
|
|
52
|
+
updatedAt: string;
|
|
53
|
+
status: "active" | "completed" | "failed";
|
|
54
|
+
}
|
|
55
|
+
export declare function createTeam(name: string, leadId: string): TeamState;
|
|
56
|
+
export declare function loadTeam(teamId: string): TeamState | null;
|
|
57
|
+
export declare function saveTeam(team: TeamState): void;
|
|
58
|
+
export declare function listTeams(): TeamState[];
|
|
59
|
+
export declare function addTeammate(teamId: string, teammate: Omit<TeammateInfo, "tokensUsed" | "startedAt">): Promise<TeammateInfo | null>;
|
|
60
|
+
export declare function updateTeammate(teamId: string, teammateId: string, updates: Partial<TeammateInfo>): Promise<boolean>;
|
|
61
|
+
export declare function addTask(teamId: string, task: Omit<TeamTask, "id" | "status" | "createdAt" | "updatedAt">): Promise<TeamTask | null>;
|
|
62
|
+
export declare function claimTask(teamId: string, taskId: string, teammateId: string): Promise<TeamTask | null>;
|
|
63
|
+
export declare function completeTask(teamId: string, taskId: string, result: string): Promise<boolean>;
|
|
64
|
+
export declare function failTask(teamId: string, taskId: string, error: string): Promise<boolean>;
|
|
65
|
+
export declare function getAvailableTasks(team: TeamState): TeamTask[];
|
|
66
|
+
export declare function sendMessage(teamId: string, from: string, to: string, content: string): Promise<TeamMessage | null>;
|
|
67
|
+
export declare function getUnreadMessages(teamId: string, recipientId: string): Promise<TeamMessage[]>;
|
|
68
|
+
export declare function markMessagesRead(teamId: string, messageIds: string[]): Promise<boolean>;
|
|
69
|
+
export declare function getTeamProgress(team: TeamState): {
|
|
70
|
+
total: number;
|
|
71
|
+
completed: number;
|
|
72
|
+
inProgress: number;
|
|
73
|
+
pending: number;
|
|
74
|
+
blocked: number;
|
|
75
|
+
percentComplete: number;
|
|
76
|
+
};
|
|
77
|
+
export declare function setTeamStatus(teamId: string, status: TeamState["status"]): Promise<boolean>;
|