squads-cli 0.5.0 → 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.
- package/README.md +161 -4
- package/dist/{chunk-HKWCBCEK.js → chunk-4CMAEQQY.js} +6 -2
- package/dist/chunk-4CMAEQQY.js.map +1 -0
- package/dist/{chunk-NA3IECJA.js → chunk-N7KDWU4W.js} +155 -58
- package/dist/chunk-N7KDWU4W.js.map +1 -0
- package/dist/{chunk-7PRYDHZW.js → chunk-NHGLXN2F.js} +8 -6
- package/dist/chunk-NHGLXN2F.js.map +1 -0
- package/dist/{chunk-QPH5OR7J.js → chunk-O7UV3FWI.js} +139 -21
- package/dist/chunk-O7UV3FWI.js.map +1 -0
- package/dist/{chunk-BV6S5AWZ.js → chunk-ZTQ7ISUR.js} +28 -109
- package/dist/chunk-ZTQ7ISUR.js.map +1 -0
- package/dist/cli.js +5493 -7665
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +110 -2
- package/dist/index.js +302 -26
- package/dist/index.js.map +1 -1
- package/dist/{memory-ZXDXF6KF.js → memory-VNF2VFRB.js} +2 -2
- package/dist/{sessions-F6LRY7EN.js → sessions-6PB7ALCE.js} +3 -3
- package/dist/{squad-parser-MSYE4PXL.js → squad-parser-4BI3G4RS.js} +4 -2
- package/dist/templates/seed/BUSINESS_BRIEF.md.template +27 -0
- package/dist/templates/seed/CLAUDE.md.template +69 -0
- package/dist/templates/seed/config/provider.yaml +4 -0
- package/dist/templates/seed/hooks/settings.json.template +31 -0
- package/dist/templates/seed/memory/company/manager/state.md +16 -0
- package/dist/templates/seed/memory/engineering/issue-solver/state.md +12 -0
- package/dist/templates/seed/memory/intelligence/intel-lead/state.md +9 -0
- package/dist/templates/seed/memory/marketing/content-drafter/state.md +12 -0
- package/dist/templates/seed/memory/operations/ops-lead/state.md +12 -0
- package/dist/templates/seed/memory/research/researcher/state.md +10 -0
- package/dist/templates/seed/skills/gh/SKILL.md +57 -0
- package/dist/templates/seed/skills/squads-cli/SKILL.md +88 -0
- package/dist/templates/seed/squads/company/SQUAD.md +49 -0
- package/dist/templates/seed/squads/company/company-critic.md +21 -0
- package/dist/templates/seed/squads/company/company-eval.md +21 -0
- package/dist/templates/seed/squads/company/event-dispatcher.md +21 -0
- package/dist/templates/seed/squads/company/goal-tracker.md +21 -0
- package/dist/templates/seed/squads/company/manager.md +66 -0
- package/dist/templates/seed/squads/engineering/SQUAD.md +48 -0
- package/dist/templates/seed/squads/engineering/code-reviewer.md +57 -0
- package/dist/templates/seed/squads/engineering/issue-solver.md +58 -0
- package/dist/templates/seed/squads/engineering/test-writer.md +50 -0
- package/dist/templates/seed/squads/intelligence/SQUAD.md +37 -0
- package/dist/templates/seed/squads/intelligence/intel-critic.md +36 -0
- package/dist/templates/seed/squads/intelligence/intel-eval.md +31 -0
- package/dist/templates/seed/squads/intelligence/intel-lead.md +71 -0
- package/dist/templates/seed/squads/marketing/SQUAD.md +47 -0
- package/dist/templates/seed/squads/marketing/content-drafter.md +71 -0
- package/dist/templates/seed/squads/marketing/growth-analyst.md +49 -0
- package/dist/templates/seed/squads/marketing/social-poster.md +44 -0
- package/dist/templates/seed/squads/operations/SQUAD.md +45 -0
- package/dist/templates/seed/squads/operations/finance-tracker.md +47 -0
- package/dist/templates/seed/squads/operations/goal-tracker.md +48 -0
- package/dist/templates/seed/squads/operations/ops-lead.md +58 -0
- package/dist/templates/seed/squads/research/SQUAD.md +38 -0
- package/dist/templates/seed/squads/research/analyst.md +27 -0
- package/dist/templates/seed/squads/research/research-critic.md +20 -0
- package/dist/templates/seed/squads/research/research-eval.md +20 -0
- package/dist/templates/seed/squads/research/researcher.md +28 -0
- package/dist/{terminal-JZSAQSN7.js → terminal-YKA4O5CX.js} +4 -2
- package/dist/{update-MAY6EXFQ.js → update-ALJKFFM7.js} +3 -2
- package/package.json +8 -21
- package/templates/seed/BUSINESS_BRIEF.md.template +27 -0
- package/templates/seed/CLAUDE.md.template +69 -0
- package/templates/seed/config/provider.yaml +4 -0
- package/templates/seed/hooks/settings.json.template +31 -0
- package/templates/seed/memory/company/manager/state.md +16 -0
- package/templates/seed/memory/engineering/issue-solver/state.md +12 -0
- package/templates/seed/memory/intelligence/intel-lead/state.md +9 -0
- package/templates/seed/memory/marketing/content-drafter/state.md +12 -0
- package/templates/seed/memory/operations/ops-lead/state.md +12 -0
- package/templates/seed/memory/research/researcher/state.md +10 -0
- package/templates/seed/skills/gh/SKILL.md +57 -0
- package/templates/seed/skills/squads-cli/SKILL.md +88 -0
- package/templates/seed/squads/company/SQUAD.md +49 -0
- package/templates/seed/squads/company/company-critic.md +21 -0
- package/templates/seed/squads/company/company-eval.md +21 -0
- package/templates/seed/squads/company/event-dispatcher.md +21 -0
- package/templates/seed/squads/company/goal-tracker.md +21 -0
- package/templates/seed/squads/company/manager.md +66 -0
- package/templates/seed/squads/engineering/SQUAD.md +48 -0
- package/templates/seed/squads/engineering/code-reviewer.md +57 -0
- package/templates/seed/squads/engineering/issue-solver.md +58 -0
- package/templates/seed/squads/engineering/test-writer.md +50 -0
- package/templates/seed/squads/intelligence/SQUAD.md +37 -0
- package/templates/seed/squads/intelligence/intel-critic.md +36 -0
- package/templates/seed/squads/intelligence/intel-eval.md +31 -0
- package/templates/seed/squads/intelligence/intel-lead.md +71 -0
- package/templates/seed/squads/marketing/SQUAD.md +47 -0
- package/templates/seed/squads/marketing/content-drafter.md +71 -0
- package/templates/seed/squads/marketing/growth-analyst.md +49 -0
- package/templates/seed/squads/marketing/social-poster.md +44 -0
- package/templates/seed/squads/operations/SQUAD.md +45 -0
- package/templates/seed/squads/operations/finance-tracker.md +47 -0
- package/templates/seed/squads/operations/goal-tracker.md +48 -0
- package/templates/seed/squads/operations/ops-lead.md +58 -0
- package/templates/seed/squads/research/SQUAD.md +38 -0
- package/templates/seed/squads/research/analyst.md +27 -0
- package/templates/seed/squads/research/research-critic.md +20 -0
- package/templates/seed/squads/research/research-eval.md +20 -0
- package/templates/seed/squads/research/researcher.md +28 -0
- package/dist/chunk-7PRYDHZW.js.map +0 -1
- package/dist/chunk-BV6S5AWZ.js.map +0 -1
- package/dist/chunk-HKWCBCEK.js.map +0 -1
- package/dist/chunk-NA3IECJA.js.map +0 -1
- package/dist/chunk-QPH5OR7J.js.map +0 -1
- package/docker/.env.example +0 -17
- package/docker/README.md +0 -92
- package/docker/docker-compose.engram.yml +0 -304
- package/docker/docker-compose.yml +0 -250
- package/docker/init-db.sql +0 -478
- package/docker/init-engram-db.sql +0 -148
- package/docker/init-langfuse-db.sh +0 -10
- package/docker/otel-collector.yaml +0 -34
- package/docker/squads-bridge/Dockerfile +0 -14
- package/docker/squads-bridge/Dockerfile.proxy +0 -14
- package/docker/squads-bridge/anthropic_proxy.py +0 -313
- package/docker/squads-bridge/requirements.txt +0 -7
- package/docker/squads-bridge/squads_bridge.py +0 -2299
- package/docker/telemetry-ping/Dockerfile +0 -10
- package/docker/telemetry-ping/deploy.sh +0 -69
- package/docker/telemetry-ping/main.py +0 -136
- package/docker/telemetry-ping/requirements.txt +0 -3
- /package/dist/{memory-ZXDXF6KF.js.map → memory-VNF2VFRB.js.map} +0 -0
- /package/dist/{sessions-F6LRY7EN.js.map → sessions-6PB7ALCE.js.map} +0 -0
- /package/dist/{squad-parser-MSYE4PXL.js.map → squad-parser-4BI3G4RS.js.map} +0 -0
- /package/dist/{terminal-JZSAQSN7.js.map → terminal-YKA4O5CX.js.map} +0 -0
- /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?:
|
|
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, dirname } 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 =
|
|
15
|
-
if (
|
|
93
|
+
const squadsPath = join2(dir, ".agents", "squads");
|
|
94
|
+
if (existsSync2(squadsPath)) {
|
|
16
95
|
return squadsPath;
|
|
17
96
|
}
|
|
18
|
-
const parent =
|
|
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
|
|
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 =
|
|
35
|
-
if (
|
|
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 =
|
|
47
|
-
if (!
|
|
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:
|
|
135
|
+
filePath: join2(squadPath, file)
|
|
57
136
|
});
|
|
58
137
|
}
|
|
59
138
|
}
|
|
@@ -61,13 +140,16 @@ function listAgents(squadsDir, squadName) {
|
|
|
61
140
|
return agents;
|
|
62
141
|
}
|
|
63
142
|
function parseSquadFile(filePath) {
|
|
64
|
-
const rawContent =
|
|
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
|
-
//
|
|
70
|
-
name: fm.name ||
|
|
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,
|
|
71
153
|
mission: fm.mission || "",
|
|
72
154
|
agents: [],
|
|
73
155
|
pipelines: [],
|
|
@@ -187,20 +269,20 @@ function parseSquadFile(filePath) {
|
|
|
187
269
|
function loadSquad(squadName) {
|
|
188
270
|
const squadsDir = findSquadsDir();
|
|
189
271
|
if (!squadsDir) return null;
|
|
190
|
-
const squadFile =
|
|
191
|
-
if (!
|
|
272
|
+
const squadFile = join2(squadsDir, squadName, "SQUAD.md");
|
|
273
|
+
if (!existsSync2(squadFile)) return null;
|
|
192
274
|
return parseSquadFile(squadFile);
|
|
193
275
|
}
|
|
194
276
|
function loadAgentDefinition(agentPath) {
|
|
195
|
-
if (!
|
|
196
|
-
return
|
|
277
|
+
if (!existsSync2(agentPath)) return "";
|
|
278
|
+
return readFileSync2(agentPath, "utf-8");
|
|
197
279
|
}
|
|
198
280
|
function addGoalToSquad(squadName, goal) {
|
|
199
281
|
const squadsDir = findSquadsDir();
|
|
200
282
|
if (!squadsDir) return false;
|
|
201
|
-
const squadFile =
|
|
202
|
-
if (!
|
|
203
|
-
let content =
|
|
283
|
+
const squadFile = join2(squadsDir, squadName, "SQUAD.md");
|
|
284
|
+
if (!existsSync2(squadFile)) return false;
|
|
285
|
+
let content = readFileSync2(squadFile, "utf-8");
|
|
204
286
|
if (!content.includes("## Goals")) {
|
|
205
287
|
const insertPoint = content.indexOf("## Dependencies");
|
|
206
288
|
if (insertPoint > 0) {
|
|
@@ -235,15 +317,15 @@ function addGoalToSquad(squadName, goal) {
|
|
|
235
317
|
- [ ] ${goal}` + content.slice(headerEnd);
|
|
236
318
|
}
|
|
237
319
|
}
|
|
238
|
-
|
|
320
|
+
writeFileSync2(squadFile, content);
|
|
239
321
|
return true;
|
|
240
322
|
}
|
|
241
323
|
function updateGoalInSquad(squadName, goalIndex, updates) {
|
|
242
324
|
const squadsDir = findSquadsDir();
|
|
243
325
|
if (!squadsDir) return false;
|
|
244
|
-
const squadFile =
|
|
245
|
-
if (!
|
|
246
|
-
const content =
|
|
326
|
+
const squadFile = join2(squadsDir, squadName, "SQUAD.md");
|
|
327
|
+
if (!existsSync2(squadFile)) return false;
|
|
328
|
+
const content = readFileSync2(squadFile, "utf-8");
|
|
247
329
|
const lines = content.split("\n");
|
|
248
330
|
let currentSection = "";
|
|
249
331
|
let goalCount = 0;
|
|
@@ -265,7 +347,7 @@ function updateGoalInSquad(squadName, goalIndex, updates) {
|
|
|
265
347
|
}
|
|
266
348
|
}
|
|
267
349
|
lines[i] = newLine;
|
|
268
|
-
|
|
350
|
+
writeFileSync2(squadFile, lines.join("\n"));
|
|
269
351
|
return true;
|
|
270
352
|
}
|
|
271
353
|
goalCount++;
|
|
@@ -274,6 +356,198 @@ function updateGoalInSquad(squadName, goalIndex, updates) {
|
|
|
274
356
|
}
|
|
275
357
|
return false;
|
|
276
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
|
+
}
|
|
277
551
|
|
|
278
552
|
// src/lib/condenser/tokens.ts
|
|
279
553
|
var RATIOS = {
|
|
@@ -1032,11 +1306,13 @@ export {
|
|
|
1032
1306
|
findSquadsDir,
|
|
1033
1307
|
formatTrackerStatus,
|
|
1034
1308
|
getCompressionLevel,
|
|
1309
|
+
getSquadLocalSkills,
|
|
1035
1310
|
listAgents,
|
|
1036
1311
|
listSquads,
|
|
1037
1312
|
loadAgentDefinition,
|
|
1038
1313
|
loadSquad,
|
|
1039
1314
|
parseSquadFile,
|
|
1315
|
+
resolveExecutionContext,
|
|
1040
1316
|
updateGoalInSquad,
|
|
1041
1317
|
updateTracker,
|
|
1042
1318
|
version
|