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,398 @@
|
|
|
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
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync, readdirSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
import { homedir } from "os";
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// STORAGE
|
|
15
|
+
// ============================================================================
|
|
16
|
+
const TEAMS_DIR = join(homedir(), ".swagmanager", "teams");
|
|
17
|
+
function ensureTeamsDir() {
|
|
18
|
+
if (!existsSync(TEAMS_DIR)) {
|
|
19
|
+
mkdirSync(TEAMS_DIR, { recursive: true });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function getTeamPath(teamId) {
|
|
23
|
+
return join(TEAMS_DIR, `${teamId}.json`);
|
|
24
|
+
}
|
|
25
|
+
function getLockPath(teamId) {
|
|
26
|
+
return join(TEAMS_DIR, `${teamId}.lock`);
|
|
27
|
+
}
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// FILE LOCKING — Prevents concurrent modifications
|
|
30
|
+
// ============================================================================
|
|
31
|
+
const LOCK_TIMEOUT_MS = 5000;
|
|
32
|
+
const LOCK_RETRY_MS = 50;
|
|
33
|
+
async function acquireLock(teamId) {
|
|
34
|
+
const lockPath = getLockPath(teamId);
|
|
35
|
+
const startTime = Date.now();
|
|
36
|
+
while (Date.now() - startTime < LOCK_TIMEOUT_MS) {
|
|
37
|
+
try {
|
|
38
|
+
// Check if lock exists and is stale
|
|
39
|
+
if (existsSync(lockPath)) {
|
|
40
|
+
const lockData = readFileSync(lockPath, "utf-8");
|
|
41
|
+
const lockTime = parseInt(lockData, 10);
|
|
42
|
+
if (Date.now() - lockTime > LOCK_TIMEOUT_MS) {
|
|
43
|
+
// Stale lock, remove it
|
|
44
|
+
unlinkSync(lockPath);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Valid lock, wait and retry
|
|
48
|
+
await new Promise(r => setTimeout(r, LOCK_RETRY_MS));
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Try to create lock
|
|
53
|
+
writeFileSync(lockPath, Date.now().toString(), { flag: "wx" });
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
if (err.code === "EEXIST") {
|
|
58
|
+
// Lock was created by another process, retry
|
|
59
|
+
await new Promise(r => setTimeout(r, LOCK_RETRY_MS));
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
function releaseLock(teamId) {
|
|
68
|
+
const lockPath = getLockPath(teamId);
|
|
69
|
+
try {
|
|
70
|
+
if (existsSync(lockPath)) {
|
|
71
|
+
unlinkSync(lockPath);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Ignore errors releasing lock
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// ============================================================================
|
|
79
|
+
// STATE OPERATIONS
|
|
80
|
+
// ============================================================================
|
|
81
|
+
export function createTeam(name, leadId) {
|
|
82
|
+
ensureTeamsDir();
|
|
83
|
+
const team = {
|
|
84
|
+
id: `team-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
|
85
|
+
name,
|
|
86
|
+
leadId,
|
|
87
|
+
teammates: [],
|
|
88
|
+
tasks: [],
|
|
89
|
+
messages: [],
|
|
90
|
+
createdAt: new Date().toISOString(),
|
|
91
|
+
updatedAt: new Date().toISOString(),
|
|
92
|
+
status: "active",
|
|
93
|
+
};
|
|
94
|
+
saveTeam(team);
|
|
95
|
+
return team;
|
|
96
|
+
}
|
|
97
|
+
export function loadTeam(teamId) {
|
|
98
|
+
const path = getTeamPath(teamId);
|
|
99
|
+
if (!existsSync(path))
|
|
100
|
+
return null;
|
|
101
|
+
try {
|
|
102
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export function saveTeam(team) {
|
|
109
|
+
ensureTeamsDir();
|
|
110
|
+
team.updatedAt = new Date().toISOString();
|
|
111
|
+
writeFileSync(getTeamPath(team.id), JSON.stringify(team, null, 2));
|
|
112
|
+
}
|
|
113
|
+
export function listTeams() {
|
|
114
|
+
ensureTeamsDir();
|
|
115
|
+
const files = existsSync(TEAMS_DIR)
|
|
116
|
+
? readdirSync(TEAMS_DIR).filter((f) => f.endsWith(".json") && !f.endsWith(".lock"))
|
|
117
|
+
: [];
|
|
118
|
+
return files.map((f) => {
|
|
119
|
+
try {
|
|
120
|
+
return JSON.parse(readFileSync(join(TEAMS_DIR, f), "utf-8"));
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}).filter(Boolean);
|
|
126
|
+
}
|
|
127
|
+
// ============================================================================
|
|
128
|
+
// TEAMMATE MANAGEMENT
|
|
129
|
+
// ============================================================================
|
|
130
|
+
export async function addTeammate(teamId, teammate) {
|
|
131
|
+
if (!await acquireLock(teamId)) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
const team = loadTeam(teamId);
|
|
136
|
+
if (!team)
|
|
137
|
+
return null;
|
|
138
|
+
const newTeammate = {
|
|
139
|
+
...teammate,
|
|
140
|
+
tokensUsed: { input: 0, output: 0 },
|
|
141
|
+
startedAt: new Date().toISOString(),
|
|
142
|
+
};
|
|
143
|
+
team.teammates.push(newTeammate);
|
|
144
|
+
saveTeam(team);
|
|
145
|
+
return newTeammate;
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
releaseLock(teamId);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
export async function updateTeammate(teamId, teammateId, updates) {
|
|
152
|
+
if (!await acquireLock(teamId)) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
const team = loadTeam(teamId);
|
|
157
|
+
if (!team)
|
|
158
|
+
return false;
|
|
159
|
+
const idx = team.teammates.findIndex(t => t.id === teammateId);
|
|
160
|
+
if (idx === -1)
|
|
161
|
+
return false;
|
|
162
|
+
team.teammates[idx] = { ...team.teammates[idx], ...updates };
|
|
163
|
+
saveTeam(team);
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
releaseLock(teamId);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// ============================================================================
|
|
171
|
+
// TASK MANAGEMENT
|
|
172
|
+
// ============================================================================
|
|
173
|
+
export async function addTask(teamId, task) {
|
|
174
|
+
if (!await acquireLock(teamId)) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const team = loadTeam(teamId);
|
|
179
|
+
if (!team)
|
|
180
|
+
return null;
|
|
181
|
+
const newTask = {
|
|
182
|
+
...task,
|
|
183
|
+
id: `task-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
|
184
|
+
status: "pending",
|
|
185
|
+
createdAt: new Date().toISOString(),
|
|
186
|
+
updatedAt: new Date().toISOString(),
|
|
187
|
+
};
|
|
188
|
+
team.tasks.push(newTask);
|
|
189
|
+
saveTeam(team);
|
|
190
|
+
return newTask;
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
releaseLock(teamId);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
export async function claimTask(teamId, taskId, teammateId) {
|
|
197
|
+
if (!await acquireLock(teamId)) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
const team = loadTeam(teamId);
|
|
202
|
+
if (!team)
|
|
203
|
+
return null;
|
|
204
|
+
const task = team.tasks.find(t => t.id === taskId);
|
|
205
|
+
if (!task)
|
|
206
|
+
return null;
|
|
207
|
+
// Check if task is claimable
|
|
208
|
+
if (task.status !== "pending") {
|
|
209
|
+
return null; // Already claimed or completed
|
|
210
|
+
}
|
|
211
|
+
// Check dependencies
|
|
212
|
+
if (task.dependencies?.length) {
|
|
213
|
+
const allDepsComplete = task.dependencies.every(depId => {
|
|
214
|
+
const dep = team.tasks.find(t => t.id === depId);
|
|
215
|
+
return dep?.status === "completed";
|
|
216
|
+
});
|
|
217
|
+
if (!allDepsComplete) {
|
|
218
|
+
return null; // Dependencies not met
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Check for file conflicts with other in-progress tasks
|
|
222
|
+
if (task.files?.length) {
|
|
223
|
+
const conflicts = team.tasks.filter(t => t.status === "in_progress" &&
|
|
224
|
+
t.id !== taskId &&
|
|
225
|
+
t.files?.some(f => task.files?.includes(f)));
|
|
226
|
+
if (conflicts.length > 0) {
|
|
227
|
+
return null; // File conflict
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// Claim the task
|
|
231
|
+
task.status = "in_progress";
|
|
232
|
+
task.assignedTo = teammateId;
|
|
233
|
+
task.updatedAt = new Date().toISOString();
|
|
234
|
+
saveTeam(team);
|
|
235
|
+
return task;
|
|
236
|
+
}
|
|
237
|
+
finally {
|
|
238
|
+
releaseLock(teamId);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
export async function completeTask(teamId, taskId, result) {
|
|
242
|
+
if (!await acquireLock(teamId)) {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
const team = loadTeam(teamId);
|
|
247
|
+
if (!team)
|
|
248
|
+
return false;
|
|
249
|
+
const task = team.tasks.find(t => t.id === taskId);
|
|
250
|
+
if (!task)
|
|
251
|
+
return false;
|
|
252
|
+
task.status = "completed";
|
|
253
|
+
task.result = result;
|
|
254
|
+
task.updatedAt = new Date().toISOString();
|
|
255
|
+
// Check if all tasks are done
|
|
256
|
+
const allDone = team.tasks.every(t => t.status === "completed");
|
|
257
|
+
if (allDone) {
|
|
258
|
+
team.status = "completed";
|
|
259
|
+
}
|
|
260
|
+
saveTeam(team);
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
releaseLock(teamId);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
export async function failTask(teamId, taskId, error) {
|
|
268
|
+
if (!await acquireLock(teamId)) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
const team = loadTeam(teamId);
|
|
273
|
+
if (!team)
|
|
274
|
+
return false;
|
|
275
|
+
const task = team.tasks.find(t => t.id === taskId);
|
|
276
|
+
if (!task)
|
|
277
|
+
return false;
|
|
278
|
+
task.status = "blocked";
|
|
279
|
+
task.error = error;
|
|
280
|
+
task.updatedAt = new Date().toISOString();
|
|
281
|
+
saveTeam(team);
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
releaseLock(teamId);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
export function getAvailableTasks(team) {
|
|
289
|
+
return team.tasks.filter(task => {
|
|
290
|
+
if (task.status !== "pending")
|
|
291
|
+
return false;
|
|
292
|
+
// Check dependencies
|
|
293
|
+
if (task.dependencies?.length) {
|
|
294
|
+
const allDepsComplete = task.dependencies.every(depId => {
|
|
295
|
+
const dep = team.tasks.find(t => t.id === depId);
|
|
296
|
+
return dep?.status === "completed";
|
|
297
|
+
});
|
|
298
|
+
if (!allDepsComplete)
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
// Check file conflicts
|
|
302
|
+
if (task.files?.length) {
|
|
303
|
+
const conflicts = team.tasks.filter(t => t.status === "in_progress" &&
|
|
304
|
+
t.files?.some(f => task.files?.includes(f)));
|
|
305
|
+
if (conflicts.length > 0)
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
return true;
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
// ============================================================================
|
|
312
|
+
// MESSAGING
|
|
313
|
+
// ============================================================================
|
|
314
|
+
export async function sendMessage(teamId, from, to, content) {
|
|
315
|
+
if (!await acquireLock(teamId)) {
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
const team = loadTeam(teamId);
|
|
320
|
+
if (!team)
|
|
321
|
+
return null;
|
|
322
|
+
const message = {
|
|
323
|
+
id: `msg-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
|
324
|
+
from,
|
|
325
|
+
to,
|
|
326
|
+
content,
|
|
327
|
+
timestamp: new Date().toISOString(),
|
|
328
|
+
read: false,
|
|
329
|
+
};
|
|
330
|
+
team.messages.push(message);
|
|
331
|
+
saveTeam(team);
|
|
332
|
+
return message;
|
|
333
|
+
}
|
|
334
|
+
finally {
|
|
335
|
+
releaseLock(teamId);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
export async function getUnreadMessages(teamId, recipientId) {
|
|
339
|
+
const team = loadTeam(teamId);
|
|
340
|
+
if (!team)
|
|
341
|
+
return [];
|
|
342
|
+
return team.messages.filter(m => !m.read &&
|
|
343
|
+
(m.to === recipientId || m.to === "all"));
|
|
344
|
+
}
|
|
345
|
+
export async function markMessagesRead(teamId, messageIds) {
|
|
346
|
+
if (!await acquireLock(teamId)) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
try {
|
|
350
|
+
const team = loadTeam(teamId);
|
|
351
|
+
if (!team)
|
|
352
|
+
return false;
|
|
353
|
+
for (const msg of team.messages) {
|
|
354
|
+
if (messageIds.includes(msg.id)) {
|
|
355
|
+
msg.read = true;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
saveTeam(team);
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
finally {
|
|
362
|
+
releaseLock(teamId);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
// ============================================================================
|
|
366
|
+
// TEAM STATUS
|
|
367
|
+
// ============================================================================
|
|
368
|
+
export function getTeamProgress(team) {
|
|
369
|
+
const total = team.tasks.length;
|
|
370
|
+
const completed = team.tasks.filter(t => t.status === "completed").length;
|
|
371
|
+
const inProgress = team.tasks.filter(t => t.status === "in_progress").length;
|
|
372
|
+
const pending = team.tasks.filter(t => t.status === "pending").length;
|
|
373
|
+
const blocked = team.tasks.filter(t => t.status === "blocked").length;
|
|
374
|
+
return {
|
|
375
|
+
total,
|
|
376
|
+
completed,
|
|
377
|
+
inProgress,
|
|
378
|
+
pending,
|
|
379
|
+
blocked,
|
|
380
|
+
percentComplete: total > 0 ? Math.round((completed / total) * 100) : 0,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
export async function setTeamStatus(teamId, status) {
|
|
384
|
+
if (!await acquireLock(teamId)) {
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
try {
|
|
388
|
+
const team = loadTeam(teamId);
|
|
389
|
+
if (!team)
|
|
390
|
+
return false;
|
|
391
|
+
team.status = status;
|
|
392
|
+
saveTeam(team);
|
|
393
|
+
return true;
|
|
394
|
+
}
|
|
395
|
+
finally {
|
|
396
|
+
releaseLock(teamId);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Teammate — Independent agent instance in a Team
|
|
3
|
+
*
|
|
4
|
+
* Following Anthropic's official patterns:
|
|
5
|
+
* - Runs in separate context window (worker thread)
|
|
6
|
+
* - Works on tasks from shared task list
|
|
7
|
+
* - Can message other teammates directly
|
|
8
|
+
* - Full tool access (not restricted like subagents)
|
|
9
|
+
*/
|
|
10
|
+
import { Worker } from "worker_threads";
|
|
11
|
+
export interface TeammateWorkerData {
|
|
12
|
+
teamId: string;
|
|
13
|
+
teammateId: string;
|
|
14
|
+
teammateName: string;
|
|
15
|
+
model: string;
|
|
16
|
+
cwd: string;
|
|
17
|
+
parentConversationId: string;
|
|
18
|
+
teamName: string;
|
|
19
|
+
authToken?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface TeammateMessage {
|
|
22
|
+
type: "progress" | "task_started" | "task_completed" | "message_sent" | "done" | "error";
|
|
23
|
+
teammateId: string;
|
|
24
|
+
taskId?: string;
|
|
25
|
+
content: string;
|
|
26
|
+
tokensUsed?: {
|
|
27
|
+
input: number;
|
|
28
|
+
output: number;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export declare function spawnTeammate(teamId: string, teammateId: string, teammateName: string, model: string, cwd: string, parentConversationId: string, teamName: string): Promise<Worker>;
|