squads-cli 0.4.8 → 0.4.9
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/dist/{chunk-IDZYXBZY.js → chunk-HIQ2APYR.js} +13 -269
- package/dist/chunk-HIQ2APYR.js.map +1 -0
- package/dist/chunk-HKWCBCEK.js +225 -0
- package/dist/chunk-HKWCBCEK.js.map +1 -0
- package/dist/chunk-NA3IECJA.js +288 -0
- package/dist/chunk-NA3IECJA.js.map +1 -0
- package/dist/cli.js +358 -573
- package/dist/cli.js.map +1 -1
- package/dist/{sessions-B6GVXJ2H.js → sessions-R4VWIGFR.js} +3 -2
- package/dist/terminal-JZSAQSN7.js +53 -0
- package/dist/terminal-JZSAQSN7.js.map +1 -0
- package/dist/update-MAY6EXFQ.js +17 -0
- package/dist/update-MAY6EXFQ.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-IDZYXBZY.js.map +0 -1
- /package/dist/{sessions-B6GVXJ2H.js.map → sessions-R4VWIGFR.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
autoUpdateOnStartup,
|
|
4
|
+
checkForUpdate,
|
|
5
|
+
performUpdate,
|
|
6
|
+
refreshVersionCache
|
|
7
|
+
} from "./chunk-HKWCBCEK.js";
|
|
2
8
|
import {
|
|
3
9
|
appendToMemory,
|
|
4
10
|
findMemoryDir,
|
|
@@ -6,38 +12,40 @@ import {
|
|
|
6
12
|
listMemoryEntries,
|
|
7
13
|
searchMemory
|
|
8
14
|
} from "./chunk-FUHBEL3L.js";
|
|
15
|
+
import {
|
|
16
|
+
cleanupStaleSessions,
|
|
17
|
+
detectSquad,
|
|
18
|
+
getLiveSessionSummaryAsync,
|
|
19
|
+
sessionsCommand,
|
|
20
|
+
sessionsHistoryCommand,
|
|
21
|
+
sessionsSummaryCommand,
|
|
22
|
+
startSession,
|
|
23
|
+
stopSession,
|
|
24
|
+
updateHeartbeat
|
|
25
|
+
} from "./chunk-HIQ2APYR.js";
|
|
9
26
|
import {
|
|
10
27
|
RESET,
|
|
11
28
|
barChart,
|
|
12
29
|
bold,
|
|
13
30
|
box,
|
|
14
|
-
cleanupStaleSessions,
|
|
15
31
|
colors,
|
|
16
|
-
detectSquad,
|
|
17
|
-
getLiveSessionSummaryAsync,
|
|
18
32
|
gradient,
|
|
19
33
|
icons,
|
|
20
34
|
padEnd,
|
|
21
35
|
progressBar,
|
|
22
|
-
sessionsCommand,
|
|
23
|
-
sessionsHistoryCommand,
|
|
24
|
-
sessionsSummaryCommand,
|
|
25
36
|
sparkline,
|
|
26
|
-
startSession,
|
|
27
|
-
stopSession,
|
|
28
37
|
truncate,
|
|
29
|
-
updateHeartbeat,
|
|
30
38
|
writeLine
|
|
31
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-NA3IECJA.js";
|
|
32
40
|
import {
|
|
33
41
|
__require
|
|
34
42
|
} from "./chunk-7OCVIDC7.js";
|
|
35
43
|
|
|
36
44
|
// src/cli.ts
|
|
37
45
|
import { config } from "dotenv";
|
|
38
|
-
import { existsSync as
|
|
39
|
-
import { join as
|
|
40
|
-
import { homedir as
|
|
46
|
+
import { existsSync as existsSync18 } from "fs";
|
|
47
|
+
import { join as join20 } from "path";
|
|
48
|
+
import { homedir as homedir4 } from "os";
|
|
41
49
|
import { Command } from "commander";
|
|
42
50
|
import chalk4 from "chalk";
|
|
43
51
|
|
|
@@ -47,227 +55,18 @@ var require2 = createRequire(import.meta.url);
|
|
|
47
55
|
var pkg = require2("../package.json");
|
|
48
56
|
var version = pkg.version;
|
|
49
57
|
|
|
50
|
-
// src/lib/update.ts
|
|
51
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from "fs";
|
|
52
|
-
import { join, dirname } from "path";
|
|
53
|
-
import { homedir } from "os";
|
|
54
|
-
import { execSync } from "child_process";
|
|
55
|
-
import { fileURLToPath } from "url";
|
|
56
|
-
function getPackageVersion() {
|
|
57
|
-
try {
|
|
58
|
-
const __filename3 = fileURLToPath(import.meta.url);
|
|
59
|
-
const __dirname3 = dirname(__filename3);
|
|
60
|
-
const possiblePaths = [
|
|
61
|
-
join(__dirname3, "..", "..", "package.json"),
|
|
62
|
-
// From dist/lib/
|
|
63
|
-
join(__dirname3, "..", "package.json"),
|
|
64
|
-
// From dist/
|
|
65
|
-
join(__dirname3, "package.json")
|
|
66
|
-
// Same dir
|
|
67
|
-
];
|
|
68
|
-
for (const pkgPath of possiblePaths) {
|
|
69
|
-
if (existsSync(pkgPath)) {
|
|
70
|
-
const pkg2 = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
71
|
-
return pkg2.version || "0.0.0";
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
} catch {
|
|
75
|
-
}
|
|
76
|
-
return "0.0.0";
|
|
77
|
-
}
|
|
78
|
-
var CURRENT_VERSION = getPackageVersion();
|
|
79
|
-
var CACHE_DIR = join(homedir(), ".squads");
|
|
80
|
-
var CACHE_FILE = join(CACHE_DIR, "update-check.json");
|
|
81
|
-
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
82
|
-
function isNewerVersion(v1, v2) {
|
|
83
|
-
const parts1 = v1.replace(/^v/, "").split(".").map(Number);
|
|
84
|
-
const parts2 = v2.replace(/^v/, "").split(".").map(Number);
|
|
85
|
-
for (let i = 0; i < 3; i++) {
|
|
86
|
-
const p1 = parts1[i] || 0;
|
|
87
|
-
const p2 = parts2[i] || 0;
|
|
88
|
-
if (p2 > p1) return true;
|
|
89
|
-
if (p2 < p1) return false;
|
|
90
|
-
}
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
function readCache() {
|
|
94
|
-
try {
|
|
95
|
-
if (!existsSync(CACHE_FILE)) return null;
|
|
96
|
-
const data = JSON.parse(readFileSync(CACHE_FILE, "utf-8"));
|
|
97
|
-
return data;
|
|
98
|
-
} catch {
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
function writeCache(latestVersion) {
|
|
103
|
-
try {
|
|
104
|
-
if (!existsSync(CACHE_DIR)) {
|
|
105
|
-
mkdirSync(CACHE_DIR, { recursive: true });
|
|
106
|
-
}
|
|
107
|
-
const cache = {
|
|
108
|
-
latestVersion,
|
|
109
|
-
checkedAt: Date.now()
|
|
110
|
-
};
|
|
111
|
-
writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
112
|
-
} catch {
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
function fetchLatestVersion() {
|
|
116
|
-
try {
|
|
117
|
-
const result = execSync("npm view squads-cli version 2>/dev/null", {
|
|
118
|
-
encoding: "utf-8",
|
|
119
|
-
timeout: 5e3
|
|
120
|
-
}).trim();
|
|
121
|
-
return result || null;
|
|
122
|
-
} catch {
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
function checkForUpdate() {
|
|
127
|
-
const result = {
|
|
128
|
-
currentVersion: CURRENT_VERSION,
|
|
129
|
-
latestVersion: CURRENT_VERSION,
|
|
130
|
-
updateAvailable: false
|
|
131
|
-
};
|
|
132
|
-
const cache = readCache();
|
|
133
|
-
const now = Date.now();
|
|
134
|
-
if (cache) {
|
|
135
|
-
result.latestVersion = cache.latestVersion;
|
|
136
|
-
result.updateAvailable = isNewerVersion(CURRENT_VERSION, cache.latestVersion);
|
|
137
|
-
if (now - cache.checkedAt >= CACHE_TTL_MS) {
|
|
138
|
-
triggerBackgroundRefresh();
|
|
139
|
-
}
|
|
140
|
-
return result;
|
|
141
|
-
}
|
|
142
|
-
triggerBackgroundRefresh();
|
|
143
|
-
return result;
|
|
144
|
-
}
|
|
145
|
-
function triggerBackgroundRefresh() {
|
|
146
|
-
try {
|
|
147
|
-
const { spawn: spawn8 } = __require("child_process");
|
|
148
|
-
const child = spawn8("npm", ["view", "squads-cli", "version"], {
|
|
149
|
-
detached: true,
|
|
150
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
151
|
-
shell: true
|
|
152
|
-
});
|
|
153
|
-
let output = "";
|
|
154
|
-
child.stdout?.on("data", (data) => {
|
|
155
|
-
output += data.toString();
|
|
156
|
-
});
|
|
157
|
-
child.on("close", () => {
|
|
158
|
-
const version2 = output.trim();
|
|
159
|
-
if (version2 && /^\d+\.\d+\.\d+/.test(version2)) {
|
|
160
|
-
writeCache(version2);
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
child.unref();
|
|
164
|
-
} catch {
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
function performUpdate() {
|
|
168
|
-
try {
|
|
169
|
-
execSync("npm update -g squads-cli", {
|
|
170
|
-
encoding: "utf-8",
|
|
171
|
-
stdio: "inherit",
|
|
172
|
-
timeout: 12e4
|
|
173
|
-
// 2 minutes
|
|
174
|
-
});
|
|
175
|
-
try {
|
|
176
|
-
unlinkSync(CACHE_FILE);
|
|
177
|
-
} catch {
|
|
178
|
-
}
|
|
179
|
-
return { success: true };
|
|
180
|
-
} catch (err) {
|
|
181
|
-
return {
|
|
182
|
-
success: false,
|
|
183
|
-
error: err instanceof Error ? err.message : "Unknown error"
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
function refreshVersionCache() {
|
|
188
|
-
const latestVersion = fetchLatestVersion();
|
|
189
|
-
if (latestVersion) {
|
|
190
|
-
writeCache(latestVersion);
|
|
191
|
-
return {
|
|
192
|
-
currentVersion: CURRENT_VERSION,
|
|
193
|
-
latestVersion,
|
|
194
|
-
updateAvailable: isNewerVersion(CURRENT_VERSION, latestVersion)
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
return checkForUpdate();
|
|
198
|
-
}
|
|
199
|
-
var AUTO_UPDATE_CACHE_FILE = join(CACHE_DIR, "auto-update.json");
|
|
200
|
-
var AUTO_UPDATE_COOLDOWN_MS = 60 * 60 * 1e3;
|
|
201
|
-
function readAutoUpdateCache() {
|
|
202
|
-
try {
|
|
203
|
-
if (!existsSync(AUTO_UPDATE_CACHE_FILE)) return null;
|
|
204
|
-
return JSON.parse(readFileSync(AUTO_UPDATE_CACHE_FILE, "utf-8"));
|
|
205
|
-
} catch {
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
function writeAutoUpdateCache(cache) {
|
|
210
|
-
try {
|
|
211
|
-
if (!existsSync(CACHE_DIR)) {
|
|
212
|
-
mkdirSync(CACHE_DIR, { recursive: true });
|
|
213
|
-
}
|
|
214
|
-
writeFileSync(AUTO_UPDATE_CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
215
|
-
} catch {
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
async function autoUpdateOnStartup(silent = false) {
|
|
219
|
-
if (process.env.CI || process.env.SQUADS_NO_AUTO_UPDATE) return;
|
|
220
|
-
const autoCache = readAutoUpdateCache();
|
|
221
|
-
const now = Date.now();
|
|
222
|
-
if (autoCache && now - autoCache.lastAttempt < AUTO_UPDATE_COOLDOWN_MS) {
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
const info = checkForUpdate();
|
|
226
|
-
if (!info.updateAvailable) return;
|
|
227
|
-
writeAutoUpdateCache({ lastAttempt: now, lastSuccess: autoCache?.lastSuccess });
|
|
228
|
-
try {
|
|
229
|
-
const { spawn: spawn8 } = await import("child_process");
|
|
230
|
-
const child = spawn8("npm", ["update", "-g", "squads-cli"], {
|
|
231
|
-
detached: true,
|
|
232
|
-
stdio: silent ? "ignore" : ["ignore", "pipe", "pipe"],
|
|
233
|
-
shell: true
|
|
234
|
-
});
|
|
235
|
-
if (!silent && child.stdout) {
|
|
236
|
-
await new Promise((resolve) => {
|
|
237
|
-
child.on("close", (code) => {
|
|
238
|
-
if (code === 0) {
|
|
239
|
-
console.log(`
|
|
240
|
-
\x1B[32m\u2713\x1B[0m Update successful! v${info.latestVersion} will be used on your next run.
|
|
241
|
-
`);
|
|
242
|
-
writeAutoUpdateCache({ lastAttempt: now, lastSuccess: now });
|
|
243
|
-
try {
|
|
244
|
-
unlinkSync(CACHE_FILE);
|
|
245
|
-
} catch {
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
resolve();
|
|
249
|
-
});
|
|
250
|
-
setTimeout(() => resolve(), 3e4);
|
|
251
|
-
});
|
|
252
|
-
} else {
|
|
253
|
-
child.unref();
|
|
254
|
-
}
|
|
255
|
-
} catch {
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
58
|
// src/commands/init.ts
|
|
260
59
|
import chalk from "chalk";
|
|
261
60
|
import ora from "ora";
|
|
262
61
|
import fs from "fs/promises";
|
|
263
62
|
import path from "path";
|
|
264
|
-
import { execSync as
|
|
63
|
+
import { execSync as execSync2, spawn } from "child_process";
|
|
265
64
|
import { createInterface } from "readline";
|
|
266
65
|
|
|
267
66
|
// src/lib/git.ts
|
|
268
|
-
import { execSync
|
|
269
|
-
import { existsSync
|
|
270
|
-
import { join
|
|
67
|
+
import { execSync, exec } from "child_process";
|
|
68
|
+
import { existsSync } from "fs";
|
|
69
|
+
import { join } from "path";
|
|
271
70
|
import { promisify } from "util";
|
|
272
71
|
var execAsync = promisify(exec);
|
|
273
72
|
function checkGitStatus(cwd = process.cwd()) {
|
|
@@ -277,12 +76,12 @@ function checkGitStatus(cwd = process.cwd()) {
|
|
|
277
76
|
isDirty: false,
|
|
278
77
|
uncommittedCount: 0
|
|
279
78
|
};
|
|
280
|
-
if (!
|
|
79
|
+
if (!existsSync(join(cwd, ".git"))) {
|
|
281
80
|
return status;
|
|
282
81
|
}
|
|
283
82
|
status.isGitRepo = true;
|
|
284
83
|
try {
|
|
285
|
-
const combined =
|
|
84
|
+
const combined = execSync(
|
|
286
85
|
'echo "BRANCH:" && git rev-parse --abbrev-ref HEAD && echo "REMOTES:" && git remote -v && echo "STATUS:" && git status --porcelain',
|
|
287
86
|
{ cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }
|
|
288
87
|
);
|
|
@@ -366,10 +165,10 @@ function getGitHubStatsOptimized(basePath, days = 30) {
|
|
|
366
165
|
const since = new Date(Date.now() - days * 24 * 60 * 60 * 1e3).toISOString();
|
|
367
166
|
const results = [];
|
|
368
167
|
for (const repo of repos) {
|
|
369
|
-
const repoPath =
|
|
370
|
-
if (!
|
|
168
|
+
const repoPath = join(basePath, repo);
|
|
169
|
+
if (!existsSync(repoPath)) continue;
|
|
371
170
|
try {
|
|
372
|
-
const output =
|
|
171
|
+
const output = execSync(
|
|
373
172
|
`echo '{"prs":' && gh pr list --state all --json number,title,createdAt,mergedAt,labels --limit 50 2>/dev/null && echo ',"issues":' && gh issue list --state all --json number,title,state,closedAt,labels --limit 50 2>/dev/null && echo '}'`,
|
|
374
173
|
{ cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 1e4 }
|
|
375
174
|
);
|
|
@@ -380,11 +179,11 @@ function getGitHubStatsOptimized(basePath, days = 30) {
|
|
|
380
179
|
results.push({ repo, prs, issues });
|
|
381
180
|
} catch {
|
|
382
181
|
try {
|
|
383
|
-
const prsOutput =
|
|
182
|
+
const prsOutput = execSync(
|
|
384
183
|
`gh pr list --state all --json number,title,createdAt,mergedAt,labels --limit 50 2>/dev/null`,
|
|
385
184
|
{ cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }
|
|
386
185
|
);
|
|
387
|
-
const issuesOutput =
|
|
186
|
+
const issuesOutput = execSync(
|
|
388
187
|
`gh issue list --state all --json number,title,state,closedAt,labels --limit 50 2>/dev/null`,
|
|
389
188
|
{ cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }
|
|
390
189
|
);
|
|
@@ -500,12 +299,12 @@ function getMultiRepoGitStats(basePath, days = 30) {
|
|
|
500
299
|
};
|
|
501
300
|
const allCommits = [];
|
|
502
301
|
for (const repo of SQUAD_REPOS) {
|
|
503
|
-
const repoPath =
|
|
504
|
-
if (!
|
|
302
|
+
const repoPath = join(basePath, repo);
|
|
303
|
+
if (!existsSync(repoPath) || !existsSync(join(repoPath, ".git"))) {
|
|
505
304
|
continue;
|
|
506
305
|
}
|
|
507
306
|
try {
|
|
508
|
-
const logOutput =
|
|
307
|
+
const logOutput = execSync(
|
|
509
308
|
`git log --since="${days} days ago" --format="%H|%aN|%ad|%s" --date=short 2>/dev/null`,
|
|
510
309
|
{ cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
511
310
|
).trim();
|
|
@@ -562,12 +361,12 @@ function getActivitySparkline(basePath, days = 7) {
|
|
|
562
361
|
activity.push(0);
|
|
563
362
|
}
|
|
564
363
|
for (const repo of SQUAD_REPOS) {
|
|
565
|
-
const repoPath =
|
|
566
|
-
if (!
|
|
364
|
+
const repoPath = join(basePath, repo);
|
|
365
|
+
if (!existsSync(repoPath) || !existsSync(join(repoPath, ".git"))) {
|
|
567
366
|
continue;
|
|
568
367
|
}
|
|
569
368
|
try {
|
|
570
|
-
const logOutput =
|
|
369
|
+
const logOutput = execSync(
|
|
571
370
|
`git log --since="${days} days ago" --format="%ad" --date=short 2>/dev/null`,
|
|
572
371
|
{ cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
573
372
|
).trim();
|
|
@@ -587,13 +386,13 @@ function getActivitySparkline(basePath, days = 7) {
|
|
|
587
386
|
}
|
|
588
387
|
|
|
589
388
|
// src/lib/telemetry.ts
|
|
590
|
-
import { existsSync as
|
|
591
|
-
import { join as
|
|
592
|
-
import { homedir
|
|
389
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
390
|
+
import { join as join2 } from "path";
|
|
391
|
+
import { homedir } from "os";
|
|
593
392
|
import { randomUUID } from "crypto";
|
|
594
|
-
var TELEMETRY_DIR =
|
|
595
|
-
var CONFIG_PATH =
|
|
596
|
-
var EVENTS_PATH =
|
|
393
|
+
var TELEMETRY_DIR = join2(homedir(), ".squads-cli");
|
|
394
|
+
var CONFIG_PATH = join2(TELEMETRY_DIR, "telemetry.json");
|
|
395
|
+
var EVENTS_PATH = join2(TELEMETRY_DIR, "events.json");
|
|
597
396
|
var TELEMETRY_ENDPOINT = Buffer.from(
|
|
598
397
|
"aHR0cHM6Ly9zcXVhZHMtdGVsZW1ldHJ5LTk3ODg3MTgxNzYxMC51cy1jZW50cmFsMS5ydW4uYXBwL3Bpbmc=",
|
|
599
398
|
"base64"
|
|
@@ -602,24 +401,24 @@ var TELEMETRY_KEY = Buffer.from("c3FfdGVsX3YxXzdmOGE5YjJjM2Q0ZTVmNmE=", "base64"
|
|
|
602
401
|
var eventQueue = [];
|
|
603
402
|
var flushScheduled = false;
|
|
604
403
|
function ensureDir() {
|
|
605
|
-
if (!
|
|
606
|
-
|
|
404
|
+
if (!existsSync2(TELEMETRY_DIR)) {
|
|
405
|
+
mkdirSync(TELEMETRY_DIR, { recursive: true });
|
|
607
406
|
}
|
|
608
407
|
}
|
|
609
408
|
function getConfig() {
|
|
610
409
|
ensureDir();
|
|
611
|
-
if (!
|
|
410
|
+
if (!existsSync2(CONFIG_PATH)) {
|
|
612
411
|
const config2 = {
|
|
613
412
|
enabled: true,
|
|
614
413
|
// Opt-out by default (common for CLIs)
|
|
615
414
|
anonymousId: randomUUID(),
|
|
616
415
|
firstRun: (/* @__PURE__ */ new Date()).toISOString()
|
|
617
416
|
};
|
|
618
|
-
|
|
417
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config2, null, 2));
|
|
619
418
|
return config2;
|
|
620
419
|
}
|
|
621
420
|
try {
|
|
622
|
-
return JSON.parse(
|
|
421
|
+
return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
623
422
|
} catch {
|
|
624
423
|
return { enabled: false, anonymousId: "", firstRun: "" };
|
|
625
424
|
}
|
|
@@ -679,9 +478,9 @@ async function flushEvents() {
|
|
|
679
478
|
function storeEventLocally(event) {
|
|
680
479
|
ensureDir();
|
|
681
480
|
let events = [];
|
|
682
|
-
if (
|
|
481
|
+
if (existsSync2(EVENTS_PATH)) {
|
|
683
482
|
try {
|
|
684
|
-
events = JSON.parse(
|
|
483
|
+
events = JSON.parse(readFileSync(EVENTS_PATH, "utf-8"));
|
|
685
484
|
} catch {
|
|
686
485
|
events = [];
|
|
687
486
|
}
|
|
@@ -690,7 +489,7 @@ function storeEventLocally(event) {
|
|
|
690
489
|
if (events.length > 1e3) {
|
|
691
490
|
events = events.slice(-1e3);
|
|
692
491
|
}
|
|
693
|
-
|
|
492
|
+
writeFileSync(EVENTS_PATH, JSON.stringify(events, null, 2));
|
|
694
493
|
}
|
|
695
494
|
var Events = {
|
|
696
495
|
// Lifecycle
|
|
@@ -787,7 +586,7 @@ async function promptEmail() {
|
|
|
787
586
|
}
|
|
788
587
|
function commandExists(cmd) {
|
|
789
588
|
try {
|
|
790
|
-
|
|
589
|
+
execSync2(`which ${cmd}`, { stdio: "ignore" });
|
|
791
590
|
return true;
|
|
792
591
|
} catch {
|
|
793
592
|
return false;
|
|
@@ -795,7 +594,7 @@ function commandExists(cmd) {
|
|
|
795
594
|
}
|
|
796
595
|
function dockerRunning() {
|
|
797
596
|
try {
|
|
798
|
-
|
|
597
|
+
execSync2("docker info", { stdio: "ignore" });
|
|
799
598
|
return true;
|
|
800
599
|
} catch {
|
|
801
600
|
return false;
|
|
@@ -803,12 +602,12 @@ function dockerRunning() {
|
|
|
803
602
|
}
|
|
804
603
|
function checkClaudeAuth() {
|
|
805
604
|
try {
|
|
806
|
-
|
|
605
|
+
execSync2("which claude", { stdio: "ignore" });
|
|
807
606
|
} catch {
|
|
808
607
|
return { installed: false, loggedIn: false };
|
|
809
608
|
}
|
|
810
609
|
try {
|
|
811
|
-
const result =
|
|
610
|
+
const result = execSync2("claude --version", { stdio: "pipe" }).toString();
|
|
812
611
|
return { installed: true, loggedIn: result.includes("claude") };
|
|
813
612
|
} catch {
|
|
814
613
|
return { installed: true, loggedIn: false };
|
|
@@ -816,7 +615,7 @@ function checkClaudeAuth() {
|
|
|
816
615
|
}
|
|
817
616
|
function checkGhAuth() {
|
|
818
617
|
try {
|
|
819
|
-
|
|
618
|
+
execSync2("gh auth status", { stdio: "ignore" });
|
|
820
619
|
return true;
|
|
821
620
|
} catch {
|
|
822
621
|
return false;
|
|
@@ -953,7 +752,7 @@ async function setupInfrastructure(cwd) {
|
|
|
953
752
|
let allRunning = true;
|
|
954
753
|
for (const service of services) {
|
|
955
754
|
try {
|
|
956
|
-
|
|
755
|
+
execSync2(`docker ps --filter "name=${service}" --filter "status=running" -q`, { stdio: "pipe" });
|
|
957
756
|
} catch {
|
|
958
757
|
allRunning = false;
|
|
959
758
|
}
|
|
@@ -1365,21 +1164,21 @@ squads goal list # View goals
|
|
|
1365
1164
|
// src/commands/run.ts
|
|
1366
1165
|
import ora2 from "ora";
|
|
1367
1166
|
import { spawn as spawn2 } from "child_process";
|
|
1368
|
-
import { join as
|
|
1369
|
-
import { existsSync as
|
|
1167
|
+
import { join as join4, dirname } from "path";
|
|
1168
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
1370
1169
|
|
|
1371
1170
|
// src/lib/squad-parser.ts
|
|
1372
|
-
import { readFileSync as
|
|
1373
|
-
import { join as
|
|
1171
|
+
import { readFileSync as readFileSync2, existsSync as existsSync3, readdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1172
|
+
import { join as join3, basename } from "path";
|
|
1374
1173
|
import matter from "gray-matter";
|
|
1375
1174
|
function findSquadsDir() {
|
|
1376
1175
|
let dir = process.cwd();
|
|
1377
1176
|
for (let i = 0; i < 5; i++) {
|
|
1378
|
-
const squadsPath =
|
|
1379
|
-
if (
|
|
1177
|
+
const squadsPath = join3(dir, ".agents", "squads");
|
|
1178
|
+
if (existsSync3(squadsPath)) {
|
|
1380
1179
|
return squadsPath;
|
|
1381
1180
|
}
|
|
1382
|
-
const parent =
|
|
1181
|
+
const parent = join3(dir, "..");
|
|
1383
1182
|
if (parent === dir) break;
|
|
1384
1183
|
dir = parent;
|
|
1385
1184
|
}
|
|
@@ -1388,14 +1187,14 @@ function findSquadsDir() {
|
|
|
1388
1187
|
function findProjectRoot() {
|
|
1389
1188
|
const squadsDir = findSquadsDir();
|
|
1390
1189
|
if (!squadsDir) return null;
|
|
1391
|
-
return
|
|
1190
|
+
return join3(squadsDir, "..", "..");
|
|
1392
1191
|
}
|
|
1393
1192
|
function hasLocalInfraConfig() {
|
|
1394
1193
|
const projectRoot = findProjectRoot();
|
|
1395
1194
|
if (!projectRoot) return false;
|
|
1396
|
-
const envPath =
|
|
1397
|
-
if (!
|
|
1398
|
-
const content =
|
|
1195
|
+
const envPath = join3(projectRoot, ".env");
|
|
1196
|
+
if (!existsSync3(envPath)) return false;
|
|
1197
|
+
const content = readFileSync2(envPath, "utf-8");
|
|
1399
1198
|
const infraKeys = ["LANGFUSE_", "SQUADS_BRIDGE", "SQUADS_POSTGRES", "SQUADS_REDIS"];
|
|
1400
1199
|
return infraKeys.some((key) => content.includes(key));
|
|
1401
1200
|
}
|
|
@@ -1404,8 +1203,8 @@ function listSquads(squadsDir) {
|
|
|
1404
1203
|
const entries = readdirSync(squadsDir, { withFileTypes: true });
|
|
1405
1204
|
for (const entry of entries) {
|
|
1406
1205
|
if (entry.isDirectory() && !entry.name.startsWith("_")) {
|
|
1407
|
-
const squadFile =
|
|
1408
|
-
if (
|
|
1206
|
+
const squadFile = join3(squadsDir, entry.name, "SQUAD.md");
|
|
1207
|
+
if (existsSync3(squadFile)) {
|
|
1409
1208
|
squads.push(entry.name);
|
|
1410
1209
|
}
|
|
1411
1210
|
}
|
|
@@ -1416,8 +1215,8 @@ function listAgents(squadsDir, squadName) {
|
|
|
1416
1215
|
const agents = [];
|
|
1417
1216
|
const dirs = squadName ? [squadName] : readdirSync(squadsDir, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith("_")).map((e) => e.name);
|
|
1418
1217
|
for (const dir of dirs) {
|
|
1419
|
-
const squadPath =
|
|
1420
|
-
if (!
|
|
1218
|
+
const squadPath = join3(squadsDir, dir);
|
|
1219
|
+
if (!existsSync3(squadPath)) continue;
|
|
1421
1220
|
const files = readdirSync(squadPath);
|
|
1422
1221
|
for (const file of files) {
|
|
1423
1222
|
if (file.endsWith(".md") && file !== "SQUAD.md") {
|
|
@@ -1426,7 +1225,7 @@ function listAgents(squadsDir, squadName) {
|
|
|
1426
1225
|
name: agentName,
|
|
1427
1226
|
role: `Agent in ${dir}`,
|
|
1428
1227
|
trigger: "manual",
|
|
1429
|
-
filePath:
|
|
1228
|
+
filePath: join3(squadPath, file)
|
|
1430
1229
|
});
|
|
1431
1230
|
}
|
|
1432
1231
|
}
|
|
@@ -1434,7 +1233,7 @@ function listAgents(squadsDir, squadName) {
|
|
|
1434
1233
|
return agents;
|
|
1435
1234
|
}
|
|
1436
1235
|
function parseSquadFile(filePath) {
|
|
1437
|
-
const rawContent =
|
|
1236
|
+
const rawContent = readFileSync2(filePath, "utf-8");
|
|
1438
1237
|
const { data: frontmatter, content: bodyContent } = matter(rawContent);
|
|
1439
1238
|
const fm = frontmatter;
|
|
1440
1239
|
const lines = bodyContent.split("\n");
|
|
@@ -1555,20 +1354,20 @@ function parseSquadFile(filePath) {
|
|
|
1555
1354
|
function loadSquad(squadName) {
|
|
1556
1355
|
const squadsDir = findSquadsDir();
|
|
1557
1356
|
if (!squadsDir) return null;
|
|
1558
|
-
const squadFile =
|
|
1559
|
-
if (!
|
|
1357
|
+
const squadFile = join3(squadsDir, squadName, "SQUAD.md");
|
|
1358
|
+
if (!existsSync3(squadFile)) return null;
|
|
1560
1359
|
return parseSquadFile(squadFile);
|
|
1561
1360
|
}
|
|
1562
1361
|
function loadAgentDefinition(agentPath) {
|
|
1563
|
-
if (!
|
|
1564
|
-
return
|
|
1362
|
+
if (!existsSync3(agentPath)) return "";
|
|
1363
|
+
return readFileSync2(agentPath, "utf-8");
|
|
1565
1364
|
}
|
|
1566
1365
|
function addGoalToSquad(squadName, goal2) {
|
|
1567
1366
|
const squadsDir = findSquadsDir();
|
|
1568
1367
|
if (!squadsDir) return false;
|
|
1569
|
-
const squadFile =
|
|
1570
|
-
if (!
|
|
1571
|
-
let content =
|
|
1368
|
+
const squadFile = join3(squadsDir, squadName, "SQUAD.md");
|
|
1369
|
+
if (!existsSync3(squadFile)) return false;
|
|
1370
|
+
let content = readFileSync2(squadFile, "utf-8");
|
|
1572
1371
|
if (!content.includes("## Goals")) {
|
|
1573
1372
|
const insertPoint = content.indexOf("## Dependencies");
|
|
1574
1373
|
if (insertPoint > 0) {
|
|
@@ -1603,15 +1402,15 @@ function addGoalToSquad(squadName, goal2) {
|
|
|
1603
1402
|
- [ ] ${goal2}` + content.slice(headerEnd);
|
|
1604
1403
|
}
|
|
1605
1404
|
}
|
|
1606
|
-
|
|
1405
|
+
writeFileSync2(squadFile, content);
|
|
1607
1406
|
return true;
|
|
1608
1407
|
}
|
|
1609
1408
|
function updateGoalInSquad(squadName, goalIndex, updates) {
|
|
1610
1409
|
const squadsDir = findSquadsDir();
|
|
1611
1410
|
if (!squadsDir) return false;
|
|
1612
|
-
const squadFile =
|
|
1613
|
-
if (!
|
|
1614
|
-
const content =
|
|
1411
|
+
const squadFile = join3(squadsDir, squadName, "SQUAD.md");
|
|
1412
|
+
if (!existsSync3(squadFile)) return false;
|
|
1413
|
+
const content = readFileSync2(squadFile, "utf-8");
|
|
1615
1414
|
const lines = content.split("\n");
|
|
1616
1415
|
let currentSection = "";
|
|
1617
1416
|
let goalCount = 0;
|
|
@@ -1633,7 +1432,7 @@ function updateGoalInSquad(squadName, goalIndex, updates) {
|
|
|
1633
1432
|
}
|
|
1634
1433
|
}
|
|
1635
1434
|
lines[i] = newLine;
|
|
1636
|
-
|
|
1435
|
+
writeFileSync2(squadFile, lines.join("\n"));
|
|
1637
1436
|
return true;
|
|
1638
1437
|
}
|
|
1639
1438
|
goalCount++;
|
|
@@ -1882,7 +1681,7 @@ function generateExecutionId() {
|
|
|
1882
1681
|
}
|
|
1883
1682
|
function selectMcpConfig(squadName) {
|
|
1884
1683
|
const home = process.env.HOME || "";
|
|
1885
|
-
const configsDir =
|
|
1684
|
+
const configsDir = join4(home, ".claude", "mcp-configs");
|
|
1886
1685
|
const squadConfigs = {
|
|
1887
1686
|
website: "website.json",
|
|
1888
1687
|
// chrome-devtools, nano-banana
|
|
@@ -1897,12 +1696,12 @@ function selectMcpConfig(squadName) {
|
|
|
1897
1696
|
};
|
|
1898
1697
|
const configFile = squadConfigs[squadName.toLowerCase()];
|
|
1899
1698
|
if (configFile) {
|
|
1900
|
-
const configPath =
|
|
1901
|
-
if (
|
|
1699
|
+
const configPath = join4(configsDir, configFile);
|
|
1700
|
+
if (existsSync4(configPath)) {
|
|
1902
1701
|
return configPath;
|
|
1903
1702
|
}
|
|
1904
1703
|
}
|
|
1905
|
-
return
|
|
1704
|
+
return join4(home, ".claude.json");
|
|
1906
1705
|
}
|
|
1907
1706
|
function detectTaskType(agentName) {
|
|
1908
1707
|
const name = agentName.toLowerCase();
|
|
@@ -1918,12 +1717,12 @@ function detectTaskType(agentName) {
|
|
|
1918
1717
|
return "execution";
|
|
1919
1718
|
}
|
|
1920
1719
|
function ensureProjectTrusted(projectPath) {
|
|
1921
|
-
const configPath =
|
|
1922
|
-
if (!
|
|
1720
|
+
const configPath = join4(process.env.HOME || "", ".claude.json");
|
|
1721
|
+
if (!existsSync4(configPath)) {
|
|
1923
1722
|
return;
|
|
1924
1723
|
}
|
|
1925
1724
|
try {
|
|
1926
|
-
const config2 = JSON.parse(
|
|
1725
|
+
const config2 = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
1927
1726
|
if (!config2.projects) {
|
|
1928
1727
|
config2.projects = {};
|
|
1929
1728
|
}
|
|
@@ -1932,7 +1731,7 @@ function ensureProjectTrusted(projectPath) {
|
|
|
1932
1731
|
}
|
|
1933
1732
|
if (!config2.projects[projectPath].hasTrustDialogAccepted) {
|
|
1934
1733
|
config2.projects[projectPath].hasTrustDialogAccepted = true;
|
|
1935
|
-
|
|
1734
|
+
writeFileSync3(configPath, JSON.stringify(config2, null, 2));
|
|
1936
1735
|
}
|
|
1937
1736
|
} catch {
|
|
1938
1737
|
}
|
|
@@ -1940,25 +1739,25 @@ function ensureProjectTrusted(projectPath) {
|
|
|
1940
1739
|
function getProjectRoot() {
|
|
1941
1740
|
const squadsDir = findSquadsDir();
|
|
1942
1741
|
if (squadsDir) {
|
|
1943
|
-
return
|
|
1742
|
+
return dirname(dirname(squadsDir));
|
|
1944
1743
|
}
|
|
1945
1744
|
return process.cwd();
|
|
1946
1745
|
}
|
|
1947
1746
|
function getExecutionLogPath(squadName, agentName) {
|
|
1948
1747
|
const memoryDir = findMemoryDir();
|
|
1949
1748
|
if (!memoryDir) return null;
|
|
1950
|
-
return
|
|
1749
|
+
return join4(memoryDir, squadName, agentName, "executions.md");
|
|
1951
1750
|
}
|
|
1952
1751
|
function logExecution(record) {
|
|
1953
1752
|
const logPath = getExecutionLogPath(record.squadName, record.agentName);
|
|
1954
1753
|
if (!logPath) return;
|
|
1955
|
-
const dir =
|
|
1956
|
-
if (!
|
|
1957
|
-
|
|
1754
|
+
const dir = dirname(logPath);
|
|
1755
|
+
if (!existsSync4(dir)) {
|
|
1756
|
+
mkdirSync2(dir, { recursive: true });
|
|
1958
1757
|
}
|
|
1959
1758
|
let content = "";
|
|
1960
|
-
if (
|
|
1961
|
-
content =
|
|
1759
|
+
if (existsSync4(logPath)) {
|
|
1760
|
+
content = readFileSync3(logPath, "utf-8").trimEnd();
|
|
1962
1761
|
} else {
|
|
1963
1762
|
content = `# ${record.squadName}/${record.agentName} - Execution Log`;
|
|
1964
1763
|
}
|
|
@@ -1971,12 +1770,12 @@ function logExecution(record) {
|
|
|
1971
1770
|
- Trigger: ${record.trigger || "manual"}
|
|
1972
1771
|
- Task Type: ${record.taskType || "execution"}
|
|
1973
1772
|
`;
|
|
1974
|
-
|
|
1773
|
+
writeFileSync3(logPath, content + entry);
|
|
1975
1774
|
}
|
|
1976
1775
|
function updateExecutionStatus(squadName, agentName, executionId, status, details) {
|
|
1977
1776
|
const logPath = getExecutionLogPath(squadName, agentName);
|
|
1978
|
-
if (!logPath || !
|
|
1979
|
-
let content =
|
|
1777
|
+
if (!logPath || !existsSync4(logPath)) return;
|
|
1778
|
+
let content = readFileSync3(logPath, "utf-8");
|
|
1980
1779
|
const endTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
1981
1780
|
const execMarker = `<!-- exec:${executionId} -->`;
|
|
1982
1781
|
const markerIndex = content.indexOf(execMarker);
|
|
@@ -1997,7 +1796,7 @@ function updateExecutionStatus(squadName, agentName, executionId, status, detail
|
|
|
1997
1796
|
- Error: ${details.error}`;
|
|
1998
1797
|
}
|
|
1999
1798
|
content = content.slice(0, entryStart) + updatedEntry + content.slice(entryEnd);
|
|
2000
|
-
|
|
1799
|
+
writeFileSync3(logPath, content);
|
|
2001
1800
|
}
|
|
2002
1801
|
function extractMcpServersFromDefinition(definition) {
|
|
2003
1802
|
const servers = /* @__PURE__ */ new Set();
|
|
@@ -2076,8 +1875,8 @@ async function runSquad(squad, squadsDir, options) {
|
|
|
2076
1875
|
if (options.parallel) {
|
|
2077
1876
|
const agentFiles = squad.agents.map((a) => ({
|
|
2078
1877
|
name: a.name,
|
|
2079
|
-
path:
|
|
2080
|
-
})).filter((a) =>
|
|
1878
|
+
path: join4(squadsDir, squad.name, `${a.name}.md`)
|
|
1879
|
+
})).filter((a) => existsSync4(a.path));
|
|
2081
1880
|
if (agentFiles.length === 0) {
|
|
2082
1881
|
writeLine(` ${icons.error} ${colors.red}No agent files found${RESET}`);
|
|
2083
1882
|
return;
|
|
@@ -2113,8 +1912,8 @@ async function runSquad(squad, squadsDir, options) {
|
|
|
2113
1912
|
writeLine();
|
|
2114
1913
|
for (let i = 0; i < pipeline.agents.length; i++) {
|
|
2115
1914
|
const agentName = pipeline.agents[i];
|
|
2116
|
-
const agentPath =
|
|
2117
|
-
if (
|
|
1915
|
+
const agentPath = join4(squadsDir, squad.name, `${agentName}.md`);
|
|
1916
|
+
if (existsSync4(agentPath)) {
|
|
2118
1917
|
writeLine(` ${colors.dim}[${i + 1}/${pipeline.agents.length}]${RESET}`);
|
|
2119
1918
|
await runAgent(agentName, agentPath, squad.name, options);
|
|
2120
1919
|
writeLine();
|
|
@@ -2124,8 +1923,8 @@ async function runSquad(squad, squadsDir, options) {
|
|
|
2124
1923
|
}
|
|
2125
1924
|
} else {
|
|
2126
1925
|
if (options.agent) {
|
|
2127
|
-
const agentPath =
|
|
2128
|
-
if (
|
|
1926
|
+
const agentPath = join4(squadsDir, squad.name, `${options.agent}.md`);
|
|
1927
|
+
if (existsSync4(agentPath)) {
|
|
2129
1928
|
await runAgent(options.agent, agentPath, squad.name, options);
|
|
2130
1929
|
} else {
|
|
2131
1930
|
writeLine(` ${icons.error} ${colors.red}Agent ${options.agent} not found${RESET}`);
|
|
@@ -2136,8 +1935,8 @@ async function runSquad(squad, squadsDir, options) {
|
|
|
2136
1935
|
(a) => a.name.includes("lead") || a.trigger === "Manual"
|
|
2137
1936
|
);
|
|
2138
1937
|
if (orchestrator) {
|
|
2139
|
-
const agentPath =
|
|
2140
|
-
if (
|
|
1938
|
+
const agentPath = join4(squadsDir, squad.name, `${orchestrator.name}.md`);
|
|
1939
|
+
if (existsSync4(agentPath)) {
|
|
2141
1940
|
await runAgent(orchestrator.name, agentPath, squad.name, options);
|
|
2142
1941
|
}
|
|
2143
1942
|
} else {
|
|
@@ -2163,9 +1962,9 @@ async function runLeadMode(squad, squadsDir, options) {
|
|
|
2163
1962
|
if (!squad) return;
|
|
2164
1963
|
const agentFiles = squad.agents.map((a) => ({
|
|
2165
1964
|
name: a.name,
|
|
2166
|
-
path:
|
|
1965
|
+
path: join4(squadsDir, squad.name, `${a.name}.md`),
|
|
2167
1966
|
role: a.role || ""
|
|
2168
|
-
})).filter((a) =>
|
|
1967
|
+
})).filter((a) => existsSync4(a.path));
|
|
2169
1968
|
if (agentFiles.length === 0) {
|
|
2170
1969
|
writeLine(` ${icons.error} ${colors.red}No agent files found${RESET}`);
|
|
2171
1970
|
return;
|
|
@@ -2284,9 +2083,9 @@ async function runAgent(agentName, agentPath, squadName, options) {
|
|
|
2284
2083
|
}
|
|
2285
2084
|
const squadsDir = findSquadsDir();
|
|
2286
2085
|
if (squadsDir) {
|
|
2287
|
-
const squadFilePath =
|
|
2288
|
-
if (
|
|
2289
|
-
const squadContent =
|
|
2086
|
+
const squadFilePath = join4(squadsDir, squadName, "SQUAD.md");
|
|
2087
|
+
if (existsSync4(squadFilePath)) {
|
|
2088
|
+
const squadContent = readFileSync3(squadFilePath, "utf-8");
|
|
2290
2089
|
const permContext = buildContextFromSquad(squadName, squadContent, agentName);
|
|
2291
2090
|
const mcpServers = extractMcpServersFromDefinition(definition);
|
|
2292
2091
|
const execRequest = {
|
|
@@ -2566,8 +2365,8 @@ async function listCommand(options) {
|
|
|
2566
2365
|
}
|
|
2567
2366
|
|
|
2568
2367
|
// src/commands/status.ts
|
|
2569
|
-
import { existsSync as
|
|
2570
|
-
import { join as
|
|
2368
|
+
import { existsSync as existsSync5, statSync } from "fs";
|
|
2369
|
+
import { join as join5 } from "path";
|
|
2571
2370
|
async function statusCommand(squadName, options = {}) {
|
|
2572
2371
|
await track(Events.CLI_STATUS, { squad: squadName || "all", verbose: options.verbose });
|
|
2573
2372
|
const squadsDir = findSquadsDir();
|
|
@@ -2620,8 +2419,8 @@ async function showOverallStatus(squadsDir, _options) {
|
|
|
2620
2419
|
let lastActivity = `${colors.dim}\u2014${RESET}`;
|
|
2621
2420
|
let activityColor = colors.dim;
|
|
2622
2421
|
if (memoryDir) {
|
|
2623
|
-
const squadMemoryPath =
|
|
2624
|
-
if (
|
|
2422
|
+
const squadMemoryPath = join5(memoryDir, squadName);
|
|
2423
|
+
if (existsSync5(squadMemoryPath)) {
|
|
2625
2424
|
const states = getSquadState(squadName);
|
|
2626
2425
|
memoryStatus = `${colors.green}${states.length} ${states.length === 1 ? "entry" : "entries"}${RESET}`;
|
|
2627
2426
|
let mostRecent = 0;
|
|
@@ -2723,14 +2522,14 @@ async function showSquadStatus(squadName, squadsDir, options) {
|
|
|
2723
2522
|
}
|
|
2724
2523
|
|
|
2725
2524
|
// src/commands/stack.ts
|
|
2726
|
-
import { existsSync as
|
|
2727
|
-
import { join as
|
|
2728
|
-
import { homedir as
|
|
2729
|
-
import { execSync as
|
|
2525
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, copyFileSync } from "fs";
|
|
2526
|
+
import { join as join6, dirname as dirname2 } from "path";
|
|
2527
|
+
import { homedir as homedir2 } from "os";
|
|
2528
|
+
import { execSync as execSync3, spawn as spawn3 } from "child_process";
|
|
2730
2529
|
import { createInterface as createInterface2 } from "readline";
|
|
2731
|
-
import { fileURLToPath
|
|
2732
|
-
var __filename2 =
|
|
2733
|
-
var __dirname2 =
|
|
2530
|
+
import { fileURLToPath } from "url";
|
|
2531
|
+
var __filename2 = fileURLToPath(import.meta.url);
|
|
2532
|
+
var __dirname2 = dirname2(__filename2);
|
|
2734
2533
|
var DEFAULT_CONFIG = {
|
|
2735
2534
|
SQUADS_DATABASE_URL: "postgresql://squads:squads@localhost:5433/squads",
|
|
2736
2535
|
SQUADS_BRIDGE_URL: "http://localhost:8088",
|
|
@@ -2739,8 +2538,8 @@ var DEFAULT_CONFIG = {
|
|
|
2739
2538
|
LANGFUSE_SECRET_KEY: "",
|
|
2740
2539
|
REDIS_URL: "redis://localhost:6379"
|
|
2741
2540
|
};
|
|
2742
|
-
var CONFIG_PATH2 =
|
|
2743
|
-
var SQUADS_DATA_DIR =
|
|
2541
|
+
var CONFIG_PATH2 = join6(homedir2(), ".squadsrc");
|
|
2542
|
+
var SQUADS_DATA_DIR = join6(homedir2(), ".squads");
|
|
2744
2543
|
var SERVICES = {
|
|
2745
2544
|
bridge: {
|
|
2746
2545
|
name: "Bridge API",
|
|
@@ -2874,25 +2673,25 @@ async function confirm2(question, defaultYes = true) {
|
|
|
2874
2673
|
function findPackageDockerDir() {
|
|
2875
2674
|
const candidates = [
|
|
2876
2675
|
// From npm package (relative to dist/commands/stack.js)
|
|
2877
|
-
|
|
2676
|
+
join6(__dirname2, "..", "..", "docker"),
|
|
2878
2677
|
// Local development
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2678
|
+
join6(process.cwd(), "docker"),
|
|
2679
|
+
join6(process.cwd(), "..", "squads-cli", "docker"),
|
|
2680
|
+
join6(homedir2(), "agents-squads", "squads-cli", "docker")
|
|
2882
2681
|
];
|
|
2883
2682
|
for (const dir of candidates) {
|
|
2884
|
-
if (
|
|
2683
|
+
if (existsSync6(join6(dir, "docker-compose.yml"))) {
|
|
2885
2684
|
return dir;
|
|
2886
2685
|
}
|
|
2887
2686
|
}
|
|
2888
2687
|
return null;
|
|
2889
2688
|
}
|
|
2890
2689
|
function loadStackConfig() {
|
|
2891
|
-
if (!
|
|
2690
|
+
if (!existsSync6(CONFIG_PATH2)) {
|
|
2892
2691
|
return null;
|
|
2893
2692
|
}
|
|
2894
2693
|
try {
|
|
2895
|
-
const content =
|
|
2694
|
+
const content = readFileSync4(CONFIG_PATH2, "utf-8");
|
|
2896
2695
|
const config2 = {};
|
|
2897
2696
|
for (const line of content.split("\n")) {
|
|
2898
2697
|
const trimmed = line.trim();
|
|
@@ -2933,7 +2732,7 @@ function saveStackConfig(config2) {
|
|
|
2933
2732
|
"# To activate: source ~/.squadsrc",
|
|
2934
2733
|
""
|
|
2935
2734
|
];
|
|
2936
|
-
|
|
2735
|
+
writeFileSync4(CONFIG_PATH2, lines.join("\n"));
|
|
2937
2736
|
}
|
|
2938
2737
|
function applyStackConfig() {
|
|
2939
2738
|
const config2 = loadStackConfig();
|
|
@@ -2946,7 +2745,7 @@ function applyStackConfig() {
|
|
|
2946
2745
|
}
|
|
2947
2746
|
function isDockerRunning() {
|
|
2948
2747
|
try {
|
|
2949
|
-
|
|
2748
|
+
execSync3("docker info", { stdio: "ignore" });
|
|
2950
2749
|
return true;
|
|
2951
2750
|
} catch {
|
|
2952
2751
|
return false;
|
|
@@ -2954,7 +2753,7 @@ function isDockerRunning() {
|
|
|
2954
2753
|
}
|
|
2955
2754
|
function getContainerStatus(name) {
|
|
2956
2755
|
try {
|
|
2957
|
-
const runningOutput =
|
|
2756
|
+
const runningOutput = execSync3(
|
|
2958
2757
|
`docker inspect ${name} --format '{{.State.Running}}'`,
|
|
2959
2758
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] }
|
|
2960
2759
|
).trim();
|
|
@@ -2964,7 +2763,7 @@ function getContainerStatus(name) {
|
|
|
2964
2763
|
}
|
|
2965
2764
|
let port;
|
|
2966
2765
|
try {
|
|
2967
|
-
const portOutput =
|
|
2766
|
+
const portOutput = execSync3(
|
|
2968
2767
|
`docker inspect ${name} --format '{{range .NetworkSettings.Ports}}{{range .}}{{.HostPort}}{{end}}{{end}}'`,
|
|
2969
2768
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] }
|
|
2970
2769
|
).trim();
|
|
@@ -2973,7 +2772,7 @@ function getContainerStatus(name) {
|
|
|
2973
2772
|
}
|
|
2974
2773
|
let healthy = true;
|
|
2975
2774
|
try {
|
|
2976
|
-
const healthOutput =
|
|
2775
|
+
const healthOutput = execSync3(
|
|
2977
2776
|
`docker inspect ${name} --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}'`,
|
|
2978
2777
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] }
|
|
2979
2778
|
).trim();
|
|
@@ -3005,13 +2804,13 @@ async function checkService(url, timeout = 2e3) {
|
|
|
3005
2804
|
}
|
|
3006
2805
|
function getLangfuseKeysFromDockerEnv() {
|
|
3007
2806
|
const envPaths2 = [
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
2807
|
+
join6(process.cwd(), "docker", ".env"),
|
|
2808
|
+
join6(process.cwd(), "..", "squads-cli", "docker", ".env"),
|
|
2809
|
+
join6(homedir2(), "agents-squads", "squads-cli", "docker", ".env")
|
|
3011
2810
|
];
|
|
3012
2811
|
for (const envPath of envPaths2) {
|
|
3013
|
-
if (
|
|
3014
|
-
const content =
|
|
2812
|
+
if (existsSync6(envPath)) {
|
|
2813
|
+
const content = readFileSync4(envPath, "utf-8");
|
|
3015
2814
|
const publicMatch = content.match(/LANGFUSE_PUBLIC_KEY=(\S+)/);
|
|
3016
2815
|
const secretMatch = content.match(/LANGFUSE_SECRET_KEY=(\S+)/);
|
|
3017
2816
|
if (publicMatch && secretMatch) {
|
|
@@ -3026,12 +2825,12 @@ function getLangfuseKeysFromDockerEnv() {
|
|
|
3026
2825
|
}
|
|
3027
2826
|
function findDockerComposeDir() {
|
|
3028
2827
|
const candidates = [
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
2828
|
+
join6(process.cwd(), "docker"),
|
|
2829
|
+
join6(process.cwd(), "..", "squads-cli", "docker"),
|
|
2830
|
+
join6(homedir2(), "agents-squads", "squads-cli", "docker")
|
|
3032
2831
|
];
|
|
3033
2832
|
for (const dir of candidates) {
|
|
3034
|
-
if (
|
|
2833
|
+
if (existsSync6(join6(dir, "docker-compose.yml"))) {
|
|
3035
2834
|
return dir;
|
|
3036
2835
|
}
|
|
3037
2836
|
}
|
|
@@ -3057,7 +2856,7 @@ async function stackInitCommand() {
|
|
|
3057
2856
|
writeLine();
|
|
3058
2857
|
writeLine(` ${bold}Step 2: Docker Compose Files${RESET}`);
|
|
3059
2858
|
let composeDir = findPackageDockerDir();
|
|
3060
|
-
const targetDir =
|
|
2859
|
+
const targetDir = join6(SQUADS_DATA_DIR, "docker");
|
|
3061
2860
|
if (!composeDir) {
|
|
3062
2861
|
writeLine(` ${colors.red}${icons.error}${RESET} Docker compose files not found`);
|
|
3063
2862
|
writeLine(` ${colors.dim}This shouldn't happen if you installed via npm.${RESET}`);
|
|
@@ -3065,20 +2864,20 @@ async function stackInitCommand() {
|
|
|
3065
2864
|
writeLine();
|
|
3066
2865
|
return;
|
|
3067
2866
|
}
|
|
3068
|
-
if (composeDir !== targetDir && !
|
|
2867
|
+
if (composeDir !== targetDir && !existsSync6(targetDir)) {
|
|
3069
2868
|
writeLine(` ${colors.cyan}${icons.progress}${RESET} Copying docker files to ${colors.dim}~/.squads/docker${RESET}`);
|
|
3070
2869
|
try {
|
|
3071
|
-
|
|
3072
|
-
|
|
2870
|
+
mkdirSync3(SQUADS_DATA_DIR, { recursive: true });
|
|
2871
|
+
mkdirSync3(targetDir, { recursive: true });
|
|
3073
2872
|
const filesToCopy = [
|
|
3074
2873
|
"docker-compose.yml",
|
|
3075
2874
|
"docker-compose.engram.yml",
|
|
3076
2875
|
".env.example"
|
|
3077
2876
|
];
|
|
3078
2877
|
for (const file of filesToCopy) {
|
|
3079
|
-
const src =
|
|
3080
|
-
const dst =
|
|
3081
|
-
if (
|
|
2878
|
+
const src = join6(composeDir, file);
|
|
2879
|
+
const dst = join6(targetDir, file);
|
|
2880
|
+
if (existsSync6(src)) {
|
|
3082
2881
|
copyFileSync(src, dst);
|
|
3083
2882
|
}
|
|
3084
2883
|
}
|
|
@@ -3087,7 +2886,7 @@ async function stackInitCommand() {
|
|
|
3087
2886
|
} catch {
|
|
3088
2887
|
writeLine(` ${colors.yellow}${icons.warning}${RESET} Could not copy files, using source location`);
|
|
3089
2888
|
}
|
|
3090
|
-
} else if (
|
|
2889
|
+
} else if (existsSync6(targetDir)) {
|
|
3091
2890
|
composeDir = targetDir;
|
|
3092
2891
|
writeLine(` ${colors.green}${icons.success}${RESET} Using ${colors.dim}~/.squads/docker${RESET}`);
|
|
3093
2892
|
} else {
|
|
@@ -3095,10 +2894,10 @@ async function stackInitCommand() {
|
|
|
3095
2894
|
}
|
|
3096
2895
|
writeLine();
|
|
3097
2896
|
writeLine(` ${bold}Step 3: Environment Configuration${RESET}`);
|
|
3098
|
-
const envPath =
|
|
3099
|
-
const envExamplePath =
|
|
3100
|
-
if (!
|
|
3101
|
-
if (
|
|
2897
|
+
const envPath = join6(composeDir, ".env");
|
|
2898
|
+
const envExamplePath = join6(composeDir, ".env.example");
|
|
2899
|
+
if (!existsSync6(envPath)) {
|
|
2900
|
+
if (existsSync6(envExamplePath)) {
|
|
3102
2901
|
copyFileSync(envExamplePath, envPath);
|
|
3103
2902
|
writeLine(` ${colors.cyan}${icons.progress}${RESET} Created .env from template`);
|
|
3104
2903
|
} else {
|
|
@@ -3127,13 +2926,13 @@ LANGFUSE_PORT=3100
|
|
|
3127
2926
|
OTEL_PORT=4318
|
|
3128
2927
|
BRIDGE_PORT=8088
|
|
3129
2928
|
`;
|
|
3130
|
-
|
|
2929
|
+
writeFileSync4(envPath, minimalEnv);
|
|
3131
2930
|
writeLine(` ${colors.cyan}${icons.progress}${RESET} Created default .env`);
|
|
3132
2931
|
}
|
|
3133
2932
|
} else {
|
|
3134
2933
|
writeLine(` ${colors.green}${icons.success}${RESET} .env exists`);
|
|
3135
2934
|
}
|
|
3136
|
-
const envContent =
|
|
2935
|
+
const envContent = readFileSync4(envPath, "utf-8");
|
|
3137
2936
|
const missingSecrets = [];
|
|
3138
2937
|
const llmProvider = envContent.match(/LLM_PROVIDER=(\w+)/)?.[1] || "ollama";
|
|
3139
2938
|
if (llmProvider === "openai") {
|
|
@@ -3174,7 +2973,7 @@ BRIDGE_PORT=8088
|
|
|
3174
2973
|
writeLine();
|
|
3175
2974
|
writeLine(` ${colors.cyan}${icons.progress}${RESET} Starting containers...`);
|
|
3176
2975
|
try {
|
|
3177
|
-
|
|
2976
|
+
execSync3("docker compose up -d", {
|
|
3178
2977
|
cwd: composeDir,
|
|
3179
2978
|
stdio: "inherit"
|
|
3180
2979
|
});
|
|
@@ -3374,7 +3173,7 @@ async function stackHealthCommand(verbose = false) {
|
|
|
3374
3173
|
let logs;
|
|
3375
3174
|
if (!ok && verbose) {
|
|
3376
3175
|
try {
|
|
3377
|
-
logs =
|
|
3176
|
+
logs = execSync3(`docker logs ${container.name} --tail 10 2>&1`, {
|
|
3378
3177
|
encoding: "utf-8",
|
|
3379
3178
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3380
3179
|
});
|
|
@@ -3425,7 +3224,7 @@ function stackLogsCommand(service, tail = 50) {
|
|
|
3425
3224
|
};
|
|
3426
3225
|
const container = containerMap[service] || `squads-${service}`;
|
|
3427
3226
|
try {
|
|
3428
|
-
|
|
3227
|
+
execSync3(`docker logs ${container} --tail ${tail}`, { stdio: "inherit" });
|
|
3429
3228
|
} catch {
|
|
3430
3229
|
writeLine(` ${colors.red}${icons.error}${RESET} Container ${container} not found`);
|
|
3431
3230
|
}
|
|
@@ -3812,9 +3611,9 @@ async function memoryExtractCommand(options = {}) {
|
|
|
3812
3611
|
}
|
|
3813
3612
|
|
|
3814
3613
|
// src/commands/sync.ts
|
|
3815
|
-
import { execSync as
|
|
3816
|
-
import { existsSync as
|
|
3817
|
-
import { join as
|
|
3614
|
+
import { execSync as execSync4 } from "child_process";
|
|
3615
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, readdirSync as readdirSync2 } from "fs";
|
|
3616
|
+
import { join as join7 } from "path";
|
|
3818
3617
|
var PATH_TO_SQUAD = {
|
|
3819
3618
|
"squads-cli": "product",
|
|
3820
3619
|
"agents-squads-web": "website",
|
|
@@ -3842,21 +3641,21 @@ var MESSAGE_TO_SQUAD = {
|
|
|
3842
3641
|
"infra": "engineering"
|
|
3843
3642
|
};
|
|
3844
3643
|
function getLastSyncTime(memoryDir) {
|
|
3845
|
-
const syncFile =
|
|
3846
|
-
if (
|
|
3847
|
-
return
|
|
3644
|
+
const syncFile = join7(memoryDir, ".last-sync");
|
|
3645
|
+
if (existsSync7(syncFile)) {
|
|
3646
|
+
return readFileSync5(syncFile, "utf-8").trim();
|
|
3848
3647
|
}
|
|
3849
3648
|
return null;
|
|
3850
3649
|
}
|
|
3851
3650
|
function updateLastSyncTime(memoryDir) {
|
|
3852
|
-
const syncFile =
|
|
3853
|
-
|
|
3651
|
+
const syncFile = join7(memoryDir, ".last-sync");
|
|
3652
|
+
writeFileSync5(syncFile, (/* @__PURE__ */ new Date()).toISOString());
|
|
3854
3653
|
}
|
|
3855
3654
|
function getRecentCommits(since) {
|
|
3856
3655
|
const commits = [];
|
|
3857
3656
|
try {
|
|
3858
3657
|
const sinceArg = since ? `--since="${since}"` : "-n 20";
|
|
3859
|
-
const logOutput =
|
|
3658
|
+
const logOutput = execSync4(
|
|
3860
3659
|
`git log ${sinceArg} --format="%H|%aI|%s" --name-only`,
|
|
3861
3660
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
3862
3661
|
).trim();
|
|
@@ -3922,22 +3721,22 @@ ${messages}
|
|
|
3922
3721
|
`;
|
|
3923
3722
|
}
|
|
3924
3723
|
function appendToSquadMemory(memoryDir, squad, summary) {
|
|
3925
|
-
const squadMemoryDir =
|
|
3926
|
-
if (!
|
|
3927
|
-
|
|
3724
|
+
const squadMemoryDir = join7(memoryDir, squad);
|
|
3725
|
+
if (!existsSync7(squadMemoryDir)) {
|
|
3726
|
+
mkdirSync4(squadMemoryDir, { recursive: true });
|
|
3928
3727
|
}
|
|
3929
3728
|
let agentDir;
|
|
3930
|
-
const existingDirs =
|
|
3729
|
+
const existingDirs = existsSync7(squadMemoryDir) ? readdirSync2(squadMemoryDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name) : [];
|
|
3931
3730
|
if (existingDirs.length > 0) {
|
|
3932
|
-
agentDir =
|
|
3731
|
+
agentDir = join7(squadMemoryDir, existingDirs[0]);
|
|
3933
3732
|
} else {
|
|
3934
|
-
agentDir =
|
|
3935
|
-
|
|
3733
|
+
agentDir = join7(squadMemoryDir, `${squad}-lead`);
|
|
3734
|
+
mkdirSync4(agentDir, { recursive: true });
|
|
3936
3735
|
}
|
|
3937
|
-
const statePath =
|
|
3736
|
+
const statePath = join7(agentDir, "state.md");
|
|
3938
3737
|
let content = "";
|
|
3939
|
-
if (
|
|
3940
|
-
content =
|
|
3738
|
+
if (existsSync7(statePath)) {
|
|
3739
|
+
content = readFileSync5(statePath, "utf-8");
|
|
3941
3740
|
} else {
|
|
3942
3741
|
content = `# ${squad} Squad - State
|
|
3943
3742
|
|
|
@@ -3949,13 +3748,13 @@ Updated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
|
|
|
3949
3748
|
`Updated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`
|
|
3950
3749
|
);
|
|
3951
3750
|
content += summary;
|
|
3952
|
-
|
|
3751
|
+
writeFileSync5(statePath, content);
|
|
3953
3752
|
return true;
|
|
3954
3753
|
}
|
|
3955
3754
|
function gitPullMemory() {
|
|
3956
3755
|
try {
|
|
3957
|
-
|
|
3958
|
-
const status =
|
|
3756
|
+
execSync4("git fetch origin", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
3757
|
+
const status = execSync4("git status -sb", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
3959
3758
|
const behindMatch = status.match(/behind (\d+)/);
|
|
3960
3759
|
const aheadMatch = status.match(/ahead (\d+)/);
|
|
3961
3760
|
const behind = behindMatch ? parseInt(behindMatch[1]) : 0;
|
|
@@ -3963,7 +3762,7 @@ function gitPullMemory() {
|
|
|
3963
3762
|
if (behind === 0) {
|
|
3964
3763
|
return { success: true, output: "Already up to date", behind: 0, ahead };
|
|
3965
3764
|
}
|
|
3966
|
-
const output =
|
|
3765
|
+
const output = execSync4("git pull --rebase origin main", {
|
|
3967
3766
|
encoding: "utf-8",
|
|
3968
3767
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3969
3768
|
});
|
|
@@ -3975,18 +3774,18 @@ function gitPullMemory() {
|
|
|
3975
3774
|
}
|
|
3976
3775
|
function gitPushMemory() {
|
|
3977
3776
|
try {
|
|
3978
|
-
const status =
|
|
3777
|
+
const status = execSync4("git status --porcelain .agents/memory/", {
|
|
3979
3778
|
encoding: "utf-8",
|
|
3980
3779
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3981
3780
|
}).trim();
|
|
3982
3781
|
if (status) {
|
|
3983
|
-
|
|
3984
|
-
|
|
3782
|
+
execSync4("git add .agents/memory/", { stdio: ["pipe", "pipe", "pipe"] });
|
|
3783
|
+
execSync4('git commit -m "chore: sync squad memory"', {
|
|
3985
3784
|
encoding: "utf-8",
|
|
3986
3785
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3987
3786
|
});
|
|
3988
3787
|
}
|
|
3989
|
-
const output =
|
|
3788
|
+
const output = execSync4("git push origin main", {
|
|
3990
3789
|
encoding: "utf-8",
|
|
3991
3790
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3992
3791
|
});
|
|
@@ -4226,28 +4025,28 @@ async function goalProgressCommand(squadName, goalIndex, progress2) {
|
|
|
4226
4025
|
}
|
|
4227
4026
|
|
|
4228
4027
|
// src/commands/feedback.ts
|
|
4229
|
-
import { readFileSync as
|
|
4230
|
-
import { join as
|
|
4028
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync3 } from "fs";
|
|
4029
|
+
import { join as join8, dirname as dirname3 } from "path";
|
|
4231
4030
|
function getFeedbackPath(squadName) {
|
|
4232
4031
|
const memoryDir = findMemoryDir();
|
|
4233
4032
|
if (!memoryDir) return null;
|
|
4234
4033
|
const squad = loadSquad(squadName);
|
|
4235
4034
|
const agentName = squad?.agents[0]?.name || `${squadName}-lead`;
|
|
4236
|
-
return
|
|
4035
|
+
return join8(memoryDir, squadName, agentName, "feedback.md");
|
|
4237
4036
|
}
|
|
4238
4037
|
function getOutputPath(squadName) {
|
|
4239
4038
|
const memoryDir = findMemoryDir();
|
|
4240
4039
|
if (!memoryDir) return null;
|
|
4241
4040
|
const squad = loadSquad(squadName);
|
|
4242
4041
|
const agentName = squad?.agents[0]?.name || `${squadName}-lead`;
|
|
4243
|
-
return
|
|
4042
|
+
return join8(memoryDir, squadName, agentName, "output.md");
|
|
4244
4043
|
}
|
|
4245
4044
|
function getLastExecution(squadName) {
|
|
4246
4045
|
const outputPath = getOutputPath(squadName);
|
|
4247
|
-
if (!outputPath || !
|
|
4046
|
+
if (!outputPath || !existsSync8(outputPath)) {
|
|
4248
4047
|
return null;
|
|
4249
4048
|
}
|
|
4250
|
-
const content =
|
|
4049
|
+
const content = readFileSync6(outputPath, "utf-8");
|
|
4251
4050
|
const lines = content.split("\n");
|
|
4252
4051
|
let date = "unknown";
|
|
4253
4052
|
let summary = lines.slice(0, 5).join("\n");
|
|
@@ -4299,9 +4098,9 @@ async function feedbackAddCommand(squadName, rating, feedback2, options) {
|
|
|
4299
4098
|
return;
|
|
4300
4099
|
}
|
|
4301
4100
|
const lastExec = getLastExecution(squadName);
|
|
4302
|
-
const dir =
|
|
4303
|
-
if (!
|
|
4304
|
-
|
|
4101
|
+
const dir = dirname3(feedbackPath);
|
|
4102
|
+
if (!existsSync8(dir)) {
|
|
4103
|
+
mkdirSync5(dir, { recursive: true });
|
|
4305
4104
|
}
|
|
4306
4105
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
4307
4106
|
let entry = `
|
|
@@ -4329,15 +4128,15 @@ _Date: ${date}_
|
|
|
4329
4128
|
}
|
|
4330
4129
|
}
|
|
4331
4130
|
let existing = "";
|
|
4332
|
-
if (
|
|
4333
|
-
existing =
|
|
4131
|
+
if (existsSync8(feedbackPath)) {
|
|
4132
|
+
existing = readFileSync6(feedbackPath, "utf-8");
|
|
4334
4133
|
} else {
|
|
4335
4134
|
existing = `# ${squadName} - Feedback Log
|
|
4336
4135
|
|
|
4337
4136
|
> Execution feedback and learnings
|
|
4338
4137
|
`;
|
|
4339
4138
|
}
|
|
4340
|
-
|
|
4139
|
+
writeFileSync6(feedbackPath, existing + entry);
|
|
4341
4140
|
const stars = `${colors.yellow}${"\u2605".repeat(ratingNum)}${"\u2606".repeat(5 - ratingNum)}${RESET}`;
|
|
4342
4141
|
writeLine();
|
|
4343
4142
|
writeLine(` ${icons.success} Feedback recorded for ${colors.cyan}${squadName}${RESET}`);
|
|
@@ -4351,11 +4150,11 @@ _Date: ${date}_
|
|
|
4351
4150
|
async function feedbackShowCommand(squadName, options) {
|
|
4352
4151
|
await track(Events.CLI_FEEDBACK_SHOW, { squad: squadName });
|
|
4353
4152
|
const feedbackPath = getFeedbackPath(squadName);
|
|
4354
|
-
if (!feedbackPath || !
|
|
4153
|
+
if (!feedbackPath || !existsSync8(feedbackPath)) {
|
|
4355
4154
|
writeLine(` ${colors.yellow}No feedback recorded for ${squadName}${RESET}`);
|
|
4356
4155
|
return;
|
|
4357
4156
|
}
|
|
4358
|
-
const content =
|
|
4157
|
+
const content = readFileSync6(feedbackPath, "utf-8");
|
|
4359
4158
|
const entries = parseFeedbackHistory(content);
|
|
4360
4159
|
const limit = options.limit ? parseInt(options.limit) : 5;
|
|
4361
4160
|
const recent = entries.slice(-limit).reverse();
|
|
@@ -4400,10 +4199,10 @@ async function feedbackStatsCommand() {
|
|
|
4400
4199
|
writeLine(` ${colors.purple}${box.teeRight}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.teeLeft}${RESET}`);
|
|
4401
4200
|
for (const squad of squads) {
|
|
4402
4201
|
const feedbackPath = getFeedbackPath(squad);
|
|
4403
|
-
if (!feedbackPath || !
|
|
4202
|
+
if (!feedbackPath || !existsSync8(feedbackPath)) {
|
|
4404
4203
|
continue;
|
|
4405
4204
|
}
|
|
4406
|
-
const content =
|
|
4205
|
+
const content = readFileSync6(feedbackPath, "utf-8");
|
|
4407
4206
|
const entries = parseFeedbackHistory(content);
|
|
4408
4207
|
if (entries.length === 0) continue;
|
|
4409
4208
|
const avgRating = entries.reduce((sum, e) => sum + e.rating, 0) / entries.length;
|
|
@@ -4426,8 +4225,8 @@ async function feedbackStatsCommand() {
|
|
|
4426
4225
|
}
|
|
4427
4226
|
|
|
4428
4227
|
// src/commands/dashboard.ts
|
|
4429
|
-
import { readdirSync as readdirSync4, existsSync as
|
|
4430
|
-
import { join as
|
|
4228
|
+
import { readdirSync as readdirSync4, existsSync as existsSync9, statSync as statSync2 } from "fs";
|
|
4229
|
+
import { join as join9 } from "path";
|
|
4431
4230
|
|
|
4432
4231
|
// src/lib/providers.ts
|
|
4433
4232
|
var PROVIDERS = {
|
|
@@ -5286,16 +5085,16 @@ async function closeDatabase() {
|
|
|
5286
5085
|
function getLastActivityDate(squadName) {
|
|
5287
5086
|
const memoryDir = findMemoryDir();
|
|
5288
5087
|
if (!memoryDir) return "unknown";
|
|
5289
|
-
const squadMemory =
|
|
5290
|
-
if (!
|
|
5088
|
+
const squadMemory = join9(memoryDir, squadName);
|
|
5089
|
+
if (!existsSync9(squadMemory)) return "\u2014";
|
|
5291
5090
|
let latestTime = 0;
|
|
5292
5091
|
try {
|
|
5293
5092
|
const agents = readdirSync4(squadMemory, { withFileTypes: true }).filter((e) => e.isDirectory());
|
|
5294
5093
|
for (const agent of agents) {
|
|
5295
|
-
const agentPath =
|
|
5094
|
+
const agentPath = join9(squadMemory, agent.name);
|
|
5296
5095
|
const files = readdirSync4(agentPath).filter((f) => f.endsWith(".md"));
|
|
5297
5096
|
for (const file of files) {
|
|
5298
|
-
const filePath =
|
|
5097
|
+
const filePath = join9(agentPath, file);
|
|
5299
5098
|
const stats = statSync2(filePath);
|
|
5300
5099
|
if (stats.mtimeMs > latestTime) {
|
|
5301
5100
|
latestTime = stats.mtimeMs;
|
|
@@ -5542,11 +5341,11 @@ async function dashboardCommand(options = {}) {
|
|
|
5542
5341
|
await closeDatabase();
|
|
5543
5342
|
}
|
|
5544
5343
|
function findAgentsSquadsDir() {
|
|
5545
|
-
const parentDir =
|
|
5546
|
-
if (
|
|
5344
|
+
const parentDir = join9(process.cwd(), "..");
|
|
5345
|
+
if (existsSync9(join9(parentDir, "hq"))) {
|
|
5547
5346
|
return parentDir;
|
|
5548
5347
|
}
|
|
5549
|
-
if (
|
|
5348
|
+
if (existsSync9(join9(process.cwd(), ".git"))) {
|
|
5550
5349
|
return process.cwd();
|
|
5551
5350
|
}
|
|
5552
5351
|
return null;
|
|
@@ -5935,7 +5734,7 @@ function renderInsightsCached(cache) {
|
|
|
5935
5734
|
}
|
|
5936
5735
|
|
|
5937
5736
|
// src/commands/issues.ts
|
|
5938
|
-
import { execSync as
|
|
5737
|
+
import { execSync as execSync5 } from "child_process";
|
|
5939
5738
|
function getLabelName(label) {
|
|
5940
5739
|
return typeof label === "string" ? label : label.name;
|
|
5941
5740
|
}
|
|
@@ -5948,7 +5747,7 @@ async function issuesCommand(options = {}) {
|
|
|
5948
5747
|
writeLine(` ${gradient("squads")} ${colors.dim}issues${RESET}`);
|
|
5949
5748
|
writeLine();
|
|
5950
5749
|
try {
|
|
5951
|
-
|
|
5750
|
+
execSync5("gh --version", { stdio: "pipe" });
|
|
5952
5751
|
} catch {
|
|
5953
5752
|
writeLine(` ${colors.red}GitHub CLI (gh) not found${RESET}`);
|
|
5954
5753
|
writeLine(` ${colors.dim}Install: brew install gh${RESET}`);
|
|
@@ -5959,7 +5758,7 @@ async function issuesCommand(options = {}) {
|
|
|
5959
5758
|
let totalOpen = 0;
|
|
5960
5759
|
for (const repo of repos) {
|
|
5961
5760
|
try {
|
|
5962
|
-
const result =
|
|
5761
|
+
const result = execSync5(
|
|
5963
5762
|
`gh issue list -R ${org}/${repo} --state open --json number,title,state,labels,createdAt --limit 50`,
|
|
5964
5763
|
{ stdio: "pipe", encoding: "utf-8" }
|
|
5965
5764
|
);
|
|
@@ -6010,7 +5809,7 @@ async function issuesCommand(options = {}) {
|
|
|
6010
5809
|
}
|
|
6011
5810
|
|
|
6012
5811
|
// src/commands/solve-issues.ts
|
|
6013
|
-
import { execSync as
|
|
5812
|
+
import { execSync as execSync6, spawn as spawn4 } from "child_process";
|
|
6014
5813
|
import ora3 from "ora";
|
|
6015
5814
|
var DEFAULT_ORG2 = "agents-squads";
|
|
6016
5815
|
var DEFAULT_REPOS2 = ["hq", "agents-squads-web", "squads-cli", "agents-squads"];
|
|
@@ -6020,7 +5819,7 @@ async function solveIssuesCommand(options = {}) {
|
|
|
6020
5819
|
writeLine(` ${gradient("squads")} ${colors.dim}solve-issues${RESET}`);
|
|
6021
5820
|
writeLine();
|
|
6022
5821
|
try {
|
|
6023
|
-
|
|
5822
|
+
execSync6("gh --version", { stdio: "pipe" });
|
|
6024
5823
|
} catch {
|
|
6025
5824
|
writeLine(` ${colors.red}GitHub CLI (gh) not found${RESET}`);
|
|
6026
5825
|
writeLine(` ${colors.dim}Install: brew install gh${RESET}`);
|
|
@@ -6030,7 +5829,7 @@ async function solveIssuesCommand(options = {}) {
|
|
|
6030
5829
|
if (options.issue) {
|
|
6031
5830
|
const repo = options.repo || "hq";
|
|
6032
5831
|
try {
|
|
6033
|
-
const result =
|
|
5832
|
+
const result = execSync6(
|
|
6034
5833
|
`gh issue view ${options.issue} -R ${DEFAULT_ORG2}/${repo} --json number,title,labels,body`,
|
|
6035
5834
|
{ stdio: "pipe", encoding: "utf-8" }
|
|
6036
5835
|
);
|
|
@@ -6043,7 +5842,7 @@ async function solveIssuesCommand(options = {}) {
|
|
|
6043
5842
|
} else {
|
|
6044
5843
|
for (const repo of repos) {
|
|
6045
5844
|
try {
|
|
6046
|
-
const result =
|
|
5845
|
+
const result = execSync6(
|
|
6047
5846
|
`gh issue list -R ${DEFAULT_ORG2}/${repo} --label "ready-to-fix" --state open --json number,title,labels --limit 20`,
|
|
6048
5847
|
{ stdio: "pipe", encoding: "utf-8" }
|
|
6049
5848
|
);
|
|
@@ -6097,7 +5896,7 @@ function showSolveInstructions(issues) {
|
|
|
6097
5896
|
async function solveWithClaude(issues) {
|
|
6098
5897
|
const spinner = ora3("Starting issue solver...").start();
|
|
6099
5898
|
try {
|
|
6100
|
-
|
|
5899
|
+
execSync6("which claude", { stdio: "pipe" });
|
|
6101
5900
|
} catch {
|
|
6102
5901
|
spinner.fail("Claude CLI not found");
|
|
6103
5902
|
writeLine(` ${colors.dim}Install: npm install -g @anthropic-ai/claude-code${RESET}`);
|
|
@@ -6183,9 +5982,9 @@ function executeClaudePrompt(prompt2) {
|
|
|
6183
5982
|
}
|
|
6184
5983
|
|
|
6185
5984
|
// src/commands/open-issues.ts
|
|
6186
|
-
import { execSync as
|
|
5985
|
+
import { execSync as execSync7, spawn as spawn5 } from "child_process";
|
|
6187
5986
|
import { readdirSync as readdirSync5 } from "fs";
|
|
6188
|
-
import { join as
|
|
5987
|
+
import { join as join10 } from "path";
|
|
6189
5988
|
import ora4 from "ora";
|
|
6190
5989
|
var ISSUE_FINDER_PATTERNS = [
|
|
6191
5990
|
"*-eval.md",
|
|
@@ -6243,7 +6042,7 @@ function findEvalAgents(squadsDir, filterSquad) {
|
|
|
6243
6042
|
const agents = [];
|
|
6244
6043
|
const squads = readdirSync5(squadsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).filter((d) => !filterSquad || d.name === filterSquad).map((d) => d.name);
|
|
6245
6044
|
for (const squad of squads) {
|
|
6246
|
-
const squadPath =
|
|
6045
|
+
const squadPath = join10(squadsDir, squad);
|
|
6247
6046
|
const files = readdirSync5(squadPath).filter((f) => f.endsWith(".md"));
|
|
6248
6047
|
for (const file of files) {
|
|
6249
6048
|
const isEval = ISSUE_FINDER_PATTERNS.some((pattern) => {
|
|
@@ -6254,7 +6053,7 @@ function findEvalAgents(squadsDir, filterSquad) {
|
|
|
6254
6053
|
agents.push({
|
|
6255
6054
|
name: file,
|
|
6256
6055
|
squad,
|
|
6257
|
-
path:
|
|
6056
|
+
path: join10(squadPath, file)
|
|
6258
6057
|
});
|
|
6259
6058
|
}
|
|
6260
6059
|
}
|
|
@@ -6280,7 +6079,7 @@ function showRunInstructions(agents) {
|
|
|
6280
6079
|
async function runEvaluators(agents) {
|
|
6281
6080
|
const spinner = ora4("Starting evaluators...").start();
|
|
6282
6081
|
try {
|
|
6283
|
-
|
|
6082
|
+
execSync7("which claude", { stdio: "pipe" });
|
|
6284
6083
|
} catch {
|
|
6285
6084
|
spinner.fail("Claude CLI not found");
|
|
6286
6085
|
writeLine(` ${colors.dim}Install: npm install -g @anthropic-ai/claude-code${RESET}`);
|
|
@@ -6364,9 +6163,9 @@ import open from "open";
|
|
|
6364
6163
|
|
|
6365
6164
|
// src/lib/auth.ts
|
|
6366
6165
|
import { createClient } from "@supabase/supabase-js";
|
|
6367
|
-
import { existsSync as
|
|
6368
|
-
import { join as
|
|
6369
|
-
import { homedir as
|
|
6166
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6 } from "fs";
|
|
6167
|
+
import { join as join11 } from "path";
|
|
6168
|
+
import { homedir as homedir3 } from "os";
|
|
6370
6169
|
import "open";
|
|
6371
6170
|
import http from "http";
|
|
6372
6171
|
var PERSONAL_DOMAINS = [
|
|
@@ -6395,8 +6194,8 @@ var PERSONAL_DOMAINS = [
|
|
|
6395
6194
|
"tutanota.com",
|
|
6396
6195
|
"hey.com"
|
|
6397
6196
|
];
|
|
6398
|
-
var AUTH_DIR =
|
|
6399
|
-
var AUTH_PATH =
|
|
6197
|
+
var AUTH_DIR = join11(homedir3(), ".squads-cli");
|
|
6198
|
+
var AUTH_PATH = join11(AUTH_DIR, "auth.json");
|
|
6400
6199
|
function isPersonalEmail(email) {
|
|
6401
6200
|
const domain = email.split("@")[1]?.toLowerCase();
|
|
6402
6201
|
return PERSONAL_DOMAINS.includes(domain);
|
|
@@ -6405,22 +6204,22 @@ function getEmailDomain(email) {
|
|
|
6405
6204
|
return email.split("@")[1]?.toLowerCase() || "";
|
|
6406
6205
|
}
|
|
6407
6206
|
function saveSession(session2) {
|
|
6408
|
-
if (!
|
|
6409
|
-
|
|
6207
|
+
if (!existsSync10(AUTH_DIR)) {
|
|
6208
|
+
mkdirSync6(AUTH_DIR, { recursive: true });
|
|
6410
6209
|
}
|
|
6411
|
-
|
|
6210
|
+
writeFileSync7(AUTH_PATH, JSON.stringify(session2, null, 2));
|
|
6412
6211
|
}
|
|
6413
6212
|
function loadSession() {
|
|
6414
|
-
if (!
|
|
6213
|
+
if (!existsSync10(AUTH_PATH)) return null;
|
|
6415
6214
|
try {
|
|
6416
|
-
return JSON.parse(
|
|
6215
|
+
return JSON.parse(readFileSync7(AUTH_PATH, "utf-8"));
|
|
6417
6216
|
} catch {
|
|
6418
6217
|
return null;
|
|
6419
6218
|
}
|
|
6420
6219
|
}
|
|
6421
6220
|
function clearSession() {
|
|
6422
|
-
if (
|
|
6423
|
-
|
|
6221
|
+
if (existsSync10(AUTH_PATH)) {
|
|
6222
|
+
writeFileSync7(AUTH_PATH, "");
|
|
6424
6223
|
}
|
|
6425
6224
|
}
|
|
6426
6225
|
function startAuthCallbackServer(port = 54321) {
|
|
@@ -6642,26 +6441,26 @@ async function updateCommand(options = {}) {
|
|
|
6642
6441
|
}
|
|
6643
6442
|
|
|
6644
6443
|
// src/commands/progress.ts
|
|
6645
|
-
import { execSync as
|
|
6646
|
-
import { existsSync as
|
|
6647
|
-
import { join as
|
|
6444
|
+
import { execSync as execSync8 } from "child_process";
|
|
6445
|
+
import { existsSync as existsSync11, readFileSync as readFileSync8, writeFileSync as writeFileSync8, mkdirSync as mkdirSync7 } from "fs";
|
|
6446
|
+
import { join as join12 } from "path";
|
|
6648
6447
|
function getTasksFilePath() {
|
|
6649
6448
|
const memoryDir = findMemoryDir();
|
|
6650
6449
|
if (!memoryDir) {
|
|
6651
6450
|
const cwd = process.cwd();
|
|
6652
|
-
const agentsDir =
|
|
6653
|
-
if (!
|
|
6654
|
-
|
|
6451
|
+
const agentsDir = join12(cwd, ".agents");
|
|
6452
|
+
if (!existsSync11(agentsDir)) {
|
|
6453
|
+
mkdirSync7(agentsDir, { recursive: true });
|
|
6655
6454
|
}
|
|
6656
|
-
return
|
|
6455
|
+
return join12(agentsDir, "tasks.json");
|
|
6657
6456
|
}
|
|
6658
|
-
return
|
|
6457
|
+
return join12(memoryDir, "..", "tasks.json");
|
|
6659
6458
|
}
|
|
6660
6459
|
function loadTasks() {
|
|
6661
6460
|
const tasksPath = getTasksFilePath();
|
|
6662
|
-
if (
|
|
6461
|
+
if (existsSync11(tasksPath)) {
|
|
6663
6462
|
try {
|
|
6664
|
-
return JSON.parse(
|
|
6463
|
+
return JSON.parse(readFileSync8(tasksPath, "utf-8"));
|
|
6665
6464
|
} catch {
|
|
6666
6465
|
return { tasks: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
6667
6466
|
}
|
|
@@ -6671,7 +6470,7 @@ function loadTasks() {
|
|
|
6671
6470
|
function saveTasks(data) {
|
|
6672
6471
|
const tasksPath = getTasksFilePath();
|
|
6673
6472
|
data.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
6674
|
-
|
|
6473
|
+
writeFileSync8(tasksPath, JSON.stringify(data, null, 2));
|
|
6675
6474
|
}
|
|
6676
6475
|
function getRecentActivity() {
|
|
6677
6476
|
const activity = [];
|
|
@@ -6687,7 +6486,7 @@ function getRecentActivity() {
|
|
|
6687
6486
|
marketing: ["marketing", "content", "social"]
|
|
6688
6487
|
};
|
|
6689
6488
|
try {
|
|
6690
|
-
const logOutput =
|
|
6489
|
+
const logOutput = execSync8(
|
|
6691
6490
|
'git log --since="24 hours ago" --format="%h|%aI|%s" 2>/dev/null',
|
|
6692
6491
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
6693
6492
|
).trim();
|
|
@@ -6821,7 +6620,7 @@ function getElapsedTime(startTime) {
|
|
|
6821
6620
|
}
|
|
6822
6621
|
|
|
6823
6622
|
// src/commands/results.ts
|
|
6824
|
-
import { execSync as
|
|
6623
|
+
import { execSync as execSync9 } from "child_process";
|
|
6825
6624
|
function getGitStats(days = 7) {
|
|
6826
6625
|
const stats = /* @__PURE__ */ new Map();
|
|
6827
6626
|
const squadKeywords = {
|
|
@@ -6836,7 +6635,7 @@ function getGitStats(days = 7) {
|
|
|
6836
6635
|
marketing: ["marketing"]
|
|
6837
6636
|
};
|
|
6838
6637
|
try {
|
|
6839
|
-
const logOutput =
|
|
6638
|
+
const logOutput = execSync9(
|
|
6840
6639
|
`git log --since="${days} days ago" --format="%s" --name-only 2>/dev/null`,
|
|
6841
6640
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
6842
6641
|
).trim();
|
|
@@ -6875,7 +6674,7 @@ function getGitHubStats(days = 7) {
|
|
|
6875
6674
|
const prsMerged = /* @__PURE__ */ new Map();
|
|
6876
6675
|
const issuesClosed = /* @__PURE__ */ new Map();
|
|
6877
6676
|
try {
|
|
6878
|
-
const prsOutput =
|
|
6677
|
+
const prsOutput = execSync9(
|
|
6879
6678
|
`gh pr list --state all --json title,createdAt,mergedAt --limit 50 2>/dev/null`,
|
|
6880
6679
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
6881
6680
|
);
|
|
@@ -6890,7 +6689,7 @@ function getGitHubStats(days = 7) {
|
|
|
6890
6689
|
prsMerged.set(squad, (prsMerged.get(squad) || 0) + 1);
|
|
6891
6690
|
}
|
|
6892
6691
|
}
|
|
6893
|
-
const issuesOutput =
|
|
6692
|
+
const issuesOutput = execSync9(
|
|
6894
6693
|
`gh issue list --state closed --json title,closedAt --limit 50 2>/dev/null`,
|
|
6895
6694
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
6896
6695
|
);
|
|
@@ -7023,8 +6822,8 @@ async function resultsCommand(options = {}) {
|
|
|
7023
6822
|
}
|
|
7024
6823
|
|
|
7025
6824
|
// src/commands/history.ts
|
|
7026
|
-
import { existsSync as
|
|
7027
|
-
import { join as
|
|
6825
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
6826
|
+
import { join as join13 } from "path";
|
|
7028
6827
|
var BRIDGE_URL2 = process.env.SQUADS_BRIDGE_URL || "http://localhost:8088";
|
|
7029
6828
|
var FETCH_TIMEOUT_MS2 = 3e3;
|
|
7030
6829
|
async function fetchWithTimeout2(url, timeoutMs = FETCH_TIMEOUT_MS2) {
|
|
@@ -7069,12 +6868,12 @@ async function fetchFromBridge2(days, squad) {
|
|
|
7069
6868
|
function fetchFromLocal(days, squad) {
|
|
7070
6869
|
const executions = [];
|
|
7071
6870
|
const historyPaths = [
|
|
7072
|
-
|
|
7073
|
-
|
|
6871
|
+
join13(process.cwd(), ".agents/sessions/history.jsonl"),
|
|
6872
|
+
join13(process.env.HOME || "", "agents-squads/hq/.agents/sessions/history.jsonl")
|
|
7074
6873
|
];
|
|
7075
6874
|
let historyPath;
|
|
7076
6875
|
for (const path3 of historyPaths) {
|
|
7077
|
-
if (
|
|
6876
|
+
if (existsSync12(path3)) {
|
|
7078
6877
|
historyPath = path3;
|
|
7079
6878
|
break;
|
|
7080
6879
|
}
|
|
@@ -7083,7 +6882,7 @@ function fetchFromLocal(days, squad) {
|
|
|
7083
6882
|
return [];
|
|
7084
6883
|
}
|
|
7085
6884
|
try {
|
|
7086
|
-
const content =
|
|
6885
|
+
const content = readFileSync9(historyPath, "utf-8");
|
|
7087
6886
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
7088
6887
|
const cutoff = Date.now() - days * 24 * 60 * 60 * 1e3;
|
|
7089
6888
|
for (const line of lines) {
|
|
@@ -7419,19 +7218,19 @@ async function healthCommand(options = {}) {
|
|
|
7419
7218
|
}
|
|
7420
7219
|
|
|
7421
7220
|
// src/commands/workers.ts
|
|
7422
|
-
import { execSync as
|
|
7423
|
-
import { existsSync as
|
|
7424
|
-
import { join as
|
|
7221
|
+
import { execSync as execSync10 } from "child_process";
|
|
7222
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
|
|
7223
|
+
import { join as join14 } from "path";
|
|
7425
7224
|
function getTasksFilePath2() {
|
|
7426
7225
|
const memoryDir = findMemoryDir();
|
|
7427
7226
|
if (!memoryDir) return null;
|
|
7428
|
-
return
|
|
7227
|
+
return join14(memoryDir, "..", "tasks.json");
|
|
7429
7228
|
}
|
|
7430
7229
|
function loadActiveTasks() {
|
|
7431
7230
|
const tasksPath = getTasksFilePath2();
|
|
7432
|
-
if (!tasksPath || !
|
|
7231
|
+
if (!tasksPath || !existsSync13(tasksPath)) return [];
|
|
7433
7232
|
try {
|
|
7434
|
-
const data = JSON.parse(
|
|
7233
|
+
const data = JSON.parse(readFileSync10(tasksPath, "utf-8"));
|
|
7435
7234
|
return data.tasks?.filter((t) => t.status === "active") || [];
|
|
7436
7235
|
} catch {
|
|
7437
7236
|
return [];
|
|
@@ -7440,7 +7239,7 @@ function loadActiveTasks() {
|
|
|
7440
7239
|
function getRunningProcesses() {
|
|
7441
7240
|
const processes = [];
|
|
7442
7241
|
try {
|
|
7443
|
-
const psOutput =
|
|
7242
|
+
const psOutput = execSync10(
|
|
7444
7243
|
'ps aux | grep -E "claude|squads|astro|node.*agent" | grep -v grep',
|
|
7445
7244
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
7446
7245
|
).trim();
|
|
@@ -7491,7 +7290,7 @@ async function workersCommand(options = {}) {
|
|
|
7491
7290
|
writeLine();
|
|
7492
7291
|
if (options.kill) {
|
|
7493
7292
|
try {
|
|
7494
|
-
|
|
7293
|
+
execSync10(`kill ${options.kill}`, { stdio: "pipe" });
|
|
7495
7294
|
writeLine(` ${icons.success} Killed process ${colors.cyan}${options.kill}${RESET}`);
|
|
7496
7295
|
writeLine();
|
|
7497
7296
|
return;
|
|
@@ -7578,8 +7377,8 @@ function getElapsedTime2(startTime) {
|
|
|
7578
7377
|
}
|
|
7579
7378
|
|
|
7580
7379
|
// src/commands/context-feed.ts
|
|
7581
|
-
import { existsSync as
|
|
7582
|
-
import { join as
|
|
7380
|
+
import { existsSync as existsSync14, statSync as statSync3, readdirSync as readdirSync6, readFileSync as readFileSync11 } from "fs";
|
|
7381
|
+
import { join as join15 } from "path";
|
|
7583
7382
|
var BRIDGE_URL3 = process.env.SQUADS_BRIDGE_URL || "http://localhost:8088";
|
|
7584
7383
|
async function syncBriefToBridge(brief, sourcePath) {
|
|
7585
7384
|
try {
|
|
@@ -7608,10 +7407,10 @@ async function syncBriefToBridge(brief, sourcePath) {
|
|
|
7608
7407
|
}
|
|
7609
7408
|
function readBusinessBrief(squadsDir) {
|
|
7610
7409
|
if (!squadsDir) return void 0;
|
|
7611
|
-
const briefPath =
|
|
7612
|
-
if (!
|
|
7410
|
+
const briefPath = join15(squadsDir, "..", "BUSINESS_BRIEF.md");
|
|
7411
|
+
if (!existsSync14(briefPath)) return void 0;
|
|
7613
7412
|
try {
|
|
7614
|
-
const content =
|
|
7413
|
+
const content = readFileSync11(briefPath, "utf-8");
|
|
7615
7414
|
const brief = { raw: content };
|
|
7616
7415
|
const priorityMatch = content.match(/##\s*#1 Priority\s*\n+\*\*([^*]+)\*\*/);
|
|
7617
7416
|
if (priorityMatch) {
|
|
@@ -7661,7 +7460,7 @@ function readBusinessBrief(squadsDir) {
|
|
|
7661
7460
|
async function collectBriefingData(options) {
|
|
7662
7461
|
const squadsDir = findSquadsDir();
|
|
7663
7462
|
const memoryDir = findMemoryDir();
|
|
7664
|
-
const baseDir = squadsDir ?
|
|
7463
|
+
const baseDir = squadsDir ? join15(squadsDir, "..", "..", "..") : null;
|
|
7665
7464
|
const allSquads = squadsDir ? listSquads(squadsDir) : [];
|
|
7666
7465
|
if (options.squad && !allSquads.includes(options.squad)) {
|
|
7667
7466
|
return {
|
|
@@ -7701,14 +7500,14 @@ async function collectBriefingData(options) {
|
|
|
7701
7500
|
}
|
|
7702
7501
|
let lastActivity;
|
|
7703
7502
|
if (memoryDir) {
|
|
7704
|
-
const squadMemoryPath =
|
|
7705
|
-
if (
|
|
7503
|
+
const squadMemoryPath = join15(memoryDir, squadName);
|
|
7504
|
+
if (existsSync14(squadMemoryPath)) {
|
|
7706
7505
|
let mostRecent = 0;
|
|
7707
7506
|
try {
|
|
7708
7507
|
const walkDir = (dir) => {
|
|
7709
7508
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
7710
7509
|
for (const entry of entries) {
|
|
7711
|
-
const fullPath =
|
|
7510
|
+
const fullPath = join15(dir, entry.name);
|
|
7712
7511
|
if (entry.isDirectory()) {
|
|
7713
7512
|
walkDir(fullPath);
|
|
7714
7513
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -7788,7 +7587,7 @@ async function collectBriefingData(options) {
|
|
|
7788
7587
|
}
|
|
7789
7588
|
const brief = readBusinessBrief(squadsDir);
|
|
7790
7589
|
if (brief && squadsDir) {
|
|
7791
|
-
const briefPath =
|
|
7590
|
+
const briefPath = join15(squadsDir, "..", "BUSINESS_BRIEF.md");
|
|
7792
7591
|
syncBriefToBridge(brief, briefPath).catch(() => {
|
|
7793
7592
|
});
|
|
7794
7593
|
}
|
|
@@ -7996,7 +7795,7 @@ async function runCommand2(command, args, clear) {
|
|
|
7996
7795
|
// src/commands/live.ts
|
|
7997
7796
|
import blessed from "blessed";
|
|
7998
7797
|
import contrib from "blessed-contrib";
|
|
7999
|
-
import { execSync as
|
|
7798
|
+
import { execSync as execSync11 } from "child_process";
|
|
8000
7799
|
async function liveCommand(_options) {
|
|
8001
7800
|
const screen = blessed.screen({
|
|
8002
7801
|
smartCSR: true,
|
|
@@ -8039,7 +7838,7 @@ async function liveCommand(_options) {
|
|
|
8039
7838
|
});
|
|
8040
7839
|
function getAgents() {
|
|
8041
7840
|
try {
|
|
8042
|
-
const output =
|
|
7841
|
+
const output = execSync11('ps aux | grep -E "claude|node.*squads" | grep -v grep', {
|
|
8043
7842
|
encoding: "utf-8",
|
|
8044
7843
|
timeout: 5e3
|
|
8045
7844
|
});
|
|
@@ -8088,7 +7887,7 @@ async function liveCommand(_options) {
|
|
|
8088
7887
|
}
|
|
8089
7888
|
function getRecentActivity2() {
|
|
8090
7889
|
try {
|
|
8091
|
-
const output =
|
|
7890
|
+
const output = execSync11(
|
|
8092
7891
|
"gh issue list --repo agents-squads/squads-cli --state open --limit 5 --json number,title,createdAt 2>/dev/null",
|
|
8093
7892
|
{ encoding: "utf-8", timeout: 1e4 }
|
|
8094
7893
|
);
|
|
@@ -8102,7 +7901,7 @@ async function liveCommand(_options) {
|
|
|
8102
7901
|
}
|
|
8103
7902
|
function getMemoryUpdates() {
|
|
8104
7903
|
try {
|
|
8105
|
-
const output =
|
|
7904
|
+
const output = execSync11(
|
|
8106
7905
|
'find .agents/memory -name "state.md" -mmin -60 2>/dev/null | head -5',
|
|
8107
7906
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
8108
7907
|
);
|
|
@@ -8178,7 +7977,7 @@ async function liveCommand(_options) {
|
|
|
8178
7977
|
}
|
|
8179
7978
|
|
|
8180
7979
|
// src/commands/top.ts
|
|
8181
|
-
import { execSync as
|
|
7980
|
+
import { execSync as execSync12 } from "child_process";
|
|
8182
7981
|
var ESC = "\x1B";
|
|
8183
7982
|
var CLEAR_SCREEN = `${ESC}[2J`;
|
|
8184
7983
|
var CURSOR_HOME = `${ESC}[H`;
|
|
@@ -8212,7 +8011,7 @@ function getProcessData() {
|
|
|
8212
8011
|
let claudeCount = 0;
|
|
8213
8012
|
let agentCount = 0;
|
|
8214
8013
|
try {
|
|
8215
|
-
const psOutput =
|
|
8014
|
+
const psOutput = execSync12(
|
|
8216
8015
|
'ps aux | grep -E "[c]laude" | head -15',
|
|
8217
8016
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
8218
8017
|
);
|
|
@@ -8237,7 +8036,7 @@ function getProcessData() {
|
|
|
8237
8036
|
} catch {
|
|
8238
8037
|
}
|
|
8239
8038
|
try {
|
|
8240
|
-
const tmuxOutput =
|
|
8039
|
+
const tmuxOutput = execSync12("tmux ls 2>/dev/null | grep squads- | wc -l", { encoding: "utf-8" });
|
|
8241
8040
|
agentCount = parseInt(tmuxOutput.trim()) || 0;
|
|
8242
8041
|
} catch {
|
|
8243
8042
|
}
|
|
@@ -8340,7 +8139,7 @@ async function detectSquadCommand() {
|
|
|
8340
8139
|
|
|
8341
8140
|
// src/commands/trigger.ts
|
|
8342
8141
|
import chalk3 from "chalk";
|
|
8343
|
-
import { existsSync as
|
|
8142
|
+
import { existsSync as existsSync15 } from "fs";
|
|
8344
8143
|
var SCHEDULER_URL = process.env.SCHEDULER_URL || "http://localhost:8090";
|
|
8345
8144
|
async function fetchScheduler(path3, options) {
|
|
8346
8145
|
const res = await fetch(`${SCHEDULER_URL}${path3}`, {
|
|
@@ -8386,12 +8185,12 @@ async function listTriggers(squad) {
|
|
|
8386
8185
|
}
|
|
8387
8186
|
async function syncTriggers() {
|
|
8388
8187
|
console.log(chalk3.gray("Syncing triggers from SQUAD.md files...\n"));
|
|
8389
|
-
const { execSync:
|
|
8188
|
+
const { execSync: execSync14 } = await import("child_process");
|
|
8390
8189
|
const hqPath = process.env.HQ_PATH || `${process.env.HOME}/agents-squads/hq`;
|
|
8391
8190
|
try {
|
|
8392
8191
|
const venvPython = `${hqPath}/squads-scheduler/.venv/bin/python`;
|
|
8393
|
-
const pythonCmd =
|
|
8394
|
-
const output =
|
|
8192
|
+
const pythonCmd = existsSync15(venvPython) ? venvPython : "python3";
|
|
8193
|
+
const output = execSync14(
|
|
8395
8194
|
`${pythonCmd} ${hqPath}/squads-scheduler/sync_triggers.py`,
|
|
8396
8195
|
{ encoding: "utf-8", cwd: hqPath }
|
|
8397
8196
|
);
|
|
@@ -8474,13 +8273,13 @@ function registerTriggerCommand(program2) {
|
|
|
8474
8273
|
|
|
8475
8274
|
// src/commands/skill.ts
|
|
8476
8275
|
import ora6 from "ora";
|
|
8477
|
-
import { existsSync as
|
|
8478
|
-
import { join as
|
|
8276
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync8, writeFileSync as writeFileSync9, readFileSync as readFileSync13 } from "fs";
|
|
8277
|
+
import { join as join17, basename as basename2, dirname as dirname4 } from "path";
|
|
8479
8278
|
|
|
8480
8279
|
// src/lib/anthropic.ts
|
|
8481
8280
|
import Anthropic from "@anthropic-ai/sdk";
|
|
8482
|
-
import { readFileSync as
|
|
8483
|
-
import { join as
|
|
8281
|
+
import { readFileSync as readFileSync12, readdirSync as readdirSync7 } from "fs";
|
|
8282
|
+
import { join as join16 } from "path";
|
|
8484
8283
|
var client = null;
|
|
8485
8284
|
function getClient() {
|
|
8486
8285
|
if (!client) {
|
|
@@ -8509,12 +8308,12 @@ function loadSkillFiles(skillPath) {
|
|
|
8509
8308
|
function walkDir(dir, prefix = "") {
|
|
8510
8309
|
const entries = readdirSync7(dir, { withFileTypes: true });
|
|
8511
8310
|
for (const entry of entries) {
|
|
8512
|
-
const fullPath =
|
|
8311
|
+
const fullPath = join16(dir, entry.name);
|
|
8513
8312
|
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
8514
8313
|
if (entry.isDirectory()) {
|
|
8515
8314
|
walkDir(fullPath, relativePath);
|
|
8516
8315
|
} else if (entry.isFile()) {
|
|
8517
|
-
const content =
|
|
8316
|
+
const content = readFileSync12(fullPath, "utf-8");
|
|
8518
8317
|
files.push({
|
|
8519
8318
|
name: relativePath,
|
|
8520
8319
|
content
|
|
@@ -8678,14 +8477,14 @@ async function skillUploadCommand(skillPath) {
|
|
|
8678
8477
|
writeLine();
|
|
8679
8478
|
return;
|
|
8680
8479
|
}
|
|
8681
|
-
const fullPath = skillPath.startsWith("/") ? skillPath :
|
|
8682
|
-
if (!
|
|
8480
|
+
const fullPath = skillPath.startsWith("/") ? skillPath : join17(process.cwd(), skillPath);
|
|
8481
|
+
if (!existsSync16(fullPath)) {
|
|
8683
8482
|
writeLine(` ${icons.error} ${colors.red}Directory not found: ${skillPath}${RESET}`);
|
|
8684
8483
|
writeLine();
|
|
8685
8484
|
return;
|
|
8686
8485
|
}
|
|
8687
|
-
const skillMdPath =
|
|
8688
|
-
if (!
|
|
8486
|
+
const skillMdPath = join17(fullPath, "SKILL.md");
|
|
8487
|
+
if (!existsSync16(skillMdPath)) {
|
|
8689
8488
|
writeLine(` ${icons.error} ${colors.red}SKILL.md not found in ${skillPath}${RESET}`);
|
|
8690
8489
|
writeLine();
|
|
8691
8490
|
writeLine(` ${colors.dim}Create a SKILL.md file or use:${RESET}`);
|
|
@@ -8796,7 +8595,7 @@ async function skillConvertCommand(agentPath, options) {
|
|
|
8796
8595
|
const [squad, agent] = agentPath.split("/");
|
|
8797
8596
|
squadName = squad;
|
|
8798
8597
|
agentName = agent.replace(".md", "");
|
|
8799
|
-
agentFilePath =
|
|
8598
|
+
agentFilePath = join17(squadsDir, squad, `${agentName}.md`);
|
|
8800
8599
|
} else {
|
|
8801
8600
|
agentName = agentPath.replace(".md", "");
|
|
8802
8601
|
const foundPath = findAgentFile(squadsDir, agentName);
|
|
@@ -8807,22 +8606,22 @@ async function skillConvertCommand(agentPath, options) {
|
|
|
8807
8606
|
return;
|
|
8808
8607
|
}
|
|
8809
8608
|
agentFilePath = foundPath;
|
|
8810
|
-
squadName = basename2(
|
|
8609
|
+
squadName = basename2(dirname4(agentFilePath));
|
|
8811
8610
|
}
|
|
8812
|
-
if (!
|
|
8611
|
+
if (!existsSync16(agentFilePath)) {
|
|
8813
8612
|
writeLine(` ${icons.error} ${colors.red}Agent file not found: ${agentFilePath}${RESET}`);
|
|
8814
8613
|
writeLine();
|
|
8815
8614
|
return;
|
|
8816
8615
|
}
|
|
8817
|
-
const agentContent =
|
|
8616
|
+
const agentContent = readFileSync13(agentFilePath, "utf-8");
|
|
8818
8617
|
const skillName = `${squadName}-${agentName}`;
|
|
8819
|
-
const outputDir = options.output ||
|
|
8820
|
-
if (!
|
|
8821
|
-
|
|
8618
|
+
const outputDir = options.output || join17(dirname4(squadsDir), "skills", skillName);
|
|
8619
|
+
if (!existsSync16(outputDir)) {
|
|
8620
|
+
mkdirSync8(outputDir, { recursive: true });
|
|
8822
8621
|
}
|
|
8823
8622
|
const skillMd = convertAgentToSkill(agentContent, squadName, agentName);
|
|
8824
|
-
const skillMdPath =
|
|
8825
|
-
|
|
8623
|
+
const skillMdPath = join17(outputDir, "SKILL.md");
|
|
8624
|
+
writeFileSync9(skillMdPath, skillMd);
|
|
8826
8625
|
writeLine(` ${icons.success} ${colors.green}Converted:${RESET} ${agentPath}`);
|
|
8827
8626
|
writeLine();
|
|
8828
8627
|
writeLine(` ${colors.dim}Output:${RESET} ${outputDir}`);
|
|
@@ -8839,8 +8638,8 @@ function findAgentFile(squadsDir, agentName) {
|
|
|
8839
8638
|
const { readdirSync: readdirSync9 } = __require("fs");
|
|
8840
8639
|
const squads = readdirSync9(squadsDir, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith("_")).map((d) => d.name);
|
|
8841
8640
|
for (const squad of squads) {
|
|
8842
|
-
const agentPath =
|
|
8843
|
-
if (
|
|
8641
|
+
const agentPath = join17(squadsDir, squad, `${agentName}.md`);
|
|
8642
|
+
if (existsSync16(agentPath)) {
|
|
8844
8643
|
return agentPath;
|
|
8845
8644
|
}
|
|
8846
8645
|
}
|
|
@@ -8881,8 +8680,8 @@ function formatBytes(bytes) {
|
|
|
8881
8680
|
}
|
|
8882
8681
|
|
|
8883
8682
|
// src/commands/permissions.ts
|
|
8884
|
-
import { readFileSync as
|
|
8885
|
-
import { join as
|
|
8683
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
8684
|
+
import { join as join18 } from "path";
|
|
8886
8685
|
function registerPermissionsCommand(program2) {
|
|
8887
8686
|
const permissions = program2.command("permissions").alias("perms").description("Manage and validate squad permissions");
|
|
8888
8687
|
permissions.command("show <squad>").description("Show permission context for a squad").action(permissionsShowCommand);
|
|
@@ -8904,8 +8703,8 @@ async function permissionsShowCommand(squadName) {
|
|
|
8904
8703
|
writeLine();
|
|
8905
8704
|
return;
|
|
8906
8705
|
}
|
|
8907
|
-
const squadFilePath =
|
|
8908
|
-
const squadContent =
|
|
8706
|
+
const squadFilePath = join18(squadsDir, squadName, "SQUAD.md");
|
|
8707
|
+
const squadContent = readFileSync14(squadFilePath, "utf-8");
|
|
8909
8708
|
const context2 = buildContextFromSquad(squadName, squadContent);
|
|
8910
8709
|
const defaults = getDefaultContext(squadName);
|
|
8911
8710
|
const isDefault = JSON.stringify(context2.permissions) === JSON.stringify(defaults.permissions);
|
|
@@ -8999,8 +8798,8 @@ async function permissionsCheckCommand(squadName, options) {
|
|
|
8999
8798
|
writeLine();
|
|
9000
8799
|
return;
|
|
9001
8800
|
}
|
|
9002
|
-
const squadFilePath =
|
|
9003
|
-
const squadContent =
|
|
8801
|
+
const squadFilePath = join18(squadsDir, squadName, "SQUAD.md");
|
|
8802
|
+
const squadContent = readFileSync14(squadFilePath, "utf-8");
|
|
9004
8803
|
const context2 = buildContextFromSquad(squadName, squadContent, options.agent);
|
|
9005
8804
|
const request = {
|
|
9006
8805
|
mcpServers: options.mcp,
|
|
@@ -9433,8 +9232,8 @@ function createBudgetBar(percent, width = 10) {
|
|
|
9433
9232
|
}
|
|
9434
9233
|
|
|
9435
9234
|
// src/lib/executions.ts
|
|
9436
|
-
import { readFileSync as
|
|
9437
|
-
import { join as
|
|
9235
|
+
import { readFileSync as readFileSync15, existsSync as existsSync17, readdirSync as readdirSync8 } from "fs";
|
|
9236
|
+
import { join as join19 } from "path";
|
|
9438
9237
|
function parseExecutionEntry(content, squad, agent) {
|
|
9439
9238
|
const idMatch = content.match(/<!-- exec:(\S+) -->/);
|
|
9440
9239
|
if (!idMatch) return null;
|
|
@@ -9472,8 +9271,8 @@ function parseExecutionEntry(content, squad, agent) {
|
|
|
9472
9271
|
};
|
|
9473
9272
|
}
|
|
9474
9273
|
function parseExecutionLog(filePath, squad, agent) {
|
|
9475
|
-
if (!
|
|
9476
|
-
const content =
|
|
9274
|
+
if (!existsSync17(filePath)) return [];
|
|
9275
|
+
const content = readFileSync15(filePath, "utf-8");
|
|
9477
9276
|
const executions = [];
|
|
9478
9277
|
const entries = content.split(/\n---\n/);
|
|
9479
9278
|
for (const entry of entries) {
|
|
@@ -9511,11 +9310,11 @@ function listExecutions(options = {}) {
|
|
|
9511
9310
|
const squads = readdirSync8(memoryDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
9512
9311
|
for (const squad of squads) {
|
|
9513
9312
|
if (filterSquad && squad !== filterSquad) continue;
|
|
9514
|
-
const squadPath =
|
|
9313
|
+
const squadPath = join19(memoryDir, squad);
|
|
9515
9314
|
const agents = readdirSync8(squadPath, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
9516
9315
|
for (const agent of agents) {
|
|
9517
9316
|
if (filterAgent && agent !== filterAgent) continue;
|
|
9518
|
-
const logPath =
|
|
9317
|
+
const logPath = join19(squadPath, agent, "executions.md");
|
|
9519
9318
|
const agentExecutions = parseExecutionLog(logPath, squad, agent);
|
|
9520
9319
|
executions.push(...agentExecutions);
|
|
9521
9320
|
}
|
|
@@ -9765,12 +9564,12 @@ async function execStatsCommand(options = {}) {
|
|
|
9765
9564
|
// src/commands/tonight.ts
|
|
9766
9565
|
import ora7 from "ora";
|
|
9767
9566
|
import fs2 from "fs/promises";
|
|
9768
|
-
import path2, { dirname as
|
|
9769
|
-
import { execSync as
|
|
9567
|
+
import path2, { dirname as dirname5 } from "path";
|
|
9568
|
+
import { execSync as execSync13, spawn as spawn7 } from "child_process";
|
|
9770
9569
|
function getProjectRoot2() {
|
|
9771
9570
|
const squadsDir = findSquadsDir();
|
|
9772
9571
|
if (squadsDir) {
|
|
9773
|
-
return
|
|
9572
|
+
return dirname5(dirname5(squadsDir));
|
|
9774
9573
|
}
|
|
9775
9574
|
return process.cwd();
|
|
9776
9575
|
}
|
|
@@ -9789,10 +9588,10 @@ async function getCurrentCost() {
|
|
|
9789
9588
|
}
|
|
9790
9589
|
function killAllSessions() {
|
|
9791
9590
|
try {
|
|
9792
|
-
const sessions2 =
|
|
9591
|
+
const sessions2 = execSync13('tmux ls 2>/dev/null | grep "squads-tonight-" | cut -d: -f1', { encoding: "utf-8" }).trim().split("\n").filter(Boolean);
|
|
9793
9592
|
for (const session2 of sessions2) {
|
|
9794
9593
|
try {
|
|
9795
|
-
|
|
9594
|
+
execSync13(`tmux kill-session -t "${session2}"`, { stdio: "ignore" });
|
|
9796
9595
|
} catch {
|
|
9797
9596
|
}
|
|
9798
9597
|
}
|
|
@@ -9803,7 +9602,7 @@ function killAllSessions() {
|
|
|
9803
9602
|
}
|
|
9804
9603
|
function getRunningSessionCount() {
|
|
9805
9604
|
try {
|
|
9806
|
-
const output =
|
|
9605
|
+
const output = execSync13('tmux ls 2>/dev/null | grep "squads-tonight-" | wc -l', { encoding: "utf-8" });
|
|
9807
9606
|
return parseInt(output.trim()) || 0;
|
|
9808
9607
|
} catch {
|
|
9809
9608
|
return 0;
|
|
@@ -10018,7 +9817,7 @@ async function tonightStatusCommand() {
|
|
|
10018
9817
|
}
|
|
10019
9818
|
writeLine();
|
|
10020
9819
|
try {
|
|
10021
|
-
const sessions2 =
|
|
9820
|
+
const sessions2 = execSync13("tmux ls 2>/dev/null | grep squads-tonight", { encoding: "utf-8" }).trim().split("\n").filter(Boolean);
|
|
10022
9821
|
if (sessions2.length > 0) {
|
|
10023
9822
|
writeLine(` ${colors.dim}Sessions:${RESET}`);
|
|
10024
9823
|
for (const session2 of sessions2) {
|
|
@@ -10098,12 +9897,12 @@ process.stderr.on("error", (err) => {
|
|
|
10098
9897
|
throw err;
|
|
10099
9898
|
});
|
|
10100
9899
|
var envPaths = [
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
9900
|
+
join20(process.cwd(), ".env"),
|
|
9901
|
+
join20(process.cwd(), "..", "hq", ".env"),
|
|
9902
|
+
join20(homedir4(), "agents-squads", "hq", ".env")
|
|
10104
9903
|
];
|
|
10105
9904
|
for (const envPath of envPaths) {
|
|
10106
|
-
if (
|
|
9905
|
+
if (existsSync18(envPath)) {
|
|
10107
9906
|
config({ path: envPath, quiet: true });
|
|
10108
9907
|
break;
|
|
10109
9908
|
}
|
|
@@ -10122,6 +9921,19 @@ program.name("squads").description("A CLI for humans and agents").version(versio
|
|
|
10122
9921
|
process.exit(err.exitCode);
|
|
10123
9922
|
}
|
|
10124
9923
|
throw err;
|
|
9924
|
+
}).action(async () => {
|
|
9925
|
+
const { gradient: gradient2, colors: colors2, RESET: RESET3 } = await import("./terminal-JZSAQSN7.js");
|
|
9926
|
+
const { checkForUpdate: checkForUpdate2 } = await import("./update-MAY6EXFQ.js");
|
|
9927
|
+
console.log();
|
|
9928
|
+
console.log(` ${gradient2("squads")} ${colors2.dim}v${version}${RESET3}`);
|
|
9929
|
+
console.log();
|
|
9930
|
+
const updateInfo = checkForUpdate2();
|
|
9931
|
+
if (updateInfo.updateAvailable) {
|
|
9932
|
+
console.log(` ${colors2.cyan}\u2B06${RESET3} Update available: ${colors2.dim}${updateInfo.currentVersion}${RESET3} \u2192 ${colors2.green}${updateInfo.latestVersion}${RESET3}`);
|
|
9933
|
+
console.log(` ${colors2.dim}Run \`squads update\` to install${RESET3}`);
|
|
9934
|
+
console.log();
|
|
9935
|
+
}
|
|
9936
|
+
await statusCommand(void 0, {});
|
|
10125
9937
|
});
|
|
10126
9938
|
program.command("init").description("Initialize a new squad project").option("-t, --template <template>", "Project template", "default").option("--skip-infra", "Skip infrastructure setup prompt").action(initCommand);
|
|
10127
9939
|
program.command("run <target>").description("Run a squad or agent").option("-v, --verbose", "Verbose output").option("-d, --dry-run", "Show what would be run without executing").option("-e, --execute", "Execute agent via Claude CLI (requires claude installed)").option("-a, --agent <agent>", "Run specific agent within squad").option("-t, --timeout <minutes>", "Execution timeout in minutes (default: 30)", "30").option("-p, --parallel", "Run all agents in parallel (N tmux sessions)").option("-l, --lead", "Lead mode: single orchestrator using Task tool for parallelization").option("-f, --foreground", "Run in foreground (no tmux, blocks terminal)").option("--use-api", "Use API credits instead of subscription").option("--effort <level>", "Effort level: high, medium, low (default: from SQUAD.md or high)").option("--skills <skills...>", "Skills to load (skill IDs or local paths)").action((target, options) => runCommand(target, { ...options, timeout: parseInt(options.timeout, 10) }));
|
|
@@ -10191,11 +10003,11 @@ sessions.command("history").description("Show session history and statistics").o
|
|
|
10191
10003
|
json: options.json
|
|
10192
10004
|
}));
|
|
10193
10005
|
sessions.command("summary").description("Show pretty session summary (auto-detects current session or pass JSON)").option("-d, --data <json>", "JSON data for summary (overrides auto-detection)").option("-f, --file <path>", "Path to JSON file with summary data").option("-j, --json", "Output as JSON instead of pretty format").action(async (options) => {
|
|
10194
|
-
const { buildCurrentSessionSummary } = await import("./sessions-
|
|
10006
|
+
const { buildCurrentSessionSummary } = await import("./sessions-R4VWIGFR.js");
|
|
10195
10007
|
let data;
|
|
10196
10008
|
if (options.file) {
|
|
10197
|
-
const { readFileSync:
|
|
10198
|
-
data = JSON.parse(
|
|
10009
|
+
const { readFileSync: readFileSync16 } = await import("fs");
|
|
10010
|
+
data = JSON.parse(readFileSync16(options.file, "utf-8"));
|
|
10199
10011
|
} else if (options.data) {
|
|
10200
10012
|
data = JSON.parse(options.data);
|
|
10201
10013
|
} else if (!process.stdin.isTTY) {
|
|
@@ -10291,31 +10103,4 @@ try {
|
|
|
10291
10103
|
} catch (error) {
|
|
10292
10104
|
handleError(error);
|
|
10293
10105
|
}
|
|
10294
|
-
if (!process.argv.slice(2).length) {
|
|
10295
|
-
console.log(`
|
|
10296
|
-
${chalk4.bold.magenta("squads")} - AI agent squad management
|
|
10297
|
-
|
|
10298
|
-
${chalk4.dim("Quick start:")}
|
|
10299
|
-
${chalk4.cyan("squads status")} View all squads status
|
|
10300
|
-
${chalk4.cyan("squads run <squad>")} Run a squad
|
|
10301
|
-
${chalk4.cyan('squads memory query "<term>"')} Search squad memory
|
|
10302
|
-
|
|
10303
|
-
${chalk4.dim("Goals & Feedback:")}
|
|
10304
|
-
${chalk4.cyan('squads goal set <squad> "<goal>"')} Set a goal
|
|
10305
|
-
${chalk4.cyan("squads goal list")} View active goals
|
|
10306
|
-
${chalk4.cyan('squads feedback add <squad> 4 "msg"')} Rate last execution
|
|
10307
|
-
|
|
10308
|
-
${chalk4.dim("Smart Triggers:")}
|
|
10309
|
-
${chalk4.cyan("squads trigger list")} View all triggers
|
|
10310
|
-
${chalk4.cyan("squads trigger sync")} Sync from SQUAD.md
|
|
10311
|
-
${chalk4.cyan("squads trigger fire <name>")} Manually fire trigger
|
|
10312
|
-
|
|
10313
|
-
${chalk4.dim("Examples:")}
|
|
10314
|
-
${chalk4.cyan("squads run website")} Run website squad
|
|
10315
|
-
${chalk4.cyan('squads goal set finance "Track costs"')} Set finance goal
|
|
10316
|
-
${chalk4.cyan("squads trigger status")} Scheduler health
|
|
10317
|
-
|
|
10318
|
-
${chalk4.dim("Run")} ${chalk4.cyan("squads --help")} ${chalk4.dim("for all commands.")}
|
|
10319
|
-
`);
|
|
10320
|
-
}
|
|
10321
10106
|
//# sourceMappingURL=cli.js.map
|