claude-flow-novice 2.16.0 → 2.16.1

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.
Files changed (154) hide show
  1. package/.claude/cfn-extras/skills/GOOGLE_SHEETS_SKILLS_README.md +1 -1
  2. package/.claude/cfn-extras/skills/google-sheets-api-coordinator/SKILL.md +1 -1
  3. package/.claude/cfn-extras/skills/google-sheets-formula-builder/SKILL.md +1 -1
  4. package/.claude/cfn-extras/skills/google-sheets-progress/SKILL.md +1 -1
  5. package/.claude/commands/CFN_LOOP_FRONTEND.md +1 -1
  6. package/.claude/commands/cfn-loop-cli.md +124 -46
  7. package/.claude/commands/cfn-loop-frontend.md +1 -1
  8. package/.claude/commands/cfn-loop-task.md +2 -2
  9. package/.claude/commands/deprecated/cfn-loop.md +2 -2
  10. package/.claude/hooks/cfn-invoke-post-edit.sh +31 -5
  11. package/.claude/hooks/cfn-post-edit.config.json +9 -2
  12. package/.claude/root-claude-distribute/CFN-CLAUDE.md +1 -1
  13. package/.claude/skills/cfn-backlog-management/SKILL.md +1 -1
  14. package/.claude/skills/cfn-loop-orchestration/NORTH_STAR_INDEX.md +1 -1
  15. package/claude-assets/agents/cfn-dev-team/analysts/root-cause-analyst.md +2 -2
  16. package/claude-assets/agents/cfn-dev-team/architecture/base-template-generator.md +1 -1
  17. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +2 -2
  18. package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +1 -1
  19. package/claude-assets/agents/cfn-dev-team/dev-ops/devops-engineer.md +1 -1
  20. package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +2 -2
  21. package/claude-assets/agents/cfn-dev-team/dev-ops/github-commit-agent.md +2 -2
  22. package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +1 -1
  23. package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +1 -1
  24. package/claude-assets/agents/cfn-dev-team/developers/data/data-engineer.md +1 -1
  25. package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +1 -1
  26. package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +1 -1
  27. package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +1 -1
  28. package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +1 -1
  29. package/claude-assets/agents/cfn-dev-team/documentation/pseudocode.md +1 -1
  30. package/claude-assets/agents/cfn-dev-team/product-owners/accessibility-advocate-persona.md +1 -1
  31. package/claude-assets/agents/cfn-dev-team/product-owners/cto-agent.md +1 -1
  32. package/claude-assets/agents/cfn-dev-team/product-owners/power-user-persona.md +1 -1
  33. package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +1 -1
  34. package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +1 -1
  35. package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +1 -1
  36. package/claude-assets/agents/cfn-dev-team/testers/contract-tester.md +1 -1
  37. package/claude-assets/agents/cfn-dev-team/testers/e2e/playwright-tester.md +1 -1
  38. package/claude-assets/agents/cfn-dev-team/testers/integration-tester.md +1 -1
  39. package/claude-assets/agents/cfn-dev-team/testers/load-testing-specialist.md +1 -1
  40. package/claude-assets/agents/cfn-dev-team/testers/mutation-testing-specialist.md +1 -1
  41. package/claude-assets/agents/cfn-dev-team/testers/unit/tdd-london-unit-swarm.md +1 -1
  42. package/claude-assets/agents/cfn-dev-team/utility/agent-builder.md +11 -0
  43. package/claude-assets/agents/cfn-dev-team/utility/analyst.md +1 -1
  44. package/claude-assets/agents/cfn-dev-team/utility/claude-code-expert.md +1 -1
  45. package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +1 -1
  46. package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +1 -1
  47. package/claude-assets/agents/cfn-dev-team/utility/researcher.md +1 -1
  48. package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +1 -1
  49. package/claude-assets/agents/custom/cfn-docker-expert.md +1 -0
  50. package/claude-assets/agents/custom/cfn-loops-cli-expert.md +326 -17
  51. package/claude-assets/agents/custom/cfn-redis-operations.md +529 -529
  52. package/claude-assets/agents/custom/cfn-system-expert.md +1 -1
  53. package/claude-assets/agents/custom/trigger-dev-expert.md +369 -0
  54. package/claude-assets/agents/docker-team/micro-sprint-planner.md +747 -747
  55. package/claude-assets/agents/project-only-agents/npm-package-specialist.md +1 -1
  56. package/claude-assets/cfn-extras/skills/GOOGLE_SHEETS_SKILLS_README.md +1 -1
  57. package/claude-assets/cfn-extras/skills/google-sheets-api-coordinator/SKILL.md +1 -1
  58. package/claude-assets/cfn-extras/skills/google-sheets-formula-builder/SKILL.md +1 -1
  59. package/claude-assets/cfn-extras/skills/google-sheets-progress/SKILL.md +1 -1
  60. package/claude-assets/commands/CFN_LOOP_FRONTEND.md +1 -1
  61. package/claude-assets/commands/cfn-loop-cli.md +124 -46
  62. package/claude-assets/commands/cfn-loop-frontend.md +1 -1
  63. package/claude-assets/commands/cfn-loop-task.md +2 -2
  64. package/claude-assets/commands/deprecated/cfn-loop.md +2 -2
  65. package/claude-assets/hooks/GIT-HOOKS-USAGE-EXAMPLES.md +116 -0
  66. package/claude-assets/hooks/README-GIT-HOOKS.md +443 -0
  67. package/claude-assets/hooks/cfn-invoke-post-edit.sh +31 -5
  68. package/claude-assets/hooks/cfn-post-edit.config.json +9 -2
  69. package/claude-assets/hooks/install-git-hooks.sh +243 -0
  70. package/claude-assets/hooks/subagent-start.sh +98 -0
  71. package/claude-assets/hooks/subagent-stop.sh +93 -0
  72. package/claude-assets/hooks/validators/credential-scanner.sh +172 -0
  73. package/claude-assets/root-claude-distribute/CFN-CLAUDE.md +1 -1
  74. package/claude-assets/skills/cfn-backlog-management/SKILL.md +1 -1
  75. package/claude-assets/skills/cfn-dependency-ingestion/SKILL.md +41 -13
  76. package/claude-assets/skills/cfn-dependency-ingestion/ingest.sh +237 -0
  77. package/claude-assets/skills/cfn-dependency-ingestion/manifests/cli-mode-dependencies.txt +73 -0
  78. package/claude-assets/skills/cfn-dependency-ingestion/manifests/shared-dependencies.txt +57 -0
  79. package/claude-assets/skills/cfn-dependency-ingestion/manifests/trigger-dev-dependencies.txt +82 -0
  80. package/claude-assets/skills/cfn-dependency-ingestion/manifests/trigger-mode-dependencies.txt +80 -0
  81. package/claude-assets/skills/cfn-environment-sanitization/sanitize-environment.sh +14 -4
  82. package/claude-assets/skills/cfn-loop-orchestration/NORTH_STAR_INDEX.md +1 -1
  83. package/claude-assets/skills/cfn-provider-routing/SKILL.md +23 -0
  84. package/claude-assets/skills/docker-build/build.sh +1 -1
  85. package/dist/agent/skill-mcp-selector.js +2 -1
  86. package/dist/agent/skill-mcp-selector.js.map +1 -1
  87. package/dist/agents/agent-loader.js +165 -146
  88. package/dist/agents/agent-loader.js.map +1 -1
  89. package/dist/cli/agent-executor.js +470 -26
  90. package/dist/cli/agent-executor.js.map +1 -1
  91. package/dist/cli/agent-prompt-builder.js +2 -2
  92. package/dist/cli/agent-prompt-builder.js.map +1 -1
  93. package/dist/cli/agent-spawn.js +7 -4
  94. package/dist/cli/agent-spawn.js.map +1 -1
  95. package/dist/cli/agent-spawner.js +51 -4
  96. package/dist/cli/agent-spawner.js.map +1 -1
  97. package/dist/cli/agent-token-manager.js +2 -1
  98. package/dist/cli/agent-token-manager.js.map +1 -1
  99. package/dist/cli/anthropic-client.js +117 -11
  100. package/dist/cli/anthropic-client.js.map +1 -1
  101. package/dist/cli/cfn-context.js +2 -1
  102. package/dist/cli/cfn-context.js.map +1 -1
  103. package/dist/cli/cfn-metrics.js +2 -1
  104. package/dist/cli/cfn-metrics.js.map +1 -1
  105. package/dist/cli/cfn-redis.js +2 -1
  106. package/dist/cli/cfn-redis.js.map +1 -1
  107. package/dist/cli/cli-agent-context.js +2 -0
  108. package/dist/cli/cli-agent-context.js.map +1 -1
  109. package/dist/cli/config-manager.js +4 -252
  110. package/dist/cli/config-manager.js.map +1 -1
  111. package/dist/cli/conversation-fork-cleanup.js +2 -1
  112. package/dist/cli/conversation-fork-cleanup.js.map +1 -1
  113. package/dist/cli/conversation-fork.js +2 -1
  114. package/dist/cli/conversation-fork.js.map +1 -1
  115. package/dist/cli/coordination/agent-messaging.js +415 -0
  116. package/dist/cli/coordination/agent-messaging.js.map +1 -0
  117. package/dist/cli/coordination/wait-for-threshold.js +232 -0
  118. package/dist/cli/coordination/wait-for-threshold.js.map +1 -0
  119. package/dist/cli/iteration-history.js +2 -1
  120. package/dist/cli/iteration-history.js.map +1 -1
  121. package/dist/cli/process-lifecycle.js +5 -1
  122. package/dist/cli/process-lifecycle.js.map +1 -1
  123. package/dist/cli/spawn-agent-cli.js +41 -6
  124. package/dist/cli/spawn-agent-cli.js.map +1 -1
  125. package/dist/coordination/redis-waiting-mode.js +4 -0
  126. package/dist/coordination/redis-waiting-mode.js.map +1 -1
  127. package/dist/lib/artifact-registry.js +4 -0
  128. package/dist/lib/artifact-registry.js.map +1 -1
  129. package/dist/lib/connection-pool.js +390 -0
  130. package/dist/lib/connection-pool.js.map +1 -0
  131. package/dist/lib/environment-contract.js +258 -0
  132. package/dist/lib/environment-contract.js.map +1 -0
  133. package/dist/lib/query-optimizer.js +388 -0
  134. package/dist/lib/query-optimizer.js.map +1 -0
  135. package/dist/lib/result-cache.js +285 -0
  136. package/dist/lib/result-cache.js.map +1 -0
  137. package/dist/mcp/auth-middleware.js +2 -1
  138. package/dist/mcp/auth-middleware.js.map +1 -1
  139. package/dist/mcp/playwright-mcp-server-auth.js +2 -1
  140. package/dist/mcp/playwright-mcp-server-auth.js.map +1 -1
  141. package/package.json +3 -1
  142. package/scripts/build-agent-image.sh +1 -1
  143. package/scripts/cost-allocation-tracker.sh +632 -0
  144. package/scripts/docker-rebuild-all-agents.sh +2 -2
  145. package/scripts/reorganize-tests.sh +280 -0
  146. package/scripts/trigger-dev-setup.sh +12 -0
  147. package/tests/README.md +45 -0
  148. package/.claude/commands/cost-savings-status.md +0 -34
  149. package/.claude/commands/metrics-summary.md +0 -58
  150. package/claude-assets/agents/cfn-dev-team/dev-ops/monitoring-specialist.md +0 -768
  151. package/claude-assets/agents/custom/test-mcp-access.md +0 -24
  152. package/claude-assets/commands/cost-savings-status.md +0 -34
  153. package/claude-assets/commands/metrics-summary.md +0 -58
  154. package/tests/test-memory-leak-task-mode.sh +0 -435
@@ -5,17 +5,47 @@
5
5
  * Supports streaming responses and tool execution.
6
6
  */ import Anthropic from '@anthropic-ai/sdk';
7
7
  import fs from 'fs/promises';
8
+ import fsSync from 'fs';
8
9
  import path from 'path';
9
10
  import { exec } from 'child_process';
10
11
  import { promisify } from 'util';
11
12
  import { executeTool } from './tool-executor.js';
12
13
  const execAsync = promisify(exec);
14
+ // File-based debug logging (for background agents)
15
+ const AGENT_ID = process.env.AGENT_ID || 'unknown';
16
+ const API_LOG_FILE = `/tmp/cfn-api-${AGENT_ID}.log`;
17
+ function apiDebugLog(message, data) {
18
+ const timestamp = new Date().toISOString();
19
+ const logEntry = data ? `${timestamp} [${AGENT_ID}] ${message} ${JSON.stringify(data)}\n` : `${timestamp} [${AGENT_ID}] ${message}\n`;
20
+ try {
21
+ fsSync.appendFileSync(API_LOG_FILE, logEntry);
22
+ } catch (err) {
23
+ // Ignore logging errors
24
+ }
25
+ }
13
26
  /**
14
27
  * Get API configuration from environment and config files
28
+ *
29
+ * Provider resolution order:
30
+ * 1. CLAUDE_API_PROVIDER env var (legacy)
31
+ * 2. PROVIDER env var (set by agent-spawner from --provider flag)
32
+ * 3. Config file (.claude/config/api-provider.json)
33
+ * 4. Default to Z.ai (cost-effective fallback per project requirements)
34
+ *
35
+ * BUG FIX: Previously only checked CLAUDE_API_PROVIDER, ignoring --provider flag
36
+ * which sets PROVIDER env var via agent-spawner.ts
15
37
  */ export async function getAPIConfig() {
16
- // Check environment variable
17
- const envProvider = process.env.CLAUDE_API_PROVIDER;
18
- if (envProvider === 'zai') {
38
+ // Check environment variables - support both CLAUDE_API_PROVIDER (legacy) and PROVIDER (from CLI --provider flag)
39
+ const envProvider = process.env.CLAUDE_API_PROVIDER || process.env.PROVIDER;
40
+ // Debug logging for provider routing (helps diagnose auth errors)
41
+ apiDebugLog('getAPIConfig: Provider detection', {
42
+ CLAUDE_API_PROVIDER: process.env.CLAUDE_API_PROVIDER,
43
+ PROVIDER: process.env.PROVIDER,
44
+ resolved: envProvider
45
+ });
46
+ console.error(`[provider-routing] CLAUDE_API_PROVIDER=${process.env.CLAUDE_API_PROVIDER || 'unset'}, PROVIDER=${process.env.PROVIDER || 'unset'}, resolved=${envProvider || 'none'}`);
47
+ if (envProvider === 'zai' || envProvider === 'z.ai') {
48
+ console.error('[provider-routing] Using Z.ai provider');
19
49
  return {
20
50
  provider: 'zai',
21
51
  apiKey: process.env.ZAI_API_KEY || process.env.ANTHROPIC_API_KEY,
@@ -23,6 +53,7 @@ const execAsync = promisify(exec);
23
53
  };
24
54
  }
25
55
  if (envProvider === 'kimi') {
56
+ console.error('[provider-routing] Using Kimi provider');
26
57
  return {
27
58
  provider: 'kimi',
28
59
  apiKey: process.env.KIMI_API_KEY,
@@ -30,17 +61,26 @@ const execAsync = promisify(exec);
30
61
  };
31
62
  }
32
63
  if (envProvider === 'openrouter') {
64
+ console.error('[provider-routing] Using OpenRouter provider');
33
65
  return {
34
66
  provider: 'openrouter',
35
67
  apiKey: process.env.OPENROUTER_API_KEY,
36
68
  baseURL: process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1'
37
69
  };
38
70
  }
71
+ if (envProvider === 'anthropic') {
72
+ console.error('[provider-routing] Using Anthropic provider (explicit)');
73
+ return {
74
+ provider: 'anthropic',
75
+ apiKey: process.env.ANTHROPIC_API_KEY
76
+ };
77
+ }
39
78
  // Check config file
40
79
  try {
41
80
  const configPath = path.join('.claude', 'config', 'api-provider.json');
42
81
  const config = JSON.parse(await fs.readFile(configPath, 'utf-8'));
43
82
  if (config.provider === 'zai' || config.provider === 'z.ai') {
83
+ console.error('[provider-routing] Using Z.ai provider (from config file)');
44
84
  return {
45
85
  provider: 'zai',
46
86
  apiKey: config.apiKey || process.env.ZAI_API_KEY || process.env.ANTHROPIC_API_KEY,
@@ -48,6 +88,7 @@ const execAsync = promisify(exec);
48
88
  };
49
89
  }
50
90
  if (config.provider === 'kimi') {
91
+ console.error('[provider-routing] Using Kimi provider (from config file)');
51
92
  return {
52
93
  provider: 'kimi',
53
94
  apiKey: config.apiKey || process.env.KIMI_API_KEY,
@@ -55,36 +96,76 @@ const execAsync = promisify(exec);
55
96
  };
56
97
  }
57
98
  if (config.provider === 'openrouter') {
99
+ console.error('[provider-routing] Using OpenRouter provider (from config file)');
58
100
  return {
59
101
  provider: 'openrouter',
60
102
  apiKey: config.apiKey || process.env.OPENROUTER_API_KEY,
61
103
  baseURL: config.baseURL || process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1'
62
104
  };
63
105
  }
106
+ if (config.provider === 'anthropic') {
107
+ console.error('[provider-routing] Using Anthropic provider (from config file)');
108
+ return {
109
+ provider: 'anthropic',
110
+ apiKey: config.apiKey || process.env.ANTHROPIC_API_KEY
111
+ };
112
+ }
64
113
  } catch {
65
114
  // Config file doesn't exist, use defaults
66
115
  }
67
- // Default to Anthropic
116
+ // Default to Z.ai (cost-effective fallback per project requirements)
117
+ // BUG FIX: Previously defaulted to Anthropic which caused auth errors when no provider specified
118
+ console.error('[provider-routing] Using Z.ai provider (default fallback)');
68
119
  return {
69
- provider: 'anthropic',
70
- apiKey: process.env.ANTHROPIC_API_KEY
120
+ provider: 'zai',
121
+ apiKey: process.env.ZAI_API_KEY || process.env.ANTHROPIC_API_KEY,
122
+ baseURL: process.env.ZAI_BASE_URL || 'https://api.z.ai/api/anthropic'
71
123
  };
72
124
  }
125
+ /**
126
+ * Validate provider configuration before creating client
127
+ * Provides clear error messages for missing credentials
128
+ */ export function validateProviderConfig(config) {
129
+ if (!config.apiKey) {
130
+ const envVarMap = {
131
+ 'zai': 'ZAI_API_KEY (or ANTHROPIC_API_KEY)',
132
+ 'anthropic': 'ANTHROPIC_API_KEY',
133
+ 'kimi': 'KIMI_API_KEY',
134
+ 'openrouter': 'OPENROUTER_API_KEY'
135
+ };
136
+ const requiredVar = envVarMap[config.provider] || `${config.provider.toUpperCase()}_API_KEY`;
137
+ throw new Error(`[provider-validation] API key not found for provider '${config.provider}'. ` + `Set the ${requiredVar} environment variable.\n` + `Tip: If using --provider flag, ensure the corresponding API key is exported.`);
138
+ }
139
+ // Provider-specific validation
140
+ if (config.provider === 'kimi' || config.provider === 'openrouter') {
141
+ console.error(`[provider-validation] WARNING: Provider '${config.provider}' uses OpenAI-compatible API format.`);
142
+ console.error(`[provider-validation] The current implementation uses Anthropic SDK which may not be compatible.`);
143
+ console.error(`[provider-validation] Consider using provider 'zai' or 'anthropic' for now.`);
144
+ }
145
+ }
73
146
  /**
74
147
  * Create Anthropic client with appropriate configuration
148
+ *
149
+ * Supports providers that use Anthropic-compatible API format:
150
+ * - anthropic: Direct Anthropic API
151
+ * - zai: Z.ai proxy (Anthropic-compatible)
152
+ *
153
+ * For OpenAI-compatible providers (kimi, openrouter), this client
154
+ * may not work correctly. Future enhancement: add OpenAI client support.
75
155
  */ export async function createClient() {
76
156
  const config = await getAPIConfig();
77
- if (!config.apiKey) {
78
- throw new Error(`API key not found. Set ${config.provider === 'zai' ? 'ZAI_API_KEY' : 'ANTHROPIC_API_KEY'} environment variable.`);
79
- }
157
+ // Validate configuration before attempting API call
158
+ validateProviderConfig(config);
80
159
  const clientOptions = {
81
160
  apiKey: config.apiKey,
82
161
  timeout: 120000,
83
162
  maxRetries: 2
84
163
  };
85
- if (config.provider === 'zai' && config.baseURL) {
164
+ // Z.ai uses Anthropic-compatible API format with custom base URL
165
+ if ((config.provider === 'zai' || config.provider === 'anthropic') && config.baseURL) {
86
166
  clientOptions.baseURL = config.baseURL;
87
167
  }
168
+ console.error(`[anthropic-client] Creating client for provider: ${config.provider}`);
88
169
  return new Anthropic(clientOptions);
89
170
  }
90
171
  /**
@@ -286,11 +367,22 @@ const execAsync = promisify(exec);
286
367
  }
287
368
  // Make API request (non-streaming for now to handle tool_use)
288
369
  const response = await client.messages.create(requestParams);
370
+ apiDebugLog('executeWithTools: API response received', {
371
+ iteration,
372
+ contentBlockCount: response.content.length,
373
+ blockTypes: response.content.map((b)=>b.type),
374
+ stopReason: response.stop_reason
375
+ });
289
376
  totalInputTokens += response.usage.input_tokens;
290
377
  totalOutputTokens += response.usage.output_tokens;
291
378
  // Extract content blocks
292
379
  const textBlocks = response.content.filter((block)=>block.type === 'text');
293
380
  const toolUseBlocks = response.content.filter((block)=>block.type === 'tool_use');
381
+ apiDebugLog('executeWithTools: Blocks extracted', {
382
+ textBlockCount: textBlocks.length,
383
+ toolUseBlockCount: toolUseBlocks.length,
384
+ toolNames: toolUseBlocks.map((b)=>b.name)
385
+ });
294
386
  // Stream text output
295
387
  for (const block of textBlocks){
296
388
  if (block.type === 'text') {
@@ -363,11 +455,21 @@ const execAsync = promisify(exec);
363
455
  let heartbeatInterval = null;
364
456
  const taskId = process.env.TASK_ID;
365
457
  // Bug #6 Fix: Read Redis connection parameters from process.env and interpolate in TypeScript
366
- const redisHost = process.env.CFN_REDIS_HOST || 'cfn-redis';
458
+ // FIX: Default to 'localhost' for CLI mode (host execution), not 'cfn-redis' (Docker)
459
+ const redisHost = process.env.CFN_REDIS_HOST || 'localhost';
367
460
  const redisPort = process.env.CFN_REDIS_PORT || '6379';
368
461
  try {
462
+ apiDebugLog('executeAgentAPI: ENTRY', {
463
+ agentType,
464
+ agentId,
465
+ hasTools: !!tools,
466
+ toolsLength: tools?.length || 0,
467
+ toolNames: tools?.map((t)=>t.name) || []
468
+ });
369
469
  console.log(`[anthropic-client] Executing agent: ${agentType}`);
370
470
  console.log(`[anthropic-client] Agent ID: ${agentId}`);
471
+ console.error(`[TOOL DEBUG executeAgentAPI] tools parameter: ${tools ? `Array[${tools.length}]` : 'undefined'}`);
472
+ console.error(`[TOOL DEBUG executeAgentAPI] tools names: ${tools?.map((t)=>t.name).join(', ') || 'NONE'}`);
371
473
  if (messages && messages.length > 1) {
372
474
  console.log(`[anthropic-client] Continuing conversation (${messages.length} messages)`);
373
475
  }
@@ -387,6 +489,10 @@ const execAsync = promisify(exec);
387
489
  // Otherwise use simple streaming
388
490
  let response;
389
491
  if (tools && tools.length > 0) {
492
+ apiDebugLog('executeAgentAPI: Using tool execution path', {
493
+ toolCount: tools.length,
494
+ toolNames: tools.map((t)=>t.name)
495
+ });
390
496
  console.log(`[anthropic-client] Tools enabled: ${tools.map((t)=>t.name).join(', ')}`);
391
497
  response = await executeWithTools({
392
498
  model,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/anthropic-client.ts"],"sourcesContent":["/**\r\n * Anthropic API Client\r\n *\r\n * Handles communication with Claude API (Anthropic or z.ai provider).\r\n * Supports streaming responses and tool execution.\r\n */\r\n\r\nimport Anthropic from '@anthropic-ai/sdk';\r\nimport fs from 'fs/promises';\r\nimport path from 'path';\r\nimport { exec } from 'child_process';\r\nimport { promisify } from 'util';\r\nimport { executeTool, type ToolUse, type ToolResult } from './tool-executor.js';\r\n\r\nconst execAsync = promisify(exec);\r\n\r\nexport interface APIConfig {\r\n provider: 'anthropic' | 'zai' | 'kimi' | 'openrouter';\r\n apiKey?: string;\r\n baseURL?: string;\r\n}\r\n\r\nexport interface MessageOptions {\r\n model: string;\r\n prompt: string;\r\n systemPrompt?: string;\r\n maxTokens?: number;\r\n temperature?: number;\r\n stream?: boolean;\r\n tools?: any[];\r\n messages?: Array<{ role: string; content: string }>; // Sprint 4: Conversation forking\r\n}\r\n\r\nexport interface MessageResponse {\r\n content: string;\r\n usage: {\r\n inputTokens: number;\r\n outputTokens: number;\r\n };\r\n stopReason: string;\r\n}\r\n\r\n/**\r\n * Get API configuration from environment and config files\r\n */\r\nexport async function getAPIConfig(): Promise<APIConfig> {\r\n // Check environment variable\r\n const envProvider = process.env.CLAUDE_API_PROVIDER;\r\n\r\n if (envProvider === 'zai') {\r\n return {\r\n provider: 'zai',\r\n apiKey: process.env.ZAI_API_KEY || process.env.ANTHROPIC_API_KEY,\r\n baseURL: process.env.ZAI_BASE_URL || 'https://api.z.ai/api/anthropic',\r\n };\r\n }\r\n\r\n if (envProvider === 'kimi') {\r\n return {\r\n provider: 'kimi',\r\n apiKey: process.env.KIMI_API_KEY,\r\n baseURL: process.env.KIMI_BASE_URL || 'https://api.moonshot.cn/v1',\r\n };\r\n }\r\n\r\n if (envProvider === 'openrouter') {\r\n return {\r\n provider: 'openrouter',\r\n apiKey: process.env.OPENROUTER_API_KEY,\r\n baseURL: process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1',\r\n };\r\n }\r\n\r\n // Check config file\r\n try {\r\n const configPath = path.join('.claude', 'config', 'api-provider.json');\r\n const config = JSON.parse(await fs.readFile(configPath, 'utf-8'));\r\n\r\n if (config.provider === 'zai' || config.provider === 'z.ai') {\r\n return {\r\n provider: 'zai',\r\n apiKey: config.apiKey || process.env.ZAI_API_KEY || process.env.ANTHROPIC_API_KEY,\r\n baseURL: config.baseURL || process.env.ZAI_BASE_URL || 'https://api.z.ai/api/anthropic',\r\n };\r\n }\r\n\r\n if (config.provider === 'kimi') {\r\n return {\r\n provider: 'kimi',\r\n apiKey: config.apiKey || process.env.KIMI_API_KEY,\r\n baseURL: config.baseURL || process.env.KIMI_BASE_URL || 'https://api.moonshot.cn/v1',\r\n };\r\n }\r\n\r\n if (config.provider === 'openrouter') {\r\n return {\r\n provider: 'openrouter',\r\n apiKey: config.apiKey || process.env.OPENROUTER_API_KEY,\r\n baseURL: config.baseURL || process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1',\r\n };\r\n }\r\n } catch {\r\n // Config file doesn't exist, use defaults\r\n }\r\n\r\n // Default to Anthropic\r\n return {\r\n provider: 'anthropic',\r\n apiKey: process.env.ANTHROPIC_API_KEY,\r\n };\r\n}\r\n\r\n/**\r\n * Create Anthropic client with appropriate configuration\r\n */\r\nexport async function createClient(): Promise<Anthropic> {\r\n const config = await getAPIConfig();\r\n\r\n if (!config.apiKey) {\r\n throw new Error(\r\n `API key not found. Set ${config.provider === 'zai' ? 'ZAI_API_KEY' : 'ANTHROPIC_API_KEY'} environment variable.`\r\n );\r\n }\r\n\r\n const clientOptions: any = {\r\n apiKey: config.apiKey,\r\n timeout: 120000, // 2 minutes (120 seconds)\r\n maxRetries: 2,\r\n };\r\n\r\n if (config.provider === 'zai' && config.baseURL) {\r\n clientOptions.baseURL = config.baseURL;\r\n }\r\n\r\n return new Anthropic(clientOptions);\r\n}\r\n\r\n/**\r\n * Map agent model name to API model ID (provider-specific)\r\n */\r\nexport function mapModelName(agentModel: string, provider: 'anthropic' | 'zai' = 'anthropic'): string {\r\n // Z.ai uses GLM models - try glm-4.6 first for all models\r\n if (provider === 'zai') {\r\n const zaiModelMap: Record<string, string> = {\r\n haiku: 'glm-4.6',\r\n sonnet: 'glm-4.6',\r\n opus: 'glm-4.6',\r\n };\r\n return zaiModelMap[agentModel] || 'glm-4.6';\r\n }\r\n\r\n // Anthropic uses Claude models\r\n const modelMap: Record<string, string> = {\r\n haiku: 'claude-3-5-haiku-20241022',\r\n sonnet: 'claude-3-5-sonnet-20241022',\r\n opus: 'claude-3-opus-20240229',\r\n };\r\n\r\n return modelMap[agentModel] || modelMap.haiku;\r\n}\r\n\r\n/**\r\n * Get fallback model for Z.ai (glm-4.6 -> glm-4.5-air)\r\n */\r\nfunction getFallbackModel(model: string): string | null {\r\n if (model === 'glm-4.6') {\r\n return 'glm-4.5-air';\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Send message to Claude API with streaming support and automatic fallback\r\n */\r\nexport async function sendMessage(\r\n options: MessageOptions,\r\n onChunk?: (text: string) => void\r\n): Promise<MessageResponse> {\r\n const client = await createClient();\r\n const config = await getAPIConfig();\r\n\r\n // Primary model (glm-4.6 for Z.ai, Claude for Anthropic)\r\n let model = mapModelName(options.model, config.provider);\r\n const maxTokens = options.maxTokens || 16000; // Sprint 6: 16K hard limit for GLM-4.6 (agents target 10K for buffer)\r\n const temperature = options.temperature ?? 1.0;\r\n\r\n // Streaming supported for both providers; retry without streaming if a provider rejects it\n let enableStreaming = !!options.stream;\n\r\n console.log(`[anthropic-client] Provider: ${config.provider}`);\r\n console.log(`[anthropic-client] Model: ${model}`);\r\n console.log(`[anthropic-client] Max tokens: ${maxTokens}`);\r\n console.log(`[anthropic-client] Stream: ${enableStreaming ? 'enabled' : 'disabled'}`);\r\n console.log('');\r\n\r\n // Sprint 4: Use messages array if provided (conversation forking)\r\n const messages: Anthropic.MessageParam[] = options.messages\r\n ? options.messages.map(m => ({\r\n role: m.role as 'user' | 'assistant',\r\n content: m.content,\r\n }))\r\n : [\r\n {\r\n role: 'user',\r\n content: options.prompt,\r\n },\r\n ];\r\n\r\n // Retry logic: Try primary model (glm-4.6), fall back to glm-4.5 on error\r\n let lastError: Error | null = null;\r\n let attempts = 0;\r\n const maxAttempts = 2; // Primary + fallback\r\n\r\n while (attempts < maxAttempts) {\r\n const currentModel = attempts === 0 ? model : getFallbackModel(model);\r\n\r\n if (!currentModel) {\r\n // No fallback available, throw last error\r\n throw lastError || new Error('No model available');\r\n }\r\n\r\n attempts++;\r\n\r\n if (attempts > 1) {\r\n console.log(`[anthropic-client] Retrying with fallback model: ${currentModel}`);\r\n }\r\n\r\n const requestParams: Anthropic.MessageCreateParams = {\r\n model: currentModel,\r\n max_tokens: maxTokens,\r\n temperature,\r\n messages,\r\n };\r\n\r\n if (options.systemPrompt) {\r\n requestParams.system = options.systemPrompt;\r\n }\r\n\r\n if (options.tools && options.tools.length > 0) {\r\n requestParams.tools = options.tools;\r\n }\r\n\r\n try {\n // Streaming response (preferred)\n if (enableStreaming) {\n let fullContent = '';\n let inputTokens = 0;\n let outputTokens = 0;\n let stopReason = 'end_turn';\n\n console.log('[anthropic-client] Creating streaming request...');\n const stream = await client.messages.create({\n ...requestParams,\n stream: true,\n });\n\n console.log('[anthropic-client] Stream created, processing events...');\n for await (const event of stream) {\n console.log('[anthropic-client] Event type:', event.type);\n if (event.type === 'message_start') {\n // @ts-ignore - usage exists on message_start\n inputTokens = event.message.usage?.input_tokens || 0;\n } else if (event.type === 'content_block_delta') {\n // @ts-ignore - text exists on delta\n const text = event.delta?.text || '';\n fullContent += text;\n if (onChunk) {\n onChunk(text);\n }\n } else if (event.type === 'message_delta') {\n // @ts-ignore - usage exists on message_delta\n outputTokens = event.usage?.output_tokens || 0;\n // @ts-ignore - stop_reason exists on delta\n stopReason = event.delta?.stop_reason || 'end_turn';\n }\n }\n\n return {\n content: fullContent,\n usage: {\n inputTokens,\n outputTokens,\n },\n stopReason,\n };\n }\n\n // Non-streaming response\n const response = await client.messages.create(requestParams);\n\n const content =\n response.content\n .filter((block) => block.type === 'text')\n .map((block) => (block as any).text)\n .join('\\n') || '';\n\n return {\n content,\n usage: {\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n },\n stopReason: response.stop_reason || 'end_turn',\n };\n } catch (error) {\n // If streaming fails on Z.ai, retry once without streaming before falling back to model fallback logic\n if (enableStreaming && config.provider === 'zai') {\n console.warn('[anthropic-client] Streaming failed on z.ai, retrying without streaming:', error);\n enableStreaming = false;\n attempts--; // do not consume a model attempt\n continue;\n }\n\n lastError = error instanceof Error ? error : new Error(String(error));\n console.error(`[anthropic-client] Error with model ${currentModel}:`, lastError.message);\n\n // If this was the last attempt, throw the error\n if (attempts >= maxAttempts) {\n throw lastError;\n }\n\n // Continue to next attempt with fallback model\n console.log('[anthropic-client] Will retry with fallback model...');\n }\n }\n\r\n // Should never reach here\r\n throw lastError || new Error('All retry attempts failed');\r\n}\r\n\r\n/**\r\n * Execute agent with tool support (agentic loop)\r\n *\r\n * Handles:\r\n * 1. Send message with tools\r\n * 2. Get response\r\n * 3. If tool_use blocks, execute tools and send results back\r\n * 4. Repeat until final text response\r\n */\r\nasync function executeWithTools(\r\n options: MessageOptions,\r\n onChunk?: (text: string) => void\r\n): Promise<MessageResponse> {\r\n const client = await createClient();\r\n const config = await getAPIConfig();\r\n\r\n const model = mapModelName(options.model, config.provider);\r\n const maxTokens = options.maxTokens || 16000;\r\n const temperature = options.temperature ?? 1.0;\r\n\r\n // Build initial messages array\r\n const messages: Anthropic.MessageParam[] = options.messages\r\n ? options.messages.map(m => ({\r\n role: m.role as 'user' | 'assistant',\r\n content: m.content,\r\n }))\r\n : [\r\n {\r\n role: 'user',\r\n content: options.prompt,\r\n },\r\n ];\r\n\r\n let totalInputTokens = 0;\r\n let totalOutputTokens = 0;\r\n let fullTextContent = '';\r\n const MAX_ITERATIONS = 20; // Prevent infinite loops (increased for exploration phase)\r\n let iteration = 0;\r\n\r\n while (iteration < MAX_ITERATIONS) {\r\n iteration++;\r\n console.log(`[executeWithTools] Iteration ${iteration}`);\r\n\r\n const requestParams: Anthropic.MessageCreateParams = {\r\n model,\r\n max_tokens: maxTokens,\r\n temperature,\r\n messages,\r\n };\r\n\r\n if (options.systemPrompt) {\r\n requestParams.system = options.systemPrompt;\r\n }\r\n\r\n if (options.tools && options.tools.length > 0) {\r\n requestParams.tools = options.tools;\r\n }\r\n\r\n // Make API request (non-streaming for now to handle tool_use)\r\n const response = await client.messages.create(requestParams);\r\n\r\n totalInputTokens += response.usage.input_tokens;\r\n totalOutputTokens += response.usage.output_tokens;\r\n\r\n // Extract content blocks\r\n const textBlocks = response.content.filter(block => block.type === 'text');\r\n const toolUseBlocks = response.content.filter(block => block.type === 'tool_use');\r\n\r\n // Stream text output\r\n for (const block of textBlocks) {\r\n if (block.type === 'text') {\r\n const text = (block as any).text;\r\n fullTextContent += text;\r\n if (onChunk) {\r\n onChunk(text);\r\n }\r\n }\r\n }\r\n\r\n // If no tool uses, we're done\r\n if (toolUseBlocks.length === 0) {\r\n console.log(`[executeWithTools] No tool uses, completing`);\r\n return {\r\n content: fullTextContent,\r\n usage: {\r\n inputTokens: totalInputTokens,\r\n outputTokens: totalOutputTokens,\r\n },\r\n stopReason: response.stop_reason || 'end_turn',\r\n };\r\n }\r\n\r\n // Execute tools\r\n console.log(`[executeWithTools] Executing ${toolUseBlocks.length} tool(s)`);\r\n const toolResults: ToolResult[] = [];\r\n\r\n for (const toolUseBlock of toolUseBlocks) {\r\n if (toolUseBlock.type !== 'tool_use') continue;\r\n\r\n const toolUse: ToolUse = {\r\n type: 'tool_use',\r\n id: (toolUseBlock as any).id,\r\n name: (toolUseBlock as any).name,\r\n input: (toolUseBlock as any).input,\r\n };\r\n\r\n console.log(`[executeWithTools] Tool: ${toolUse.name}`);\r\n const result = await executeTool(toolUse);\r\n toolResults.push(result);\r\n\r\n // Stream tool result\r\n if (onChunk) {\r\n onChunk(`\\n[Tool: ${toolUse.name}] ${result.content.substring(0, 100)}${result.content.length > 100 ? '...' : ''}\\n`);\r\n }\r\n }\r\n\r\n // Add assistant message with tool_use\r\n messages.push({\r\n role: 'assistant',\r\n content: response.content as any,\r\n });\r\n\r\n // Add tool results as user message\r\n messages.push({\r\n role: 'user',\r\n content: toolResults as any,\r\n });\r\n\r\n // Continue to next iteration\r\n }\r\n\r\n // Reached max iterations\r\n console.warn(`[executeWithTools] Reached max iterations (${MAX_ITERATIONS})`);\r\n return {\r\n content: fullTextContent,\r\n usage: {\r\n inputTokens: totalInputTokens,\r\n outputTokens: totalOutputTokens,\r\n },\r\n stopReason: 'max_tokens',\r\n };\r\n}\r\n\r\n/**\r\n * Execute agent via API with full lifecycle\r\n */\r\nexport async function executeAgentAPI(\r\n agentType: string,\r\n agentId: string,\r\n model: string,\r\n prompt: string,\r\n systemPrompt?: string,\r\n messages?: Array<{ role: string; content: string }>, // Sprint 4: Conversation forking\r\n maxTokens?: number, // Sprint 6: Configurable token limit\r\n tools?: any[] // Tool definitions for agent capabilities\r\n): Promise<{ success: boolean; output: string; usage: any; error?: string }> {\r\n // Start heartbeat monitoring (declare at function scope for error handling)\r\n let heartbeatInterval: NodeJS.Timeout | null = null;\r\n const taskId = process.env.TASK_ID;\r\n\r\n // Bug #6 Fix: Read Redis connection parameters from process.env and interpolate in TypeScript\r\n const redisHost = process.env.CFN_REDIS_HOST || 'cfn-redis';\r\n const redisPort = process.env.CFN_REDIS_PORT || '6379';\r\n\r\n try {\r\n console.log(`[anthropic-client] Executing agent: ${agentType}`);\r\n console.log(`[anthropic-client] Agent ID: ${agentId}`);\r\n if (messages && messages.length > 1) {\r\n console.log(`[anthropic-client] Continuing conversation (${messages.length} messages)`);\r\n }\r\n console.log('');\r\n\r\n if (taskId) {\r\n heartbeatInterval = setInterval(async () => {\r\n try {\r\n await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} hset \"swarm:${taskId}:agent:${agentId}\" heartbeat \"${Date.now()}\" status \"working\"`);\r\n } catch (err) {\r\n console.error('[heartbeat] Error sending heartbeat:', err);\r\n }\r\n }, 30000); // Every 30 seconds\r\n\r\n console.log(`[heartbeat] Monitoring started for agent ${agentId} (30s interval)`);\r\n }\r\n\r\n let fullOutput = '';\r\n\r\n // If tools provided, use agentic loop with tool execution\r\n // Otherwise use simple streaming\r\n let response: MessageResponse;\r\n\r\n if (tools && tools.length > 0) {\r\n console.log(`[anthropic-client] Tools enabled: ${tools.map(t => t.name).join(', ')}`);\r\n response = await executeWithTools(\r\n {\r\n model,\r\n prompt,\r\n systemPrompt,\r\n messages,\r\n maxTokens,\r\n tools\r\n },\r\n (chunk) => {\r\n process.stdout.write(chunk);\r\n fullOutput += chunk;\r\n }\r\n );\r\n } else {\r\n response = await sendMessage(\r\n {\r\n model,\r\n prompt,\r\n systemPrompt,\r\n stream: true,\r\n messages,\r\n maxTokens,\r\n },\r\n (chunk) => {\r\n process.stdout.write(chunk);\r\n fullOutput += chunk;\r\n }\r\n );\r\n }\r\n\r\n console.log('\\n');\r\n console.log('=== Agent Execution Complete ===');\r\n console.log(`Input tokens: ${response.usage.inputTokens}`);\r\n console.log(`Output tokens: ${response.usage.outputTokens}`);\r\n console.log(`Stop reason: ${response.stopReason}`);\r\n\r\n // Stop heartbeat and send final status\r\n if (heartbeatInterval) {\r\n clearInterval(heartbeatInterval);\r\n\r\n if (taskId) {\r\n await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} hset \"swarm:${taskId}:agent:${agentId}\" heartbeat \"${Date.now()}\" status \"complete\"`);\r\n console.log(`[heartbeat] Monitoring stopped - agent ${agentId} complete`);\r\n }\r\n }\r\n\r\n return {\r\n success: true,\r\n output: response.content,\r\n usage: response.usage,\r\n };\r\n } catch (error) {\r\n console.error('[anthropic-client] Error:', error);\r\n\r\n // Stop heartbeat and send error status\r\n if (heartbeatInterval) {\r\n clearInterval(heartbeatInterval);\r\n\r\n if (taskId) {\r\n try {\r\n await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} hset \"swarm:${taskId}:agent:${agentId}\" heartbeat \"${Date.now()}\" status \"error\"`);\r\n console.log(`[heartbeat] Monitoring stopped - agent ${agentId} error`);\r\n } catch (err) {\r\n // Ignore heartbeat errors during error handling\r\n }\r\n }\r\n }\r\n\r\n return {\r\n success: false,\r\n output: '',\r\n usage: { inputTokens: 0, outputTokens: 0 },\r\n error: error instanceof Error ? error.message : String(error),\r\n };\r\n }\r\n}\r\n"],"names":["Anthropic","fs","path","exec","promisify","executeTool","execAsync","getAPIConfig","envProvider","process","env","CLAUDE_API_PROVIDER","provider","apiKey","ZAI_API_KEY","ANTHROPIC_API_KEY","baseURL","ZAI_BASE_URL","KIMI_API_KEY","KIMI_BASE_URL","OPENROUTER_API_KEY","OPENROUTER_BASE_URL","configPath","join","config","JSON","parse","readFile","createClient","Error","clientOptions","timeout","maxRetries","mapModelName","agentModel","zaiModelMap","haiku","sonnet","opus","modelMap","getFallbackModel","model","sendMessage","options","onChunk","client","maxTokens","temperature","enableStreaming","stream","console","log","messages","map","m","role","content","prompt","lastError","attempts","maxAttempts","currentModel","requestParams","max_tokens","systemPrompt","system","tools","length","fullContent","inputTokens","outputTokens","stopReason","create","event","type","message","usage","input_tokens","text","delta","output_tokens","stop_reason","response","filter","block","error","warn","String","executeWithTools","totalInputTokens","totalOutputTokens","fullTextContent","MAX_ITERATIONS","iteration","textBlocks","toolUseBlocks","toolResults","toolUseBlock","toolUse","id","name","input","result","push","substring","executeAgentAPI","agentType","agentId","heartbeatInterval","taskId","TASK_ID","redisHost","CFN_REDIS_HOST","redisPort","CFN_REDIS_PORT","setInterval","Date","now","err","fullOutput","t","chunk","stdout","write","clearInterval","success","output"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/cli/anthropic-client.ts"],"sourcesContent":["/**\r\n * Anthropic API Client\r\n *\r\n * Handles communication with Claude API (Anthropic or z.ai provider).\r\n * Supports streaming responses and tool execution.\r\n */\r\n\r\nimport Anthropic from '@anthropic-ai/sdk';\r\nimport fs from 'fs/promises';\r\nimport fsSync from 'fs';\r\nimport path from 'path';\r\nimport { exec } from 'child_process';\r\nimport { promisify } from 'util';\r\nimport { executeTool, type ToolUse, type ToolResult } from './tool-executor.js';\r\n\r\nconst execAsync = promisify(exec);\r\n\r\n// File-based debug logging (for background agents)\r\nconst AGENT_ID = process.env.AGENT_ID || 'unknown';\r\nconst API_LOG_FILE = `/tmp/cfn-api-${AGENT_ID}.log`;\r\nfunction apiDebugLog(message: string, data?: any) {\r\n const timestamp = new Date().toISOString();\r\n const logEntry = data\r\n ? `${timestamp} [${AGENT_ID}] ${message} ${JSON.stringify(data)}\\n`\r\n : `${timestamp} [${AGENT_ID}] ${message}\\n`;\r\n try {\r\n fsSync.appendFileSync(API_LOG_FILE, logEntry);\r\n } catch (err) {\r\n // Ignore logging errors\r\n }\r\n}\r\n\r\nexport interface APIConfig {\r\n provider: 'anthropic' | 'zai' | 'kimi' | 'openrouter';\r\n apiKey?: string;\r\n baseURL?: string;\r\n}\r\n\r\nexport interface MessageOptions {\r\n model: string;\r\n prompt: string;\r\n systemPrompt?: string;\r\n maxTokens?: number;\r\n temperature?: number;\r\n stream?: boolean;\r\n tools?: any[];\r\n messages?: Array<{ role: string; content: string }>; // Sprint 4: Conversation forking\r\n}\r\n\r\nexport interface MessageResponse {\r\n content: string;\r\n usage: {\r\n inputTokens: number;\r\n outputTokens: number;\r\n };\r\n stopReason: string;\r\n}\r\n\r\n/**\r\n * Get API configuration from environment and config files\r\n *\r\n * Provider resolution order:\r\n * 1. CLAUDE_API_PROVIDER env var (legacy)\r\n * 2. PROVIDER env var (set by agent-spawner from --provider flag)\r\n * 3. Config file (.claude/config/api-provider.json)\r\n * 4. Default to Z.ai (cost-effective fallback per project requirements)\r\n *\r\n * BUG FIX: Previously only checked CLAUDE_API_PROVIDER, ignoring --provider flag\r\n * which sets PROVIDER env var via agent-spawner.ts\r\n */\r\nexport async function getAPIConfig(): Promise<APIConfig> {\r\n // Check environment variables - support both CLAUDE_API_PROVIDER (legacy) and PROVIDER (from CLI --provider flag)\r\n const envProvider = process.env.CLAUDE_API_PROVIDER || process.env.PROVIDER;\r\n\r\n // Debug logging for provider routing (helps diagnose auth errors)\r\n apiDebugLog('getAPIConfig: Provider detection', {\r\n CLAUDE_API_PROVIDER: process.env.CLAUDE_API_PROVIDER,\r\n PROVIDER: process.env.PROVIDER,\r\n resolved: envProvider\r\n });\r\n console.error(`[provider-routing] CLAUDE_API_PROVIDER=${process.env.CLAUDE_API_PROVIDER || 'unset'}, PROVIDER=${process.env.PROVIDER || 'unset'}, resolved=${envProvider || 'none'}`);\r\n\r\n if (envProvider === 'zai' || envProvider === 'z.ai') {\r\n console.error('[provider-routing] Using Z.ai provider');\r\n return {\r\n provider: 'zai',\r\n apiKey: process.env.ZAI_API_KEY || process.env.ANTHROPIC_API_KEY,\r\n baseURL: process.env.ZAI_BASE_URL || 'https://api.z.ai/api/anthropic',\r\n };\r\n }\r\n\r\n if (envProvider === 'kimi') {\r\n console.error('[provider-routing] Using Kimi provider');\r\n return {\r\n provider: 'kimi',\r\n apiKey: process.env.KIMI_API_KEY,\r\n baseURL: process.env.KIMI_BASE_URL || 'https://api.moonshot.cn/v1',\r\n };\r\n }\r\n\r\n if (envProvider === 'openrouter') {\r\n console.error('[provider-routing] Using OpenRouter provider');\r\n return {\r\n provider: 'openrouter',\r\n apiKey: process.env.OPENROUTER_API_KEY,\r\n baseURL: process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1',\r\n };\r\n }\r\n\r\n if (envProvider === 'anthropic') {\r\n console.error('[provider-routing] Using Anthropic provider (explicit)');\r\n return {\r\n provider: 'anthropic',\r\n apiKey: process.env.ANTHROPIC_API_KEY,\r\n };\r\n }\r\n\r\n // Check config file\r\n try {\r\n const configPath = path.join('.claude', 'config', 'api-provider.json');\r\n const config = JSON.parse(await fs.readFile(configPath, 'utf-8'));\r\n\r\n if (config.provider === 'zai' || config.provider === 'z.ai') {\r\n console.error('[provider-routing] Using Z.ai provider (from config file)');\r\n return {\r\n provider: 'zai',\r\n apiKey: config.apiKey || process.env.ZAI_API_KEY || process.env.ANTHROPIC_API_KEY,\r\n baseURL: config.baseURL || process.env.ZAI_BASE_URL || 'https://api.z.ai/api/anthropic',\r\n };\r\n }\r\n\r\n if (config.provider === 'kimi') {\r\n console.error('[provider-routing] Using Kimi provider (from config file)');\r\n return {\r\n provider: 'kimi',\r\n apiKey: config.apiKey || process.env.KIMI_API_KEY,\r\n baseURL: config.baseURL || process.env.KIMI_BASE_URL || 'https://api.moonshot.cn/v1',\r\n };\r\n }\r\n\r\n if (config.provider === 'openrouter') {\r\n console.error('[provider-routing] Using OpenRouter provider (from config file)');\r\n return {\r\n provider: 'openrouter',\r\n apiKey: config.apiKey || process.env.OPENROUTER_API_KEY,\r\n baseURL: config.baseURL || process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1',\r\n };\r\n }\r\n\r\n if (config.provider === 'anthropic') {\r\n console.error('[provider-routing] Using Anthropic provider (from config file)');\r\n return {\r\n provider: 'anthropic',\r\n apiKey: config.apiKey || process.env.ANTHROPIC_API_KEY,\r\n };\r\n }\r\n } catch {\r\n // Config file doesn't exist, use defaults\r\n }\r\n\r\n // Default to Z.ai (cost-effective fallback per project requirements)\r\n // BUG FIX: Previously defaulted to Anthropic which caused auth errors when no provider specified\r\n console.error('[provider-routing] Using Z.ai provider (default fallback)');\r\n return {\r\n provider: 'zai',\r\n apiKey: process.env.ZAI_API_KEY || process.env.ANTHROPIC_API_KEY,\r\n baseURL: process.env.ZAI_BASE_URL || 'https://api.z.ai/api/anthropic',\r\n };\r\n}\r\n\r\n/**\r\n * Validate provider configuration before creating client\r\n * Provides clear error messages for missing credentials\r\n */\r\nexport function validateProviderConfig(config: APIConfig): void {\r\n if (!config.apiKey) {\r\n const envVarMap: Record<string, string> = {\r\n 'zai': 'ZAI_API_KEY (or ANTHROPIC_API_KEY)',\r\n 'anthropic': 'ANTHROPIC_API_KEY',\r\n 'kimi': 'KIMI_API_KEY',\r\n 'openrouter': 'OPENROUTER_API_KEY'\r\n };\r\n const requiredVar = envVarMap[config.provider] || `${config.provider.toUpperCase()}_API_KEY`;\r\n throw new Error(\r\n `[provider-validation] API key not found for provider '${config.provider}'. ` +\r\n `Set the ${requiredVar} environment variable.\\n` +\r\n `Tip: If using --provider flag, ensure the corresponding API key is exported.`\r\n );\r\n }\r\n\r\n // Provider-specific validation\r\n if (config.provider === 'kimi' || config.provider === 'openrouter') {\r\n console.error(`[provider-validation] WARNING: Provider '${config.provider}' uses OpenAI-compatible API format.`);\r\n console.error(`[provider-validation] The current implementation uses Anthropic SDK which may not be compatible.`);\r\n console.error(`[provider-validation] Consider using provider 'zai' or 'anthropic' for now.`);\r\n }\r\n}\r\n\r\n/**\r\n * Create Anthropic client with appropriate configuration\r\n *\r\n * Supports providers that use Anthropic-compatible API format:\r\n * - anthropic: Direct Anthropic API\r\n * - zai: Z.ai proxy (Anthropic-compatible)\r\n *\r\n * For OpenAI-compatible providers (kimi, openrouter), this client\r\n * may not work correctly. Future enhancement: add OpenAI client support.\r\n */\r\nexport async function createClient(): Promise<Anthropic> {\r\n const config = await getAPIConfig();\r\n\r\n // Validate configuration before attempting API call\r\n validateProviderConfig(config);\r\n\r\n const clientOptions: any = {\r\n apiKey: config.apiKey,\r\n timeout: 120000, // 2 minutes (120 seconds)\r\n maxRetries: 2,\r\n };\r\n\r\n // Z.ai uses Anthropic-compatible API format with custom base URL\r\n if ((config.provider === 'zai' || config.provider === 'anthropic') && config.baseURL) {\r\n clientOptions.baseURL = config.baseURL;\r\n }\r\n\r\n console.error(`[anthropic-client] Creating client for provider: ${config.provider}`);\r\n return new Anthropic(clientOptions);\r\n}\r\n\r\n/**\r\n * Map agent model name to API model ID (provider-specific)\r\n */\r\nexport function mapModelName(agentModel: string, provider: 'anthropic' | 'zai' = 'anthropic'): string {\r\n // Z.ai uses GLM models - try glm-4.6 first for all models\r\n if (provider === 'zai') {\r\n const zaiModelMap: Record<string, string> = {\r\n haiku: 'glm-4.6',\r\n sonnet: 'glm-4.6',\r\n opus: 'glm-4.6',\r\n };\r\n return zaiModelMap[agentModel] || 'glm-4.6';\r\n }\r\n\r\n // Anthropic uses Claude models\r\n const modelMap: Record<string, string> = {\r\n haiku: 'claude-3-5-haiku-20241022',\r\n sonnet: 'claude-3-5-sonnet-20241022',\r\n opus: 'claude-3-opus-20240229',\r\n };\r\n\r\n return modelMap[agentModel] || modelMap.haiku;\r\n}\r\n\r\n/**\r\n * Get fallback model for Z.ai (glm-4.6 -> glm-4.5-air)\r\n */\r\nfunction getFallbackModel(model: string): string | null {\r\n if (model === 'glm-4.6') {\r\n return 'glm-4.5-air';\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Send message to Claude API with streaming support and automatic fallback\r\n */\r\nexport async function sendMessage(\r\n options: MessageOptions,\r\n onChunk?: (text: string) => void\r\n): Promise<MessageResponse> {\r\n const client = await createClient();\r\n const config = await getAPIConfig();\r\n\r\n // Primary model (glm-4.6 for Z.ai, Claude for Anthropic)\r\n let model = mapModelName(options.model, config.provider);\r\n const maxTokens = options.maxTokens || 16000; // Sprint 6: 16K hard limit for GLM-4.6 (agents target 10K for buffer)\r\n const temperature = options.temperature ?? 1.0;\r\n\r\n // Streaming supported for both providers; retry without streaming if a provider rejects it\r\n let enableStreaming = !!options.stream;\r\n\r\n console.log(`[anthropic-client] Provider: ${config.provider}`);\r\n console.log(`[anthropic-client] Model: ${model}`);\r\n console.log(`[anthropic-client] Max tokens: ${maxTokens}`);\r\n console.log(`[anthropic-client] Stream: ${enableStreaming ? 'enabled' : 'disabled'}`);\r\n console.log('');\r\n\r\n // Sprint 4: Use messages array if provided (conversation forking)\r\n const messages: Anthropic.MessageParam[] = options.messages\r\n ? options.messages.map(m => ({\r\n role: m.role as 'user' | 'assistant',\r\n content: m.content,\r\n }))\r\n : [\r\n {\r\n role: 'user',\r\n content: options.prompt,\r\n },\r\n ];\r\n\r\n // Retry logic: Try primary model (glm-4.6), fall back to glm-4.5 on error\r\n let lastError: Error | null = null;\r\n let attempts = 0;\r\n const maxAttempts = 2; // Primary + fallback\r\n\r\n while (attempts < maxAttempts) {\r\n const currentModel = attempts === 0 ? model : getFallbackModel(model);\r\n\r\n if (!currentModel) {\r\n // No fallback available, throw last error\r\n throw lastError || new Error('No model available');\r\n }\r\n\r\n attempts++;\r\n\r\n if (attempts > 1) {\r\n console.log(`[anthropic-client] Retrying with fallback model: ${currentModel}`);\r\n }\r\n\r\n const requestParams: Anthropic.MessageCreateParams = {\r\n model: currentModel,\r\n max_tokens: maxTokens,\r\n temperature,\r\n messages,\r\n };\r\n\r\n if (options.systemPrompt) {\r\n requestParams.system = options.systemPrompt;\r\n }\r\n\r\n if (options.tools && options.tools.length > 0) {\r\n requestParams.tools = options.tools;\r\n }\r\n\r\n try {\r\n // Streaming response (preferred)\r\n if (enableStreaming) {\r\n let fullContent = '';\r\n let inputTokens = 0;\r\n let outputTokens = 0;\r\n let stopReason = 'end_turn';\r\n\r\n console.log('[anthropic-client] Creating streaming request...');\r\n const stream = await client.messages.create({\r\n ...requestParams,\r\n stream: true,\r\n });\r\n\r\n console.log('[anthropic-client] Stream created, processing events...');\r\n for await (const event of stream) {\r\n console.log('[anthropic-client] Event type:', event.type);\r\n if (event.type === 'message_start') {\r\n // @ts-ignore - usage exists on message_start\r\n inputTokens = event.message.usage?.input_tokens || 0;\r\n } else if (event.type === 'content_block_delta') {\r\n // @ts-ignore - text exists on delta\r\n const text = event.delta?.text || '';\r\n fullContent += text;\r\n if (onChunk) {\r\n onChunk(text);\r\n }\r\n } else if (event.type === 'message_delta') {\r\n // @ts-ignore - usage exists on message_delta\r\n outputTokens = event.usage?.output_tokens || 0;\r\n // @ts-ignore - stop_reason exists on delta\r\n stopReason = event.delta?.stop_reason || 'end_turn';\r\n }\r\n }\r\n\r\n return {\r\n content: fullContent,\r\n usage: {\r\n inputTokens,\r\n outputTokens,\r\n },\r\n stopReason,\r\n };\r\n }\r\n\r\n // Non-streaming response\r\n const response = await client.messages.create(requestParams);\r\n\r\n const content =\r\n response.content\r\n .filter((block) => block.type === 'text')\r\n .map((block) => (block as any).text)\r\n .join('\\n') || '';\r\n\r\n return {\r\n content,\r\n usage: {\r\n inputTokens: response.usage.input_tokens,\r\n outputTokens: response.usage.output_tokens,\r\n },\r\n stopReason: response.stop_reason || 'end_turn',\r\n };\r\n } catch (error) {\r\n // If streaming fails on Z.ai, retry once without streaming before falling back to model fallback logic\r\n if (enableStreaming && config.provider === 'zai') {\r\n console.warn('[anthropic-client] Streaming failed on z.ai, retrying without streaming:', error);\r\n enableStreaming = false;\r\n attempts--; // do not consume a model attempt\r\n continue;\r\n }\r\n\r\n lastError = error instanceof Error ? error : new Error(String(error));\r\n console.error(`[anthropic-client] Error with model ${currentModel}:`, lastError.message);\r\n\r\n // If this was the last attempt, throw the error\r\n if (attempts >= maxAttempts) {\r\n throw lastError;\r\n }\r\n\r\n // Continue to next attempt with fallback model\r\n console.log('[anthropic-client] Will retry with fallback model...');\r\n }\r\n }\r\n\r\n // Should never reach here\r\n throw lastError || new Error('All retry attempts failed');\r\n}\r\n\r\n/**\r\n * Execute agent with tool support (agentic loop)\r\n *\r\n * Handles:\r\n * 1. Send message with tools\r\n * 2. Get response\r\n * 3. If tool_use blocks, execute tools and send results back\r\n * 4. Repeat until final text response\r\n */\r\nasync function executeWithTools(\r\n options: MessageOptions,\r\n onChunk?: (text: string) => void\r\n): Promise<MessageResponse> {\r\n const client = await createClient();\r\n const config = await getAPIConfig();\r\n\r\n const model = mapModelName(options.model, config.provider);\r\n const maxTokens = options.maxTokens || 16000;\r\n const temperature = options.temperature ?? 1.0;\r\n\r\n // Build initial messages array\r\n const messages: Anthropic.MessageParam[] = options.messages\r\n ? options.messages.map(m => ({\r\n role: m.role as 'user' | 'assistant',\r\n content: m.content,\r\n }))\r\n : [\r\n {\r\n role: 'user',\r\n content: options.prompt,\r\n },\r\n ];\r\n\r\n let totalInputTokens = 0;\r\n let totalOutputTokens = 0;\r\n let fullTextContent = '';\r\n const MAX_ITERATIONS = 20; // Prevent infinite loops (increased for exploration phase)\r\n let iteration = 0;\r\n\r\n while (iteration < MAX_ITERATIONS) {\r\n iteration++;\r\n console.log(`[executeWithTools] Iteration ${iteration}`);\r\n\r\n const requestParams: Anthropic.MessageCreateParams = {\r\n model,\r\n max_tokens: maxTokens,\r\n temperature,\r\n messages,\r\n };\r\n\r\n if (options.systemPrompt) {\r\n requestParams.system = options.systemPrompt;\r\n }\r\n\r\n if (options.tools && options.tools.length > 0) {\r\n requestParams.tools = options.tools;\r\n }\r\n\r\n // Make API request (non-streaming for now to handle tool_use)\r\n const response = await client.messages.create(requestParams);\r\n\r\n apiDebugLog('executeWithTools: API response received', {\r\n iteration,\r\n contentBlockCount: response.content.length,\r\n blockTypes: response.content.map(b => b.type),\r\n stopReason: response.stop_reason\r\n });\r\n\r\n totalInputTokens += response.usage.input_tokens;\r\n totalOutputTokens += response.usage.output_tokens;\r\n\r\n // Extract content blocks\r\n const textBlocks = response.content.filter(block => block.type === 'text');\r\n const toolUseBlocks = response.content.filter(block => block.type === 'tool_use');\r\n\r\n apiDebugLog('executeWithTools: Blocks extracted', {\r\n textBlockCount: textBlocks.length,\r\n toolUseBlockCount: toolUseBlocks.length,\r\n toolNames: toolUseBlocks.map((b: any) => b.name)\r\n });\r\n\r\n // Stream text output\r\n for (const block of textBlocks) {\r\n if (block.type === 'text') {\r\n const text = (block as any).text;\r\n fullTextContent += text;\r\n if (onChunk) {\r\n onChunk(text);\r\n }\r\n }\r\n }\r\n\r\n // If no tool uses, we're done\r\n if (toolUseBlocks.length === 0) {\r\n console.log(`[executeWithTools] No tool uses, completing`);\r\n return {\r\n content: fullTextContent,\r\n usage: {\r\n inputTokens: totalInputTokens,\r\n outputTokens: totalOutputTokens,\r\n },\r\n stopReason: response.stop_reason || 'end_turn',\r\n };\r\n }\r\n\r\n // Execute tools\r\n console.log(`[executeWithTools] Executing ${toolUseBlocks.length} tool(s)`);\r\n const toolResults: ToolResult[] = [];\r\n\r\n for (const toolUseBlock of toolUseBlocks) {\r\n if (toolUseBlock.type !== 'tool_use') continue;\r\n\r\n const toolUse: ToolUse = {\r\n type: 'tool_use',\r\n id: (toolUseBlock as any).id,\r\n name: (toolUseBlock as any).name,\r\n input: (toolUseBlock as any).input,\r\n };\r\n\r\n console.log(`[executeWithTools] Tool: ${toolUse.name}`);\r\n const result = await executeTool(toolUse);\r\n toolResults.push(result);\r\n\r\n // Stream tool result\r\n if (onChunk) {\r\n onChunk(`\\n[Tool: ${toolUse.name}] ${result.content.substring(0, 100)}${result.content.length > 100 ? '...' : ''}\\n`);\r\n }\r\n }\r\n\r\n // Add assistant message with tool_use\r\n messages.push({\r\n role: 'assistant',\r\n content: response.content as any,\r\n });\r\n\r\n // Add tool results as user message\r\n messages.push({\r\n role: 'user',\r\n content: toolResults as any,\r\n });\r\n\r\n // Continue to next iteration\r\n }\r\n\r\n // Reached max iterations\r\n console.warn(`[executeWithTools] Reached max iterations (${MAX_ITERATIONS})`);\r\n return {\r\n content: fullTextContent,\r\n usage: {\r\n inputTokens: totalInputTokens,\r\n outputTokens: totalOutputTokens,\r\n },\r\n stopReason: 'max_tokens',\r\n };\r\n}\r\n\r\n/**\r\n * Execute agent via API with full lifecycle\r\n */\r\nexport async function executeAgentAPI(\r\n agentType: string,\r\n agentId: string,\r\n model: string,\r\n prompt: string,\r\n systemPrompt?: string,\r\n messages?: Array<{ role: string; content: string }>, // Sprint 4: Conversation forking\r\n maxTokens?: number, // Sprint 6: Configurable token limit\r\n tools?: any[] // Tool definitions for agent capabilities\r\n): Promise<{ success: boolean; output: string; usage: any; error?: string }> {\r\n // Start heartbeat monitoring (declare at function scope for error handling)\r\n let heartbeatInterval: NodeJS.Timeout | null = null;\r\n const taskId = process.env.TASK_ID;\r\n\r\n // Bug #6 Fix: Read Redis connection parameters from process.env and interpolate in TypeScript\r\n // FIX: Default to 'localhost' for CLI mode (host execution), not 'cfn-redis' (Docker)\r\n const redisHost = process.env.CFN_REDIS_HOST || 'localhost';\r\n const redisPort = process.env.CFN_REDIS_PORT || '6379';\r\n\r\n try {\r\n apiDebugLog('executeAgentAPI: ENTRY', {\r\n agentType,\r\n agentId,\r\n hasTools: !!tools,\r\n toolsLength: tools?.length || 0,\r\n toolNames: tools?.map(t => t.name) || []\r\n });\r\n console.log(`[anthropic-client] Executing agent: ${agentType}`);\r\n console.log(`[anthropic-client] Agent ID: ${agentId}`);\r\n console.error(`[TOOL DEBUG executeAgentAPI] tools parameter: ${tools ? `Array[${tools.length}]` : 'undefined'}`);\r\n console.error(`[TOOL DEBUG executeAgentAPI] tools names: ${tools?.map(t => t.name).join(', ') || 'NONE'}`);\r\n if (messages && messages.length > 1) {\r\n console.log(`[anthropic-client] Continuing conversation (${messages.length} messages)`);\r\n }\r\n console.log('');\r\n\r\n if (taskId) {\r\n heartbeatInterval = setInterval(async () => {\r\n try {\r\n await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} hset \"swarm:${taskId}:agent:${agentId}\" heartbeat \"${Date.now()}\" status \"working\"`);\r\n } catch (err) {\r\n console.error('[heartbeat] Error sending heartbeat:', err);\r\n }\r\n }, 30000); // Every 30 seconds\r\n\r\n console.log(`[heartbeat] Monitoring started for agent ${agentId} (30s interval)`);\r\n }\r\n\r\n let fullOutput = '';\r\n\r\n // If tools provided, use agentic loop with tool execution\r\n // Otherwise use simple streaming\r\n let response: MessageResponse;\r\n\r\n if (tools && tools.length > 0) {\r\n apiDebugLog('executeAgentAPI: Using tool execution path', {\r\n toolCount: tools.length,\r\n toolNames: tools.map(t => t.name)\r\n });\r\n console.log(`[anthropic-client] Tools enabled: ${tools.map(t => t.name).join(', ')}`);\r\n response = await executeWithTools(\r\n {\r\n model,\r\n prompt,\r\n systemPrompt,\r\n messages,\r\n maxTokens,\r\n tools\r\n },\r\n (chunk) => {\r\n process.stdout.write(chunk);\r\n fullOutput += chunk;\r\n }\r\n );\r\n } else {\r\n response = await sendMessage(\r\n {\r\n model,\r\n prompt,\r\n systemPrompt,\r\n stream: true,\r\n messages,\r\n maxTokens,\r\n },\r\n (chunk) => {\r\n process.stdout.write(chunk);\r\n fullOutput += chunk;\r\n }\r\n );\r\n }\r\n\r\n console.log('\\n');\r\n console.log('=== Agent Execution Complete ===');\r\n console.log(`Input tokens: ${response.usage.inputTokens}`);\r\n console.log(`Output tokens: ${response.usage.outputTokens}`);\r\n console.log(`Stop reason: ${response.stopReason}`);\r\n\r\n // Stop heartbeat and send final status\r\n if (heartbeatInterval) {\r\n clearInterval(heartbeatInterval);\r\n\r\n if (taskId) {\r\n await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} hset \"swarm:${taskId}:agent:${agentId}\" heartbeat \"${Date.now()}\" status \"complete\"`);\r\n console.log(`[heartbeat] Monitoring stopped - agent ${agentId} complete`);\r\n }\r\n }\r\n\r\n return {\r\n success: true,\r\n output: response.content,\r\n usage: response.usage,\r\n };\r\n } catch (error) {\r\n console.error('[anthropic-client] Error:', error);\r\n\r\n // Stop heartbeat and send error status\r\n if (heartbeatInterval) {\r\n clearInterval(heartbeatInterval);\r\n\r\n if (taskId) {\r\n try {\r\n await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} hset \"swarm:${taskId}:agent:${agentId}\" heartbeat \"${Date.now()}\" status \"error\"`);\r\n console.log(`[heartbeat] Monitoring stopped - agent ${agentId} error`);\r\n } catch (err) {\r\n // Ignore heartbeat errors during error handling\r\n }\r\n }\r\n }\r\n\r\n return {\r\n success: false,\r\n output: '',\r\n usage: { inputTokens: 0, outputTokens: 0 },\r\n error: error instanceof Error ? error.message : String(error),\r\n };\r\n }\r\n}\r\n"],"names":["Anthropic","fs","fsSync","path","exec","promisify","executeTool","execAsync","AGENT_ID","process","env","API_LOG_FILE","apiDebugLog","message","data","timestamp","Date","toISOString","logEntry","JSON","stringify","appendFileSync","err","getAPIConfig","envProvider","CLAUDE_API_PROVIDER","PROVIDER","resolved","console","error","provider","apiKey","ZAI_API_KEY","ANTHROPIC_API_KEY","baseURL","ZAI_BASE_URL","KIMI_API_KEY","KIMI_BASE_URL","OPENROUTER_API_KEY","OPENROUTER_BASE_URL","configPath","join","config","parse","readFile","validateProviderConfig","envVarMap","requiredVar","toUpperCase","Error","createClient","clientOptions","timeout","maxRetries","mapModelName","agentModel","zaiModelMap","haiku","sonnet","opus","modelMap","getFallbackModel","model","sendMessage","options","onChunk","client","maxTokens","temperature","enableStreaming","stream","log","messages","map","m","role","content","prompt","lastError","attempts","maxAttempts","currentModel","requestParams","max_tokens","systemPrompt","system","tools","length","fullContent","inputTokens","outputTokens","stopReason","create","event","type","usage","input_tokens","text","delta","output_tokens","stop_reason","response","filter","block","warn","String","executeWithTools","totalInputTokens","totalOutputTokens","fullTextContent","MAX_ITERATIONS","iteration","contentBlockCount","blockTypes","b","textBlocks","toolUseBlocks","textBlockCount","toolUseBlockCount","toolNames","name","toolResults","toolUseBlock","toolUse","id","input","result","push","substring","executeAgentAPI","agentType","agentId","heartbeatInterval","taskId","TASK_ID","redisHost","CFN_REDIS_HOST","redisPort","CFN_REDIS_PORT","hasTools","toolsLength","t","setInterval","now","fullOutput","toolCount","chunk","stdout","write","clearInterval","success","output"],"mappings":"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"}
@@ -3,7 +3,8 @@ import { exec } from 'child_process';
3
3
  import { promisify } from 'util';
4
4
  const execAsync = promisify(exec);
5
5
  // Bug #6 Fix: Read Redis connection parameters from process.env
6
- const redisHost = process.env.CFN_REDIS_HOST || 'cfn-redis';
6
+ // FIX: Default to 'localhost' for CLI mode (host execution), not 'cfn-redis' (Docker)
7
+ const redisHost = process.env.CFN_REDIS_HOST || 'localhost';
7
8
  const redisPort = process.env.CFN_REDIS_PORT || '6379';
8
9
  // ============================================================================
9
10
  // Redis Epic Context Functions
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/cfn-context.ts"],"sourcesContent":["#!/usr/bin/env node\r\n/**\r\n * cfn-context - Epic context operations for CLI agents\r\n *\r\n * Provides functions to:\r\n * 1. Load epic/phase context from Redis\r\n * 2. Store epic/phase context to Redis\r\n * 3. Format context for agent system prompts\r\n *\r\n * Also provides ACE context operations CLI:\r\n * cfn-context reflect Run ACE reflection\r\n * cfn-context curate Merge contexts\r\n * cfn-context inject Inject into tasks\r\n * cfn-context query Search contexts\r\n * cfn-context stats Show analytics\r\n */\r\n\r\nimport { spawn } from 'child_process';\r\nimport { exec } from 'child_process';\r\nimport { promisify } from 'util';\r\n\r\nconst execAsync = promisify(exec);\r\n\r\n// Bug #6 Fix: Read Redis connection parameters from process.env\r\nconst redisHost = process.env.CFN_REDIS_HOST || 'cfn-redis';\r\nconst redisPort = process.env.CFN_REDIS_PORT || '6379';\r\n\r\n// ============================================================================\r\n// Epic Context Interfaces (for CLI Agent System Prompts)\r\n// ============================================================================\r\n\r\nexport interface EpicContextData {\r\n epicGoal?: string;\r\n epicName?: string;\r\n inScope?: string[];\r\n outOfScope?: string[];\r\n phases?: string[];\r\n currentPhase?: string;\r\n riskProfile?: string;\r\n stakeholders?: string[];\r\n references?: string[];\r\n timeline?: {\r\n start?: string;\r\n end?: string;\r\n milestones?: Array<{ phase: string; date: string }>;\r\n };\r\n}\r\n\r\nexport interface PhaseContextData {\r\n phaseName?: string;\r\n phaseNumber?: number;\r\n dependencies?: string[];\r\n deliverables?: string[];\r\n blockers?: string[];\r\n resources?: {\r\n agentCount?: number;\r\n estimatedDuration?: number;\r\n costBudget?: number;\r\n };\r\n}\r\n\r\nexport interface SuccessCriteriaData {\r\n acceptanceCriteria?: string[];\r\n gateThreshold?: number;\r\n consensusThreshold?: number;\r\n qualityGates?: {\r\n testCoverage?: number;\r\n securityScore?: number;\r\n performanceBudget?: number;\r\n };\r\n definitionOfDone?: string[];\r\n nonFunctionalRequirements?: string[];\r\n}\r\n\r\n// ============================================================================\r\n// Redis Epic Context Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Load epic context from Redis\r\n *\r\n * Redis key: swarm:{taskId}:epic-context\r\n */\r\nexport async function loadEpicContext(taskId: string): Promise<EpicContextData | null> {\r\n try {\r\n const { stdout } = await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} get \"swarm:${taskId}:epic-context\"`);\r\n const result = stdout.trim();\r\n\r\n if (result === '(nil)' || !result) {\r\n return null;\r\n }\r\n\r\n return JSON.parse(result) as EpicContextData;\r\n } catch (error) {\r\n console.warn(`[cfn-context] Failed to load epic context for task ${taskId}:`, error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Load phase context from Redis\r\n *\r\n * Redis key: swarm:{taskId}:phase-context\r\n */\r\nexport async function loadPhaseContext(taskId: string): Promise<PhaseContextData | null> {\r\n try {\r\n const { stdout } = await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} get \"swarm:${taskId}:phase-context\"`);\r\n const result = stdout.trim();\r\n\r\n if (result === '(nil)' || !result) {\r\n return null;\r\n }\r\n\r\n return JSON.parse(result) as PhaseContextData;\r\n } catch (error) {\r\n console.warn(`[cfn-context] Failed to load phase context for task ${taskId}:`, error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Load success criteria from Redis\r\n *\r\n * Redis key: swarm:{taskId}:success-criteria\r\n */\r\nexport async function loadSuccessCriteria(taskId: string): Promise<SuccessCriteriaData | null> {\r\n try {\r\n const { stdout } = await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} get \"swarm:${taskId}:success-criteria\"`);\r\n const result = stdout.trim();\r\n\r\n if (result === '(nil)' || !result) {\r\n return null;\r\n }\r\n\r\n return JSON.parse(result) as SuccessCriteriaData;\r\n } catch (error) {\r\n console.warn(`[cfn-context] Failed to load success criteria for task ${taskId}:`, error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Store epic context to Redis\r\n *\r\n * Redis key: swarm:{taskId}:epic-context\r\n * TTL: 7 days\r\n */\r\nexport async function storeEpicContext(taskId: string, context: EpicContextData): Promise<boolean> {\r\n try {\r\n const contextJson = JSON.stringify(context);\r\n await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} setex \"swarm:${taskId}:epic-context\" 604800 '${contextJson.replace(/'/g, \"\\\\'\")}'`);\r\n console.log(`[cfn-context] Stored epic context for task ${taskId}`);\r\n return true;\r\n } catch (error) {\r\n console.error(`[cfn-context] Failed to store epic context for task ${taskId}:`, error);\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Store phase context to Redis\r\n *\r\n * Redis key: swarm:{taskId}:phase-context\r\n * TTL: 7 days\r\n */\r\nexport async function storePhaseContext(taskId: string, context: PhaseContextData): Promise<boolean> {\r\n try {\r\n const contextJson = JSON.stringify(context);\r\n await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} setex \"swarm:${taskId}:phase-context\" 604800 '${contextJson.replace(/'/g, \"\\\\'\")}'`);\r\n console.log(`[cfn-context] Stored phase context for task ${taskId}`);\r\n return true;\r\n } catch (error) {\r\n console.error(`[cfn-context] Failed to store phase context for task ${taskId}:`, error);\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Store success criteria to Redis\r\n *\r\n * Redis key: swarm:{taskId}:success-criteria\r\n * TTL: 7 days\r\n */\r\nexport async function storeSuccessCriteria(taskId: string, criteria: SuccessCriteriaData): Promise<boolean> {\r\n try {\r\n const criteriaJson = JSON.stringify(criteria);\r\n await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} setex \"swarm:${taskId}:success-criteria\" 604800 '${criteriaJson.replace(/'/g, \"\\\\'\")}'`);\r\n console.log(`[cfn-context] Stored success criteria for task ${taskId}`);\r\n return true;\r\n } catch (error) {\r\n console.error(`[cfn-context] Failed to store success criteria for task ${taskId}:`, error);\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Format epic context as markdown for system prompt\r\n */\r\nexport function formatEpicContextForPrompt(epic: EpicContextData): string {\r\n if (!epic.epicGoal && !epic.inScope && !epic.outOfScope) {\r\n return '';\r\n }\r\n\r\n const sections: string[] = [];\r\n\r\n sections.push('## Epic Context');\r\n sections.push('');\r\n\r\n if (epic.epicName) {\r\n sections.push(`**Epic:** ${epic.epicName}`);\r\n sections.push('');\r\n }\r\n\r\n if (epic.epicGoal) {\r\n sections.push('**Goal:**');\r\n sections.push(epic.epicGoal);\r\n sections.push('');\r\n }\r\n\r\n if (epic.currentPhase) {\r\n sections.push(`**Current Phase:** ${epic.currentPhase}`);\r\n sections.push('');\r\n }\r\n\r\n if (epic.inScope && epic.inScope.length > 0) {\r\n sections.push('**In Scope:**');\r\n for (const item of epic.inScope) {\r\n sections.push(`- ${item}`);\r\n }\r\n sections.push('');\r\n }\r\n\r\n if (epic.outOfScope && epic.outOfScope.length > 0) {\r\n sections.push('**Out of Scope:**');\r\n for (const item of epic.outOfScope) {\r\n sections.push(`- ${item}`);\r\n }\r\n sections.push('');\r\n }\r\n\r\n if (epic.references && epic.references.length > 0) {\r\n sections.push('**References:**');\r\n for (const ref of epic.references) {\r\n sections.push(`- ${ref}`);\r\n }\r\n sections.push('');\r\n }\r\n\r\n return sections.join('\\n');\r\n}\r\n\r\n// ============================================================================\r\n// ACE Context Operations CLI (Original Functionality)\r\n// ============================================================================\r\n\r\ninterface ContextOptions {\r\n category?: string;\r\n tags?: string;\r\n confidence?: number;\r\n limit?: number;\r\n taskId?: string;\r\n phase?: string;\r\n}\r\n\r\nfunction parseArgs(args: string[]): { subcommand: string; query?: string; options: ContextOptions } {\r\n const subcommand = args[0] || 'stats';\r\n let query: string | undefined;\r\n const options: ContextOptions = {};\r\n\r\n // For query subcommand, first arg after subcommand is the query\r\n if (subcommand === 'query' && args[1] && !args[1].startsWith('--')) {\r\n query = args[1];\r\n }\r\n\r\n for (let i = 1; i < args.length; i += 2) {\r\n const key = args[i];\r\n const value = args[i + 1];\r\n\r\n switch (key) {\r\n case '--category':\r\n options.category = value;\r\n break;\r\n case '--tags':\r\n options.tags = value;\r\n break;\r\n case '--confidence':\r\n options.confidence = parseFloat(value);\r\n break;\r\n case '--limit':\r\n options.limit = parseInt(value, 10);\r\n break;\r\n case '--task-id':\r\n options.taskId = value;\r\n break;\r\n case '--phase':\r\n options.phase = value;\r\n break;\r\n }\r\n }\r\n\r\n return { subcommand, query, options };\r\n}\r\n\r\nasync function executeContext(subcommand: string, query: string | undefined, options: ContextOptions): Promise<void> {\r\n let slashCommand: string;\r\n\r\n switch (subcommand) {\r\n case 'reflect':\r\n slashCommand = '/context-reflect';\r\n if (options.taskId) slashCommand += ` --task-id ${options.taskId}`;\r\n break;\r\n\r\n case 'curate':\r\n slashCommand = '/context-curate';\r\n break;\r\n\r\n case 'inject':\r\n slashCommand = '/context-inject';\r\n if (options.taskId) slashCommand += ` --task-id ${options.taskId}`;\r\n if (options.phase) slashCommand += ` --phase ${options.phase}`;\r\n break;\r\n\r\n case 'query':\r\n if (!query) {\r\n console.error('Error: Query string required for query subcommand');\r\n console.error('Usage: cfn-context query <search-term> [options]');\r\n process.exit(1);\r\n }\r\n slashCommand = `/context-query \"${query}\"`;\r\n if (options.category) slashCommand += ` --category ${options.category}`;\r\n if (options.tags) slashCommand += ` --tags ${options.tags}`;\r\n if (options.confidence) slashCommand += ` --confidence ${options.confidence}`;\r\n break;\r\n\r\n case 'stats':\r\n slashCommand = '/context-stats';\r\n break;\r\n\r\n default:\r\n console.error(`Unknown subcommand: ${subcommand}`);\r\n console.error('Valid subcommands: reflect, curate, inject, query, stats');\r\n process.exit(1);\r\n }\r\n\r\n console.log(`[cfn-context] Executing: ${slashCommand}`);\r\n console.log('[cfn-context] Note: This delegates to claude-flow-novice slash commands');\r\n console.log('[cfn-context] Use Claude Code CLI for actual execution\\n');\r\n\r\n console.log('To execute this context operation, run in Claude Code:');\r\n console.log(` ${slashCommand}`);\r\n}\r\n\r\nfunction showHelp(): void {\r\n console.log(`\r\ncfn-context - ACE Context Operations CLI\r\n\r\nUsage:\r\n cfn-context reflect [options] Run ACE reflection on recent tasks\r\n cfn-context curate Merge reflection deltas into context\r\n cfn-context inject [options] Inject context into tasks\r\n cfn-context query <term> [options] Search contexts\r\n cfn-context stats Show context analytics\r\n\r\nOptions (reflect):\r\n --task-id <id> Reflect on specific task\r\n\r\nOptions (inject):\r\n --task-id <id> Inject into specific task\r\n --phase <name> Inject based on phase\r\n\r\nOptions (query):\r\n --category <cat> Filter by category\r\n --tags <tags> Filter by tags (comma-separated)\r\n --confidence <n> Minimum confidence score (0-1)\r\n --limit <n> Max results\r\n\r\nExamples:\r\n cfn-context reflect --task-id task-123\r\n cfn-context curate\r\n cfn-context inject --phase implementation\r\n cfn-context query \"redis coordination\" --category technical\r\n cfn-context stats\r\n\r\nContext Categories:\r\n technical Technical patterns and solutions\r\n architectural Design decisions and patterns\r\n operational Deployment and operations\r\n quality Testing and quality practices\r\n\r\nFor more info: https://docs.claude.com/cfn-context\r\n `);\r\n}\r\n\r\nasync function main(args: string[] = process.argv.slice(2)): Promise<void> {\r\n if (args.includes('--help') || args.includes('-h')) {\r\n showHelp();\r\n return;\r\n }\r\n\r\n const { subcommand, query, options } = parseArgs(args);\r\n await executeContext(subcommand, query, options);\r\n}\r\n\r\n// Run if called directly\r\nconst isMainModule = import.meta.url.endsWith(process.argv[1]?.replace(/\\\\/g, '/') || '');\r\nif (isMainModule) {\r\n main().catch((err) => {\r\n console.error('[cfn-context] Fatal error:', err);\r\n process.exit(1);\r\n });\r\n}\r\n\r\nexport { main };\r\n"],"names":["exec","promisify","execAsync","redisHost","process","env","CFN_REDIS_HOST","redisPort","CFN_REDIS_PORT","loadEpicContext","taskId","stdout","result","trim","JSON","parse","error","console","warn","loadPhaseContext","loadSuccessCriteria","storeEpicContext","context","contextJson","stringify","replace","log","storePhaseContext","storeSuccessCriteria","criteria","criteriaJson","formatEpicContextForPrompt","epic","epicGoal","inScope","outOfScope","sections","push","epicName","currentPhase","length","item","references","ref","join","parseArgs","args","subcommand","query","options","startsWith","i","key","value","category","tags","confidence","parseFloat","limit","parseInt","phase","executeContext","slashCommand","exit","showHelp","main","argv","slice","includes","isMainModule","url","endsWith","catch","err"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/cli/cfn-context.ts"],"sourcesContent":["#!/usr/bin/env node\r\n/**\r\n * cfn-context - Epic context operations for CLI agents\r\n *\r\n * Provides functions to:\r\n * 1. Load epic/phase context from Redis\r\n * 2. Store epic/phase context to Redis\r\n * 3. Format context for agent system prompts\r\n *\r\n * Also provides ACE context operations CLI:\r\n * cfn-context reflect Run ACE reflection\r\n * cfn-context curate Merge contexts\r\n * cfn-context inject Inject into tasks\r\n * cfn-context query Search contexts\r\n * cfn-context stats Show analytics\r\n */\r\n\r\nimport { spawn } from 'child_process';\r\nimport { exec } from 'child_process';\r\nimport { promisify } from 'util';\r\n\r\nconst execAsync = promisify(exec);\r\n\r\n// Bug #6 Fix: Read Redis connection parameters from process.env\r\n// FIX: Default to 'localhost' for CLI mode (host execution), not 'cfn-redis' (Docker)\r\nconst redisHost = process.env.CFN_REDIS_HOST || 'localhost';\r\nconst redisPort = process.env.CFN_REDIS_PORT || '6379';\r\n\r\n// ============================================================================\r\n// Epic Context Interfaces (for CLI Agent System Prompts)\r\n// ============================================================================\r\n\r\nexport interface EpicContextData {\r\n epicGoal?: string;\r\n epicName?: string;\r\n inScope?: string[];\r\n outOfScope?: string[];\r\n phases?: string[];\r\n currentPhase?: string;\r\n riskProfile?: string;\r\n stakeholders?: string[];\r\n references?: string[];\r\n timeline?: {\r\n start?: string;\r\n end?: string;\r\n milestones?: Array<{ phase: string; date: string }>;\r\n };\r\n}\r\n\r\nexport interface PhaseContextData {\r\n phaseName?: string;\r\n phaseNumber?: number;\r\n dependencies?: string[];\r\n deliverables?: string[];\r\n blockers?: string[];\r\n resources?: {\r\n agentCount?: number;\r\n estimatedDuration?: number;\r\n costBudget?: number;\r\n };\r\n}\r\n\r\nexport interface SuccessCriteriaData {\r\n acceptanceCriteria?: string[];\r\n gateThreshold?: number;\r\n consensusThreshold?: number;\r\n qualityGates?: {\r\n testCoverage?: number;\r\n securityScore?: number;\r\n performanceBudget?: number;\r\n };\r\n definitionOfDone?: string[];\r\n nonFunctionalRequirements?: string[];\r\n}\r\n\r\n// ============================================================================\r\n// Redis Epic Context Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Load epic context from Redis\r\n *\r\n * Redis key: swarm:{taskId}:epic-context\r\n */\r\nexport async function loadEpicContext(taskId: string): Promise<EpicContextData | null> {\r\n try {\r\n const { stdout } = await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} get \"swarm:${taskId}:epic-context\"`);\r\n const result = stdout.trim();\r\n\r\n if (result === '(nil)' || !result) {\r\n return null;\r\n }\r\n\r\n return JSON.parse(result) as EpicContextData;\r\n } catch (error) {\r\n console.warn(`[cfn-context] Failed to load epic context for task ${taskId}:`, error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Load phase context from Redis\r\n *\r\n * Redis key: swarm:{taskId}:phase-context\r\n */\r\nexport async function loadPhaseContext(taskId: string): Promise<PhaseContextData | null> {\r\n try {\r\n const { stdout } = await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} get \"swarm:${taskId}:phase-context\"`);\r\n const result = stdout.trim();\r\n\r\n if (result === '(nil)' || !result) {\r\n return null;\r\n }\r\n\r\n return JSON.parse(result) as PhaseContextData;\r\n } catch (error) {\r\n console.warn(`[cfn-context] Failed to load phase context for task ${taskId}:`, error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Load success criteria from Redis\r\n *\r\n * Redis key: swarm:{taskId}:success-criteria\r\n */\r\nexport async function loadSuccessCriteria(taskId: string): Promise<SuccessCriteriaData | null> {\r\n try {\r\n const { stdout } = await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} get \"swarm:${taskId}:success-criteria\"`);\r\n const result = stdout.trim();\r\n\r\n if (result === '(nil)' || !result) {\r\n return null;\r\n }\r\n\r\n return JSON.parse(result) as SuccessCriteriaData;\r\n } catch (error) {\r\n console.warn(`[cfn-context] Failed to load success criteria for task ${taskId}:`, error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Store epic context to Redis\r\n *\r\n * Redis key: swarm:{taskId}:epic-context\r\n * TTL: 7 days\r\n */\r\nexport async function storeEpicContext(taskId: string, context: EpicContextData): Promise<boolean> {\r\n try {\r\n const contextJson = JSON.stringify(context);\r\n await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} setex \"swarm:${taskId}:epic-context\" 604800 '${contextJson.replace(/'/g, \"\\\\'\")}'`);\r\n console.log(`[cfn-context] Stored epic context for task ${taskId}`);\r\n return true;\r\n } catch (error) {\r\n console.error(`[cfn-context] Failed to store epic context for task ${taskId}:`, error);\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Store phase context to Redis\r\n *\r\n * Redis key: swarm:{taskId}:phase-context\r\n * TTL: 7 days\r\n */\r\nexport async function storePhaseContext(taskId: string, context: PhaseContextData): Promise<boolean> {\r\n try {\r\n const contextJson = JSON.stringify(context);\r\n await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} setex \"swarm:${taskId}:phase-context\" 604800 '${contextJson.replace(/'/g, \"\\\\'\")}'`);\r\n console.log(`[cfn-context] Stored phase context for task ${taskId}`);\r\n return true;\r\n } catch (error) {\r\n console.error(`[cfn-context] Failed to store phase context for task ${taskId}:`, error);\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Store success criteria to Redis\r\n *\r\n * Redis key: swarm:{taskId}:success-criteria\r\n * TTL: 7 days\r\n */\r\nexport async function storeSuccessCriteria(taskId: string, criteria: SuccessCriteriaData): Promise<boolean> {\r\n try {\r\n const criteriaJson = JSON.stringify(criteria);\r\n await execAsync(`redis-cli -h ${redisHost} -p ${redisPort} setex \"swarm:${taskId}:success-criteria\" 604800 '${criteriaJson.replace(/'/g, \"\\\\'\")}'`);\r\n console.log(`[cfn-context] Stored success criteria for task ${taskId}`);\r\n return true;\r\n } catch (error) {\r\n console.error(`[cfn-context] Failed to store success criteria for task ${taskId}:`, error);\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Format epic context as markdown for system prompt\r\n */\r\nexport function formatEpicContextForPrompt(epic: EpicContextData): string {\r\n if (!epic.epicGoal && !epic.inScope && !epic.outOfScope) {\r\n return '';\r\n }\r\n\r\n const sections: string[] = [];\r\n\r\n sections.push('## Epic Context');\r\n sections.push('');\r\n\r\n if (epic.epicName) {\r\n sections.push(`**Epic:** ${epic.epicName}`);\r\n sections.push('');\r\n }\r\n\r\n if (epic.epicGoal) {\r\n sections.push('**Goal:**');\r\n sections.push(epic.epicGoal);\r\n sections.push('');\r\n }\r\n\r\n if (epic.currentPhase) {\r\n sections.push(`**Current Phase:** ${epic.currentPhase}`);\r\n sections.push('');\r\n }\r\n\r\n if (epic.inScope && epic.inScope.length > 0) {\r\n sections.push('**In Scope:**');\r\n for (const item of epic.inScope) {\r\n sections.push(`- ${item}`);\r\n }\r\n sections.push('');\r\n }\r\n\r\n if (epic.outOfScope && epic.outOfScope.length > 0) {\r\n sections.push('**Out of Scope:**');\r\n for (const item of epic.outOfScope) {\r\n sections.push(`- ${item}`);\r\n }\r\n sections.push('');\r\n }\r\n\r\n if (epic.references && epic.references.length > 0) {\r\n sections.push('**References:**');\r\n for (const ref of epic.references) {\r\n sections.push(`- ${ref}`);\r\n }\r\n sections.push('');\r\n }\r\n\r\n return sections.join('\\n');\r\n}\r\n\r\n// ============================================================================\r\n// ACE Context Operations CLI (Original Functionality)\r\n// ============================================================================\r\n\r\ninterface ContextOptions {\r\n category?: string;\r\n tags?: string;\r\n confidence?: number;\r\n limit?: number;\r\n taskId?: string;\r\n phase?: string;\r\n}\r\n\r\nfunction parseArgs(args: string[]): { subcommand: string; query?: string; options: ContextOptions } {\r\n const subcommand = args[0] || 'stats';\r\n let query: string | undefined;\r\n const options: ContextOptions = {};\r\n\r\n // For query subcommand, first arg after subcommand is the query\r\n if (subcommand === 'query' && args[1] && !args[1].startsWith('--')) {\r\n query = args[1];\r\n }\r\n\r\n for (let i = 1; i < args.length; i += 2) {\r\n const key = args[i];\r\n const value = args[i + 1];\r\n\r\n switch (key) {\r\n case '--category':\r\n options.category = value;\r\n break;\r\n case '--tags':\r\n options.tags = value;\r\n break;\r\n case '--confidence':\r\n options.confidence = parseFloat(value);\r\n break;\r\n case '--limit':\r\n options.limit = parseInt(value, 10);\r\n break;\r\n case '--task-id':\r\n options.taskId = value;\r\n break;\r\n case '--phase':\r\n options.phase = value;\r\n break;\r\n }\r\n }\r\n\r\n return { subcommand, query, options };\r\n}\r\n\r\nasync function executeContext(subcommand: string, query: string | undefined, options: ContextOptions): Promise<void> {\r\n let slashCommand: string;\r\n\r\n switch (subcommand) {\r\n case 'reflect':\r\n slashCommand = '/context-reflect';\r\n if (options.taskId) slashCommand += ` --task-id ${options.taskId}`;\r\n break;\r\n\r\n case 'curate':\r\n slashCommand = '/context-curate';\r\n break;\r\n\r\n case 'inject':\r\n slashCommand = '/context-inject';\r\n if (options.taskId) slashCommand += ` --task-id ${options.taskId}`;\r\n if (options.phase) slashCommand += ` --phase ${options.phase}`;\r\n break;\r\n\r\n case 'query':\r\n if (!query) {\r\n console.error('Error: Query string required for query subcommand');\r\n console.error('Usage: cfn-context query <search-term> [options]');\r\n process.exit(1);\r\n }\r\n slashCommand = `/context-query \"${query}\"`;\r\n if (options.category) slashCommand += ` --category ${options.category}`;\r\n if (options.tags) slashCommand += ` --tags ${options.tags}`;\r\n if (options.confidence) slashCommand += ` --confidence ${options.confidence}`;\r\n break;\r\n\r\n case 'stats':\r\n slashCommand = '/context-stats';\r\n break;\r\n\r\n default:\r\n console.error(`Unknown subcommand: ${subcommand}`);\r\n console.error('Valid subcommands: reflect, curate, inject, query, stats');\r\n process.exit(1);\r\n }\r\n\r\n console.log(`[cfn-context] Executing: ${slashCommand}`);\r\n console.log('[cfn-context] Note: This delegates to claude-flow-novice slash commands');\r\n console.log('[cfn-context] Use Claude Code CLI for actual execution\\n');\r\n\r\n console.log('To execute this context operation, run in Claude Code:');\r\n console.log(` ${slashCommand}`);\r\n}\r\n\r\nfunction showHelp(): void {\r\n console.log(`\r\ncfn-context - ACE Context Operations CLI\r\n\r\nUsage:\r\n cfn-context reflect [options] Run ACE reflection on recent tasks\r\n cfn-context curate Merge reflection deltas into context\r\n cfn-context inject [options] Inject context into tasks\r\n cfn-context query <term> [options] Search contexts\r\n cfn-context stats Show context analytics\r\n\r\nOptions (reflect):\r\n --task-id <id> Reflect on specific task\r\n\r\nOptions (inject):\r\n --task-id <id> Inject into specific task\r\n --phase <name> Inject based on phase\r\n\r\nOptions (query):\r\n --category <cat> Filter by category\r\n --tags <tags> Filter by tags (comma-separated)\r\n --confidence <n> Minimum confidence score (0-1)\r\n --limit <n> Max results\r\n\r\nExamples:\r\n cfn-context reflect --task-id task-123\r\n cfn-context curate\r\n cfn-context inject --phase implementation\r\n cfn-context query \"redis coordination\" --category technical\r\n cfn-context stats\r\n\r\nContext Categories:\r\n technical Technical patterns and solutions\r\n architectural Design decisions and patterns\r\n operational Deployment and operations\r\n quality Testing and quality practices\r\n\r\nFor more info: https://docs.claude.com/cfn-context\r\n `);\r\n}\r\n\r\nasync function main(args: string[] = process.argv.slice(2)): Promise<void> {\r\n if (args.includes('--help') || args.includes('-h')) {\r\n showHelp();\r\n return;\r\n }\r\n\r\n const { subcommand, query, options } = parseArgs(args);\r\n await executeContext(subcommand, query, options);\r\n}\r\n\r\n// Run if called directly\r\nconst isMainModule = import.meta.url.endsWith(process.argv[1]?.replace(/\\\\/g, '/') || '');\r\nif (isMainModule) {\r\n main().catch((err) => {\r\n console.error('[cfn-context] Fatal error:', err);\r\n process.exit(1);\r\n });\r\n}\r\n\r\nexport { main };\r\n"],"names":["exec","promisify","execAsync","redisHost","process","env","CFN_REDIS_HOST","redisPort","CFN_REDIS_PORT","loadEpicContext","taskId","stdout","result","trim","JSON","parse","error","console","warn","loadPhaseContext","loadSuccessCriteria","storeEpicContext","context","contextJson","stringify","replace","log","storePhaseContext","storeSuccessCriteria","criteria","criteriaJson","formatEpicContextForPrompt","epic","epicGoal","inScope","outOfScope","sections","push","epicName","currentPhase","length","item","references","ref","join","parseArgs","args","subcommand","query","options","startsWith","i","key","value","category","tags","confidence","parseFloat","limit","parseInt","phase","executeContext","slashCommand","exit","showHelp","main","argv","slice","includes","isMainModule","url","endsWith","catch","err"],"mappings":"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"}
@@ -9,7 +9,8 @@
9
9
  */ import { spawn } from 'child_process';
10
10
  import { resolve } from 'path';
11
11
  // Bug #6 Fix: Read Redis connection parameters from process.env
12
- const redisHost = process.env.CFN_REDIS_HOST || 'cfn-redis';
12
+ // FIX: Default to 'localhost' for CLI mode (host execution), not 'cfn-redis' (Docker)
13
+ const redisHost = process.env.CFN_REDIS_HOST || 'localhost';
13
14
  const redisPort = process.env.CFN_REDIS_PORT || '6379';
14
15
  function parseArgs(args) {
15
16
  const subcommand = args[0] || 'fleet';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/cfn-metrics.ts"],"sourcesContent":["#!/usr/bin/env node\r\n/**\r\n * cfn-metrics - Monitoring and analytics\r\n *\r\n * Usage:\r\n * cfn-metrics agent Show agent metrics\r\n * cfn-metrics consensus Show consensus scores\r\n * cfn-metrics fleet Show fleet status\r\n */\r\n\r\nimport { spawn } from 'child_process';\r\nimport { resolve } from 'path';\r\n\r\n// Bug #6 Fix: Read Redis connection parameters from process.env\r\nconst redisHost = process.env.CFN_REDIS_HOST || 'cfn-redis';\r\nconst redisPort = process.env.CFN_REDIS_PORT || '6379';\r\n\r\ninterface MetricsOptions {\r\n agentId?: string;\r\n taskId?: string;\r\n period?: string;\r\n format?: string;\r\n}\r\n\r\nfunction parseArgs(args: string[]): { subcommand: string; options: MetricsOptions } {\r\n const subcommand = args[0] || 'fleet';\r\n const options: MetricsOptions = {};\r\n\r\n for (let i = 1; i < args.length; i += 2) {\r\n const key = args[i];\r\n const value = args[i + 1];\r\n\r\n switch (key) {\r\n case '--agent-id':\r\n options.agentId = value;\r\n break;\r\n case '--task-id':\r\n options.taskId = value;\r\n break;\r\n case '--period':\r\n options.period = value;\r\n break;\r\n case '--format':\r\n options.format = value;\r\n break;\r\n }\r\n }\r\n\r\n return { subcommand, options };\r\n}\r\n\r\nasync function executeMetrics(subcommand: string, options: MetricsOptions): Promise<void> {\r\n const portalPath = resolve(process.cwd(), '.claude/skills/web-portal');\r\n\r\n switch (subcommand) {\r\n case 'agent': {\r\n console.log('[cfn-metrics] Fetching agent metrics...');\r\n\r\n const script = resolve(portalPath, 'invoke-portal-metrics.sh');\r\n const args: string[] = [];\r\n\r\n if (options.agentId) {\r\n args.push('--agent-id', options.agentId);\r\n }\r\n if (options.period) {\r\n args.push('--period', options.period);\r\n }\r\n\r\n const proc = spawn('bash', [script, ...args], { stdio: 'inherit' });\r\n\r\n proc.on('exit', (code) => process.exit(code || 0));\r\n proc.on('error', (err) => {\r\n console.error('[cfn-metrics] Error:', err.message);\r\n console.log('\\nFallback: Use web portal for metrics:');\r\n console.log(' http://localhost:3000/metrics');\r\n process.exit(1);\r\n });\r\n break;\r\n }\r\n\r\n case 'consensus': {\r\n console.log('[cfn-metrics] Fetching consensus scores...');\r\n\r\n if (!options.taskId) {\r\n console.error('Error: --task-id required for consensus metrics');\r\n process.exit(1);\r\n }\r\n\r\n // Query Redis for consensus data\r\n const redisKey = `swarm:${options.taskId}:consensus:*`;\r\n const proc = spawn('redis-cli', ['-h', redisHost, '-p', redisPort, '--scan', '--pattern', redisKey], { stdio: 'inherit' });\r\n\r\n proc.on('exit', (code) => {\r\n if (code === 0) {\r\n console.log('\\nTo see consensus values, run:');\r\n console.log(` redis-cli -h ${redisHost} -p ${redisPort} get swarm:${options.taskId}:consensus:loop2`);\r\n }\r\n process.exit(code || 0);\r\n });\r\n\r\n proc.on('error', (err) => {\r\n console.error('[cfn-metrics] Redis error:', err.message);\r\n process.exit(1);\r\n });\r\n break;\r\n }\r\n\r\n case 'fleet': {\r\n console.log('[cfn-metrics] Fetching fleet status...');\r\n\r\n const script = resolve(portalPath, 'invoke-portal-agents.sh');\r\n const proc = spawn('bash', [script, '--status', 'all'], { stdio: 'inherit' });\r\n\r\n proc.on('exit', (code) => process.exit(code || 0));\r\n proc.on('error', (err) => {\r\n console.error('[cfn-metrics] Error:', err.message);\r\n process.exit(1);\r\n });\r\n break;\r\n }\r\n\r\n default:\r\n console.error(`Unknown subcommand: ${subcommand}`);\r\n console.error('Valid subcommands: agent, consensus, fleet');\r\n process.exit(1);\r\n }\r\n}\r\n\r\nfunction showHelp(): void {\r\n console.log(`\r\ncfn-metrics - Monitoring and Analytics CLI\r\n\r\nUsage:\r\n cfn-metrics agent [options] Show agent performance metrics\r\n cfn-metrics consensus [options] Show consensus scores\r\n cfn-metrics fleet Show fleet status\r\n\r\nOptions (agent):\r\n --agent-id <id> Specific agent metrics\r\n --period <time> Time period (1h, 24h, 7d)\r\n --format <type> Output format (json, table)\r\n\r\nOptions (consensus):\r\n --task-id <id> Task to show consensus for (required)\r\n\r\nExamples:\r\n cfn-metrics agent --agent-id coder-1 --period 1h\r\n cfn-metrics consensus --task-id task-123\r\n cfn-metrics fleet\r\n\r\nMetrics Available:\r\n - Agent execution time\r\n - Confidence scores over time\r\n - Tool usage statistics\r\n - Consensus validation results\r\n - Fleet health and availability\r\n\r\nIntegration: Metrics also available via web portal at http://localhost:3000/metrics\r\n\r\nFor more info: https://docs.claude.com/cfn-metrics\r\n `);\r\n}\r\n\r\nasync function main(args: string[] = process.argv.slice(2)): Promise<void> {\r\n if (args.includes('--help') || args.includes('-h')) {\r\n showHelp();\r\n return;\r\n }\r\n\r\n const { subcommand, options } = parseArgs(args);\r\n await executeMetrics(subcommand, options);\r\n}\r\n\r\n// Run if called directly\r\nconst isMainModule = import.meta.url.endsWith(process.argv[1]?.replace(/\\\\/g, '/') || '');\r\nif (isMainModule) {\r\n main().catch((err) => {\r\n console.error('[cfn-metrics] Fatal error:', err);\r\n process.exit(1);\r\n });\r\n}\r\n\r\nexport { main };\r\n"],"names":["spawn","resolve","redisHost","process","env","CFN_REDIS_HOST","redisPort","CFN_REDIS_PORT","parseArgs","args","subcommand","options","i","length","key","value","agentId","taskId","period","format","executeMetrics","portalPath","cwd","console","log","script","push","proc","stdio","on","code","exit","err","error","message","redisKey","showHelp","main","argv","slice","includes","isMainModule","url","endsWith","replace","catch"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/cli/cfn-metrics.ts"],"sourcesContent":["#!/usr/bin/env node\r\n/**\r\n * cfn-metrics - Monitoring and analytics\r\n *\r\n * Usage:\r\n * cfn-metrics agent Show agent metrics\r\n * cfn-metrics consensus Show consensus scores\r\n * cfn-metrics fleet Show fleet status\r\n */\r\n\r\nimport { spawn } from 'child_process';\r\nimport { resolve } from 'path';\r\n\r\n// Bug #6 Fix: Read Redis connection parameters from process.env\r\n// FIX: Default to 'localhost' for CLI mode (host execution), not 'cfn-redis' (Docker)\r\nconst redisHost = process.env.CFN_REDIS_HOST || 'localhost';\r\nconst redisPort = process.env.CFN_REDIS_PORT || '6379';\r\n\r\ninterface MetricsOptions {\r\n agentId?: string;\r\n taskId?: string;\r\n period?: string;\r\n format?: string;\r\n}\r\n\r\nfunction parseArgs(args: string[]): { subcommand: string; options: MetricsOptions } {\r\n const subcommand = args[0] || 'fleet';\r\n const options: MetricsOptions = {};\r\n\r\n for (let i = 1; i < args.length; i += 2) {\r\n const key = args[i];\r\n const value = args[i + 1];\r\n\r\n switch (key) {\r\n case '--agent-id':\r\n options.agentId = value;\r\n break;\r\n case '--task-id':\r\n options.taskId = value;\r\n break;\r\n case '--period':\r\n options.period = value;\r\n break;\r\n case '--format':\r\n options.format = value;\r\n break;\r\n }\r\n }\r\n\r\n return { subcommand, options };\r\n}\r\n\r\nasync function executeMetrics(subcommand: string, options: MetricsOptions): Promise<void> {\r\n const portalPath = resolve(process.cwd(), '.claude/skills/web-portal');\r\n\r\n switch (subcommand) {\r\n case 'agent': {\r\n console.log('[cfn-metrics] Fetching agent metrics...');\r\n\r\n const script = resolve(portalPath, 'invoke-portal-metrics.sh');\r\n const args: string[] = [];\r\n\r\n if (options.agentId) {\r\n args.push('--agent-id', options.agentId);\r\n }\r\n if (options.period) {\r\n args.push('--period', options.period);\r\n }\r\n\r\n const proc = spawn('bash', [script, ...args], { stdio: 'inherit' });\r\n\r\n proc.on('exit', (code) => process.exit(code || 0));\r\n proc.on('error', (err) => {\r\n console.error('[cfn-metrics] Error:', err.message);\r\n console.log('\\nFallback: Use web portal for metrics:');\r\n console.log(' http://localhost:3000/metrics');\r\n process.exit(1);\r\n });\r\n break;\r\n }\r\n\r\n case 'consensus': {\r\n console.log('[cfn-metrics] Fetching consensus scores...');\r\n\r\n if (!options.taskId) {\r\n console.error('Error: --task-id required for consensus metrics');\r\n process.exit(1);\r\n }\r\n\r\n // Query Redis for consensus data\r\n const redisKey = `swarm:${options.taskId}:consensus:*`;\r\n const proc = spawn('redis-cli', ['-h', redisHost, '-p', redisPort, '--scan', '--pattern', redisKey], { stdio: 'inherit' });\r\n\r\n proc.on('exit', (code) => {\r\n if (code === 0) {\r\n console.log('\\nTo see consensus values, run:');\r\n console.log(` redis-cli -h ${redisHost} -p ${redisPort} get swarm:${options.taskId}:consensus:loop2`);\r\n }\r\n process.exit(code || 0);\r\n });\r\n\r\n proc.on('error', (err) => {\r\n console.error('[cfn-metrics] Redis error:', err.message);\r\n process.exit(1);\r\n });\r\n break;\r\n }\r\n\r\n case 'fleet': {\r\n console.log('[cfn-metrics] Fetching fleet status...');\r\n\r\n const script = resolve(portalPath, 'invoke-portal-agents.sh');\r\n const proc = spawn('bash', [script, '--status', 'all'], { stdio: 'inherit' });\r\n\r\n proc.on('exit', (code) => process.exit(code || 0));\r\n proc.on('error', (err) => {\r\n console.error('[cfn-metrics] Error:', err.message);\r\n process.exit(1);\r\n });\r\n break;\r\n }\r\n\r\n default:\r\n console.error(`Unknown subcommand: ${subcommand}`);\r\n console.error('Valid subcommands: agent, consensus, fleet');\r\n process.exit(1);\r\n }\r\n}\r\n\r\nfunction showHelp(): void {\r\n console.log(`\r\ncfn-metrics - Monitoring and Analytics CLI\r\n\r\nUsage:\r\n cfn-metrics agent [options] Show agent performance metrics\r\n cfn-metrics consensus [options] Show consensus scores\r\n cfn-metrics fleet Show fleet status\r\n\r\nOptions (agent):\r\n --agent-id <id> Specific agent metrics\r\n --period <time> Time period (1h, 24h, 7d)\r\n --format <type> Output format (json, table)\r\n\r\nOptions (consensus):\r\n --task-id <id> Task to show consensus for (required)\r\n\r\nExamples:\r\n cfn-metrics agent --agent-id coder-1 --period 1h\r\n cfn-metrics consensus --task-id task-123\r\n cfn-metrics fleet\r\n\r\nMetrics Available:\r\n - Agent execution time\r\n - Confidence scores over time\r\n - Tool usage statistics\r\n - Consensus validation results\r\n - Fleet health and availability\r\n\r\nIntegration: Metrics also available via web portal at http://localhost:3000/metrics\r\n\r\nFor more info: https://docs.claude.com/cfn-metrics\r\n `);\r\n}\r\n\r\nasync function main(args: string[] = process.argv.slice(2)): Promise<void> {\r\n if (args.includes('--help') || args.includes('-h')) {\r\n showHelp();\r\n return;\r\n }\r\n\r\n const { subcommand, options } = parseArgs(args);\r\n await executeMetrics(subcommand, options);\r\n}\r\n\r\n// Run if called directly\r\nconst isMainModule = import.meta.url.endsWith(process.argv[1]?.replace(/\\\\/g, '/') || '');\r\nif (isMainModule) {\r\n main().catch((err) => {\r\n console.error('[cfn-metrics] Fatal error:', err);\r\n process.exit(1);\r\n });\r\n}\r\n\r\nexport { main };\r\n"],"names":["spawn","resolve","redisHost","process","env","CFN_REDIS_HOST","redisPort","CFN_REDIS_PORT","parseArgs","args","subcommand","options","i","length","key","value","agentId","taskId","period","format","executeMetrics","portalPath","cwd","console","log","script","push","proc","stdio","on","code","exit","err","error","message","redisKey","showHelp","main","argv","slice","includes","isMainModule","url","endsWith","replace","catch"],"mappings":"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"}
@@ -9,7 +9,8 @@
9
9
  */ import { spawn } from 'child_process';
10
10
  import { resolve } from 'path';
11
11
  // Bug #6 Fix: Read Redis connection parameters from process.env
12
- const redisHost = process.env.CFN_REDIS_HOST || 'cfn-redis';
12
+ // FIX: Default to 'localhost' for CLI mode (host execution), not 'cfn-redis' (Docker)
13
+ const redisHost = process.env.CFN_REDIS_HOST || 'localhost';
13
14
  const redisPort = process.env.CFN_REDIS_PORT || '6379';
14
15
  function parseArgs(args) {
15
16
  const subcommand = args[0] || 'pattern';