claude-flow-novice 2.14.10 → 2.14.12

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 (31) hide show
  1. package/.claude/commands/CFN_LOOP_TASK_MODE copy.md +495 -0
  2. package/.claude/commands/cfn-loop-cli.md +1 -1
  3. package/.claude/skills/cfn-agent-selector/SKILL.md +2 -2
  4. package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +5 -72
  5. package/.claude/skills/cfn-redis-coordination/get-context.sh +113 -0
  6. package/.claude/skills/cfn-redis-coordination/store-context.sh +74 -19
  7. package/claude-assets/agents/cfn-dev-team/CLAUDE.md +3 -3
  8. package/claude-assets/agents/cfn-dev-team/README.md +1 -1
  9. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +2 -2
  10. package/claude-assets/agents/cfn-dev-team/developers/README.md +3 -3
  11. package/claude-assets/agents/cfn-dev-team/documentation/agent-type-guidelines.md +1 -1
  12. package/claude-assets/agents/cfn-dev-team/test-agent.md +2 -2
  13. package/claude-assets/commands/CFN_LOOP_TASK_MODE copy.md +495 -0
  14. package/claude-assets/commands/cfn-loop-cli.md +1 -1
  15. package/claude-assets/skills/cfn-agent-selector/SKILL.md +2 -2
  16. package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +5 -72
  17. package/claude-assets/skills/cfn-redis-coordination/get-context.sh +113 -0
  18. package/claude-assets/skills/cfn-redis-coordination/store-context.sh +74 -19
  19. package/dist/agents/agent-loader.js +146 -165
  20. package/dist/cli/config-manager.js +91 -109
  21. package/dist/cli/config-manager.js.map +1 -1
  22. package/package.json +1 -1
  23. package/scripts/init-project.js +21 -3
  24. package/.claude/skills/cfn-agent-selector/SKILL.md.backup_before_replace +0 -91
  25. package/claude-assets/agents/cfn-dev-team/CLAUDE.md.backup_before_replace +0 -1086
  26. package/claude-assets/agents/cfn-dev-team/README.md.backup_before_replace +0 -116
  27. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md.backup_before_replace +0 -451
  28. package/claude-assets/agents/cfn-dev-team/developers/README.md.backup_before_replace +0 -69
  29. package/claude-assets/agents/cfn-dev-team/documentation/agent-type-guidelines.md.backup_before_replace +0 -465
  30. package/claude-assets/agents/cfn-dev-team/test-agent.md.backup_before_replace +0 -141
  31. package/claude-assets/skills/cfn-agent-selector/SKILL.md.backup_before_replace +0 -91
@@ -0,0 +1,113 @@
1
+ #!/bin/bash
2
+ # Retrieve CFN Loop task context from Redis
3
+ # Used by CLI-spawned agents to get structured context from orchestrator
4
+ #
5
+ # Usage:
6
+ # get-context.sh --task-id <id> [--namespace <ns>]
7
+ # get-context.sh --task-id <id> --key <key> [--namespace <ns>]
8
+ # get-context.sh <task_id> (legacy mode)
9
+
10
+ set -euo pipefail
11
+
12
+ # Initialize variables
13
+ TASK_ID=""
14
+ KEY=""
15
+ NAMESPACE="swarm"
16
+ FORMAT="json" # json or raw
17
+
18
+ # Parse arguments
19
+ while [[ $# -gt 0 ]]; do
20
+ case $1 in
21
+ --task-id)
22
+ TASK_ID="$2"
23
+ shift 2
24
+ ;;
25
+ --key)
26
+ KEY="$2"
27
+ shift 2
28
+ ;;
29
+ --namespace)
30
+ NAMESPACE="$2"
31
+ shift 2
32
+ ;;
33
+ --format)
34
+ FORMAT="$2"
35
+ shift 2
36
+ ;;
37
+ *)
38
+ # Legacy mode: positional argument
39
+ if [ -z "$TASK_ID" ]; then
40
+ TASK_ID="$1"
41
+ fi
42
+ shift
43
+ ;;
44
+ esac
45
+ done
46
+
47
+ # Validate required arguments
48
+ if [ -z "$TASK_ID" ]; then
49
+ echo "Error: --task-id or TASK_ID required" >&2
50
+ echo "Usage: $0 --task-id <id> [--key <key>] [--namespace <ns>] [--format <json|raw>]" >&2
51
+ echo " or: $0 <task_id> (legacy)" >&2
52
+ exit 1
53
+ fi
54
+
55
+ REDIS_KEY="${NAMESPACE}:${TASK_ID}:context"
56
+
57
+ # Check if context exists
58
+ if ! redis-cli EXISTS "$REDIS_KEY" >/dev/null 2>&1; then
59
+ echo "⚠️ No context found for task: $TASK_ID" >&2
60
+ exit 1
61
+ fi
62
+
63
+ # Handle specific key retrieval
64
+ if [ -n "$KEY" ]; then
65
+ VALUE=$(redis-cli HGET "$REDIS_KEY" "$KEY" 2>/dev/null || echo "")
66
+ if [ -z "$VALUE" ]; then
67
+ echo "⚠️ Key '$KEY' not found in context for task: $TASK_ID" >&2
68
+ exit 1
69
+ fi
70
+
71
+ if [ "$FORMAT" = "raw" ]; then
72
+ echo "$VALUE"
73
+ else
74
+ echo "{\"$KEY\":$VALUE}"
75
+ fi
76
+ exit 0
77
+ fi
78
+
79
+ # Handle full context retrieval
80
+ ALL_FIELDS=$(redis-cli HGETALL "$REDIS_KEY" 2>/dev/null || echo "")
81
+
82
+ if [ -z "$ALL_FIELDS" ]; then
83
+ echo "⚠️ Empty context for task: $TASK_ID" >&2
84
+ exit 1
85
+ fi
86
+
87
+ # Format as JSON
88
+ if [ "$FORMAT" = "json" ]; then
89
+ echo "{"
90
+ first=true
91
+ while IFS= read -r field; do
92
+ if [ -z "$field" ]; then continue; fi
93
+ if [ "$first" = true ]; then
94
+ first=false
95
+ else
96
+ echo ","
97
+ fi
98
+ # Skip empty lines and properly format JSON values
99
+ if [[ $field =~ ^[0-9]+$ ]]; then
100
+ # Numeric value
101
+ echo -n " \"$field\": $(redis-cli HGET "$REDIS_KEY" "$field")"
102
+ else
103
+ # String value
104
+ value=$(redis-cli HGET "$REDIS_KEY" "$field" | sed 's/"/\\"/g')
105
+ echo -n " \"$field\": \"$value\""
106
+ fi
107
+ done <<< "$ALL_FIELDS"
108
+ echo ""
109
+ echo "}"
110
+ else
111
+ # Raw format
112
+ redis-cli HGETALL "$REDIS_KEY"
113
+ fi
@@ -1,34 +1,89 @@
1
1
  #!/bin/bash
2
2
  # Store CFN Loop task context in Redis
3
- # Used by orchestrator to pass context to CLI-spawned agents
3
+ # Used by orchestrator to pass structured context to CLI-spawned agents
4
4
  #
5
- # Usage: store-context.sh <task_id> <context_json>
5
+ # Usage:
6
+ # store-context.sh --task-id <id> --key <key> --value <value> [--namespace <ns>]
7
+ # store-context.sh <task_id> <context_json> (legacy mode)
6
8
 
7
9
  set -euo pipefail
8
10
 
9
- TASK_ID="${1:-}"
10
- CONTEXT="${2:-}"
11
+ # Initialize variables
12
+ TASK_ID=""
13
+ KEY=""
14
+ VALUE=""
15
+ NAMESPACE="swarm"
16
+ CONTEXT=""
11
17
 
18
+ # Parse arguments
19
+ while [[ $# -gt 0 ]]; do
20
+ case $1 in
21
+ --task-id)
22
+ TASK_ID="$2"
23
+ shift 2
24
+ ;;
25
+ --key)
26
+ KEY="$2"
27
+ shift 2
28
+ ;;
29
+ --value)
30
+ VALUE="$2"
31
+ shift 2
32
+ ;;
33
+ --namespace)
34
+ NAMESPACE="$2"
35
+ shift 2
36
+ ;;
37
+ *)
38
+ # Legacy mode: positional arguments
39
+ if [ -z "$TASK_ID" ]; then
40
+ TASK_ID="$1"
41
+ elif [ -z "$CONTEXT" ]; then
42
+ CONTEXT="$1"
43
+ fi
44
+ shift
45
+ ;;
46
+ esac
47
+ done
48
+
49
+ # Validate required arguments
12
50
  if [ -z "$TASK_ID" ]; then
13
- echo "Error: TASK_ID required" >&2
14
- echo "Usage: $0 <task_id> <context_json>" >&2
51
+ echo "Error: --task-id or TASK_ID required" >&2
52
+ echo "Usage: $0 --task-id <id> --key <key> --value <value> [--namespace <ns>]" >&2
53
+ echo " or: $0 <task_id> <context_json> (legacy)" >&2
15
54
  exit 1
16
55
  fi
17
56
 
18
- if [ -z "$CONTEXT" ]; then
19
- echo "Error: CONTEXT required" >&2
20
- echo "Usage: $0 <task_id> <context_json>" >&2
21
- exit 1
57
+ # Handle structured mode (new)
58
+ if [ -n "$KEY" ] && [ -n "$VALUE" ]; then
59
+ # Store structured context with specific key
60
+ REDIS_KEY="${NAMESPACE}:${TASK_ID}:context"
61
+
62
+ redis-cli HSET "$REDIS_KEY" \
63
+ "$KEY" "$VALUE" \
64
+ "updated_at" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
65
+ > /dev/null
66
+
67
+ # Set TTL (24 hours)
68
+ redis-cli EXPIRE "$REDIS_KEY" 86400 > /dev/null
69
+
70
+ echo "✅ Context stored: $KEY for task: $TASK_ID"
71
+ exit 0
22
72
  fi
23
73
 
24
- # Store context in Redis
25
- redis-cli HSET "cfn_loop:task:${TASK_ID}:context" \
26
- "task_description" "$CONTEXT" \
27
- "stored_at" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
28
- > /dev/null
74
+ # Handle legacy mode
75
+ if [ -n "$CONTEXT" ]; then
76
+ redis-cli HSET "swarm:${TASK_ID}:context" \
77
+ "task_description" "$CONTEXT" \
78
+ "stored_at" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
79
+ > /dev/null
80
+
81
+ # Set TTL (24 hours)
82
+ redis-cli EXPIRE "swarm:${TASK_ID}:context" 86400 > /dev/null
29
83
 
30
- # Set TTL (24 hours)
31
- redis-cli EXPIRE "cfn_loop:task:${TASK_ID}:context" 86400 > /dev/null
84
+ echo "✅ Context stored for task: $TASK_ID"
85
+ exit 0
86
+ fi
32
87
 
33
- echo " Context stored for task: $TASK_ID"
34
- exit 0
88
+ echo "Error: Either --key/--value or <context_json> required" >&2
89
+ exit 1
@@ -1,145 +1,12 @@
1
- "use strict";
2
1
  /**
3
2
  * Dynamic Agent Loader - Reads agent definitions from .claude/agents/ directory
4
3
  * Single source of truth for agent types in the system
5
- */ var __awaiter = this && this.__awaiter || function(thisArg, _arguments, P, generator) {
6
- function adopt(value) {
7
- return value instanceof P ? value : new P(function(resolve) {
8
- resolve(value);
9
- });
10
- }
11
- return new (P || (P = Promise))(function(resolve, reject) {
12
- function fulfilled(value) {
13
- try {
14
- step(generator.next(value));
15
- } catch (e) {
16
- reject(e);
17
- }
18
- }
19
- function rejected(value) {
20
- try {
21
- step(generator["throw"](value));
22
- } catch (e) {
23
- reject(e);
24
- }
25
- }
26
- function step(result) {
27
- result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
28
- }
29
- step((generator = generator.apply(thisArg, _arguments || [])).next());
30
- });
31
- };
32
- var __generator = this && this.__generator || function(thisArg, body) {
33
- var _ = {
34
- label: 0,
35
- sent: function() {
36
- if (t[0] & 1) throw t[1];
37
- return t[1];
38
- },
39
- trys: [],
40
- ops: []
41
- }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
42
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
43
- return this;
44
- }), g;
45
- function verb(n) {
46
- return function(v) {
47
- return step([
48
- n,
49
- v
50
- ]);
51
- };
52
- }
53
- function step(op) {
54
- if (f) throw new TypeError("Generator is already executing.");
55
- while(g && (g = 0, op[0] && (_ = 0)), _)try {
56
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
57
- if (y = 0, t) op = [
58
- op[0] & 2,
59
- t.value
60
- ];
61
- switch(op[0]){
62
- case 0:
63
- case 1:
64
- t = op;
65
- break;
66
- case 4:
67
- _.label++;
68
- return {
69
- value: op[1],
70
- done: false
71
- };
72
- case 5:
73
- _.label++;
74
- y = op[1];
75
- op = [
76
- 0
77
- ];
78
- continue;
79
- case 7:
80
- op = _.ops.pop();
81
- _.trys.pop();
82
- continue;
83
- default:
84
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
85
- _ = 0;
86
- continue;
87
- }
88
- if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
89
- _.label = op[1];
90
- break;
91
- }
92
- if (op[0] === 6 && _.label < t[1]) {
93
- _.label = t[1];
94
- t = op;
95
- break;
96
- }
97
- if (t && _.label < t[2]) {
98
- _.label = t[2];
99
- _.ops.push(op);
100
- break;
101
- }
102
- if (t[2]) _.ops.pop();
103
- _.trys.pop();
104
- continue;
105
- }
106
- op = body.call(thisArg, _);
107
- } catch (e) {
108
- op = [
109
- 6,
110
- e
111
- ];
112
- y = 0;
113
- } finally{
114
- f = t = 0;
115
- }
116
- if (op[0] & 5) throw op[1];
117
- return {
118
- value: op[0] ? op[1] : void 0,
119
- done: true
120
- };
121
- }
122
- };
123
- var __spreadArray = this && this.__spreadArray || function(to, from, pack) {
124
- if (pack || arguments.length === 2) for(var i = 0, l = from.length, ar; i < l; i++){
125
- if (ar || !(i in from)) {
126
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
127
- ar[i] = from[i];
128
- }
129
- }
130
- return to.concat(ar || Array.prototype.slice.call(from));
131
- };
132
- Object.defineProperty(exports, "__esModule", {
133
- value: true
134
- });
135
- exports.refreshAgents = exports.getAgentsByCategory = exports.isValidAgentType = exports.searchAgents = exports.getAgentCategories = exports.getAllAgents = exports.getAgent = exports.getAvailableAgentTypes = exports.agentLoader = exports.AgentLoader = void 0;
136
- exports.resolveLegacyAgentType = resolveLegacyAgentType;
137
- var node_fs_1 = require("node:fs");
138
- var glob_1 = require("glob");
139
- var node_path_1 = require("node:path");
140
- var yaml_1 = require("yaml");
4
+ */ import { readFileSync, existsSync } from 'node:fs';
5
+ import { glob } from 'glob';
6
+ import { resolve, dirname } from 'node:path';
7
+ import { parse as parseYaml } from 'yaml';
141
8
  // Legacy agent type mapping for backward compatibility
142
- var LEGACY_AGENT_MAPPING = {
9
+ const LEGACY_AGENT_MAPPING = {
143
10
  analyst: 'code-analyzer',
144
11
  coordinator: 'hierarchical-coordinator',
145
12
  optimizer: 'perf-analyzer',
@@ -150,40 +17,38 @@ var LEGACY_AGENT_MAPPING = {
150
17
  };
151
18
  /**
152
19
  * Resolve legacy agent types to current equivalents
153
- */ function resolveLegacyAgentType(legacyType) {
20
+ */ export function resolveLegacyAgentType(legacyType) {
154
21
  return LEGACY_AGENT_MAPPING[legacyType] || legacyType;
155
22
  }
156
- var AgentLoader = /** @class */ function() {
157
- function AgentLoader() {
158
- this.agentCache = new Map();
159
- this.categoriesCache = [];
160
- this.lastLoadTime = 0;
161
- this.CACHE_EXPIRY = 60000; // 1 minute cache
162
- }
163
- AgentLoader.prototype.getAgentsDirectory = function() {
164
- var currentDir = process.cwd();
23
+ export class AgentLoader {
24
+ agentCache = new Map();
25
+ categoriesCache = [];
26
+ lastLoadTime = 0;
27
+ CACHE_EXPIRY = 60_000;
28
+ getAgentsDirectory() {
29
+ let currentDir = process.cwd();
165
30
  while(currentDir !== '/'){
166
- var claudeAgentsPath = (0, node_path_1.resolve)(currentDir, '.claude', 'agents');
167
- if ((0, node_fs_1.existsSync)(claudeAgentsPath)) {
31
+ const claudeAgentsPath = resolve(currentDir, '.claude', 'agents');
32
+ if (existsSync(claudeAgentsPath)) {
168
33
  return claudeAgentsPath;
169
34
  }
170
- currentDir = (0, node_path_1.dirname)(currentDir);
35
+ currentDir = dirname(currentDir);
171
36
  }
172
- return (0, node_path_1.resolve)(process.cwd(), '.claude', 'agents');
173
- };
174
- AgentLoader.prototype.parseAgentFile = function(filePath) {
37
+ return resolve(process.cwd(), '.claude', 'agents');
38
+ }
39
+ parseAgentFile(filePath) {
175
40
  try {
176
- var content = (0, node_fs_1.readFileSync)(filePath, 'utf-8');
177
- var frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
41
+ const content = readFileSync(filePath, 'utf-8');
42
+ const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
178
43
  if (!frontmatterMatch) {
179
- console.warn("No frontmatter found in ".concat(filePath));
44
+ console.warn(`No frontmatter found in ${filePath}`);
180
45
  return null;
181
46
  }
182
- var yamlContent = frontmatterMatch[1], markdownContent = frontmatterMatch[2];
183
- var frontmatter = (0, yaml_1.parse)(yamlContent);
184
- var description = frontmatter.description;
47
+ const [, yamlContent, markdownContent] = frontmatterMatch;
48
+ const frontmatter = parseYaml(yamlContent);
49
+ const description = frontmatter.description;
185
50
  if (!frontmatter.name || !description) {
186
- console.warn("Missing required fields (name, description) in ".concat(filePath));
51
+ console.warn(`Missing required fields (name, description) in ${filePath}`);
187
52
  return null;
188
53
  }
189
54
  return {
@@ -204,13 +69,129 @@ var AgentLoader = /** @class */ function() {
204
69
  content: markdownContent.trim()
205
70
  };
206
71
  } catch (error) {
207
- console.error("Error parsing agent file ".concat(filePath, ":"), error);
72
+ console.error(`Error parsing agent file ${filePath}:`, error);
208
73
  return null;
209
74
  }
210
- };
211
- AgentLoader.prototype.parseTools = function(frontmatter) {
212
- var extractTools = function(input) {
75
+ }
76
+ parseTools(frontmatter) {
77
+ const extractTools = (input)=>{
213
78
  if (Array.isArray(input)) return input.map(String);
79
+ if (typeof input === 'string') {
80
+ return input.split(/[,\s]+/).map((t)=>t.trim()).filter((t)=>t.length > 0);
81
+ }
82
+ return [];
83
+ };
84
+ // Safely handle tools and capabilities.tools
85
+ const toolsFromFrontmatter = frontmatter.tools ? extractTools(frontmatter.tools) : [];
86
+ const toolsFromCapabilities = frontmatter.capabilities && typeof frontmatter.capabilities === 'object' ? extractTools(Object(frontmatter.capabilities).tools) : [];
87
+ return [
88
+ ...toolsFromFrontmatter,
89
+ ...toolsFromCapabilities
90
+ ];
91
+ }
92
+ async loadAgents() {
93
+ const agentsDir = this.getAgentsDirectory();
94
+ if (!existsSync(agentsDir)) {
95
+ console.warn(`Agents directory not found: ${agentsDir}`);
96
+ return;
97
+ }
98
+ const agentFiles = await new Promise((resolve, reject)=>{
99
+ glob('**/*.md', {
100
+ cwd: agentsDir,
101
+ ignore: [
102
+ '**/README.md',
103
+ '**/MIGRATION_SUMMARY.md'
104
+ ],
105
+ absolute: true
106
+ }, (err, matches)=>{
107
+ if (err) reject(err);
108
+ else resolve(matches);
109
+ });
110
+ });
111
+ this.agentCache.clear();
112
+ this.categoriesCache = [];
113
+ const categoryMap = new Map();
114
+ for (const filePath of agentFiles){
115
+ const agent = this.parseAgentFile(filePath);
116
+ if (agent) {
117
+ this.agentCache.set(agent.name, agent);
118
+ const relativePath = filePath.replace(agentsDir, '');
119
+ const pathParts = relativePath.split('/');
120
+ const category = pathParts[1] || 'uncategorized';
121
+ if (!categoryMap.has(category)) {
122
+ categoryMap.set(category, []);
123
+ }
124
+ categoryMap.get(category).push(agent);
125
+ }
126
+ }
127
+ this.categoriesCache = Array.from(categoryMap.entries()).map(([name, agents])=>({
128
+ name,
129
+ agents: agents.sort((a, b)=>a.name.localeCompare(b.name))
130
+ }));
131
+ this.lastLoadTime = Date.now();
132
+ }
133
+ // Rest of the methods remain similar to the original implementation
134
+ needsRefresh() {
135
+ return Date.now() - this.lastLoadTime > this.CACHE_EXPIRY;
136
+ }
137
+ async ensureLoaded() {
138
+ if (this.agentCache.size === 0 || this.needsRefresh()) {
139
+ await this.loadAgents();
140
+ }
141
+ }
142
+ async getAvailableAgentTypes() {
143
+ await this.ensureLoaded();
144
+ const currentTypes = Array.from(this.agentCache.keys());
145
+ const legacyTypes = Object.keys(LEGACY_AGENT_MAPPING);
146
+ return Array.from(new Set([
147
+ ...currentTypes,
148
+ ...legacyTypes
149
+ ])).sort();
150
+ }
151
+ async getAgent(name) {
152
+ await this.ensureLoaded();
153
+ return this.agentCache.get(name) || this.agentCache.get(resolveLegacyAgentType(name)) || null;
154
+ }
155
+ async getAllAgents() {
156
+ await this.ensureLoaded();
157
+ return Array.from(this.agentCache.values()).sort((a, b)=>a.name.localeCompare(b.name));
158
+ }
159
+ async getAgentCategories() {
160
+ await this.ensureLoaded();
161
+ return this.categoriesCache;
162
+ }
163
+ async searchAgents(query) {
164
+ await this.ensureLoaded();
165
+ const lowerQuery = query.toLowerCase();
166
+ return Array.from(this.agentCache.values()).filter((agent)=>agent.name.toLowerCase().includes(lowerQuery) || agent.description.toLowerCase().includes(lowerQuery) || agent.capabilities?.some((cap)=>cap.toLowerCase().includes(lowerQuery)));
167
+ }
168
+ async isValidAgentType(name) {
169
+ await this.ensureLoaded();
170
+ return this.agentCache.has(name) || this.agentCache.has(resolveLegacyAgentType(name));
171
+ }
172
+ async getAgentsByCategory(category) {
173
+ const categories = await this.getAgentCategories();
174
+ const found = categories.find((cat)=>cat.name === category);
175
+ return found?.agents || [];
176
+ }
177
+ async refresh() {
178
+ this.lastLoadTime = 0;
179
+ await this.loadAgents();
180
+ }
181
+ }
182
+ // Singleton instance
183
+ export const agentLoader = new AgentLoader();
184
+ // Convenience exports for use in other modules
185
+ export const getAvailableAgentTypes = ()=>agentLoader.getAvailableAgentTypes();
186
+ export const getAgent = (name)=>agentLoader.getAgent(name);
187
+ export const getAllAgents = ()=>agentLoader.getAllAgents();
188
+ export const getAgentCategories = ()=>agentLoader.getAgentCategories();
189
+ export const searchAgents = (query)=>agentLoader.searchAgents(query);
190
+ export const isValidAgentType = (name)=>agentLoader.isValidAgentType(name);
191
+ export const getAgentsByCategory = (category)=>agentLoader.getAgentsByCategory(category);
192
+ export const refreshAgents = ()=>agentLoader.refresh();
193
+
194
+ //# sourceMappingURL=agent-loader.js.map.isArray(input)) return input.map(String);
214
195
  if (typeof input === 'string') {
215
196
  return input.split(/[,\s]+/).map(function(t) {
216
197
  return t.trim();