squads-cli 0.4.13 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/README.md +161 -4
  2. package/dist/{chunk-HKWCBCEK.js → chunk-4CMAEQQY.js} +6 -2
  3. package/dist/chunk-4CMAEQQY.js.map +1 -0
  4. package/dist/{chunk-NA3IECJA.js → chunk-N7KDWU4W.js} +155 -58
  5. package/dist/chunk-N7KDWU4W.js.map +1 -0
  6. package/dist/{chunk-HIQ2APYR.js → chunk-NHGLXN2F.js} +8 -6
  7. package/dist/chunk-NHGLXN2F.js.map +1 -0
  8. package/dist/{chunk-3TSY2K7R.js → chunk-O7UV3FWI.js} +140 -21
  9. package/dist/chunk-O7UV3FWI.js.map +1 -0
  10. package/dist/chunk-ZTQ7ISUR.js +338 -0
  11. package/dist/chunk-ZTQ7ISUR.js.map +1 -0
  12. package/dist/cli.js +5232 -6194
  13. package/dist/cli.js.map +1 -1
  14. package/dist/index.d.ts +110 -2
  15. package/dist/index.js +302 -25
  16. package/dist/index.js.map +1 -1
  17. package/dist/{memory-4PVUKIDK.js → memory-VNF2VFRB.js} +8 -4
  18. package/dist/{sessions-R4VWIGFR.js → sessions-6PB7ALCE.js} +3 -3
  19. package/dist/{squad-parser-YRE2FEAA.js → squad-parser-4BI3G4RS.js} +4 -2
  20. package/dist/templates/core/AGENTS.md.template +64 -0
  21. package/dist/templates/core/BUSINESS_BRIEF.md.template +29 -0
  22. package/dist/templates/core/CLAUDE.md.template +50 -0
  23. package/dist/templates/core/provider.yaml.template +5 -0
  24. package/dist/templates/first-squad/SQUAD.md.template +23 -0
  25. package/dist/templates/first-squad/lead.md.template +44 -0
  26. package/dist/templates/memory/getting-started/state.md.template +19 -0
  27. package/dist/templates/seed/BUSINESS_BRIEF.md.template +27 -0
  28. package/dist/templates/seed/CLAUDE.md.template +69 -0
  29. package/dist/templates/seed/config/provider.yaml +4 -0
  30. package/dist/templates/seed/hooks/settings.json.template +31 -0
  31. package/dist/templates/seed/memory/company/manager/state.md +16 -0
  32. package/dist/templates/seed/memory/engineering/issue-solver/state.md +12 -0
  33. package/dist/templates/seed/memory/intelligence/intel-lead/state.md +9 -0
  34. package/dist/templates/seed/memory/marketing/content-drafter/state.md +12 -0
  35. package/dist/templates/seed/memory/operations/ops-lead/state.md +12 -0
  36. package/dist/templates/seed/memory/research/researcher/state.md +10 -0
  37. package/dist/templates/seed/skills/gh/SKILL.md +57 -0
  38. package/dist/templates/seed/skills/squads-cli/SKILL.md +88 -0
  39. package/dist/templates/seed/squads/company/SQUAD.md +49 -0
  40. package/dist/templates/seed/squads/company/company-critic.md +21 -0
  41. package/dist/templates/seed/squads/company/company-eval.md +21 -0
  42. package/dist/templates/seed/squads/company/event-dispatcher.md +21 -0
  43. package/dist/templates/seed/squads/company/goal-tracker.md +21 -0
  44. package/dist/templates/seed/squads/company/manager.md +66 -0
  45. package/dist/templates/seed/squads/engineering/SQUAD.md +48 -0
  46. package/dist/templates/seed/squads/engineering/code-reviewer.md +57 -0
  47. package/dist/templates/seed/squads/engineering/issue-solver.md +58 -0
  48. package/dist/templates/seed/squads/engineering/test-writer.md +50 -0
  49. package/dist/templates/seed/squads/intelligence/SQUAD.md +37 -0
  50. package/dist/templates/seed/squads/intelligence/intel-critic.md +36 -0
  51. package/dist/templates/seed/squads/intelligence/intel-eval.md +31 -0
  52. package/dist/templates/seed/squads/intelligence/intel-lead.md +71 -0
  53. package/dist/templates/seed/squads/marketing/SQUAD.md +47 -0
  54. package/dist/templates/seed/squads/marketing/content-drafter.md +71 -0
  55. package/dist/templates/seed/squads/marketing/growth-analyst.md +49 -0
  56. package/dist/templates/seed/squads/marketing/social-poster.md +44 -0
  57. package/dist/templates/seed/squads/operations/SQUAD.md +45 -0
  58. package/dist/templates/seed/squads/operations/finance-tracker.md +47 -0
  59. package/dist/templates/seed/squads/operations/goal-tracker.md +48 -0
  60. package/dist/templates/seed/squads/operations/ops-lead.md +58 -0
  61. package/dist/templates/seed/squads/research/SQUAD.md +38 -0
  62. package/dist/templates/seed/squads/research/analyst.md +27 -0
  63. package/dist/templates/seed/squads/research/research-critic.md +20 -0
  64. package/dist/templates/seed/squads/research/research-eval.md +20 -0
  65. package/dist/templates/seed/squads/research/researcher.md +28 -0
  66. package/dist/templates/skills/squads-learn/SKILL.md +86 -0
  67. package/dist/templates/skills/squads-workflow/instruction.md +70 -0
  68. package/dist/{terminal-JZSAQSN7.js → terminal-YKA4O5CX.js} +4 -2
  69. package/dist/{update-MAY6EXFQ.js → update-ALJKFFM7.js} +3 -2
  70. package/package.json +9 -20
  71. package/templates/core/AGENTS.md.template +64 -0
  72. package/templates/core/BUSINESS_BRIEF.md.template +29 -0
  73. package/templates/core/CLAUDE.md.template +50 -0
  74. package/templates/core/provider.yaml.template +5 -0
  75. package/templates/first-squad/SQUAD.md.template +23 -0
  76. package/templates/first-squad/lead.md.template +44 -0
  77. package/templates/memory/getting-started/state.md.template +19 -0
  78. package/templates/seed/BUSINESS_BRIEF.md.template +27 -0
  79. package/templates/seed/CLAUDE.md.template +69 -0
  80. package/templates/seed/config/provider.yaml +4 -0
  81. package/templates/seed/hooks/settings.json.template +31 -0
  82. package/templates/seed/memory/company/manager/state.md +16 -0
  83. package/templates/seed/memory/engineering/issue-solver/state.md +12 -0
  84. package/templates/seed/memory/intelligence/intel-lead/state.md +9 -0
  85. package/templates/seed/memory/marketing/content-drafter/state.md +12 -0
  86. package/templates/seed/memory/operations/ops-lead/state.md +12 -0
  87. package/templates/seed/memory/research/researcher/state.md +10 -0
  88. package/templates/seed/skills/gh/SKILL.md +57 -0
  89. package/templates/seed/skills/squads-cli/SKILL.md +88 -0
  90. package/templates/seed/squads/company/SQUAD.md +49 -0
  91. package/templates/seed/squads/company/company-critic.md +21 -0
  92. package/templates/seed/squads/company/company-eval.md +21 -0
  93. package/templates/seed/squads/company/event-dispatcher.md +21 -0
  94. package/templates/seed/squads/company/goal-tracker.md +21 -0
  95. package/templates/seed/squads/company/manager.md +66 -0
  96. package/templates/seed/squads/engineering/SQUAD.md +48 -0
  97. package/templates/seed/squads/engineering/code-reviewer.md +57 -0
  98. package/templates/seed/squads/engineering/issue-solver.md +58 -0
  99. package/templates/seed/squads/engineering/test-writer.md +50 -0
  100. package/templates/seed/squads/intelligence/SQUAD.md +37 -0
  101. package/templates/seed/squads/intelligence/intel-critic.md +36 -0
  102. package/templates/seed/squads/intelligence/intel-eval.md +31 -0
  103. package/templates/seed/squads/intelligence/intel-lead.md +71 -0
  104. package/templates/seed/squads/marketing/SQUAD.md +47 -0
  105. package/templates/seed/squads/marketing/content-drafter.md +71 -0
  106. package/templates/seed/squads/marketing/growth-analyst.md +49 -0
  107. package/templates/seed/squads/marketing/social-poster.md +44 -0
  108. package/templates/seed/squads/operations/SQUAD.md +45 -0
  109. package/templates/seed/squads/operations/finance-tracker.md +47 -0
  110. package/templates/seed/squads/operations/goal-tracker.md +48 -0
  111. package/templates/seed/squads/operations/ops-lead.md +58 -0
  112. package/templates/seed/squads/research/SQUAD.md +38 -0
  113. package/templates/seed/squads/research/analyst.md +27 -0
  114. package/templates/seed/squads/research/research-critic.md +20 -0
  115. package/templates/seed/squads/research/research-eval.md +20 -0
  116. package/templates/seed/squads/research/researcher.md +28 -0
  117. package/templates/skills/squads-learn/SKILL.md +86 -0
  118. package/templates/skills/squads-workflow/instruction.md +70 -0
  119. package/dist/chunk-3TSY2K7R.js.map +0 -1
  120. package/dist/chunk-FUHBEL3L.js +0 -203
  121. package/dist/chunk-FUHBEL3L.js.map +0 -1
  122. package/dist/chunk-HIQ2APYR.js.map +0 -1
  123. package/dist/chunk-HKWCBCEK.js.map +0 -1
  124. package/dist/chunk-NA3IECJA.js.map +0 -1
  125. package/docker/.env.example +0 -17
  126. package/docker/README.md +0 -92
  127. package/docker/docker-compose.engram.yml +0 -304
  128. package/docker/docker-compose.yml +0 -234
  129. package/docker/init-db.sql +0 -478
  130. package/docker/init-engram-db.sql +0 -148
  131. package/docker/init-langfuse-db.sh +0 -10
  132. package/docker/otel-collector.yaml +0 -34
  133. package/docker/squads-bridge/Dockerfile +0 -14
  134. package/docker/squads-bridge/Dockerfile.proxy +0 -14
  135. package/docker/squads-bridge/anthropic_proxy.py +0 -313
  136. package/docker/squads-bridge/requirements.txt +0 -7
  137. package/docker/squads-bridge/squads_bridge.py +0 -2299
  138. package/docker/telemetry-ping/Dockerfile +0 -10
  139. package/docker/telemetry-ping/deploy.sh +0 -69
  140. package/docker/telemetry-ping/main.py +0 -136
  141. package/docker/telemetry-ping/requirements.txt +0 -3
  142. /package/dist/{memory-4PVUKIDK.js.map → memory-VNF2VFRB.js.map} +0 -0
  143. /package/dist/{sessions-R4VWIGFR.js.map → sessions-6PB7ALCE.js.map} +0 -0
  144. /package/dist/{squad-parser-YRE2FEAA.js.map → squad-parser-4BI3G4RS.js.map} +0 -0
  145. /package/dist/{terminal-JZSAQSN7.js.map → terminal-YKA4O5CX.js.map} +0 -0
  146. /package/dist/{update-MAY6EXFQ.js.map → update-ALJKFFM7.js.map} +0 -0
package/dist/index.d.ts CHANGED
@@ -20,6 +20,17 @@ interface SquadContext {
20
20
  /** Cooldown between executions in seconds */
21
21
  cooldown?: number;
22
22
  }
23
+ /**
24
+ * Resolved skill with path and source information.
25
+ */
26
+ interface ResolvedSkill {
27
+ /** Skill name (directory or reference name) */
28
+ name: string;
29
+ /** Absolute path to the skill directory */
30
+ path: string;
31
+ /** Where the skill was found */
32
+ source: 'squad-local' | 'project' | 'global';
33
+ }
23
34
  interface SquadProviders {
24
35
  /** Default provider for all agents (default: anthropic) */
25
36
  default?: string;
@@ -81,7 +92,7 @@ interface Routine {
81
92
  /** Agents to run in this batch */
82
93
  agents: string[];
83
94
  /** Model to use (defaults to squad default or sonnet) */
84
- model?: 'opus' | 'sonnet' | 'haiku';
95
+ model?: string;
85
96
  /** Whether the routine is enabled */
86
97
  enabled?: boolean;
87
98
  /** Priority for execution ordering (lower = higher priority) */
@@ -91,6 +102,8 @@ interface Routine {
91
102
  }
92
103
  interface Squad {
93
104
  name: string;
105
+ /** Directory name for file path resolution (e.g., "engineering") */
106
+ dir: string;
94
107
  mission: string;
95
108
  agents: Agent[];
96
109
  pipelines: Pipeline[];
@@ -117,18 +130,113 @@ interface Squad {
117
130
  /** Raw frontmatter for accessing KPIs and other custom fields */
118
131
  frontmatter?: Record<string, unknown>;
119
132
  }
133
+ /**
134
+ * Resolved execution context with paths and metadata.
135
+ * Extends SquadContext with resolved paths for MCP, skills, and memory.
136
+ */
137
+ interface ExecutionContext extends SquadContext {
138
+ /** Squad name this context belongs to */
139
+ squadName: string;
140
+ /** Resolved paths and metadata */
141
+ resolved: {
142
+ /** Path to MCP config file to use */
143
+ mcpConfigPath: string;
144
+ /** Source of MCP config resolution */
145
+ mcpSource: 'user-override' | 'generated' | 'fallback' | 'squad-local';
146
+ /** List of MCP servers in the config */
147
+ mcpServers: string[];
148
+ /** Resolved skill directory paths (deprecated, use skills instead) */
149
+ skillPaths: string[];
150
+ /** Resolved skills with source information */
151
+ skills: ResolvedSkill[];
152
+ /** Resolved memory file paths */
153
+ memoryPaths: string[];
154
+ };
155
+ }
156
+ /**
157
+ * Find the .agents/squads directory by searching current directory and parents.
158
+ * Searches up to 5 parent directories.
159
+ * @returns Path to squads directory or null if not found
160
+ */
120
161
  declare function findSquadsDir(): string | null;
162
+ /**
163
+ * Find the root directory of the squads project (where .agents/ lives).
164
+ * @returns Path to project root or null if not in a squads project
165
+ */
121
166
  declare function findProjectRoot(): string | null;
167
+ /**
168
+ * List all squad names in the given squads directory.
169
+ * Only includes directories containing a SQUAD.md file.
170
+ * @param squadsDir - Path to the .agents/squads directory
171
+ * @returns Array of squad directory names
172
+ */
122
173
  declare function listSquads(squadsDir: string): string[];
174
+ /**
175
+ * List all agents in the squads directory or a specific squad.
176
+ * Agents are markdown files (excluding SQUAD.md) in squad directories.
177
+ * @param squadsDir - Path to the .agents/squads directory
178
+ * @param squadName - Optional squad name to filter agents
179
+ * @returns Array of Agent objects with basic metadata
180
+ */
123
181
  declare function listAgents(squadsDir: string, squadName?: string): Agent[];
182
+ /**
183
+ * Parse a SQUAD.md file into a Squad object.
184
+ * Extracts frontmatter metadata, agents, pipelines, goals, and routines.
185
+ * @param filePath - Path to the SQUAD.md file
186
+ * @returns Parsed Squad object with all extracted data
187
+ */
124
188
  declare function parseSquadFile(filePath: string): Squad;
189
+ /**
190
+ * Load and parse a squad by name.
191
+ * Convenience function that finds the squads directory and parses the squad file.
192
+ * @param squadName - Name of the squad directory (e.g., "engineering")
193
+ * @returns Parsed Squad object or null if not found
194
+ */
125
195
  declare function loadSquad(squadName: string): Squad | null;
196
+ /**
197
+ * Load raw content of an agent definition file.
198
+ * @param agentPath - Path to the agent markdown file
199
+ * @returns Raw file content or empty string if file doesn't exist
200
+ */
126
201
  declare function loadAgentDefinition(agentPath: string): string;
202
+ /**
203
+ * Add a new goal to a squad's SQUAD.md file.
204
+ * Creates the Goals section if it doesn't exist.
205
+ * @param squadName - Name of the squad directory
206
+ * @param goal - Goal description text
207
+ * @returns True if goal was added successfully
208
+ */
127
209
  declare function addGoalToSquad(squadName: string, goal: string): boolean;
210
+ /**
211
+ * Update an existing goal in a squad's SQUAD.md file.
212
+ * Can mark goal as completed or update progress text.
213
+ * @param squadName - Name of the squad directory
214
+ * @param goalIndex - Zero-based index of the goal to update
215
+ * @param updates - Object with optional completed and progress fields
216
+ * @returns True if goal was updated successfully
217
+ */
128
218
  declare function updateGoalInSquad(squadName: string, goalIndex: number, updates: {
129
219
  completed?: boolean;
130
220
  progress?: string;
131
221
  }): boolean;
222
+ /**
223
+ * Get all available squad-local skills for a squad.
224
+ * Scans .agents/squads/<squad>/skills/ directory.
225
+ */
226
+ declare function getSquadLocalSkills(squadDir: string): ResolvedSkill[];
227
+ /**
228
+ * Resolve execution context for a squad.
229
+ *
230
+ * Takes a Squad object and resolves all context references to actual paths:
231
+ * - MCP config path (four-tier resolution: squad-local, user-override, generated, fallback)
232
+ * - Skill directory paths (three-tier: squad-local, project, global)
233
+ * - Memory file paths
234
+ *
235
+ * @param squad - The squad to resolve context for
236
+ * @param forceRegenerate - Force MCP config regeneration
237
+ * @returns Resolved execution context with all paths
238
+ */
239
+ declare function resolveExecutionContext(squad: Squad, forceRegenerate?: boolean): ExecutionContext;
132
240
 
133
241
  /**
134
242
  * Token estimation and tracking for context compression.
@@ -630,4 +738,4 @@ declare function createCondenser(squadConfig?: {
630
738
  };
631
739
  }): ContextCondenser;
632
740
 
633
- export { type Agent, type CompressionLevel, type CondenserConfig, type CondenserMessage, type CondenserResult, ContextCondenser, ConversationSummarizer, type EffortLevel, FileDeduplicator, type Goal, type Pipeline, type Squad, type SquadContext, type SquadFrontmatter, type ThresholdConfig, TokenPruner, type TokenTracker, addGoalToSquad, createCondenser, createTracker, estimateMessageTokens, estimateTokens, findProjectRoot, findSquadsDir, formatTrackerStatus, getCompressionLevel, listAgents, listSquads, loadAgentDefinition, loadSquad, parseSquadFile, updateGoalInSquad, updateTracker, version };
741
+ export { type Agent, type CompressionLevel, type CondenserConfig, type CondenserMessage, type CondenserResult, ContextCondenser, ConversationSummarizer, type EffortLevel, type ExecutionContext, FileDeduplicator, type Goal, type Pipeline, type ResolvedSkill, type Squad, type SquadContext, type SquadFrontmatter, type ThresholdConfig, TokenPruner, type TokenTracker, addGoalToSquad, createCondenser, createTracker, estimateMessageTokens, estimateTokens, findProjectRoot, findSquadsDir, formatTrackerStatus, getCompressionLevel, getSquadLocalSkills, listAgents, listSquads, loadAgentDefinition, loadSquad, parseSquadFile, resolveExecutionContext, updateGoalInSquad, updateTracker, version };
package/dist/index.js CHANGED
@@ -5,17 +5,96 @@ var pkg = require2("../package.json");
5
5
  var version = pkg.version;
6
6
 
7
7
  // src/lib/squad-parser.ts
8
- import { readFileSync, existsSync, readdirSync, writeFileSync } from "fs";
9
- import { join, basename } from "path";
8
+ import { readFileSync as readFileSync2, existsSync as existsSync2, readdirSync, writeFileSync as writeFileSync2 } from "fs";
9
+ import { join as join2, basename, dirname as dirname2 } from "path";
10
10
  import matter from "gray-matter";
11
+
12
+ // src/lib/mcp-config.ts
13
+ import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
14
+ import { join, dirname } from "path";
15
+ var SERVER_REGISTRY = {};
16
+ function getHome() {
17
+ return process.env.HOME || process.env.USERPROFILE || "";
18
+ }
19
+ function getContextsDir() {
20
+ return join(getHome(), ".claude", "contexts");
21
+ }
22
+ function getMcpConfigsDir() {
23
+ return join(getHome(), ".claude", "mcp-configs");
24
+ }
25
+ function generateMcpConfig(mcpServers) {
26
+ const config = { mcpServers: {} };
27
+ for (const server of mcpServers) {
28
+ const def = SERVER_REGISTRY[server];
29
+ if (def) {
30
+ config.mcpServers[server] = def;
31
+ }
32
+ }
33
+ return config;
34
+ }
35
+ function writeMcpConfig(config, path) {
36
+ const dir = dirname(path);
37
+ if (!existsSync(dir)) {
38
+ mkdirSync(dir, { recursive: true });
39
+ }
40
+ writeFileSync(path, JSON.stringify(config, null, 2));
41
+ }
42
+ function readMcpConfig(path) {
43
+ if (!existsSync(path)) return null;
44
+ try {
45
+ const content = readFileSync(path, "utf-8");
46
+ return JSON.parse(content);
47
+ } catch {
48
+ return null;
49
+ }
50
+ }
51
+ function resolveMcpConfig(squadName, mcpServers, forceRegenerate = false) {
52
+ const home = getHome();
53
+ const userOverride = join(getMcpConfigsDir(), `${squadName}.json`);
54
+ if (existsSync(userOverride)) {
55
+ const config = readMcpConfig(userOverride);
56
+ return {
57
+ path: userOverride,
58
+ source: "user-override",
59
+ servers: config ? Object.keys(config.mcpServers) : void 0
60
+ };
61
+ }
62
+ if (mcpServers && mcpServers.length > 0) {
63
+ const generatedPath = join(getContextsDir(), `${squadName}.mcp.json`);
64
+ const shouldGenerate = forceRegenerate || !existsSync(generatedPath);
65
+ if (shouldGenerate) {
66
+ const config2 = generateMcpConfig(mcpServers);
67
+ writeMcpConfig(config2, generatedPath);
68
+ return {
69
+ path: generatedPath,
70
+ source: "generated",
71
+ servers: Object.keys(config2.mcpServers),
72
+ generated: true
73
+ };
74
+ }
75
+ const config = readMcpConfig(generatedPath);
76
+ return {
77
+ path: generatedPath,
78
+ source: "generated",
79
+ servers: config ? Object.keys(config.mcpServers) : mcpServers,
80
+ generated: false
81
+ };
82
+ }
83
+ return {
84
+ path: join(home, ".claude.json"),
85
+ source: "fallback"
86
+ };
87
+ }
88
+
89
+ // src/lib/squad-parser.ts
11
90
  function findSquadsDir() {
12
91
  let dir = process.cwd();
13
92
  for (let i = 0; i < 5; i++) {
14
- const squadsPath = join(dir, ".agents", "squads");
15
- if (existsSync(squadsPath)) {
93
+ const squadsPath = join2(dir, ".agents", "squads");
94
+ if (existsSync2(squadsPath)) {
16
95
  return squadsPath;
17
96
  }
18
- const parent = join(dir, "..");
97
+ const parent = join2(dir, "..");
19
98
  if (parent === dir) break;
20
99
  dir = parent;
21
100
  }
@@ -24,15 +103,15 @@ function findSquadsDir() {
24
103
  function findProjectRoot() {
25
104
  const squadsDir = findSquadsDir();
26
105
  if (!squadsDir) return null;
27
- return join(squadsDir, "..", "..");
106
+ return join2(squadsDir, "..", "..");
28
107
  }
29
108
  function listSquads(squadsDir) {
30
109
  const squads = [];
31
110
  const entries = readdirSync(squadsDir, { withFileTypes: true });
32
111
  for (const entry of entries) {
33
112
  if (entry.isDirectory() && !entry.name.startsWith("_")) {
34
- const squadFile = join(squadsDir, entry.name, "SQUAD.md");
35
- if (existsSync(squadFile)) {
113
+ const squadFile = join2(squadsDir, entry.name, "SQUAD.md");
114
+ if (existsSync2(squadFile)) {
36
115
  squads.push(entry.name);
37
116
  }
38
117
  }
@@ -43,8 +122,8 @@ function listAgents(squadsDir, squadName) {
43
122
  const agents = [];
44
123
  const dirs = squadName ? [squadName] : readdirSync(squadsDir, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith("_")).map((e) => e.name);
45
124
  for (const dir of dirs) {
46
- const squadPath = join(squadsDir, dir);
47
- if (!existsSync(squadPath)) continue;
125
+ const squadPath = join2(squadsDir, dir);
126
+ if (!existsSync2(squadPath)) continue;
48
127
  const files = readdirSync(squadPath);
49
128
  for (const file of files) {
50
129
  if (file.endsWith(".md") && file !== "SQUAD.md") {
@@ -53,7 +132,7 @@ function listAgents(squadsDir, squadName) {
53
132
  name: agentName,
54
133
  role: `Agent in ${dir}`,
55
134
  trigger: "manual",
56
- filePath: join(squadPath, file)
135
+ filePath: join2(squadPath, file)
57
136
  });
58
137
  }
59
138
  }
@@ -61,12 +140,16 @@ function listAgents(squadsDir, squadName) {
61
140
  return agents;
62
141
  }
63
142
  function parseSquadFile(filePath) {
64
- const rawContent = readFileSync(filePath, "utf-8");
143
+ const rawContent = readFileSync2(filePath, "utf-8");
65
144
  const { data: frontmatter, content: bodyContent } = matter(rawContent);
66
145
  const fm = frontmatter;
67
146
  const lines = bodyContent.split("\n");
147
+ const dirName = basename(dirname2(filePath));
68
148
  const squad = {
69
- name: fm.name || basename(filePath).replace(".md", ""),
149
+ // Display name can be different from dir (e.g., "Engineering Squad")
150
+ name: fm.name || dirName,
151
+ // Directory name for file path resolution
152
+ dir: dirName,
70
153
  mission: fm.mission || "",
71
154
  agents: [],
72
155
  pipelines: [],
@@ -186,20 +269,20 @@ function parseSquadFile(filePath) {
186
269
  function loadSquad(squadName) {
187
270
  const squadsDir = findSquadsDir();
188
271
  if (!squadsDir) return null;
189
- const squadFile = join(squadsDir, squadName, "SQUAD.md");
190
- if (!existsSync(squadFile)) return null;
272
+ const squadFile = join2(squadsDir, squadName, "SQUAD.md");
273
+ if (!existsSync2(squadFile)) return null;
191
274
  return parseSquadFile(squadFile);
192
275
  }
193
276
  function loadAgentDefinition(agentPath) {
194
- if (!existsSync(agentPath)) return "";
195
- return readFileSync(agentPath, "utf-8");
277
+ if (!existsSync2(agentPath)) return "";
278
+ return readFileSync2(agentPath, "utf-8");
196
279
  }
197
280
  function addGoalToSquad(squadName, goal) {
198
281
  const squadsDir = findSquadsDir();
199
282
  if (!squadsDir) return false;
200
- const squadFile = join(squadsDir, squadName, "SQUAD.md");
201
- if (!existsSync(squadFile)) return false;
202
- let content = readFileSync(squadFile, "utf-8");
283
+ const squadFile = join2(squadsDir, squadName, "SQUAD.md");
284
+ if (!existsSync2(squadFile)) return false;
285
+ let content = readFileSync2(squadFile, "utf-8");
203
286
  if (!content.includes("## Goals")) {
204
287
  const insertPoint = content.indexOf("## Dependencies");
205
288
  if (insertPoint > 0) {
@@ -234,15 +317,15 @@ function addGoalToSquad(squadName, goal) {
234
317
  - [ ] ${goal}` + content.slice(headerEnd);
235
318
  }
236
319
  }
237
- writeFileSync(squadFile, content);
320
+ writeFileSync2(squadFile, content);
238
321
  return true;
239
322
  }
240
323
  function updateGoalInSquad(squadName, goalIndex, updates) {
241
324
  const squadsDir = findSquadsDir();
242
325
  if (!squadsDir) return false;
243
- const squadFile = join(squadsDir, squadName, "SQUAD.md");
244
- if (!existsSync(squadFile)) return false;
245
- const content = readFileSync(squadFile, "utf-8");
326
+ const squadFile = join2(squadsDir, squadName, "SQUAD.md");
327
+ if (!existsSync2(squadFile)) return false;
328
+ const content = readFileSync2(squadFile, "utf-8");
246
329
  const lines = content.split("\n");
247
330
  let currentSection = "";
248
331
  let goalCount = 0;
@@ -264,7 +347,7 @@ function updateGoalInSquad(squadName, goalIndex, updates) {
264
347
  }
265
348
  }
266
349
  lines[i] = newLine;
267
- writeFileSync(squadFile, lines.join("\n"));
350
+ writeFileSync2(squadFile, lines.join("\n"));
268
351
  return true;
269
352
  }
270
353
  goalCount++;
@@ -273,6 +356,198 @@ function updateGoalInSquad(squadName, goalIndex, updates) {
273
356
  }
274
357
  return false;
275
358
  }
359
+ function findProjectSkillsDir() {
360
+ const projectRoot = findProjectRoot();
361
+ if (!projectRoot) return null;
362
+ const skillsDir = join2(projectRoot, ".claude", "skills");
363
+ return existsSync2(skillsDir) ? skillsDir : null;
364
+ }
365
+ function findGlobalSkillsDir() {
366
+ const home = process.env.HOME || process.env.USERPROFILE || "";
367
+ if (!home) return null;
368
+ const skillsDir = join2(home, ".claude", "skills");
369
+ return existsSync2(skillsDir) ? skillsDir : null;
370
+ }
371
+ function findSquadLocalSkillsDir(squadDir) {
372
+ const squadsDir = findSquadsDir();
373
+ if (!squadsDir) return null;
374
+ const skillsDir = join2(squadsDir, squadDir, "skills");
375
+ return existsSync2(skillsDir) ? skillsDir : null;
376
+ }
377
+ function listSkillsInDir(skillsDir) {
378
+ if (!existsSync2(skillsDir)) return [];
379
+ try {
380
+ const entries = readdirSync(skillsDir, { withFileTypes: true });
381
+ const skills = [];
382
+ for (const entry of entries) {
383
+ if (entry.isDirectory()) {
384
+ const skillMdPath = join2(skillsDir, entry.name, "SKILL.md");
385
+ if (existsSync2(skillMdPath)) {
386
+ skills.push(entry.name);
387
+ }
388
+ } else if (entry.isFile() && entry.name.endsWith(".md") && entry.name !== "README.md") {
389
+ skills.push(entry.name.replace(".md", ""));
390
+ }
391
+ }
392
+ return skills;
393
+ } catch {
394
+ return [];
395
+ }
396
+ }
397
+ function findMemoryDir() {
398
+ const projectRoot = findProjectRoot();
399
+ if (!projectRoot) return null;
400
+ const memoryDir = join2(projectRoot, ".agents", "memory");
401
+ return existsSync2(memoryDir) ? memoryDir : null;
402
+ }
403
+ function resolveSkill(skillName, squadDir) {
404
+ if (squadDir) {
405
+ const squadSkillsDir = findSquadLocalSkillsDir(squadDir);
406
+ if (squadSkillsDir) {
407
+ const dirPath = join2(squadSkillsDir, skillName);
408
+ if (existsSync2(dirPath) && existsSync2(join2(dirPath, "SKILL.md"))) {
409
+ return { name: skillName, path: dirPath, source: "squad-local" };
410
+ }
411
+ const filePath = join2(squadSkillsDir, `${skillName}.md`);
412
+ if (existsSync2(filePath)) {
413
+ return { name: skillName, path: filePath, source: "squad-local" };
414
+ }
415
+ }
416
+ }
417
+ const projectSkillsDir = findProjectSkillsDir();
418
+ if (projectSkillsDir) {
419
+ const dirPath = join2(projectSkillsDir, skillName);
420
+ if (existsSync2(dirPath) && existsSync2(join2(dirPath, "SKILL.md"))) {
421
+ return { name: skillName, path: dirPath, source: "project" };
422
+ }
423
+ const filePath = join2(projectSkillsDir, `${skillName}.md`);
424
+ if (existsSync2(filePath)) {
425
+ return { name: skillName, path: filePath, source: "project" };
426
+ }
427
+ }
428
+ const globalSkillsDir = findGlobalSkillsDir();
429
+ if (globalSkillsDir) {
430
+ const dirPath = join2(globalSkillsDir, skillName);
431
+ if (existsSync2(dirPath) && existsSync2(join2(dirPath, "SKILL.md"))) {
432
+ return { name: skillName, path: dirPath, source: "global" };
433
+ }
434
+ const filePath = join2(globalSkillsDir, `${skillName}.md`);
435
+ if (existsSync2(filePath)) {
436
+ return { name: skillName, path: filePath, source: "global" };
437
+ }
438
+ }
439
+ return null;
440
+ }
441
+ function getSquadLocalSkills(squadDir) {
442
+ const squadSkillsDir = findSquadLocalSkillsDir(squadDir);
443
+ if (!squadSkillsDir) return [];
444
+ const skillNames = listSkillsInDir(squadSkillsDir);
445
+ const skills = [];
446
+ for (const name of skillNames) {
447
+ const resolved = resolveSkill(name, squadDir);
448
+ if (resolved && resolved.source === "squad-local") {
449
+ skills.push(resolved);
450
+ }
451
+ }
452
+ return skills;
453
+ }
454
+ function resolveMemoryPaths(patterns) {
455
+ const memoryDir = findMemoryDir();
456
+ if (!memoryDir) return [];
457
+ const resolved = [];
458
+ for (const pattern of patterns) {
459
+ if (pattern.endsWith("/*")) {
460
+ const subdir = pattern.slice(0, -2);
461
+ const subdirPath = join2(memoryDir, subdir);
462
+ if (existsSync2(subdirPath)) {
463
+ try {
464
+ const files = readdirSync(subdirPath);
465
+ for (const file of files) {
466
+ if (file.endsWith(".md")) {
467
+ resolved.push(join2(subdirPath, file));
468
+ }
469
+ }
470
+ } catch {
471
+ }
472
+ }
473
+ } else {
474
+ const fullPath = join2(memoryDir, pattern);
475
+ if (existsSync2(fullPath)) {
476
+ resolved.push(fullPath);
477
+ }
478
+ }
479
+ }
480
+ return resolved;
481
+ }
482
+ function findSquadLocalMcpConfig(squadDir) {
483
+ const squadsDir = findSquadsDir();
484
+ if (!squadsDir) return null;
485
+ const mcpConfigPath = join2(squadsDir, squadDir, "mcp.json");
486
+ return existsSync2(mcpConfigPath) ? mcpConfigPath : null;
487
+ }
488
+ function resolveExecutionContext(squad, forceRegenerate = false) {
489
+ const ctx = squad.context || {};
490
+ const squadLocalMcpConfig = findSquadLocalMcpConfig(squad.dir);
491
+ let mcpConfigPath;
492
+ let mcpSource;
493
+ let mcpServers = [];
494
+ if (squadLocalMcpConfig) {
495
+ mcpConfigPath = squadLocalMcpConfig;
496
+ mcpSource = "squad-local";
497
+ try {
498
+ const content = readFileSync2(squadLocalMcpConfig, "utf-8");
499
+ const config = JSON.parse(content);
500
+ mcpServers = Object.keys(config.mcpServers || {});
501
+ } catch {
502
+ }
503
+ } else {
504
+ const mcpResolution = resolveMcpConfig(
505
+ squad.name,
506
+ ctx.mcp,
507
+ forceRegenerate
508
+ );
509
+ mcpConfigPath = mcpResolution.path;
510
+ mcpSource = mcpResolution.source;
511
+ mcpServers = mcpResolution.servers || [];
512
+ }
513
+ const resolvedSkills = [];
514
+ const skillPaths = [];
515
+ const squadLocalSkills = getSquadLocalSkills(squad.dir);
516
+ for (const skill of squadLocalSkills) {
517
+ resolvedSkills.push(skill);
518
+ skillPaths.push(skill.path);
519
+ }
520
+ if (ctx.skills) {
521
+ for (const skillName of ctx.skills) {
522
+ if (resolvedSkills.some((s) => s.name === skillName)) {
523
+ continue;
524
+ }
525
+ const resolved = resolveSkill(skillName, squad.dir);
526
+ if (resolved) {
527
+ resolvedSkills.push(resolved);
528
+ skillPaths.push(resolved.path);
529
+ }
530
+ }
531
+ }
532
+ const memoryPaths = ctx.memory?.load ? resolveMemoryPaths(ctx.memory.load) : [];
533
+ return {
534
+ // Copy all SquadContext fields
535
+ ...ctx,
536
+ // Add squad name
537
+ squadName: squad.name,
538
+ // Add resolved paths
539
+ resolved: {
540
+ mcpConfigPath,
541
+ mcpSource,
542
+ mcpServers,
543
+ skillPaths,
544
+ // Backward compatible
545
+ skills: resolvedSkills,
546
+ // New detailed skill info
547
+ memoryPaths
548
+ }
549
+ };
550
+ }
276
551
 
277
552
  // src/lib/condenser/tokens.ts
278
553
  var RATIOS = {
@@ -1031,11 +1306,13 @@ export {
1031
1306
  findSquadsDir,
1032
1307
  formatTrackerStatus,
1033
1308
  getCompressionLevel,
1309
+ getSquadLocalSkills,
1034
1310
  listAgents,
1035
1311
  listSquads,
1036
1312
  loadAgentDefinition,
1037
1313
  loadSquad,
1038
1314
  parseSquadFile,
1315
+ resolveExecutionContext,
1039
1316
  updateGoalInSquad,
1040
1317
  updateTracker,
1041
1318
  version