squads-cli 0.6.2 → 0.7.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 (112) hide show
  1. package/README.md +196 -1152
  2. package/dist/auth-YW3UPFSB.js +23 -0
  3. package/dist/autonomy-BWTVDEAT.js +102 -0
  4. package/dist/autonomy-BWTVDEAT.js.map +1 -0
  5. package/dist/chunk-3KCWNZWW.js +401 -0
  6. package/dist/chunk-3KCWNZWW.js.map +1 -0
  7. package/dist/chunk-67RO2HKR.js +174 -0
  8. package/dist/chunk-67RO2HKR.js.map +1 -0
  9. package/dist/chunk-7JVD7RD4.js +275 -0
  10. package/dist/chunk-7JVD7RD4.js.map +1 -0
  11. package/dist/chunk-BODLDQY7.js +452 -0
  12. package/dist/chunk-BODLDQY7.js.map +1 -0
  13. package/dist/chunk-FFFCFZ6A.js +121 -0
  14. package/dist/chunk-FFFCFZ6A.js.map +1 -0
  15. package/dist/chunk-FIWT2NMM.js +165 -0
  16. package/dist/chunk-FIWT2NMM.js.map +1 -0
  17. package/dist/chunk-L6GQCHDF.js +222 -0
  18. package/dist/chunk-L6GQCHDF.js.map +1 -0
  19. package/dist/{chunk-O7UV3FWI.js → chunk-LDM62TIX.js} +2 -2
  20. package/dist/chunk-LDM62TIX.js.map +1 -0
  21. package/dist/chunk-LOA3KWYJ.js +294 -0
  22. package/dist/chunk-LOA3KWYJ.js.map +1 -0
  23. package/dist/chunk-NA45DFXY.js +616 -0
  24. package/dist/chunk-NA45DFXY.js.map +1 -0
  25. package/dist/{chunk-4CMAEQQY.js → chunk-NQN6JPI7.js} +4 -3
  26. package/dist/chunk-NQN6JPI7.js.map +1 -0
  27. package/dist/chunk-OQJHPULO.js +103 -0
  28. package/dist/chunk-OQJHPULO.js.map +1 -0
  29. package/dist/chunk-QHNUMM4V.js +87 -0
  30. package/dist/chunk-QHNUMM4V.js.map +1 -0
  31. package/dist/chunk-RM6BWILN.js +74 -0
  32. package/dist/chunk-RM6BWILN.js.map +1 -0
  33. package/dist/chunk-WBR5J7EX.js +90 -0
  34. package/dist/chunk-WBR5J7EX.js.map +1 -0
  35. package/dist/chunk-Z2UKDBNL.js +162 -0
  36. package/dist/chunk-Z2UKDBNL.js.map +1 -0
  37. package/dist/cli.js +2136 -12600
  38. package/dist/cli.js.map +1 -1
  39. package/dist/context-M2A2DOFV.js +291 -0
  40. package/dist/context-M2A2DOFV.js.map +1 -0
  41. package/dist/context-feed-JMNW4GAM.js +391 -0
  42. package/dist/context-feed-JMNW4GAM.js.map +1 -0
  43. package/dist/cost-N37I4UTA.js +274 -0
  44. package/dist/cost-N37I4UTA.js.map +1 -0
  45. package/dist/create-554W5HNU.js +286 -0
  46. package/dist/create-554W5HNU.js.map +1 -0
  47. package/dist/daemon-XWPQPPPN.js +546 -0
  48. package/dist/daemon-XWPQPPPN.js.map +1 -0
  49. package/dist/dashboard-L7YKVQEB.js +945 -0
  50. package/dist/dashboard-L7YKVQEB.js.map +1 -0
  51. package/dist/dashboard-MFNRLCEE.js +794 -0
  52. package/dist/dashboard-MFNRLCEE.js.map +1 -0
  53. package/dist/doctor-RG75M5RO.js +346 -0
  54. package/dist/doctor-RG75M5RO.js.map +1 -0
  55. package/dist/env-config-KCLDBKYX.js +21 -0
  56. package/dist/exec-JQKBF7BL.js +197 -0
  57. package/dist/exec-JQKBF7BL.js.map +1 -0
  58. package/dist/feedback-KA2UYBZG.js +229 -0
  59. package/dist/feedback-KA2UYBZG.js.map +1 -0
  60. package/dist/github-UQTM5KMS.js +23 -0
  61. package/dist/goal-EOPC5ZCD.js +168 -0
  62. package/dist/goal-EOPC5ZCD.js.map +1 -0
  63. package/dist/health-3FZDOSR5.js +209 -0
  64. package/dist/health-3FZDOSR5.js.map +1 -0
  65. package/dist/history-TFVXJEDH.js +229 -0
  66. package/dist/history-TFVXJEDH.js.map +1 -0
  67. package/dist/index.js +1 -1
  68. package/dist/index.js.map +1 -1
  69. package/dist/init-UOWTNMIE.js +747 -0
  70. package/dist/init-UOWTNMIE.js.map +1 -0
  71. package/dist/kpi-2SQ2WCVT.js +413 -0
  72. package/dist/kpi-2SQ2WCVT.js.map +1 -0
  73. package/dist/learn-6ERTERAO.js +269 -0
  74. package/dist/learn-6ERTERAO.js.map +1 -0
  75. package/dist/list-KSOMUBMB.js +92 -0
  76. package/dist/list-KSOMUBMB.js.map +1 -0
  77. package/dist/login-ST6PAXYE.js +155 -0
  78. package/dist/login-ST6PAXYE.js.map +1 -0
  79. package/dist/memory-3CSNKXIL.js +562 -0
  80. package/dist/memory-3CSNKXIL.js.map +1 -0
  81. package/dist/progress-FKG4V2VH.js +202 -0
  82. package/dist/progress-FKG4V2VH.js.map +1 -0
  83. package/dist/providers-66PDCORB.js +65 -0
  84. package/dist/providers-66PDCORB.js.map +1 -0
  85. package/dist/results-2MJFLWEO.js +224 -0
  86. package/dist/results-2MJFLWEO.js.map +1 -0
  87. package/dist/run-72OQLH5A.js +2685 -0
  88. package/dist/run-72OQLH5A.js.map +1 -0
  89. package/dist/session-6H67XPAQ.js +64 -0
  90. package/dist/session-6H67XPAQ.js.map +1 -0
  91. package/dist/{chunk-NHGLXN2F.js → sessions-GVQIMN4W.js} +23 -459
  92. package/dist/sessions-GVQIMN4W.js.map +1 -0
  93. package/dist/{squad-parser-4BI3G4RS.js → squad-parser-CM3HOIWM.js} +2 -2
  94. package/dist/squad-parser-CM3HOIWM.js.map +1 -0
  95. package/dist/stats-ONZI557Q.js +335 -0
  96. package/dist/stats-ONZI557Q.js.map +1 -0
  97. package/dist/status-FYH42FTB.js +346 -0
  98. package/dist/status-FYH42FTB.js.map +1 -0
  99. package/dist/sync-HJZJNXHW.js +800 -0
  100. package/dist/sync-HJZJNXHW.js.map +1 -0
  101. package/dist/update-B4WMUOPO.js +83 -0
  102. package/dist/update-B4WMUOPO.js.map +1 -0
  103. package/dist/{update-ALJKFFM7.js → update-L7FGHN6W.js} +2 -2
  104. package/dist/update-L7FGHN6W.js.map +1 -0
  105. package/package.json +18 -10
  106. package/dist/chunk-4CMAEQQY.js.map +0 -1
  107. package/dist/chunk-NHGLXN2F.js.map +0 -1
  108. package/dist/chunk-O7UV3FWI.js.map +0 -1
  109. package/dist/sessions-6PB7ALCE.js +0 -16
  110. /package/dist/{sessions-6PB7ALCE.js.map → auth-YW3UPFSB.js.map} +0 -0
  111. /package/dist/{squad-parser-4BI3G4RS.js.map → env-config-KCLDBKYX.js.map} +0 -0
  112. /package/dist/{update-ALJKFFM7.js.map → github-UQTM5KMS.js.map} +0 -0
@@ -0,0 +1,800 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ Events,
4
+ track
5
+ } from "./chunk-L6GQCHDF.js";
6
+ import {
7
+ findSquadsDir
8
+ } from "./chunk-LDM62TIX.js";
9
+ import {
10
+ findMemoryDir
11
+ } from "./chunk-ZTQ7ISUR.js";
12
+ import {
13
+ RESET,
14
+ colors,
15
+ gradient,
16
+ icons,
17
+ writeLine
18
+ } from "./chunk-N7KDWU4W.js";
19
+ import "./chunk-7OCVIDC7.js";
20
+
21
+ // src/commands/sync.ts
22
+ import { execSync } from "child_process";
23
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from "fs";
24
+ import { join } from "path";
25
+
26
+ // src/lib/cycle-sync.ts
27
+ async function syncAllCycleData() {
28
+ return {
29
+ goals: { synced: 0, skipped: 0, errors: 0 },
30
+ feedback: { synced: 0, skipped: 0, errors: 0 },
31
+ kpis: { synced: 0, skipped: 0, errors: 0 },
32
+ learnings: { synced: 0, skipped: 0, errors: 0 },
33
+ duration: 0
34
+ };
35
+ }
36
+ async function isPostgresAvailable() {
37
+ return false;
38
+ }
39
+ async function closeCycleSyncPool() {
40
+ }
41
+
42
+ // src/commands/sync.ts
43
+ var PATH_TO_SQUAD = {
44
+ "squads-cli": "product",
45
+ "agents-squads-web": "website",
46
+ "research": "research",
47
+ "intelligence": "intelligence",
48
+ "customer": "customer",
49
+ "finance": "finance",
50
+ "engineering": "engineering",
51
+ "product": "product",
52
+ "company": "company",
53
+ ".agents/squads": "engineering",
54
+ ".agents/memory": "engineering"
55
+ };
56
+ var MESSAGE_TO_SQUAD = {
57
+ "cli": "product",
58
+ "website": "website",
59
+ "web": "website",
60
+ "homepage": "website",
61
+ "research": "research",
62
+ "intel": "intelligence",
63
+ "lead": "customer",
64
+ "finance": "finance",
65
+ "cost": "finance",
66
+ "engineering": "engineering",
67
+ "infra": "engineering"
68
+ };
69
+ function getLastSyncTime(memoryDir) {
70
+ const syncFile = join(memoryDir, ".last-sync");
71
+ if (existsSync(syncFile)) {
72
+ return readFileSync(syncFile, "utf-8").trim();
73
+ }
74
+ return null;
75
+ }
76
+ function updateLastSyncTime(memoryDir) {
77
+ const syncFile = join(memoryDir, ".last-sync");
78
+ writeFileSync(syncFile, (/* @__PURE__ */ new Date()).toISOString());
79
+ }
80
+ function getRecentCommits(since) {
81
+ const commits = [];
82
+ try {
83
+ const sinceArg = since ? `--since="${since}"` : "-n 20";
84
+ const logOutput = execSync(
85
+ `git log ${sinceArg} --format="%H|%aI|%s" --name-only`,
86
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
87
+ ).trim();
88
+ if (!logOutput) return commits;
89
+ const entries = logOutput.split("\n\n");
90
+ for (const entry of entries) {
91
+ const lines = entry.split("\n").filter((l) => l.trim());
92
+ if (lines.length === 0) continue;
93
+ const [header, ...fileLines] = lines;
94
+ const [hash, date, ...messageParts] = header.split("|");
95
+ const message = messageParts.join("|");
96
+ if (hash && date && message) {
97
+ commits.push({
98
+ hash: hash.substring(0, 7),
99
+ date: date.split("T")[0],
100
+ message,
101
+ files: fileLines.filter((f) => f && !f.includes("|"))
102
+ });
103
+ }
104
+ }
105
+ } catch (err) {
106
+ if (process.env.DEBUG) {
107
+ console.error("Git log failed (not a git repo or other error):", err);
108
+ }
109
+ }
110
+ return commits;
111
+ }
112
+ function detectSquadsFromCommit(commit) {
113
+ const squads = /* @__PURE__ */ new Set();
114
+ for (const file of commit.files) {
115
+ for (const [pathPattern, squad] of Object.entries(PATH_TO_SQUAD)) {
116
+ if (file.includes(pathPattern)) {
117
+ squads.add(squad);
118
+ }
119
+ }
120
+ }
121
+ const msgLower = commit.message.toLowerCase();
122
+ for (const [keyword, squad] of Object.entries(MESSAGE_TO_SQUAD)) {
123
+ if (msgLower.includes(keyword)) {
124
+ squads.add(squad);
125
+ }
126
+ }
127
+ return Array.from(squads);
128
+ }
129
+ function groupCommitsBySquad(commits) {
130
+ const grouped = /* @__PURE__ */ new Map();
131
+ for (const commit of commits) {
132
+ const squads = detectSquadsFromCommit(commit);
133
+ for (const squad of squads) {
134
+ if (!grouped.has(squad)) {
135
+ grouped.set(squad, []);
136
+ }
137
+ grouped.get(squad).push(commit);
138
+ }
139
+ }
140
+ return grouped;
141
+ }
142
+ function generateSummary(commits) {
143
+ if (commits.length === 0) return "";
144
+ const messages = commits.map((c) => `- ${c.message}`).join("\n");
145
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
146
+ return `
147
+ ## Session Update (${date})
148
+
149
+ ${messages}
150
+ `;
151
+ }
152
+ function appendToSquadMemory(memoryDir, squad, summary) {
153
+ const squadMemoryDir = join(memoryDir, squad);
154
+ if (!existsSync(squadMemoryDir)) {
155
+ mkdirSync(squadMemoryDir, { recursive: true });
156
+ }
157
+ let agentDir;
158
+ const existingDirs = existsSync(squadMemoryDir) ? readdirSync(squadMemoryDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name) : [];
159
+ if (existingDirs.length > 0) {
160
+ agentDir = join(squadMemoryDir, existingDirs[0]);
161
+ } else {
162
+ agentDir = join(squadMemoryDir, `${squad}-lead`);
163
+ mkdirSync(agentDir, { recursive: true });
164
+ }
165
+ const statePath = join(agentDir, "state.md");
166
+ let content = "";
167
+ if (existsSync(statePath)) {
168
+ content = readFileSync(statePath, "utf-8");
169
+ } else {
170
+ content = `# ${squad} Squad - State
171
+
172
+ Updated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
173
+ `;
174
+ }
175
+ content = content.replace(
176
+ /Updated:\s*\d{4}-\d{2}-\d{2}/,
177
+ `Updated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`
178
+ );
179
+ content += summary;
180
+ writeFileSync(statePath, content);
181
+ return true;
182
+ }
183
+ function gitPullMemory() {
184
+ try {
185
+ execSync("git fetch origin", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
186
+ const status = execSync("git status -sb", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
187
+ const behindMatch = status.match(/behind (\d+)/);
188
+ const aheadMatch = status.match(/ahead (\d+)/);
189
+ const behind = behindMatch ? parseInt(behindMatch[1]) : 0;
190
+ const ahead = aheadMatch ? parseInt(aheadMatch[1]) : 0;
191
+ if (behind === 0) {
192
+ return { success: true, output: "Already up to date", behind: 0, ahead };
193
+ }
194
+ const output = execSync("git pull --rebase origin main", {
195
+ encoding: "utf-8",
196
+ stdio: ["pipe", "pipe", "pipe"]
197
+ });
198
+ return { success: true, output: output.trim(), behind, ahead };
199
+ } catch (error) {
200
+ const err = error;
201
+ return { success: false, output: err.message || "Pull failed", behind: 0, ahead: 0 };
202
+ }
203
+ }
204
+ async function syncDimensionsToPostgres(verbose) {
205
+ const squadsDir = findSquadsDir();
206
+ const bridgeUrl = process.env.SQUADS_BRIDGE_URL || "http://localhost:8088";
207
+ if (!squadsDir) {
208
+ writeLine(` ${colors.red}No .agents/squads directory found${RESET}`);
209
+ return;
210
+ }
211
+ writeLine();
212
+ writeLine(` ${gradient("squads")} ${colors.dim}sync --dimensions${RESET}`);
213
+ writeLine();
214
+ writeLine(` ${icons.progress} Collecting squad definitions...`);
215
+ const squadDirs = readdirSync(squadsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
216
+ const squadsData = [];
217
+ const agentsData = [];
218
+ const { loadSquad: loadSquadFn } = await import("./squad-parser-CM3HOIWM.js");
219
+ for (const squadName of squadDirs) {
220
+ const squad = loadSquadFn(squadName);
221
+ if (!squad) continue;
222
+ squadsData.push({
223
+ name: squad.name,
224
+ mission: squad.mission || null,
225
+ domain: squad.domain || null,
226
+ default_provider: squad.providers?.default || "anthropic",
227
+ daily_budget: squad.context?.budget?.daily || 50,
228
+ cooldown_seconds: squad.context?.cooldown || 300,
229
+ metadata: {
230
+ providers: squad.providers,
231
+ context: squad.context,
232
+ permissions: squad.permissions
233
+ }
234
+ });
235
+ for (const agent of squad.agents) {
236
+ const agentPath = join(squadsDir, squadName, `${agent.name}.md`);
237
+ if (!existsSync(agentPath)) continue;
238
+ const definition = readFileSync(agentPath, "utf-8");
239
+ const mcpServers = extractMcpServersFromDef(definition);
240
+ const skills = extractSkillsFromDef(definition);
241
+ agentsData.push({
242
+ name: agent.name,
243
+ squad: squadName,
244
+ role: agent.role || null,
245
+ purpose: agent.purpose || null,
246
+ provider: agent.provider || null,
247
+ trigger_type: agent.trigger?.toLowerCase() || "manual",
248
+ mcp_servers: mcpServers,
249
+ skills,
250
+ metadata: {
251
+ schedule: agent.schedule,
252
+ outputs: agent.outputs
253
+ }
254
+ });
255
+ }
256
+ }
257
+ writeLine(` ${icons.success} Found ${colors.cyan}${squadsData.length}${RESET} squads, ${colors.cyan}${agentsData.length}${RESET} agents`);
258
+ if (verbose) {
259
+ writeLine();
260
+ for (const s of squadsData) {
261
+ writeLine(` ${colors.cyan}${s.name}${RESET} ${colors.dim}(${s.metadata.providers ? "with providers" : "default"})${RESET}`);
262
+ }
263
+ }
264
+ writeLine();
265
+ writeLine(` ${icons.progress} Syncing to Postgres...`);
266
+ try {
267
+ const response = await fetch(`${bridgeUrl}/api/sync/dimensions`, {
268
+ method: "POST",
269
+ headers: { "Content-Type": "application/json" },
270
+ body: JSON.stringify({ squads: squadsData, agents: agentsData })
271
+ });
272
+ if (!response.ok) {
273
+ const error = await response.text();
274
+ throw new Error(`Bridge returned ${response.status}: ${error}`);
275
+ }
276
+ const data = await response.json();
277
+ writeLine(` ${icons.success} Synced ${colors.green}${data.synced_squads}${RESET} squads, ${colors.green}${data.synced_agents}${RESET} agents`);
278
+ writeLine();
279
+ } catch (error) {
280
+ writeLine(` ${icons.error} ${colors.red}Sync failed: ${error}${RESET}`);
281
+ writeLine();
282
+ writeLine(` ${colors.dim}Is the bridge running? Check: curl ${bridgeUrl}/health${RESET}`);
283
+ writeLine();
284
+ }
285
+ }
286
+ function extractMcpServersFromDef(definition) {
287
+ const servers = /* @__PURE__ */ new Set();
288
+ const knownServers = ["chrome-devtools", "firecrawl", "context7", "huggingface"];
289
+ for (const server of knownServers) {
290
+ if (definition.toLowerCase().includes(server)) {
291
+ servers.add(server);
292
+ }
293
+ }
294
+ const mcpMatch = definition.match(/mcp:\s*\n((?:\s*-\s*\S+\s*\n?)+)/i);
295
+ if (mcpMatch) {
296
+ for (const line of mcpMatch[1].split("\n")) {
297
+ const m = line.match(/^\s*-\s*(\S+)/);
298
+ if (m) servers.add(m[1]);
299
+ }
300
+ }
301
+ return Array.from(servers);
302
+ }
303
+ function extractSkillsFromDef(definition) {
304
+ const skills = /* @__PURE__ */ new Set();
305
+ const skillsMatch = definition.match(/skills:\s*\n((?:\s*-\s*\S+\s*\n?)+)/i);
306
+ if (skillsMatch) {
307
+ for (const line of skillsMatch[1].split("\n")) {
308
+ const m = line.match(/^\s*-\s*(\S+)/);
309
+ if (m) skills.add(m[1]);
310
+ }
311
+ }
312
+ const slashSkills = definition.match(/\/[\w-]+/g);
313
+ if (slashSkills) {
314
+ for (const skill of slashSkills) {
315
+ if (!skill.startsWith("/exit") && !skill.startsWith("/help")) {
316
+ skills.add(skill.slice(1));
317
+ }
318
+ }
319
+ }
320
+ return Array.from(skills);
321
+ }
322
+ var COMMIT_CATEGORY_MAP = {
323
+ "feat": "success",
324
+ "fix": "failure",
325
+ "refactor": "pattern",
326
+ "perf": "pattern",
327
+ "docs": "tip",
328
+ "chore": "tip",
329
+ "test": "pattern",
330
+ "style": "tip"
331
+ };
332
+ var SIGNIFICANT_PATTERNS = [
333
+ { pattern: /\d+\s*(agents?|files?|components?)/i, weight: 2 },
334
+ // Batch operations
335
+ { pattern: /parallel|concurrent|async/i, weight: 2 },
336
+ // Parallelization
337
+ { pattern: /automat|hook|trigger/i, weight: 2 },
338
+ // Automation
339
+ { pattern: /integrat|connect|bridge/i, weight: 1.5 },
340
+ // Integration
341
+ { pattern: /improv|optim|enhanc|better/i, weight: 1.5 },
342
+ // Improvements
343
+ { pattern: /new|add|implement|create/i, weight: 1 }
344
+ // New features
345
+ ];
346
+ function analyzeCommitsForLearnings(commits) {
347
+ const learnings = [];
348
+ const squadCommits = groupCommitsBySquad(commits);
349
+ for (const [squad, squadCommitList] of squadCommits) {
350
+ const byCategory = /* @__PURE__ */ new Map();
351
+ for (const commit of squadCommitList) {
352
+ const match = commit.message.match(/^(\w+)(?:\(.*?\))?:\s*/);
353
+ const prefix = match ? match[1].toLowerCase() : "other";
354
+ if (!byCategory.has(prefix)) {
355
+ byCategory.set(prefix, []);
356
+ }
357
+ byCategory.get(prefix).push(commit);
358
+ }
359
+ for (const [prefix, categoryCommits] of byCategory) {
360
+ if (categoryCommits.length === 0) continue;
361
+ const category = COMMIT_CATEGORY_MAP[prefix] || "tip";
362
+ let significanceScore = categoryCommits.length;
363
+ const allMessages = categoryCommits.map((c) => c.message).join(" ");
364
+ for (const { pattern, weight } of SIGNIFICANT_PATTERNS) {
365
+ if (pattern.test(allMessages)) {
366
+ significanceScore *= weight;
367
+ }
368
+ }
369
+ if (significanceScore < 2) continue;
370
+ let insight;
371
+ if (categoryCommits.length === 1) {
372
+ insight = categoryCommits[0].message.replace(/^(\w+)(?:\(.*?\))?:\s*/, "");
373
+ } else {
374
+ const summaryParts = categoryCommits.slice(0, 3).map((c) => c.message.replace(/^(\w+)(?:\(.*?\))?:\s*/, ""));
375
+ insight = `${prefix}: ${summaryParts.join("; ")}${categoryCommits.length > 3 ? ` (+${categoryCommits.length - 3} more)` : ""}`;
376
+ }
377
+ const tags = /* @__PURE__ */ new Set();
378
+ for (const commit of categoryCommits) {
379
+ for (const file of commit.files) {
380
+ if (file.includes("agents")) tags.add("agents");
381
+ if (file.includes("memory")) tags.add("memory");
382
+ if (file.includes("cli")) tags.add("cli");
383
+ if (file.includes("web")) tags.add("web");
384
+ if (file.includes("hook")) tags.add("hooks");
385
+ }
386
+ }
387
+ learnings.push({
388
+ squad,
389
+ insight,
390
+ category,
391
+ tags: Array.from(tags),
392
+ context: categoryCommits.map((c) => c.hash).join(", ")
393
+ });
394
+ }
395
+ }
396
+ return learnings;
397
+ }
398
+ function appendAutoLearnings(memoryDir, learnings) {
399
+ let appended = 0;
400
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
401
+ for (const learning of learnings) {
402
+ const squadDir = join(memoryDir, learning.squad);
403
+ let agentDir;
404
+ if (existsSync(squadDir)) {
405
+ const dirs = readdirSync(squadDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
406
+ agentDir = dirs.length > 0 ? join(squadDir, dirs[0]) : join(squadDir, `${learning.squad}-lead`);
407
+ } else {
408
+ mkdirSync(squadDir, { recursive: true });
409
+ agentDir = join(squadDir, `${learning.squad}-lead`);
410
+ }
411
+ if (!existsSync(agentDir)) {
412
+ mkdirSync(agentDir, { recursive: true });
413
+ }
414
+ const learningsPath = join(agentDir, "learnings.md");
415
+ const categoryEmoji = {
416
+ success: "\u2713",
417
+ failure: "\u2717",
418
+ pattern: "\u25C6",
419
+ tip: "\u2192"
420
+ }[learning.category];
421
+ const tagsStr = learning.tags.length > 0 ? ` #${learning.tags.join(" #")}` : "";
422
+ const entry = `
423
+ ${date} ${categoryEmoji} **${learning.category.charAt(0).toUpperCase() + learning.category.slice(1)}**: ${learning.insight}${tagsStr}
424
+ `;
425
+ let content = "";
426
+ if (existsSync(learningsPath)) {
427
+ content = readFileSync(learningsPath, "utf-8");
428
+ if (content.includes(learning.insight.slice(0, 50))) {
429
+ continue;
430
+ }
431
+ } else {
432
+ content = `# ${learning.squad} Squad - Learnings
433
+
434
+ Auto-captured insights from session activity.
435
+ `;
436
+ }
437
+ writeFileSync(learningsPath, content + entry);
438
+ appended++;
439
+ }
440
+ return appended;
441
+ }
442
+ function parseLearningsFile(filePath, squad, agent) {
443
+ const content = readFileSync(filePath, "utf-8");
444
+ const learnings = [];
445
+ const sections = content.split(/^##+ /m).filter(Boolean);
446
+ for (const section of sections) {
447
+ const lines = section.trim().split("\n");
448
+ const title = lines[0]?.trim();
449
+ const body = lines.slice(1).join("\n").trim();
450
+ if (!body || body.length < 20) continue;
451
+ let category = "insight";
452
+ const titleLower = title?.toLowerCase() || "";
453
+ if (titleLower.includes("what works") || titleLower.includes("success")) category = "success";
454
+ else if (titleLower.includes("what doesn't") || titleLower.includes("unsuccessful") || titleLower.includes("fail")) category = "failure";
455
+ else if (titleLower.includes("pattern")) category = "pattern";
456
+ else if (titleLower.includes("improvement") || titleLower.includes("next")) category = "tip";
457
+ let importance = "normal";
458
+ if (body.includes("**Learning**:") || body.includes("critical") || body.includes("P1")) importance = "high";
459
+ learnings.push({
460
+ squad,
461
+ agent,
462
+ content: title ? `## ${title}
463
+ ${body}` : body,
464
+ category,
465
+ importance,
466
+ source_file: filePath
467
+ });
468
+ }
469
+ const learningMatches = content.matchAll(/\*\*Learning\*\*:\s*(.+?)(?=\n\n|\n\*\*|$)/gs);
470
+ for (const match of learningMatches) {
471
+ learnings.push({
472
+ squad,
473
+ agent,
474
+ content: match[1].trim(),
475
+ category: "insight",
476
+ importance: "high",
477
+ source_file: filePath
478
+ });
479
+ }
480
+ return learnings;
481
+ }
482
+ async function syncLearningsToPostgres(verbose) {
483
+ const bridgeUrl = process.env.SQUADS_BRIDGE_URL || "http://localhost:8088";
484
+ const memoryDir = findMemoryDir();
485
+ writeLine();
486
+ writeLine(` ${gradient("squads")} ${colors.dim}sync --learnings${RESET}`);
487
+ writeLine();
488
+ if (!memoryDir) {
489
+ writeLine(` ${icons.error} ${colors.red}No .agents/memory directory found${RESET}`);
490
+ return;
491
+ }
492
+ writeLine(` ${icons.progress} Scanning for learnings files...`);
493
+ const learningsFiles = [];
494
+ const scanDir = (dir) => {
495
+ const entries = readdirSync(dir, { withFileTypes: true });
496
+ for (const entry of entries) {
497
+ const fullPath = join(dir, entry.name);
498
+ if (entry.isDirectory()) {
499
+ scanDir(fullPath);
500
+ } else if (entry.name === "learnings.md") {
501
+ learningsFiles.push(fullPath);
502
+ }
503
+ }
504
+ };
505
+ scanDir(memoryDir);
506
+ writeLine(` ${icons.success} Found ${colors.cyan}${learningsFiles.length}${RESET} learnings files`);
507
+ const allLearnings = [];
508
+ for (const file of learningsFiles) {
509
+ const relativePath = file.replace(memoryDir + "/", "");
510
+ const parts = relativePath.split("/");
511
+ const squad = parts[0] || "unknown";
512
+ const agent = parts.length > 2 ? parts[1] : null;
513
+ const entries = parseLearningsFile(file, squad, agent);
514
+ allLearnings.push(...entries);
515
+ if (verbose && entries.length > 0) {
516
+ writeLine(` ${colors.cyan}${squad}${agent ? "/" + agent : ""}${RESET}: ${entries.length} learnings`);
517
+ }
518
+ }
519
+ writeLine(` ${icons.success} Parsed ${colors.cyan}${allLearnings.length}${RESET} total learnings`);
520
+ if (allLearnings.length === 0) {
521
+ writeLine();
522
+ writeLine(` ${colors.dim}No learnings to sync${RESET}`);
523
+ return;
524
+ }
525
+ writeLine();
526
+ writeLine(` ${icons.progress} Syncing to Postgres...`);
527
+ try {
528
+ const response = await fetch(`${bridgeUrl}/api/sync/learnings`, {
529
+ method: "POST",
530
+ headers: { "Content-Type": "application/json" },
531
+ body: JSON.stringify({ learnings: allLearnings })
532
+ });
533
+ if (!response.ok) {
534
+ const errorText = await response.text();
535
+ throw new Error(`Bridge returned ${response.status}: ${errorText}`);
536
+ }
537
+ const result = await response.json();
538
+ writeLine(` ${icons.success} Imported ${colors.green}${result.imported}${RESET} learnings${result.skipped > 0 ? `, skipped ${result.skipped} duplicates` : ""}`);
539
+ } catch (error) {
540
+ writeLine(` ${icons.error} ${colors.red}Sync failed: ${error}${RESET}`);
541
+ writeLine();
542
+ writeLine(` ${colors.dim}Is the bridge running? Check: curl ${bridgeUrl}/health${RESET}`);
543
+ }
544
+ writeLine();
545
+ }
546
+ function gitPushMemory() {
547
+ try {
548
+ const status = execSync("git status --porcelain .agents/memory/", {
549
+ encoding: "utf-8",
550
+ stdio: ["pipe", "pipe", "pipe"]
551
+ }).trim();
552
+ if (status) {
553
+ execSync("git add .agents/memory/", { stdio: ["pipe", "pipe", "pipe"] });
554
+ execSync('git commit -m "chore: sync squad memory"', {
555
+ encoding: "utf-8",
556
+ stdio: ["pipe", "pipe", "pipe"]
557
+ });
558
+ }
559
+ const output = execSync("git push origin main", {
560
+ encoding: "utf-8",
561
+ stdio: ["pipe", "pipe", "pipe"]
562
+ });
563
+ return { success: true, output: output.trim() || "Pushed successfully" };
564
+ } catch (error) {
565
+ const err = error;
566
+ return { success: false, output: err.message || "Push failed" };
567
+ }
568
+ }
569
+ async function syncCommand(options = {}) {
570
+ await track(Events.CLI_MEMORY_SYNC, { push: options.push, pull: options.pull, postgres: options.postgres, dimensions: options.dimensions, learnings: options.learnings, autoLearn: options.autoLearn });
571
+ if (options.dimensions) {
572
+ await syncDimensionsToPostgres(options.verbose);
573
+ return;
574
+ }
575
+ if (options.learnings) {
576
+ await syncLearningsToPostgres(options.verbose);
577
+ return;
578
+ }
579
+ if (options.autoLearn) {
580
+ const memoryDir2 = findMemoryDir();
581
+ if (!memoryDir2) {
582
+ writeLine(` ${colors.yellow}No .agents/memory directory found${RESET}`);
583
+ return;
584
+ }
585
+ writeLine();
586
+ writeLine(` ${gradient("squads")} ${colors.dim}memory sync --auto-learn${RESET}`);
587
+ writeLine();
588
+ const lastSync2 = getLastSyncTime(memoryDir2);
589
+ const commits2 = getRecentCommits(lastSync2 || void 0);
590
+ if (commits2.length === 0) {
591
+ writeLine(` ${colors.dim}No commits to analyze${RESET}`);
592
+ writeLine();
593
+ return;
594
+ }
595
+ writeLine(` ${icons.progress} Analyzing ${colors.cyan}${commits2.length}${RESET} commits...`);
596
+ const learnings = analyzeCommitsForLearnings(commits2);
597
+ if (learnings.length === 0) {
598
+ writeLine(` ${colors.dim}No significant patterns detected${RESET}`);
599
+ writeLine();
600
+ return;
601
+ }
602
+ writeLine(` ${icons.success} Found ${colors.cyan}${learnings.length}${RESET} learnable patterns`);
603
+ writeLine();
604
+ if (options.verbose) {
605
+ for (const learning of learnings) {
606
+ const emoji = { success: "\u2713", failure: "\u2717", pattern: "\u25C6", tip: "\u2192" }[learning.category];
607
+ writeLine(` ${colors.cyan}${learning.squad}${RESET} ${emoji} ${learning.insight.slice(0, 60)}${learning.insight.length > 60 ? "..." : ""}`);
608
+ }
609
+ writeLine();
610
+ }
611
+ const appended = appendAutoLearnings(memoryDir2, learnings);
612
+ writeLine(` ${icons.success} Captured ${colors.green}${appended}${RESET} learnings to memory`);
613
+ const bySquad2 = /* @__PURE__ */ new Map();
614
+ for (const l of learnings) {
615
+ bySquad2.set(l.squad, (bySquad2.get(l.squad) || 0) + 1);
616
+ }
617
+ for (const [squad, count] of bySquad2) {
618
+ writeLine(` ${colors.cyan}${squad}${RESET}: ${count} learnings`);
619
+ }
620
+ writeLine();
621
+ updateLastSyncTime(memoryDir2);
622
+ if (options.postgres) {
623
+ await syncLearningsToPostgres(options.verbose);
624
+ }
625
+ return;
626
+ }
627
+ const memoryDir = findMemoryDir();
628
+ const _squadsDir = findSquadsDir();
629
+ if (!memoryDir) {
630
+ writeLine(` ${colors.yellow}No .agents/memory directory found${RESET}`);
631
+ writeLine(` ${colors.dim}Run \`squads init\` to create one.${RESET}`);
632
+ return;
633
+ }
634
+ writeLine();
635
+ writeLine(` ${gradient("squads")} ${colors.dim}memory sync${RESET}`);
636
+ writeLine();
637
+ const doPull = options.pull !== false;
638
+ const doPush = options.push === true;
639
+ if (doPull) {
640
+ writeLine(` ${icons.progress} Pulling from remote...`);
641
+ const pullResult = gitPullMemory();
642
+ if (pullResult.success) {
643
+ if (pullResult.behind > 0) {
644
+ writeLine(` ${icons.success} Pulled ${colors.cyan}${pullResult.behind}${RESET} commits from remote`);
645
+ } else {
646
+ writeLine(` ${icons.success} ${colors.dim}Already up to date${RESET}`);
647
+ }
648
+ if (pullResult.ahead > 0) {
649
+ writeLine(` ${colors.dim} ${pullResult.ahead} local commits to push${RESET}`);
650
+ }
651
+ } else {
652
+ writeLine(` ${icons.error} ${colors.red}Pull failed: ${pullResult.output}${RESET}`);
653
+ }
654
+ writeLine();
655
+ }
656
+ const lastSync = getLastSyncTime(memoryDir);
657
+ if (lastSync) {
658
+ writeLine(` ${colors.dim}Last sync: ${lastSync.split("T")[0]}${RESET}`);
659
+ } else {
660
+ writeLine(` ${colors.dim}First sync${RESET}`);
661
+ }
662
+ writeLine();
663
+ const commits = getRecentCommits(lastSync || void 0);
664
+ if (commits.length === 0) {
665
+ writeLine(` ${colors.yellow}No new commits since last sync${RESET}`);
666
+ if (options.postgres) {
667
+ writeLine();
668
+ writeLine(` ${icons.progress} Syncing cycle data to Postgres...`);
669
+ const pgAvailable = await isPostgresAvailable();
670
+ if (!pgAvailable) {
671
+ writeLine(` ${icons.error} ${colors.red}Postgres not available${RESET}`);
672
+ writeLine(` ${colors.dim}Run \`squads stack up\` to start the database${RESET}`);
673
+ } else {
674
+ try {
675
+ const result = await syncAllCycleData();
676
+ const totalSynced = result.goals.synced + result.feedback.synced + result.kpis.synced + result.learnings.synced;
677
+ const totalErrors = result.goals.errors + result.feedback.errors + result.kpis.errors + result.learnings.errors;
678
+ if (totalSynced > 0 || totalErrors > 0) {
679
+ writeLine(` ${icons.success} Synced to Postgres ${colors.dim}(${result.duration}ms)${RESET}`);
680
+ if (result.goals.synced > 0) {
681
+ writeLine(` ${colors.dim}Goals:${RESET} ${colors.cyan}${result.goals.synced}${RESET}`);
682
+ }
683
+ if (result.feedback.synced > 0) {
684
+ writeLine(` ${colors.dim}Feedback:${RESET} ${colors.cyan}${result.feedback.synced}${RESET}`);
685
+ }
686
+ if (result.kpis.synced > 0) {
687
+ writeLine(` ${colors.dim}KPIs:${RESET} ${colors.cyan}${result.kpis.synced}${RESET}`);
688
+ }
689
+ if (result.learnings.synced > 0) {
690
+ writeLine(` ${colors.dim}Learnings:${RESET} ${colors.cyan}${result.learnings.synced}${RESET}`);
691
+ }
692
+ if (totalErrors > 0) {
693
+ writeLine(` ${colors.red}Errors:${RESET} ${totalErrors}`);
694
+ }
695
+ } else {
696
+ writeLine(` ${icons.success} ${colors.dim}No new cycle data to sync${RESET}`);
697
+ }
698
+ await closeCycleSyncPool();
699
+ } catch (err) {
700
+ writeLine(` ${icons.error} ${colors.red}Postgres sync failed${RESET}`);
701
+ if (process.env.DEBUG) console.error(err);
702
+ }
703
+ }
704
+ }
705
+ writeLine();
706
+ return;
707
+ }
708
+ writeLine(` ${colors.cyan}${commits.length}${RESET} commits to process`);
709
+ writeLine();
710
+ const bySquad = groupCommitsBySquad(commits);
711
+ if (bySquad.size === 0) {
712
+ writeLine(` ${colors.yellow}No squad-related commits found${RESET}`);
713
+ writeLine();
714
+ updateLastSyncTime(memoryDir);
715
+ return;
716
+ }
717
+ let updated = 0;
718
+ for (const [squad, squadCommits] of bySquad) {
719
+ const summary = generateSummary(squadCommits);
720
+ if (options.verbose) {
721
+ writeLine(` ${icons.progress} ${colors.cyan}${squad}${RESET}`);
722
+ for (const commit of squadCommits) {
723
+ writeLine(` ${colors.dim}${commit.hash} ${commit.message}${RESET}`);
724
+ }
725
+ }
726
+ const success = appendToSquadMemory(memoryDir, squad, summary);
727
+ if (success) {
728
+ writeLine(` ${icons.success} ${colors.cyan}${squad}${RESET} ${colors.dim}(${squadCommits.length} commits)${RESET}`);
729
+ updated++;
730
+ }
731
+ }
732
+ writeLine();
733
+ writeLine(` ${colors.green}${updated}${RESET} squad memories updated`);
734
+ writeLine();
735
+ updateLastSyncTime(memoryDir);
736
+ if (doPush) {
737
+ writeLine(` ${icons.progress} Pushing to remote...`);
738
+ const pushResult = gitPushMemory();
739
+ if (pushResult.success) {
740
+ writeLine(` ${icons.success} ${colors.green}Pushed memory updates to remote${RESET}`);
741
+ } else {
742
+ writeLine(` ${icons.error} ${colors.red}Push failed: ${pushResult.output}${RESET}`);
743
+ }
744
+ writeLine();
745
+ }
746
+ if (options.postgres) {
747
+ writeLine(` ${icons.progress} Syncing cycle data to Postgres...`);
748
+ const pgAvailable = await isPostgresAvailable();
749
+ if (!pgAvailable) {
750
+ writeLine(` ${icons.error} ${colors.red}Postgres not available${RESET}`);
751
+ writeLine(` ${colors.dim}Run \`squads stack up\` to start the database${RESET}`);
752
+ writeLine();
753
+ } else {
754
+ try {
755
+ const result = await syncAllCycleData();
756
+ const totalSynced = result.goals.synced + result.feedback.synced + result.kpis.synced + result.learnings.synced;
757
+ const totalErrors = result.goals.errors + result.feedback.errors + result.kpis.errors + result.learnings.errors;
758
+ if (totalSynced > 0 || totalErrors > 0) {
759
+ writeLine(` ${icons.success} Synced to Postgres ${colors.dim}(${result.duration}ms)${RESET}`);
760
+ if (result.goals.synced > 0) {
761
+ writeLine(` ${colors.dim}Goals:${RESET} ${colors.cyan}${result.goals.synced}${RESET}`);
762
+ }
763
+ if (result.feedback.synced > 0) {
764
+ writeLine(` ${colors.dim}Feedback:${RESET} ${colors.cyan}${result.feedback.synced}${RESET}`);
765
+ }
766
+ if (result.kpis.synced > 0) {
767
+ writeLine(` ${colors.dim}KPIs:${RESET} ${colors.cyan}${result.kpis.synced}${RESET}`);
768
+ }
769
+ if (result.learnings.synced > 0) {
770
+ writeLine(` ${colors.dim}Learnings:${RESET} ${colors.cyan}${result.learnings.synced}${RESET}`);
771
+ }
772
+ if (totalErrors > 0) {
773
+ writeLine(` ${colors.red}Errors:${RESET} ${totalErrors}`);
774
+ }
775
+ } else {
776
+ writeLine(` ${icons.success} ${colors.dim}No new cycle data to sync${RESET}`);
777
+ }
778
+ writeLine();
779
+ await closeCycleSyncPool();
780
+ } catch (err) {
781
+ writeLine(` ${icons.error} ${colors.red}Postgres sync failed${RESET}`);
782
+ if (process.env.DEBUG) console.error(err);
783
+ writeLine();
784
+ }
785
+ }
786
+ }
787
+ writeLine(` ${colors.dim}$${RESET} squads memory show ${colors.cyan}<squad>${RESET} ${colors.dim}View updated memory${RESET}`);
788
+ writeLine(` ${colors.dim}$${RESET} squads status ${colors.dim}See all squads${RESET}`);
789
+ if (!doPush && updated > 0) {
790
+ writeLine(` ${colors.dim}$${RESET} squads memory sync --push ${colors.dim}Push changes to remote${RESET}`);
791
+ }
792
+ if (!options.postgres) {
793
+ writeLine(` ${colors.dim}$${RESET} squads memory sync --postgres ${colors.dim}Sync to Postgres${RESET}`);
794
+ }
795
+ writeLine();
796
+ }
797
+ export {
798
+ syncCommand
799
+ };
800
+ //# sourceMappingURL=sync-HJZJNXHW.js.map