squads-cli 0.4.7 → 0.4.8
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-EGOVJOZJ.js → chunk-IDZYXBZY.js} +55 -13
- package/dist/chunk-IDZYXBZY.js.map +1 -0
- package/dist/cli.js +310 -252
- package/dist/cli.js.map +1 -1
- package/dist/{sessions-SEITSWEV.js → sessions-B6GVXJ2H.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-EGOVJOZJ.js.map +0 -1
- /package/dist/{sessions-SEITSWEV.js.map → sessions-B6GVXJ2H.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
truncate,
|
|
29
29
|
updateHeartbeat,
|
|
30
30
|
writeLine
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-IDZYXBZY.js";
|
|
32
32
|
import {
|
|
33
33
|
__require
|
|
34
34
|
} from "./chunk-7OCVIDC7.js";
|
|
@@ -47,18 +47,227 @@ var require2 = createRequire(import.meta.url);
|
|
|
47
47
|
var pkg = require2("../package.json");
|
|
48
48
|
var version = pkg.version;
|
|
49
49
|
|
|
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
|
+
|
|
50
259
|
// src/commands/init.ts
|
|
51
260
|
import chalk from "chalk";
|
|
52
261
|
import ora from "ora";
|
|
53
262
|
import fs from "fs/promises";
|
|
54
263
|
import path from "path";
|
|
55
|
-
import { execSync as
|
|
264
|
+
import { execSync as execSync3, spawn } from "child_process";
|
|
56
265
|
import { createInterface } from "readline";
|
|
57
266
|
|
|
58
267
|
// src/lib/git.ts
|
|
59
|
-
import { execSync, exec } from "child_process";
|
|
60
|
-
import { existsSync } from "fs";
|
|
61
|
-
import { join } from "path";
|
|
268
|
+
import { execSync as execSync2, exec } from "child_process";
|
|
269
|
+
import { existsSync as existsSync2 } from "fs";
|
|
270
|
+
import { join as join2 } from "path";
|
|
62
271
|
import { promisify } from "util";
|
|
63
272
|
var execAsync = promisify(exec);
|
|
64
273
|
function checkGitStatus(cwd = process.cwd()) {
|
|
@@ -68,12 +277,12 @@ function checkGitStatus(cwd = process.cwd()) {
|
|
|
68
277
|
isDirty: false,
|
|
69
278
|
uncommittedCount: 0
|
|
70
279
|
};
|
|
71
|
-
if (!
|
|
280
|
+
if (!existsSync2(join2(cwd, ".git"))) {
|
|
72
281
|
return status;
|
|
73
282
|
}
|
|
74
283
|
status.isGitRepo = true;
|
|
75
284
|
try {
|
|
76
|
-
const combined =
|
|
285
|
+
const combined = execSync2(
|
|
77
286
|
'echo "BRANCH:" && git rev-parse --abbrev-ref HEAD && echo "REMOTES:" && git remote -v && echo "STATUS:" && git status --porcelain',
|
|
78
287
|
{ cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }
|
|
79
288
|
);
|
|
@@ -157,10 +366,10 @@ function getGitHubStatsOptimized(basePath, days = 30) {
|
|
|
157
366
|
const since = new Date(Date.now() - days * 24 * 60 * 60 * 1e3).toISOString();
|
|
158
367
|
const results = [];
|
|
159
368
|
for (const repo of repos) {
|
|
160
|
-
const repoPath =
|
|
161
|
-
if (!
|
|
369
|
+
const repoPath = join2(basePath, repo);
|
|
370
|
+
if (!existsSync2(repoPath)) continue;
|
|
162
371
|
try {
|
|
163
|
-
const output =
|
|
372
|
+
const output = execSync2(
|
|
164
373
|
`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 '}'`,
|
|
165
374
|
{ cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 1e4 }
|
|
166
375
|
);
|
|
@@ -171,11 +380,11 @@ function getGitHubStatsOptimized(basePath, days = 30) {
|
|
|
171
380
|
results.push({ repo, prs, issues });
|
|
172
381
|
} catch {
|
|
173
382
|
try {
|
|
174
|
-
const prsOutput =
|
|
383
|
+
const prsOutput = execSync2(
|
|
175
384
|
`gh pr list --state all --json number,title,createdAt,mergedAt,labels --limit 50 2>/dev/null`,
|
|
176
385
|
{ cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }
|
|
177
386
|
);
|
|
178
|
-
const issuesOutput =
|
|
387
|
+
const issuesOutput = execSync2(
|
|
179
388
|
`gh issue list --state all --json number,title,state,closedAt,labels --limit 50 2>/dev/null`,
|
|
180
389
|
{ cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }
|
|
181
390
|
);
|
|
@@ -291,12 +500,12 @@ function getMultiRepoGitStats(basePath, days = 30) {
|
|
|
291
500
|
};
|
|
292
501
|
const allCommits = [];
|
|
293
502
|
for (const repo of SQUAD_REPOS) {
|
|
294
|
-
const repoPath =
|
|
295
|
-
if (!
|
|
503
|
+
const repoPath = join2(basePath, repo);
|
|
504
|
+
if (!existsSync2(repoPath) || !existsSync2(join2(repoPath, ".git"))) {
|
|
296
505
|
continue;
|
|
297
506
|
}
|
|
298
507
|
try {
|
|
299
|
-
const logOutput =
|
|
508
|
+
const logOutput = execSync2(
|
|
300
509
|
`git log --since="${days} days ago" --format="%H|%aN|%ad|%s" --date=short 2>/dev/null`,
|
|
301
510
|
{ cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
302
511
|
).trim();
|
|
@@ -353,12 +562,12 @@ function getActivitySparkline(basePath, days = 7) {
|
|
|
353
562
|
activity.push(0);
|
|
354
563
|
}
|
|
355
564
|
for (const repo of SQUAD_REPOS) {
|
|
356
|
-
const repoPath =
|
|
357
|
-
if (!
|
|
565
|
+
const repoPath = join2(basePath, repo);
|
|
566
|
+
if (!existsSync2(repoPath) || !existsSync2(join2(repoPath, ".git"))) {
|
|
358
567
|
continue;
|
|
359
568
|
}
|
|
360
569
|
try {
|
|
361
|
-
const logOutput =
|
|
570
|
+
const logOutput = execSync2(
|
|
362
571
|
`git log --since="${days} days ago" --format="%ad" --date=short 2>/dev/null`,
|
|
363
572
|
{ cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
364
573
|
).trim();
|
|
@@ -378,13 +587,13 @@ function getActivitySparkline(basePath, days = 7) {
|
|
|
378
587
|
}
|
|
379
588
|
|
|
380
589
|
// src/lib/telemetry.ts
|
|
381
|
-
import { existsSync as
|
|
382
|
-
import { join as
|
|
383
|
-
import { homedir } from "os";
|
|
590
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
591
|
+
import { join as join3 } from "path";
|
|
592
|
+
import { homedir as homedir2 } from "os";
|
|
384
593
|
import { randomUUID } from "crypto";
|
|
385
|
-
var TELEMETRY_DIR =
|
|
386
|
-
var CONFIG_PATH =
|
|
387
|
-
var EVENTS_PATH =
|
|
594
|
+
var TELEMETRY_DIR = join3(homedir2(), ".squads-cli");
|
|
595
|
+
var CONFIG_PATH = join3(TELEMETRY_DIR, "telemetry.json");
|
|
596
|
+
var EVENTS_PATH = join3(TELEMETRY_DIR, "events.json");
|
|
388
597
|
var TELEMETRY_ENDPOINT = Buffer.from(
|
|
389
598
|
"aHR0cHM6Ly9zcXVhZHMtdGVsZW1ldHJ5LTk3ODg3MTgxNzYxMC51cy1jZW50cmFsMS5ydW4uYXBwL3Bpbmc=",
|
|
390
599
|
"base64"
|
|
@@ -393,24 +602,24 @@ var TELEMETRY_KEY = Buffer.from("c3FfdGVsX3YxXzdmOGE5YjJjM2Q0ZTVmNmE=", "base64"
|
|
|
393
602
|
var eventQueue = [];
|
|
394
603
|
var flushScheduled = false;
|
|
395
604
|
function ensureDir() {
|
|
396
|
-
if (!
|
|
397
|
-
|
|
605
|
+
if (!existsSync3(TELEMETRY_DIR)) {
|
|
606
|
+
mkdirSync2(TELEMETRY_DIR, { recursive: true });
|
|
398
607
|
}
|
|
399
608
|
}
|
|
400
609
|
function getConfig() {
|
|
401
610
|
ensureDir();
|
|
402
|
-
if (!
|
|
611
|
+
if (!existsSync3(CONFIG_PATH)) {
|
|
403
612
|
const config2 = {
|
|
404
613
|
enabled: true,
|
|
405
614
|
// Opt-out by default (common for CLIs)
|
|
406
615
|
anonymousId: randomUUID(),
|
|
407
616
|
firstRun: (/* @__PURE__ */ new Date()).toISOString()
|
|
408
617
|
};
|
|
409
|
-
|
|
618
|
+
writeFileSync2(CONFIG_PATH, JSON.stringify(config2, null, 2));
|
|
410
619
|
return config2;
|
|
411
620
|
}
|
|
412
621
|
try {
|
|
413
|
-
return JSON.parse(
|
|
622
|
+
return JSON.parse(readFileSync2(CONFIG_PATH, "utf-8"));
|
|
414
623
|
} catch {
|
|
415
624
|
return { enabled: false, anonymousId: "", firstRun: "" };
|
|
416
625
|
}
|
|
@@ -470,9 +679,9 @@ async function flushEvents() {
|
|
|
470
679
|
function storeEventLocally(event) {
|
|
471
680
|
ensureDir();
|
|
472
681
|
let events = [];
|
|
473
|
-
if (
|
|
682
|
+
if (existsSync3(EVENTS_PATH)) {
|
|
474
683
|
try {
|
|
475
|
-
events = JSON.parse(
|
|
684
|
+
events = JSON.parse(readFileSync2(EVENTS_PATH, "utf-8"));
|
|
476
685
|
} catch {
|
|
477
686
|
events = [];
|
|
478
687
|
}
|
|
@@ -481,7 +690,7 @@ function storeEventLocally(event) {
|
|
|
481
690
|
if (events.length > 1e3) {
|
|
482
691
|
events = events.slice(-1e3);
|
|
483
692
|
}
|
|
484
|
-
|
|
693
|
+
writeFileSync2(EVENTS_PATH, JSON.stringify(events, null, 2));
|
|
485
694
|
}
|
|
486
695
|
var Events = {
|
|
487
696
|
// Lifecycle
|
|
@@ -578,7 +787,7 @@ async function promptEmail() {
|
|
|
578
787
|
}
|
|
579
788
|
function commandExists(cmd) {
|
|
580
789
|
try {
|
|
581
|
-
|
|
790
|
+
execSync3(`which ${cmd}`, { stdio: "ignore" });
|
|
582
791
|
return true;
|
|
583
792
|
} catch {
|
|
584
793
|
return false;
|
|
@@ -586,7 +795,7 @@ function commandExists(cmd) {
|
|
|
586
795
|
}
|
|
587
796
|
function dockerRunning() {
|
|
588
797
|
try {
|
|
589
|
-
|
|
798
|
+
execSync3("docker info", { stdio: "ignore" });
|
|
590
799
|
return true;
|
|
591
800
|
} catch {
|
|
592
801
|
return false;
|
|
@@ -594,12 +803,12 @@ function dockerRunning() {
|
|
|
594
803
|
}
|
|
595
804
|
function checkClaudeAuth() {
|
|
596
805
|
try {
|
|
597
|
-
|
|
806
|
+
execSync3("which claude", { stdio: "ignore" });
|
|
598
807
|
} catch {
|
|
599
808
|
return { installed: false, loggedIn: false };
|
|
600
809
|
}
|
|
601
810
|
try {
|
|
602
|
-
const result =
|
|
811
|
+
const result = execSync3("claude --version", { stdio: "pipe" }).toString();
|
|
603
812
|
return { installed: true, loggedIn: result.includes("claude") };
|
|
604
813
|
} catch {
|
|
605
814
|
return { installed: true, loggedIn: false };
|
|
@@ -607,7 +816,7 @@ function checkClaudeAuth() {
|
|
|
607
816
|
}
|
|
608
817
|
function checkGhAuth() {
|
|
609
818
|
try {
|
|
610
|
-
|
|
819
|
+
execSync3("gh auth status", { stdio: "ignore" });
|
|
611
820
|
return true;
|
|
612
821
|
} catch {
|
|
613
822
|
return false;
|
|
@@ -744,7 +953,7 @@ async function setupInfrastructure(cwd) {
|
|
|
744
953
|
let allRunning = true;
|
|
745
954
|
for (const service of services) {
|
|
746
955
|
try {
|
|
747
|
-
|
|
956
|
+
execSync3(`docker ps --filter "name=${service}" --filter "status=running" -q`, { stdio: "pipe" });
|
|
748
957
|
} catch {
|
|
749
958
|
allRunning = false;
|
|
750
959
|
}
|
|
@@ -1156,21 +1365,21 @@ squads goal list # View goals
|
|
|
1156
1365
|
// src/commands/run.ts
|
|
1157
1366
|
import ora2 from "ora";
|
|
1158
1367
|
import { spawn as spawn2 } from "child_process";
|
|
1159
|
-
import { join as
|
|
1160
|
-
import { existsSync as
|
|
1368
|
+
import { join as join5, dirname as dirname2 } from "path";
|
|
1369
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
1161
1370
|
|
|
1162
1371
|
// src/lib/squad-parser.ts
|
|
1163
|
-
import { readFileSync as
|
|
1164
|
-
import { join as
|
|
1372
|
+
import { readFileSync as readFileSync3, existsSync as existsSync4, readdirSync, writeFileSync as writeFileSync3 } from "fs";
|
|
1373
|
+
import { join as join4, basename } from "path";
|
|
1165
1374
|
import matter from "gray-matter";
|
|
1166
1375
|
function findSquadsDir() {
|
|
1167
1376
|
let dir = process.cwd();
|
|
1168
1377
|
for (let i = 0; i < 5; i++) {
|
|
1169
|
-
const squadsPath =
|
|
1170
|
-
if (
|
|
1378
|
+
const squadsPath = join4(dir, ".agents", "squads");
|
|
1379
|
+
if (existsSync4(squadsPath)) {
|
|
1171
1380
|
return squadsPath;
|
|
1172
1381
|
}
|
|
1173
|
-
const parent =
|
|
1382
|
+
const parent = join4(dir, "..");
|
|
1174
1383
|
if (parent === dir) break;
|
|
1175
1384
|
dir = parent;
|
|
1176
1385
|
}
|
|
@@ -1179,14 +1388,14 @@ function findSquadsDir() {
|
|
|
1179
1388
|
function findProjectRoot() {
|
|
1180
1389
|
const squadsDir = findSquadsDir();
|
|
1181
1390
|
if (!squadsDir) return null;
|
|
1182
|
-
return
|
|
1391
|
+
return join4(squadsDir, "..", "..");
|
|
1183
1392
|
}
|
|
1184
1393
|
function hasLocalInfraConfig() {
|
|
1185
1394
|
const projectRoot = findProjectRoot();
|
|
1186
1395
|
if (!projectRoot) return false;
|
|
1187
|
-
const envPath =
|
|
1188
|
-
if (!
|
|
1189
|
-
const content =
|
|
1396
|
+
const envPath = join4(projectRoot, ".env");
|
|
1397
|
+
if (!existsSync4(envPath)) return false;
|
|
1398
|
+
const content = readFileSync3(envPath, "utf-8");
|
|
1190
1399
|
const infraKeys = ["LANGFUSE_", "SQUADS_BRIDGE", "SQUADS_POSTGRES", "SQUADS_REDIS"];
|
|
1191
1400
|
return infraKeys.some((key) => content.includes(key));
|
|
1192
1401
|
}
|
|
@@ -1195,8 +1404,8 @@ function listSquads(squadsDir) {
|
|
|
1195
1404
|
const entries = readdirSync(squadsDir, { withFileTypes: true });
|
|
1196
1405
|
for (const entry of entries) {
|
|
1197
1406
|
if (entry.isDirectory() && !entry.name.startsWith("_")) {
|
|
1198
|
-
const squadFile =
|
|
1199
|
-
if (
|
|
1407
|
+
const squadFile = join4(squadsDir, entry.name, "SQUAD.md");
|
|
1408
|
+
if (existsSync4(squadFile)) {
|
|
1200
1409
|
squads.push(entry.name);
|
|
1201
1410
|
}
|
|
1202
1411
|
}
|
|
@@ -1207,8 +1416,8 @@ function listAgents(squadsDir, squadName) {
|
|
|
1207
1416
|
const agents = [];
|
|
1208
1417
|
const dirs = squadName ? [squadName] : readdirSync(squadsDir, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith("_")).map((e) => e.name);
|
|
1209
1418
|
for (const dir of dirs) {
|
|
1210
|
-
const squadPath =
|
|
1211
|
-
if (!
|
|
1419
|
+
const squadPath = join4(squadsDir, dir);
|
|
1420
|
+
if (!existsSync4(squadPath)) continue;
|
|
1212
1421
|
const files = readdirSync(squadPath);
|
|
1213
1422
|
for (const file of files) {
|
|
1214
1423
|
if (file.endsWith(".md") && file !== "SQUAD.md") {
|
|
@@ -1217,7 +1426,7 @@ function listAgents(squadsDir, squadName) {
|
|
|
1217
1426
|
name: agentName,
|
|
1218
1427
|
role: `Agent in ${dir}`,
|
|
1219
1428
|
trigger: "manual",
|
|
1220
|
-
filePath:
|
|
1429
|
+
filePath: join4(squadPath, file)
|
|
1221
1430
|
});
|
|
1222
1431
|
}
|
|
1223
1432
|
}
|
|
@@ -1225,7 +1434,7 @@ function listAgents(squadsDir, squadName) {
|
|
|
1225
1434
|
return agents;
|
|
1226
1435
|
}
|
|
1227
1436
|
function parseSquadFile(filePath) {
|
|
1228
|
-
const rawContent =
|
|
1437
|
+
const rawContent = readFileSync3(filePath, "utf-8");
|
|
1229
1438
|
const { data: frontmatter, content: bodyContent } = matter(rawContent);
|
|
1230
1439
|
const fm = frontmatter;
|
|
1231
1440
|
const lines = bodyContent.split("\n");
|
|
@@ -1346,20 +1555,20 @@ function parseSquadFile(filePath) {
|
|
|
1346
1555
|
function loadSquad(squadName) {
|
|
1347
1556
|
const squadsDir = findSquadsDir();
|
|
1348
1557
|
if (!squadsDir) return null;
|
|
1349
|
-
const squadFile =
|
|
1350
|
-
if (!
|
|
1558
|
+
const squadFile = join4(squadsDir, squadName, "SQUAD.md");
|
|
1559
|
+
if (!existsSync4(squadFile)) return null;
|
|
1351
1560
|
return parseSquadFile(squadFile);
|
|
1352
1561
|
}
|
|
1353
1562
|
function loadAgentDefinition(agentPath) {
|
|
1354
|
-
if (!
|
|
1355
|
-
return
|
|
1563
|
+
if (!existsSync4(agentPath)) return "";
|
|
1564
|
+
return readFileSync3(agentPath, "utf-8");
|
|
1356
1565
|
}
|
|
1357
1566
|
function addGoalToSquad(squadName, goal2) {
|
|
1358
1567
|
const squadsDir = findSquadsDir();
|
|
1359
1568
|
if (!squadsDir) return false;
|
|
1360
|
-
const squadFile =
|
|
1361
|
-
if (!
|
|
1362
|
-
let content =
|
|
1569
|
+
const squadFile = join4(squadsDir, squadName, "SQUAD.md");
|
|
1570
|
+
if (!existsSync4(squadFile)) return false;
|
|
1571
|
+
let content = readFileSync3(squadFile, "utf-8");
|
|
1363
1572
|
if (!content.includes("## Goals")) {
|
|
1364
1573
|
const insertPoint = content.indexOf("## Dependencies");
|
|
1365
1574
|
if (insertPoint > 0) {
|
|
@@ -1394,15 +1603,15 @@ function addGoalToSquad(squadName, goal2) {
|
|
|
1394
1603
|
- [ ] ${goal2}` + content.slice(headerEnd);
|
|
1395
1604
|
}
|
|
1396
1605
|
}
|
|
1397
|
-
|
|
1606
|
+
writeFileSync3(squadFile, content);
|
|
1398
1607
|
return true;
|
|
1399
1608
|
}
|
|
1400
1609
|
function updateGoalInSquad(squadName, goalIndex, updates) {
|
|
1401
1610
|
const squadsDir = findSquadsDir();
|
|
1402
1611
|
if (!squadsDir) return false;
|
|
1403
|
-
const squadFile =
|
|
1404
|
-
if (!
|
|
1405
|
-
const content =
|
|
1612
|
+
const squadFile = join4(squadsDir, squadName, "SQUAD.md");
|
|
1613
|
+
if (!existsSync4(squadFile)) return false;
|
|
1614
|
+
const content = readFileSync3(squadFile, "utf-8");
|
|
1406
1615
|
const lines = content.split("\n");
|
|
1407
1616
|
let currentSection = "";
|
|
1408
1617
|
let goalCount = 0;
|
|
@@ -1424,7 +1633,7 @@ function updateGoalInSquad(squadName, goalIndex, updates) {
|
|
|
1424
1633
|
}
|
|
1425
1634
|
}
|
|
1426
1635
|
lines[i] = newLine;
|
|
1427
|
-
|
|
1636
|
+
writeFileSync3(squadFile, lines.join("\n"));
|
|
1428
1637
|
return true;
|
|
1429
1638
|
}
|
|
1430
1639
|
goalCount++;
|
|
@@ -1673,7 +1882,7 @@ function generateExecutionId() {
|
|
|
1673
1882
|
}
|
|
1674
1883
|
function selectMcpConfig(squadName) {
|
|
1675
1884
|
const home = process.env.HOME || "";
|
|
1676
|
-
const configsDir =
|
|
1885
|
+
const configsDir = join5(home, ".claude", "mcp-configs");
|
|
1677
1886
|
const squadConfigs = {
|
|
1678
1887
|
website: "website.json",
|
|
1679
1888
|
// chrome-devtools, nano-banana
|
|
@@ -1688,12 +1897,12 @@ function selectMcpConfig(squadName) {
|
|
|
1688
1897
|
};
|
|
1689
1898
|
const configFile = squadConfigs[squadName.toLowerCase()];
|
|
1690
1899
|
if (configFile) {
|
|
1691
|
-
const configPath =
|
|
1692
|
-
if (
|
|
1900
|
+
const configPath = join5(configsDir, configFile);
|
|
1901
|
+
if (existsSync5(configPath)) {
|
|
1693
1902
|
return configPath;
|
|
1694
1903
|
}
|
|
1695
1904
|
}
|
|
1696
|
-
return
|
|
1905
|
+
return join5(home, ".claude.json");
|
|
1697
1906
|
}
|
|
1698
1907
|
function detectTaskType(agentName) {
|
|
1699
1908
|
const name = agentName.toLowerCase();
|
|
@@ -1709,12 +1918,12 @@ function detectTaskType(agentName) {
|
|
|
1709
1918
|
return "execution";
|
|
1710
1919
|
}
|
|
1711
1920
|
function ensureProjectTrusted(projectPath) {
|
|
1712
|
-
const configPath =
|
|
1713
|
-
if (!
|
|
1921
|
+
const configPath = join5(process.env.HOME || "", ".claude.json");
|
|
1922
|
+
if (!existsSync5(configPath)) {
|
|
1714
1923
|
return;
|
|
1715
1924
|
}
|
|
1716
1925
|
try {
|
|
1717
|
-
const config2 = JSON.parse(
|
|
1926
|
+
const config2 = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
1718
1927
|
if (!config2.projects) {
|
|
1719
1928
|
config2.projects = {};
|
|
1720
1929
|
}
|
|
@@ -1723,7 +1932,7 @@ function ensureProjectTrusted(projectPath) {
|
|
|
1723
1932
|
}
|
|
1724
1933
|
if (!config2.projects[projectPath].hasTrustDialogAccepted) {
|
|
1725
1934
|
config2.projects[projectPath].hasTrustDialogAccepted = true;
|
|
1726
|
-
|
|
1935
|
+
writeFileSync4(configPath, JSON.stringify(config2, null, 2));
|
|
1727
1936
|
}
|
|
1728
1937
|
} catch {
|
|
1729
1938
|
}
|
|
@@ -1731,25 +1940,25 @@ function ensureProjectTrusted(projectPath) {
|
|
|
1731
1940
|
function getProjectRoot() {
|
|
1732
1941
|
const squadsDir = findSquadsDir();
|
|
1733
1942
|
if (squadsDir) {
|
|
1734
|
-
return
|
|
1943
|
+
return dirname2(dirname2(squadsDir));
|
|
1735
1944
|
}
|
|
1736
1945
|
return process.cwd();
|
|
1737
1946
|
}
|
|
1738
1947
|
function getExecutionLogPath(squadName, agentName) {
|
|
1739
1948
|
const memoryDir = findMemoryDir();
|
|
1740
1949
|
if (!memoryDir) return null;
|
|
1741
|
-
return
|
|
1950
|
+
return join5(memoryDir, squadName, agentName, "executions.md");
|
|
1742
1951
|
}
|
|
1743
1952
|
function logExecution(record) {
|
|
1744
1953
|
const logPath = getExecutionLogPath(record.squadName, record.agentName);
|
|
1745
1954
|
if (!logPath) return;
|
|
1746
|
-
const dir =
|
|
1747
|
-
if (!
|
|
1748
|
-
|
|
1955
|
+
const dir = dirname2(logPath);
|
|
1956
|
+
if (!existsSync5(dir)) {
|
|
1957
|
+
mkdirSync3(dir, { recursive: true });
|
|
1749
1958
|
}
|
|
1750
1959
|
let content = "";
|
|
1751
|
-
if (
|
|
1752
|
-
content =
|
|
1960
|
+
if (existsSync5(logPath)) {
|
|
1961
|
+
content = readFileSync4(logPath, "utf-8").trimEnd();
|
|
1753
1962
|
} else {
|
|
1754
1963
|
content = `# ${record.squadName}/${record.agentName} - Execution Log`;
|
|
1755
1964
|
}
|
|
@@ -1762,12 +1971,12 @@ function logExecution(record) {
|
|
|
1762
1971
|
- Trigger: ${record.trigger || "manual"}
|
|
1763
1972
|
- Task Type: ${record.taskType || "execution"}
|
|
1764
1973
|
`;
|
|
1765
|
-
|
|
1974
|
+
writeFileSync4(logPath, content + entry);
|
|
1766
1975
|
}
|
|
1767
1976
|
function updateExecutionStatus(squadName, agentName, executionId, status, details) {
|
|
1768
1977
|
const logPath = getExecutionLogPath(squadName, agentName);
|
|
1769
|
-
if (!logPath || !
|
|
1770
|
-
let content =
|
|
1978
|
+
if (!logPath || !existsSync5(logPath)) return;
|
|
1979
|
+
let content = readFileSync4(logPath, "utf-8");
|
|
1771
1980
|
const endTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
1772
1981
|
const execMarker = `<!-- exec:${executionId} -->`;
|
|
1773
1982
|
const markerIndex = content.indexOf(execMarker);
|
|
@@ -1788,7 +1997,7 @@ function updateExecutionStatus(squadName, agentName, executionId, status, detail
|
|
|
1788
1997
|
- Error: ${details.error}`;
|
|
1789
1998
|
}
|
|
1790
1999
|
content = content.slice(0, entryStart) + updatedEntry + content.slice(entryEnd);
|
|
1791
|
-
|
|
2000
|
+
writeFileSync4(logPath, content);
|
|
1792
2001
|
}
|
|
1793
2002
|
function extractMcpServersFromDefinition(definition) {
|
|
1794
2003
|
const servers = /* @__PURE__ */ new Set();
|
|
@@ -1867,8 +2076,8 @@ async function runSquad(squad, squadsDir, options) {
|
|
|
1867
2076
|
if (options.parallel) {
|
|
1868
2077
|
const agentFiles = squad.agents.map((a) => ({
|
|
1869
2078
|
name: a.name,
|
|
1870
|
-
path:
|
|
1871
|
-
})).filter((a) =>
|
|
2079
|
+
path: join5(squadsDir, squad.name, `${a.name}.md`)
|
|
2080
|
+
})).filter((a) => existsSync5(a.path));
|
|
1872
2081
|
if (agentFiles.length === 0) {
|
|
1873
2082
|
writeLine(` ${icons.error} ${colors.red}No agent files found${RESET}`);
|
|
1874
2083
|
return;
|
|
@@ -1904,8 +2113,8 @@ async function runSquad(squad, squadsDir, options) {
|
|
|
1904
2113
|
writeLine();
|
|
1905
2114
|
for (let i = 0; i < pipeline.agents.length; i++) {
|
|
1906
2115
|
const agentName = pipeline.agents[i];
|
|
1907
|
-
const agentPath =
|
|
1908
|
-
if (
|
|
2116
|
+
const agentPath = join5(squadsDir, squad.name, `${agentName}.md`);
|
|
2117
|
+
if (existsSync5(agentPath)) {
|
|
1909
2118
|
writeLine(` ${colors.dim}[${i + 1}/${pipeline.agents.length}]${RESET}`);
|
|
1910
2119
|
await runAgent(agentName, agentPath, squad.name, options);
|
|
1911
2120
|
writeLine();
|
|
@@ -1915,8 +2124,8 @@ async function runSquad(squad, squadsDir, options) {
|
|
|
1915
2124
|
}
|
|
1916
2125
|
} else {
|
|
1917
2126
|
if (options.agent) {
|
|
1918
|
-
const agentPath =
|
|
1919
|
-
if (
|
|
2127
|
+
const agentPath = join5(squadsDir, squad.name, `${options.agent}.md`);
|
|
2128
|
+
if (existsSync5(agentPath)) {
|
|
1920
2129
|
await runAgent(options.agent, agentPath, squad.name, options);
|
|
1921
2130
|
} else {
|
|
1922
2131
|
writeLine(` ${icons.error} ${colors.red}Agent ${options.agent} not found${RESET}`);
|
|
@@ -1927,8 +2136,8 @@ async function runSquad(squad, squadsDir, options) {
|
|
|
1927
2136
|
(a) => a.name.includes("lead") || a.trigger === "Manual"
|
|
1928
2137
|
);
|
|
1929
2138
|
if (orchestrator) {
|
|
1930
|
-
const agentPath =
|
|
1931
|
-
if (
|
|
2139
|
+
const agentPath = join5(squadsDir, squad.name, `${orchestrator.name}.md`);
|
|
2140
|
+
if (existsSync5(agentPath)) {
|
|
1932
2141
|
await runAgent(orchestrator.name, agentPath, squad.name, options);
|
|
1933
2142
|
}
|
|
1934
2143
|
} else {
|
|
@@ -1954,9 +2163,9 @@ async function runLeadMode(squad, squadsDir, options) {
|
|
|
1954
2163
|
if (!squad) return;
|
|
1955
2164
|
const agentFiles = squad.agents.map((a) => ({
|
|
1956
2165
|
name: a.name,
|
|
1957
|
-
path:
|
|
2166
|
+
path: join5(squadsDir, squad.name, `${a.name}.md`),
|
|
1958
2167
|
role: a.role || ""
|
|
1959
|
-
})).filter((a) =>
|
|
2168
|
+
})).filter((a) => existsSync5(a.path));
|
|
1960
2169
|
if (agentFiles.length === 0) {
|
|
1961
2170
|
writeLine(` ${icons.error} ${colors.red}No agent files found${RESET}`);
|
|
1962
2171
|
return;
|
|
@@ -2075,9 +2284,9 @@ async function runAgent(agentName, agentPath, squadName, options) {
|
|
|
2075
2284
|
}
|
|
2076
2285
|
const squadsDir = findSquadsDir();
|
|
2077
2286
|
if (squadsDir) {
|
|
2078
|
-
const squadFilePath =
|
|
2079
|
-
if (
|
|
2080
|
-
const squadContent =
|
|
2287
|
+
const squadFilePath = join5(squadsDir, squadName, "SQUAD.md");
|
|
2288
|
+
if (existsSync5(squadFilePath)) {
|
|
2289
|
+
const squadContent = readFileSync4(squadFilePath, "utf-8");
|
|
2081
2290
|
const permContext = buildContextFromSquad(squadName, squadContent, agentName);
|
|
2082
2291
|
const mcpServers = extractMcpServersFromDefinition(definition);
|
|
2083
2292
|
const execRequest = {
|
|
@@ -2359,158 +2568,6 @@ async function listCommand(options) {
|
|
|
2359
2568
|
// src/commands/status.ts
|
|
2360
2569
|
import { existsSync as existsSync6, statSync } from "fs";
|
|
2361
2570
|
import { join as join6 } from "path";
|
|
2362
|
-
|
|
2363
|
-
// src/lib/update.ts
|
|
2364
|
-
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, unlinkSync } from "fs";
|
|
2365
|
-
import { join as join5, dirname as dirname2 } from "path";
|
|
2366
|
-
import { homedir as homedir2 } from "os";
|
|
2367
|
-
import { execSync as execSync3 } from "child_process";
|
|
2368
|
-
import { fileURLToPath } from "url";
|
|
2369
|
-
function getPackageVersion() {
|
|
2370
|
-
try {
|
|
2371
|
-
const __filename3 = fileURLToPath(import.meta.url);
|
|
2372
|
-
const __dirname3 = dirname2(__filename3);
|
|
2373
|
-
const possiblePaths = [
|
|
2374
|
-
join5(__dirname3, "..", "..", "package.json"),
|
|
2375
|
-
// From dist/lib/
|
|
2376
|
-
join5(__dirname3, "..", "package.json"),
|
|
2377
|
-
// From dist/
|
|
2378
|
-
join5(__dirname3, "package.json")
|
|
2379
|
-
// Same dir
|
|
2380
|
-
];
|
|
2381
|
-
for (const pkgPath of possiblePaths) {
|
|
2382
|
-
if (existsSync5(pkgPath)) {
|
|
2383
|
-
const pkg2 = JSON.parse(readFileSync4(pkgPath, "utf-8"));
|
|
2384
|
-
return pkg2.version || "0.0.0";
|
|
2385
|
-
}
|
|
2386
|
-
}
|
|
2387
|
-
} catch {
|
|
2388
|
-
}
|
|
2389
|
-
return "0.0.0";
|
|
2390
|
-
}
|
|
2391
|
-
var CURRENT_VERSION = getPackageVersion();
|
|
2392
|
-
var CACHE_DIR = join5(homedir2(), ".squads");
|
|
2393
|
-
var CACHE_FILE = join5(CACHE_DIR, "update-check.json");
|
|
2394
|
-
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2395
|
-
function isNewerVersion(v1, v2) {
|
|
2396
|
-
const parts1 = v1.replace(/^v/, "").split(".").map(Number);
|
|
2397
|
-
const parts2 = v2.replace(/^v/, "").split(".").map(Number);
|
|
2398
|
-
for (let i = 0; i < 3; i++) {
|
|
2399
|
-
const p1 = parts1[i] || 0;
|
|
2400
|
-
const p2 = parts2[i] || 0;
|
|
2401
|
-
if (p2 > p1) return true;
|
|
2402
|
-
if (p2 < p1) return false;
|
|
2403
|
-
}
|
|
2404
|
-
return false;
|
|
2405
|
-
}
|
|
2406
|
-
function readCache() {
|
|
2407
|
-
try {
|
|
2408
|
-
if (!existsSync5(CACHE_FILE)) return null;
|
|
2409
|
-
const data = JSON.parse(readFileSync4(CACHE_FILE, "utf-8"));
|
|
2410
|
-
return data;
|
|
2411
|
-
} catch {
|
|
2412
|
-
return null;
|
|
2413
|
-
}
|
|
2414
|
-
}
|
|
2415
|
-
function writeCache(latestVersion) {
|
|
2416
|
-
try {
|
|
2417
|
-
if (!existsSync5(CACHE_DIR)) {
|
|
2418
|
-
mkdirSync3(CACHE_DIR, { recursive: true });
|
|
2419
|
-
}
|
|
2420
|
-
const cache = {
|
|
2421
|
-
latestVersion,
|
|
2422
|
-
checkedAt: Date.now()
|
|
2423
|
-
};
|
|
2424
|
-
writeFileSync4(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
2425
|
-
} catch {
|
|
2426
|
-
}
|
|
2427
|
-
}
|
|
2428
|
-
function fetchLatestVersion() {
|
|
2429
|
-
try {
|
|
2430
|
-
const result = execSync3("npm view squads-cli version 2>/dev/null", {
|
|
2431
|
-
encoding: "utf-8",
|
|
2432
|
-
timeout: 5e3
|
|
2433
|
-
}).trim();
|
|
2434
|
-
return result || null;
|
|
2435
|
-
} catch {
|
|
2436
|
-
return null;
|
|
2437
|
-
}
|
|
2438
|
-
}
|
|
2439
|
-
function checkForUpdate() {
|
|
2440
|
-
const result = {
|
|
2441
|
-
currentVersion: CURRENT_VERSION,
|
|
2442
|
-
latestVersion: CURRENT_VERSION,
|
|
2443
|
-
updateAvailable: false
|
|
2444
|
-
};
|
|
2445
|
-
const cache = readCache();
|
|
2446
|
-
const now = Date.now();
|
|
2447
|
-
if (cache) {
|
|
2448
|
-
result.latestVersion = cache.latestVersion;
|
|
2449
|
-
result.updateAvailable = isNewerVersion(CURRENT_VERSION, cache.latestVersion);
|
|
2450
|
-
if (now - cache.checkedAt >= CACHE_TTL_MS) {
|
|
2451
|
-
triggerBackgroundRefresh();
|
|
2452
|
-
}
|
|
2453
|
-
return result;
|
|
2454
|
-
}
|
|
2455
|
-
triggerBackgroundRefresh();
|
|
2456
|
-
return result;
|
|
2457
|
-
}
|
|
2458
|
-
function triggerBackgroundRefresh() {
|
|
2459
|
-
try {
|
|
2460
|
-
const { spawn: spawn8 } = __require("child_process");
|
|
2461
|
-
const child = spawn8("npm", ["view", "squads-cli", "version"], {
|
|
2462
|
-
detached: true,
|
|
2463
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
2464
|
-
shell: true
|
|
2465
|
-
});
|
|
2466
|
-
let output = "";
|
|
2467
|
-
child.stdout?.on("data", (data) => {
|
|
2468
|
-
output += data.toString();
|
|
2469
|
-
});
|
|
2470
|
-
child.on("close", () => {
|
|
2471
|
-
const version2 = output.trim();
|
|
2472
|
-
if (version2 && /^\d+\.\d+\.\d+/.test(version2)) {
|
|
2473
|
-
writeCache(version2);
|
|
2474
|
-
}
|
|
2475
|
-
});
|
|
2476
|
-
child.unref();
|
|
2477
|
-
} catch {
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
function performUpdate() {
|
|
2481
|
-
try {
|
|
2482
|
-
execSync3("npm update -g squads-cli", {
|
|
2483
|
-
encoding: "utf-8",
|
|
2484
|
-
stdio: "inherit",
|
|
2485
|
-
timeout: 12e4
|
|
2486
|
-
// 2 minutes
|
|
2487
|
-
});
|
|
2488
|
-
try {
|
|
2489
|
-
unlinkSync(CACHE_FILE);
|
|
2490
|
-
} catch {
|
|
2491
|
-
}
|
|
2492
|
-
return { success: true };
|
|
2493
|
-
} catch (err) {
|
|
2494
|
-
return {
|
|
2495
|
-
success: false,
|
|
2496
|
-
error: err instanceof Error ? err.message : "Unknown error"
|
|
2497
|
-
};
|
|
2498
|
-
}
|
|
2499
|
-
}
|
|
2500
|
-
function refreshVersionCache() {
|
|
2501
|
-
const latestVersion = fetchLatestVersion();
|
|
2502
|
-
if (latestVersion) {
|
|
2503
|
-
writeCache(latestVersion);
|
|
2504
|
-
return {
|
|
2505
|
-
currentVersion: CURRENT_VERSION,
|
|
2506
|
-
latestVersion,
|
|
2507
|
-
updateAvailable: isNewerVersion(CURRENT_VERSION, latestVersion)
|
|
2508
|
-
};
|
|
2509
|
-
}
|
|
2510
|
-
return checkForUpdate();
|
|
2511
|
-
}
|
|
2512
|
-
|
|
2513
|
-
// src/commands/status.ts
|
|
2514
2571
|
async function statusCommand(squadName, options = {}) {
|
|
2515
2572
|
await track(Events.CLI_STATUS, { squad: squadName || "all", verbose: options.verbose });
|
|
2516
2573
|
const squadsDir = findSquadsDir();
|
|
@@ -10052,6 +10109,7 @@ for (const envPath of envPaths) {
|
|
|
10052
10109
|
}
|
|
10053
10110
|
}
|
|
10054
10111
|
applyStackConfig();
|
|
10112
|
+
await autoUpdateOnStartup();
|
|
10055
10113
|
registerExitHandler();
|
|
10056
10114
|
var program = new Command();
|
|
10057
10115
|
program.name("squads").description("A CLI for humans and agents").version(version).showSuggestionAfterError(true).configureOutput({
|
|
@@ -10133,7 +10191,7 @@ sessions.command("history").description("Show session history and statistics").o
|
|
|
10133
10191
|
json: options.json
|
|
10134
10192
|
}));
|
|
10135
10193
|
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) => {
|
|
10136
|
-
const { buildCurrentSessionSummary } = await import("./sessions-
|
|
10194
|
+
const { buildCurrentSessionSummary } = await import("./sessions-B6GVXJ2H.js");
|
|
10137
10195
|
let data;
|
|
10138
10196
|
if (options.file) {
|
|
10139
10197
|
const { readFileSync: readFileSync17 } = await import("fs");
|