squads-cli 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +196 -1152
- package/dist/auth-YW3UPFSB.js +23 -0
- package/dist/autonomy-BWTVDEAT.js +102 -0
- package/dist/autonomy-BWTVDEAT.js.map +1 -0
- package/dist/chunk-3KCWNZWW.js +401 -0
- package/dist/chunk-3KCWNZWW.js.map +1 -0
- package/dist/chunk-67RO2HKR.js +174 -0
- package/dist/chunk-67RO2HKR.js.map +1 -0
- package/dist/chunk-7JVD7RD4.js +275 -0
- package/dist/chunk-7JVD7RD4.js.map +1 -0
- package/dist/chunk-BODLDQY7.js +452 -0
- package/dist/chunk-BODLDQY7.js.map +1 -0
- package/dist/chunk-FFFCFZ6A.js +121 -0
- package/dist/chunk-FFFCFZ6A.js.map +1 -0
- package/dist/chunk-FIWT2NMM.js +165 -0
- package/dist/chunk-FIWT2NMM.js.map +1 -0
- package/dist/chunk-L6GQCHDF.js +222 -0
- package/dist/chunk-L6GQCHDF.js.map +1 -0
- package/dist/{chunk-O7UV3FWI.js → chunk-LDM62TIX.js} +2 -2
- package/dist/chunk-LDM62TIX.js.map +1 -0
- package/dist/chunk-LOA3KWYJ.js +294 -0
- package/dist/chunk-LOA3KWYJ.js.map +1 -0
- package/dist/chunk-NA45DFXY.js +616 -0
- package/dist/chunk-NA45DFXY.js.map +1 -0
- package/dist/{chunk-4CMAEQQY.js → chunk-NQN6JPI7.js} +4 -3
- package/dist/chunk-NQN6JPI7.js.map +1 -0
- package/dist/chunk-OQJHPULO.js +103 -0
- package/dist/chunk-OQJHPULO.js.map +1 -0
- package/dist/chunk-QHNUMM4V.js +87 -0
- package/dist/chunk-QHNUMM4V.js.map +1 -0
- package/dist/chunk-RM6BWILN.js +74 -0
- package/dist/chunk-RM6BWILN.js.map +1 -0
- package/dist/chunk-WBR5J7EX.js +90 -0
- package/dist/chunk-WBR5J7EX.js.map +1 -0
- package/dist/chunk-Z2UKDBNL.js +162 -0
- package/dist/chunk-Z2UKDBNL.js.map +1 -0
- package/dist/cli.js +2151 -12594
- package/dist/cli.js.map +1 -1
- package/dist/context-M2A2DOFV.js +291 -0
- package/dist/context-M2A2DOFV.js.map +1 -0
- package/dist/context-feed-JMNW4GAM.js +391 -0
- package/dist/context-feed-JMNW4GAM.js.map +1 -0
- package/dist/cost-N37I4UTA.js +274 -0
- package/dist/cost-N37I4UTA.js.map +1 -0
- package/dist/create-554W5HNU.js +286 -0
- package/dist/create-554W5HNU.js.map +1 -0
- package/dist/daemon-XWPQPPPN.js +546 -0
- package/dist/daemon-XWPQPPPN.js.map +1 -0
- package/dist/dashboard-L7YKVQEB.js +945 -0
- package/dist/dashboard-L7YKVQEB.js.map +1 -0
- package/dist/dashboard-MFNRLCEE.js +794 -0
- package/dist/dashboard-MFNRLCEE.js.map +1 -0
- package/dist/doctor-RG75M5RO.js +346 -0
- package/dist/doctor-RG75M5RO.js.map +1 -0
- package/dist/env-config-KCLDBKYX.js +21 -0
- package/dist/exec-JQKBF7BL.js +197 -0
- package/dist/exec-JQKBF7BL.js.map +1 -0
- package/dist/feedback-KA2UYBZG.js +229 -0
- package/dist/feedback-KA2UYBZG.js.map +1 -0
- package/dist/github-UQTM5KMS.js +23 -0
- package/dist/goal-EOPC5ZCD.js +168 -0
- package/dist/goal-EOPC5ZCD.js.map +1 -0
- package/dist/health-3FZDOSR5.js +209 -0
- package/dist/health-3FZDOSR5.js.map +1 -0
- package/dist/history-TFVXJEDH.js +229 -0
- package/dist/history-TFVXJEDH.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/init-UOWTNMIE.js +747 -0
- package/dist/init-UOWTNMIE.js.map +1 -0
- package/dist/kpi-2SQ2WCVT.js +413 -0
- package/dist/kpi-2SQ2WCVT.js.map +1 -0
- package/dist/learn-6ERTERAO.js +269 -0
- package/dist/learn-6ERTERAO.js.map +1 -0
- package/dist/list-KSOMUBMB.js +92 -0
- package/dist/list-KSOMUBMB.js.map +1 -0
- package/dist/login-ST6PAXYE.js +155 -0
- package/dist/login-ST6PAXYE.js.map +1 -0
- package/dist/memory-3CSNKXIL.js +562 -0
- package/dist/memory-3CSNKXIL.js.map +1 -0
- package/dist/progress-FKG4V2VH.js +202 -0
- package/dist/progress-FKG4V2VH.js.map +1 -0
- package/dist/providers-66PDCORB.js +65 -0
- package/dist/providers-66PDCORB.js.map +1 -0
- package/dist/results-2MJFLWEO.js +224 -0
- package/dist/results-2MJFLWEO.js.map +1 -0
- package/dist/run-72OQLH5A.js +2685 -0
- package/dist/run-72OQLH5A.js.map +1 -0
- package/dist/session-6H67XPAQ.js +64 -0
- package/dist/session-6H67XPAQ.js.map +1 -0
- package/dist/{chunk-NHGLXN2F.js → sessions-GVQIMN4W.js} +23 -459
- package/dist/sessions-GVQIMN4W.js.map +1 -0
- package/dist/{squad-parser-4BI3G4RS.js → squad-parser-CM3HOIWM.js} +2 -2
- package/dist/squad-parser-CM3HOIWM.js.map +1 -0
- package/dist/stats-ONZI557Q.js +335 -0
- package/dist/stats-ONZI557Q.js.map +1 -0
- package/dist/status-FYH42FTB.js +346 -0
- package/dist/status-FYH42FTB.js.map +1 -0
- package/dist/sync-HJZJNXHW.js +800 -0
- package/dist/sync-HJZJNXHW.js.map +1 -0
- package/dist/update-B4WMUOPO.js +83 -0
- package/dist/update-B4WMUOPO.js.map +1 -0
- package/dist/{update-ALJKFFM7.js → update-L7FGHN6W.js} +2 -2
- package/dist/update-L7FGHN6W.js.map +1 -0
- package/package.json +18 -10
- package/dist/chunk-4CMAEQQY.js.map +0 -1
- package/dist/chunk-NHGLXN2F.js.map +0 -1
- package/dist/chunk-O7UV3FWI.js.map +0 -1
- package/dist/sessions-6PB7ALCE.js +0 -16
- /package/dist/{sessions-6PB7ALCE.js.map → auth-YW3UPFSB.js.map} +0 -0
- /package/dist/{squad-parser-4BI3G4RS.js.map → env-config-KCLDBKYX.js.map} +0 -0
- /package/dist/{update-ALJKFFM7.js.map → github-UQTM5KMS.js.map} +0 -0
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
cleanupStaleSessions,
|
|
4
|
+
getActiveSessions,
|
|
5
|
+
getRecentSessions,
|
|
6
|
+
getSessionHistoryStats,
|
|
7
|
+
getSessionSummary
|
|
8
|
+
} from "./chunk-BODLDQY7.js";
|
|
2
9
|
import {
|
|
3
10
|
RESET,
|
|
4
11
|
bold,
|
|
@@ -9,443 +16,7 @@ import {
|
|
|
9
16
|
padEnd,
|
|
10
17
|
writeLine
|
|
11
18
|
} from "./chunk-N7KDWU4W.js";
|
|
12
|
-
import
|
|
13
|
-
__require
|
|
14
|
-
} from "./chunk-7OCVIDC7.js";
|
|
15
|
-
|
|
16
|
-
// src/lib/sessions.ts
|
|
17
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, unlinkSync, appendFileSync, createReadStream } from "fs";
|
|
18
|
-
import { join, dirname } from "path";
|
|
19
|
-
import { randomBytes } from "crypto";
|
|
20
|
-
import { createInterface } from "readline";
|
|
21
|
-
import { execSync } from "child_process";
|
|
22
|
-
var AI_TOOL_PATTERNS = [
|
|
23
|
-
{ pattern: /^claude$/, name: "claude" },
|
|
24
|
-
{ pattern: /^cursor$/i, name: "cursor" },
|
|
25
|
-
{ pattern: /^aider$/, name: "aider" },
|
|
26
|
-
{ pattern: /^gemini$/i, name: "gemini" },
|
|
27
|
-
{ pattern: /^copilot$/i, name: "copilot" },
|
|
28
|
-
{ pattern: /^cody$/i, name: "cody" },
|
|
29
|
-
{ pattern: /^continue$/i, name: "continue" }
|
|
30
|
-
];
|
|
31
|
-
var STALE_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
32
|
-
var HISTORY_FILE = "history.jsonl";
|
|
33
|
-
var ACTIVE_DIR = "active";
|
|
34
|
-
var SQUAD_DIR_MAP = {
|
|
35
|
-
"hq": "company",
|
|
36
|
-
"agents-squads-web": "website",
|
|
37
|
-
"company": "company",
|
|
38
|
-
"product": "product",
|
|
39
|
-
"engineering": "engineering",
|
|
40
|
-
"research": "research",
|
|
41
|
-
"intelligence": "intelligence",
|
|
42
|
-
"customer": "customer",
|
|
43
|
-
"finance": "finance",
|
|
44
|
-
"marketing": "marketing"
|
|
45
|
-
};
|
|
46
|
-
function findAgentsDir() {
|
|
47
|
-
let dir = process.cwd();
|
|
48
|
-
for (let i = 0; i < 5; i++) {
|
|
49
|
-
const agentsPath = join(dir, ".agents");
|
|
50
|
-
if (existsSync(agentsPath)) {
|
|
51
|
-
return agentsPath;
|
|
52
|
-
}
|
|
53
|
-
const parent = dirname(dir);
|
|
54
|
-
if (parent === dir) break;
|
|
55
|
-
dir = parent;
|
|
56
|
-
}
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
function getSessionsBaseDir() {
|
|
60
|
-
const agentsDir = findAgentsDir();
|
|
61
|
-
if (!agentsDir) return null;
|
|
62
|
-
const sessionsDir = join(agentsDir, "sessions");
|
|
63
|
-
if (!existsSync(sessionsDir)) {
|
|
64
|
-
mkdirSync(sessionsDir, { recursive: true });
|
|
65
|
-
}
|
|
66
|
-
return sessionsDir;
|
|
67
|
-
}
|
|
68
|
-
function getSessionsDir() {
|
|
69
|
-
const baseDir = getSessionsBaseDir();
|
|
70
|
-
if (!baseDir) return null;
|
|
71
|
-
const activeDir = join(baseDir, ACTIVE_DIR);
|
|
72
|
-
if (!existsSync(activeDir)) {
|
|
73
|
-
mkdirSync(activeDir, { recursive: true });
|
|
74
|
-
}
|
|
75
|
-
return activeDir;
|
|
76
|
-
}
|
|
77
|
-
function getHistoryFilePath() {
|
|
78
|
-
const baseDir = getSessionsBaseDir();
|
|
79
|
-
if (!baseDir) return null;
|
|
80
|
-
return join(baseDir, HISTORY_FILE);
|
|
81
|
-
}
|
|
82
|
-
function appendEvent(event) {
|
|
83
|
-
const historyPath = getHistoryFilePath();
|
|
84
|
-
if (!historyPath) return;
|
|
85
|
-
try {
|
|
86
|
-
const line = JSON.stringify(event) + "\n";
|
|
87
|
-
appendFileSync(historyPath, line);
|
|
88
|
-
} catch {
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
function detectSquad(cwd = process.cwd()) {
|
|
92
|
-
const match = cwd.match(/agents-squads\/([^/]+)/);
|
|
93
|
-
if (match) {
|
|
94
|
-
const dir = match[1];
|
|
95
|
-
return SQUAD_DIR_MAP[dir] || dir;
|
|
96
|
-
}
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
function detectAIProcessesFast() {
|
|
100
|
-
const processes = [];
|
|
101
|
-
try {
|
|
102
|
-
const psOutput = execSync("ps -eo pid,tty,comm 2>/dev/null", {
|
|
103
|
-
encoding: "utf-8",
|
|
104
|
-
timeout: 2e3
|
|
105
|
-
// Reduced from 5s for faster CLI response
|
|
106
|
-
}).trim();
|
|
107
|
-
if (!psOutput) return [];
|
|
108
|
-
const lines = psOutput.split("\n").filter((line) => line.trim());
|
|
109
|
-
for (const line of lines) {
|
|
110
|
-
const parts = line.trim().split(/\s+/);
|
|
111
|
-
if (parts.length < 3) continue;
|
|
112
|
-
const pid = parseInt(parts[0], 10);
|
|
113
|
-
const tty = parts[1];
|
|
114
|
-
const comm = parts.slice(2).join(" ");
|
|
115
|
-
if (isNaN(pid)) continue;
|
|
116
|
-
let toolName = null;
|
|
117
|
-
for (const { pattern, name } of AI_TOOL_PATTERNS) {
|
|
118
|
-
if (pattern.test(comm)) {
|
|
119
|
-
toolName = name;
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
if (!toolName) continue;
|
|
124
|
-
processes.push({
|
|
125
|
-
pid,
|
|
126
|
-
tty,
|
|
127
|
-
cwd: "",
|
|
128
|
-
// No cwd in fast mode
|
|
129
|
-
squad: null,
|
|
130
|
-
// No squad detection in fast mode
|
|
131
|
-
tool: toolName
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
} catch {
|
|
135
|
-
}
|
|
136
|
-
return processes;
|
|
137
|
-
}
|
|
138
|
-
async function getProcessCwd(pid) {
|
|
139
|
-
return new Promise((resolve) => {
|
|
140
|
-
try {
|
|
141
|
-
const { exec } = __require("child_process");
|
|
142
|
-
exec(`lsof -p ${pid} 2>/dev/null | grep cwd | awk '{print $NF}'`, {
|
|
143
|
-
encoding: "utf-8",
|
|
144
|
-
timeout: 3e3
|
|
145
|
-
}, (error, stdout) => {
|
|
146
|
-
resolve(error ? "" : stdout.trim());
|
|
147
|
-
});
|
|
148
|
-
} catch {
|
|
149
|
-
resolve("");
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
async function enrichProcessesWithSquad(processes) {
|
|
154
|
-
if (processes.length === 0) return processes;
|
|
155
|
-
const cwdPromises = processes.map((p) => getProcessCwd(p.pid));
|
|
156
|
-
const cwds = await Promise.all(cwdPromises);
|
|
157
|
-
return processes.map((proc, i) => ({
|
|
158
|
-
...proc,
|
|
159
|
-
cwd: cwds[i],
|
|
160
|
-
squad: detectSquad(cwds[i])
|
|
161
|
-
}));
|
|
162
|
-
}
|
|
163
|
-
async function getLiveSessionSummaryAsync(projectRoot) {
|
|
164
|
-
const processes = detectAIProcessesFast();
|
|
165
|
-
const enrichedProcesses = await enrichProcessesWithSquad(processes);
|
|
166
|
-
const root = projectRoot ?? process.cwd();
|
|
167
|
-
const projectProcesses = enrichedProcesses.filter((p) => p.cwd && p.cwd.startsWith(root));
|
|
168
|
-
const bySquad = {};
|
|
169
|
-
const byTool = {};
|
|
170
|
-
for (const proc of projectProcesses) {
|
|
171
|
-
const squad = proc.squad || "unknown";
|
|
172
|
-
bySquad[squad] = (bySquad[squad] || 0) + 1;
|
|
173
|
-
byTool[proc.tool] = (byTool[proc.tool] || 0) + 1;
|
|
174
|
-
}
|
|
175
|
-
return {
|
|
176
|
-
totalSessions: projectProcesses.length,
|
|
177
|
-
bySquad,
|
|
178
|
-
squadCount: Object.keys(bySquad).length,
|
|
179
|
-
byTool
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
function generateSessionId() {
|
|
183
|
-
return randomBytes(8).toString("hex");
|
|
184
|
-
}
|
|
185
|
-
var currentSessionId = null;
|
|
186
|
-
function getSessionId() {
|
|
187
|
-
if (currentSessionId) return currentSessionId;
|
|
188
|
-
const sessionsDir = getSessionsDir();
|
|
189
|
-
if (sessionsDir) {
|
|
190
|
-
const pid = process.pid;
|
|
191
|
-
const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
192
|
-
for (const file of files) {
|
|
193
|
-
try {
|
|
194
|
-
const content = readFileSync(join(sessionsDir, file), "utf-8");
|
|
195
|
-
const session = JSON.parse(content);
|
|
196
|
-
if (session.pid === pid) {
|
|
197
|
-
currentSessionId = session.sessionId;
|
|
198
|
-
return currentSessionId;
|
|
199
|
-
}
|
|
200
|
-
} catch {
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
currentSessionId = generateSessionId();
|
|
205
|
-
return currentSessionId;
|
|
206
|
-
}
|
|
207
|
-
function startSession(squad) {
|
|
208
|
-
const sessionsDir = getSessionsDir();
|
|
209
|
-
if (!sessionsDir) return null;
|
|
210
|
-
const sessionId = getSessionId();
|
|
211
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
212
|
-
const cwd = process.cwd();
|
|
213
|
-
const detectedSquad = squad || detectSquad(cwd);
|
|
214
|
-
const session = {
|
|
215
|
-
sessionId,
|
|
216
|
-
squad: detectedSquad,
|
|
217
|
-
startedAt: now,
|
|
218
|
-
lastHeartbeat: now,
|
|
219
|
-
cwd,
|
|
220
|
-
pid: process.pid
|
|
221
|
-
};
|
|
222
|
-
const sessionPath = join(sessionsDir, `${sessionId}.json`);
|
|
223
|
-
writeFileSync(sessionPath, JSON.stringify(session, null, 2));
|
|
224
|
-
appendEvent({
|
|
225
|
-
type: "start",
|
|
226
|
-
sessionId,
|
|
227
|
-
squad: detectedSquad,
|
|
228
|
-
ts: now,
|
|
229
|
-
cwd,
|
|
230
|
-
pid: process.pid
|
|
231
|
-
});
|
|
232
|
-
return session;
|
|
233
|
-
}
|
|
234
|
-
function updateHeartbeat() {
|
|
235
|
-
const sessionsDir = getSessionsDir();
|
|
236
|
-
if (!sessionsDir) return false;
|
|
237
|
-
const sessionId = getSessionId();
|
|
238
|
-
const sessionPath = join(sessionsDir, `${sessionId}.json`);
|
|
239
|
-
if (!existsSync(sessionPath)) {
|
|
240
|
-
startSession();
|
|
241
|
-
return true;
|
|
242
|
-
}
|
|
243
|
-
try {
|
|
244
|
-
const content = readFileSync(sessionPath, "utf-8");
|
|
245
|
-
const session = JSON.parse(content);
|
|
246
|
-
session.lastHeartbeat = (/* @__PURE__ */ new Date()).toISOString();
|
|
247
|
-
writeFileSync(sessionPath, JSON.stringify(session, null, 2));
|
|
248
|
-
return true;
|
|
249
|
-
} catch {
|
|
250
|
-
return false;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
function stopSession() {
|
|
254
|
-
const sessionsDir = getSessionsDir();
|
|
255
|
-
if (!sessionsDir) return false;
|
|
256
|
-
const sessionId = getSessionId();
|
|
257
|
-
const sessionPath = join(sessionsDir, `${sessionId}.json`);
|
|
258
|
-
if (existsSync(sessionPath)) {
|
|
259
|
-
let squad = null;
|
|
260
|
-
let durationMs;
|
|
261
|
-
try {
|
|
262
|
-
const content = readFileSync(sessionPath, "utf-8");
|
|
263
|
-
const session = JSON.parse(content);
|
|
264
|
-
squad = session.squad;
|
|
265
|
-
durationMs = Date.now() - new Date(session.startedAt).getTime();
|
|
266
|
-
} catch {
|
|
267
|
-
}
|
|
268
|
-
unlinkSync(sessionPath);
|
|
269
|
-
currentSessionId = null;
|
|
270
|
-
appendEvent({
|
|
271
|
-
type: "stop",
|
|
272
|
-
sessionId,
|
|
273
|
-
squad,
|
|
274
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
275
|
-
durationMs
|
|
276
|
-
});
|
|
277
|
-
return true;
|
|
278
|
-
}
|
|
279
|
-
return false;
|
|
280
|
-
}
|
|
281
|
-
function getActiveSessions() {
|
|
282
|
-
const sessionsDir = getSessionsDir();
|
|
283
|
-
if (!sessionsDir) return [];
|
|
284
|
-
const now = Date.now();
|
|
285
|
-
const sessions = [];
|
|
286
|
-
try {
|
|
287
|
-
const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
288
|
-
for (const file of files) {
|
|
289
|
-
try {
|
|
290
|
-
const filePath = join(sessionsDir, file);
|
|
291
|
-
const content = readFileSync(filePath, "utf-8");
|
|
292
|
-
const session = JSON.parse(content);
|
|
293
|
-
const lastHeartbeat = new Date(session.lastHeartbeat).getTime();
|
|
294
|
-
if (now - lastHeartbeat < STALE_THRESHOLD_MS) {
|
|
295
|
-
sessions.push(session);
|
|
296
|
-
}
|
|
297
|
-
} catch {
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
} catch {
|
|
301
|
-
}
|
|
302
|
-
return sessions;
|
|
303
|
-
}
|
|
304
|
-
function getSessionSummary() {
|
|
305
|
-
const sessions = getActiveSessions();
|
|
306
|
-
const bySquad = {};
|
|
307
|
-
for (const session of sessions) {
|
|
308
|
-
const squad = session.squad || "unknown";
|
|
309
|
-
bySquad[squad] = (bySquad[squad] || 0) + 1;
|
|
310
|
-
}
|
|
311
|
-
return {
|
|
312
|
-
totalSessions: sessions.length,
|
|
313
|
-
bySquad,
|
|
314
|
-
squadCount: Object.keys(bySquad).length
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
function cleanupStaleSessions() {
|
|
318
|
-
const sessionsDir = getSessionsDir();
|
|
319
|
-
if (!sessionsDir) return 0;
|
|
320
|
-
const now = Date.now();
|
|
321
|
-
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
322
|
-
let cleaned = 0;
|
|
323
|
-
try {
|
|
324
|
-
const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
325
|
-
for (const file of files) {
|
|
326
|
-
try {
|
|
327
|
-
const filePath = join(sessionsDir, file);
|
|
328
|
-
const content = readFileSync(filePath, "utf-8");
|
|
329
|
-
const session = JSON.parse(content);
|
|
330
|
-
const lastHeartbeat = new Date(session.lastHeartbeat).getTime();
|
|
331
|
-
if (now - lastHeartbeat >= STALE_THRESHOLD_MS) {
|
|
332
|
-
const durationMs = now - new Date(session.startedAt).getTime();
|
|
333
|
-
unlinkSync(filePath);
|
|
334
|
-
cleaned++;
|
|
335
|
-
appendEvent({
|
|
336
|
-
type: "stale_cleanup",
|
|
337
|
-
sessionId: session.sessionId,
|
|
338
|
-
squad: session.squad,
|
|
339
|
-
ts: nowIso,
|
|
340
|
-
durationMs
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
} catch {
|
|
344
|
-
try {
|
|
345
|
-
unlinkSync(join(sessionsDir, file));
|
|
346
|
-
cleaned++;
|
|
347
|
-
} catch {
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
} catch {
|
|
352
|
-
}
|
|
353
|
-
return cleaned;
|
|
354
|
-
}
|
|
355
|
-
async function readSessionHistory(options = {}) {
|
|
356
|
-
const historyPath = getHistoryFilePath();
|
|
357
|
-
if (!historyPath || !existsSync(historyPath)) return [];
|
|
358
|
-
const events = [];
|
|
359
|
-
const sinceMs = options.since?.getTime() || 0;
|
|
360
|
-
const untilMs = options.until?.getTime() || Date.now();
|
|
361
|
-
return new Promise((resolve) => {
|
|
362
|
-
const rl = createInterface({
|
|
363
|
-
input: createReadStream(historyPath),
|
|
364
|
-
crlfDelay: Infinity
|
|
365
|
-
});
|
|
366
|
-
rl.on("line", (line) => {
|
|
367
|
-
if (!line.trim()) return;
|
|
368
|
-
try {
|
|
369
|
-
const event = JSON.parse(line);
|
|
370
|
-
const eventMs = new Date(event.ts).getTime();
|
|
371
|
-
if (eventMs < sinceMs || eventMs > untilMs) return;
|
|
372
|
-
if (options.squad && event.squad !== options.squad) return;
|
|
373
|
-
if (options.type && event.type !== options.type) return;
|
|
374
|
-
events.push(event);
|
|
375
|
-
} catch {
|
|
376
|
-
}
|
|
377
|
-
});
|
|
378
|
-
rl.on("close", () => {
|
|
379
|
-
if (options.limit && events.length > options.limit) {
|
|
380
|
-
resolve(events.slice(-options.limit));
|
|
381
|
-
} else {
|
|
382
|
-
resolve(events);
|
|
383
|
-
}
|
|
384
|
-
});
|
|
385
|
-
rl.on("error", () => {
|
|
386
|
-
resolve([]);
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
async function getSessionHistoryStats(options = {}) {
|
|
391
|
-
const events = await readSessionHistory(options);
|
|
392
|
-
const stats = {
|
|
393
|
-
totalSessions: 0,
|
|
394
|
-
totalDurationMs: 0,
|
|
395
|
-
avgDurationMs: 0,
|
|
396
|
-
bySquad: {},
|
|
397
|
-
byDate: {},
|
|
398
|
-
peakConcurrent: 0
|
|
399
|
-
};
|
|
400
|
-
const activeSessions = /* @__PURE__ */ new Map();
|
|
401
|
-
let currentConcurrent = 0;
|
|
402
|
-
for (const event of events) {
|
|
403
|
-
const squad = event.squad || "unknown";
|
|
404
|
-
const date = event.ts.split("T")[0];
|
|
405
|
-
if (event.type === "start") {
|
|
406
|
-
stats.totalSessions++;
|
|
407
|
-
stats.byDate[date] = (stats.byDate[date] || 0) + 1;
|
|
408
|
-
if (!stats.bySquad[squad]) {
|
|
409
|
-
stats.bySquad[squad] = { count: 0, durationMs: 0 };
|
|
410
|
-
}
|
|
411
|
-
stats.bySquad[squad].count++;
|
|
412
|
-
activeSessions.set(event.sessionId, {
|
|
413
|
-
squad: event.squad,
|
|
414
|
-
startTs: new Date(event.ts).getTime()
|
|
415
|
-
});
|
|
416
|
-
currentConcurrent++;
|
|
417
|
-
stats.peakConcurrent = Math.max(stats.peakConcurrent, currentConcurrent);
|
|
418
|
-
}
|
|
419
|
-
if (event.type === "stop" || event.type === "stale_cleanup") {
|
|
420
|
-
const duration = event.durationMs || 0;
|
|
421
|
-
stats.totalDurationMs += duration;
|
|
422
|
-
if (stats.bySquad[squad]) {
|
|
423
|
-
stats.bySquad[squad].durationMs += duration;
|
|
424
|
-
}
|
|
425
|
-
if (activeSessions.has(event.sessionId)) {
|
|
426
|
-
activeSessions.delete(event.sessionId);
|
|
427
|
-
currentConcurrent = Math.max(0, currentConcurrent - 1);
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
const completedSessions = events.filter((e) => e.type === "stop" || e.type === "stale_cleanup").length;
|
|
432
|
-
if (completedSessions > 0) {
|
|
433
|
-
stats.avgDurationMs = Math.round(stats.totalDurationMs / completedSessions);
|
|
434
|
-
}
|
|
435
|
-
return stats;
|
|
436
|
-
}
|
|
437
|
-
async function getRecentSessions(limit = 20) {
|
|
438
|
-
const events = await readSessionHistory({ limit: limit * 3 });
|
|
439
|
-
const sessionEvents = /* @__PURE__ */ new Map();
|
|
440
|
-
for (const event of events) {
|
|
441
|
-
if (!sessionEvents.has(event.sessionId)) {
|
|
442
|
-
sessionEvents.set(event.sessionId, []);
|
|
443
|
-
}
|
|
444
|
-
sessionEvents.get(event.sessionId).push(event);
|
|
445
|
-
}
|
|
446
|
-
const startEvents = events.filter((e) => e.type === "start").slice(-limit);
|
|
447
|
-
return startEvents.reverse();
|
|
448
|
-
}
|
|
19
|
+
import "./chunk-7OCVIDC7.js";
|
|
449
20
|
|
|
450
21
|
// src/commands/sessions.ts
|
|
451
22
|
async function sessionsCommand(options = {}) {
|
|
@@ -604,37 +175,37 @@ async function sessionsSummaryCommand(data, options = {}) {
|
|
|
604
175
|
writeLine();
|
|
605
176
|
}
|
|
606
177
|
async function buildCurrentSessionSummary() {
|
|
607
|
-
const { existsSync
|
|
608
|
-
const { join
|
|
178
|
+
const { existsSync, readdirSync, statSync, readFileSync } = await import("fs");
|
|
179
|
+
const { join } = await import("path");
|
|
609
180
|
const { findMemoryDir } = await import("./memory-VNF2VFRB.js");
|
|
610
181
|
const memoryDir = findMemoryDir();
|
|
611
182
|
const squads = [];
|
|
612
183
|
const filesUpdated = [];
|
|
613
184
|
const sessionWindow = 2 * 60 * 60 * 1e3;
|
|
614
185
|
const now = Date.now();
|
|
615
|
-
if (memoryDir &&
|
|
616
|
-
const squadDirs =
|
|
186
|
+
if (memoryDir && existsSync(memoryDir)) {
|
|
187
|
+
const squadDirs = readdirSync(memoryDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
617
188
|
for (const squadDir of squadDirs) {
|
|
618
|
-
const squadPath =
|
|
189
|
+
const squadPath = join(memoryDir, squadDir.name);
|
|
619
190
|
let squadModified = false;
|
|
620
191
|
let stateContent = "";
|
|
621
192
|
let executionContent = "";
|
|
622
193
|
try {
|
|
623
|
-
const agentDirs =
|
|
194
|
+
const agentDirs = readdirSync(squadPath, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
624
195
|
for (const agentDir of agentDirs) {
|
|
625
|
-
const agentPath =
|
|
626
|
-
const files =
|
|
196
|
+
const agentPath = join(squadPath, agentDir.name);
|
|
197
|
+
const files = readdirSync(agentPath).filter((f) => f.endsWith(".md"));
|
|
627
198
|
for (const file of files) {
|
|
628
|
-
const filePath =
|
|
199
|
+
const filePath = join(agentPath, file);
|
|
629
200
|
const stats = statSync(filePath);
|
|
630
201
|
if (now - stats.mtimeMs < sessionWindow) {
|
|
631
202
|
squadModified = true;
|
|
632
203
|
const relativePath = `${squadDir.name}/${agentDir.name}/${file}`;
|
|
633
204
|
filesUpdated.push(relativePath);
|
|
634
205
|
if (file === "state.md") {
|
|
635
|
-
stateContent =
|
|
206
|
+
stateContent = readFileSync(filePath, "utf-8");
|
|
636
207
|
} else if (file === "executions.md") {
|
|
637
|
-
executionContent =
|
|
208
|
+
executionContent = readFileSync(filePath, "utf-8");
|
|
638
209
|
}
|
|
639
210
|
}
|
|
640
211
|
}
|
|
@@ -753,17 +324,10 @@ async function sessionsHistoryCommand(options = {}) {
|
|
|
753
324
|
writeLine(` ${colors.dim}$${RESET} squads sessions history -s website ${colors.dim}Filter by squad${RESET}`);
|
|
754
325
|
writeLine();
|
|
755
326
|
}
|
|
756
|
-
|
|
757
327
|
export {
|
|
758
|
-
detectSquad,
|
|
759
|
-
getLiveSessionSummaryAsync,
|
|
760
|
-
startSession,
|
|
761
|
-
updateHeartbeat,
|
|
762
|
-
stopSession,
|
|
763
|
-
cleanupStaleSessions,
|
|
764
|
-
sessionsCommand,
|
|
765
|
-
sessionsSummaryCommand,
|
|
766
328
|
buildCurrentSessionSummary,
|
|
767
|
-
|
|
329
|
+
sessionsCommand,
|
|
330
|
+
sessionsHistoryCommand,
|
|
331
|
+
sessionsSummaryCommand
|
|
768
332
|
};
|
|
769
|
-
//# sourceMappingURL=
|
|
333
|
+
//# sourceMappingURL=sessions-GVQIMN4W.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/sessions.ts"],"sourcesContent":["/**\n * List active Claude Code sessions across squads\n */\n\nimport {\n getActiveSessions,\n getSessionSummary,\n cleanupStaleSessions,\n getSessionHistoryStats,\n getRecentSessions,\n SessionState,\n} from '../lib/sessions.js';\nimport {\n colors,\n bold,\n RESET,\n gradient,\n box,\n padEnd,\n icons,\n writeLine,\n} from '../lib/terminal.js';\n\ninterface SessionsOptions {\n verbose?: boolean;\n json?: boolean;\n}\n\nexport async function sessionsCommand(\n options: SessionsOptions = {}\n): Promise<void> {\n // Clean up stale sessions first\n cleanupStaleSessions();\n\n const sessions = getActiveSessions();\n const summary = getSessionSummary();\n\n // JSON output for scripts\n if (options.json) {\n console.log(JSON.stringify({ sessions, summary }, null, 2));\n return;\n }\n\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}sessions${RESET}`);\n writeLine();\n\n if (sessions.length === 0) {\n writeLine(` ${colors.dim}No active sessions${RESET}`);\n writeLine();\n writeLine(` ${colors.dim}Sessions are tracked automatically when Claude Code runs.${RESET}`);\n writeLine(` ${colors.dim}Each session updates its heartbeat via squads CLI commands.${RESET}`);\n writeLine();\n return;\n }\n\n // Summary line\n const squadText = summary.squadCount === 1 ? 'squad' : 'squads';\n const sessionText = summary.totalSessions === 1 ? 'session' : 'sessions';\n writeLine(` ${colors.green}${summary.totalSessions}${RESET} active ${sessionText} ${colors.dim}across${RESET} ${colors.cyan}${summary.squadCount}${RESET} ${squadText}`);\n writeLine();\n\n // Group by squad\n const bySquad: Record<string, SessionState[]> = {};\n for (const session of sessions) {\n const squad = session.squad || 'unknown';\n if (!bySquad[squad]) bySquad[squad] = [];\n bySquad[squad].push(session);\n }\n\n // Table\n const w = { squad: 16, sessions: 10, activity: 14 };\n const tableWidth = w.squad + w.sessions + w.activity + 4;\n\n writeLine(` ${colors.purple}${box.topLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.topRight}${RESET}`);\n\n const header = ` ${colors.purple}${box.vertical}${RESET} ` +\n `${bold}${padEnd('SQUAD', w.squad)}${RESET}` +\n `${bold}${padEnd('SESSIONS', w.sessions)}${RESET}` +\n `${bold}LAST ACTIVITY${RESET}` +\n ` ${colors.purple}${box.vertical}${RESET}`;\n writeLine(header);\n\n writeLine(` ${colors.purple}${box.teeRight}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.teeLeft}${RESET}`);\n\n for (const [squad, squadSessions] of Object.entries(bySquad).sort()) {\n // Find most recent activity\n let mostRecent = 0;\n for (const session of squadSessions) {\n const ts = new Date(session.lastHeartbeat).getTime();\n if (ts > mostRecent) mostRecent = ts;\n }\n\n const lastActivity = formatTimeAgo(mostRecent);\n const activityColor = getActivityColor(mostRecent);\n\n const row = ` ${colors.purple}${box.vertical}${RESET} ` +\n `${colors.cyan}${padEnd(squad, w.squad)}${RESET}` +\n `${padEnd(String(squadSessions.length), w.sessions)}` +\n `${padEnd(`${activityColor}${lastActivity}${RESET}`, w.activity)}` +\n `${colors.purple}${box.vertical}${RESET}`;\n\n writeLine(row);\n }\n\n writeLine(` ${colors.purple}${box.bottomLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.bottomRight}${RESET}`);\n\n // Verbose: show individual sessions\n if (options.verbose) {\n writeLine();\n writeLine(` ${bold}Session Details${RESET}`);\n writeLine();\n\n for (const session of sessions) {\n const squad = session.squad || 'unknown';\n const ago = formatTimeAgo(new Date(session.lastHeartbeat).getTime());\n\n writeLine(` ${icons.active} ${colors.white}${session.sessionId}${RESET}`);\n writeLine(` ${colors.dim}squad: ${squad} | pid: ${session.pid} | heartbeat: ${ago}${RESET}`);\n writeLine(` ${colors.dim}cwd: ${session.cwd}${RESET}`);\n }\n }\n\n writeLine();\n writeLine(` ${colors.dim}$${RESET} squads sessions -v ${colors.dim}Show session details${RESET}`);\n writeLine();\n}\n\n/**\n * Format timestamp as \"Xm ago\" or \"Xs ago\"\n */\nfunction formatTimeAgo(timestamp: number): string {\n const now = Date.now();\n const diff = now - timestamp;\n\n const seconds = Math.floor(diff / 1000);\n const minutes = Math.floor(seconds / 60);\n\n if (minutes >= 1) {\n return `${minutes}m ago`;\n }\n return `${seconds}s ago`;\n}\n\n/**\n * Get color based on how recent the activity is\n */\nfunction getActivityColor(timestamp: number): string {\n const now = Date.now();\n const diff = now - timestamp;\n\n const minutes = Math.floor(diff / (1000 * 60));\n\n if (minutes < 1) return colors.green;\n if (minutes < 3) return colors.yellow;\n return colors.dim;\n}\n\ninterface HistoryOptions {\n days?: number;\n squad?: string;\n json?: boolean;\n}\n\ninterface SummaryOptions {\n json?: boolean;\n}\n\nexport interface SessionSummaryData {\n squads: Array<{\n name: string;\n actions: string;\n outputs: string;\n }>;\n decisions?: Array<{\n question: string;\n answer: string;\n }>;\n customer?: {\n vertical: string;\n persona: string;\n painPoints: string[];\n };\n nextActions?: Array<{\n squad: string;\n action: string;\n }>;\n filesUpdated?: string[];\n targets?: {\n metric: string;\n value: string;\n }[];\n model?: string; // e.g., \"Claude Opus 4.5\"\n duration?: string; // e.g., \"45m\"\n}\n\n/**\n * Show a pretty summary of session work\n */\nexport async function sessionsSummaryCommand(\n data: SessionSummaryData,\n options: SummaryOptions = {}\n): Promise<void> {\n if (options.json) {\n console.log(JSON.stringify(data, null, 2));\n return;\n }\n\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}session summary${RESET}`);\n writeLine();\n\n // Squads table\n if (data.squads.length > 0) {\n const w = { squad: 14, actions: 26, outputs: 36 };\n const tableWidth = w.squad + w.actions + w.outputs + 6;\n\n // Helper to truncate text\n const truncate = (text: string, max: number) =>\n text.length > max ? text.substring(0, max - 1) + '…' : text;\n\n writeLine(` ${colors.green}${icons.active}${RESET} ${bold}${data.squads.length} Squads Active${RESET}`);\n writeLine();\n\n writeLine(` ${colors.purple}${box.topLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.topRight}${RESET}`);\n\n const header = ` ${colors.purple}${box.vertical}${RESET} ` +\n `${bold}${padEnd('SQUAD', w.squad)}${RESET}` +\n `${bold}${padEnd('ACTIONS', w.actions)}${RESET}` +\n `${bold}${padEnd('KEY OUTPUTS', w.outputs)}${RESET}` +\n `${colors.purple}${box.vertical}${RESET}`;\n writeLine(header);\n\n writeLine(` ${colors.purple}${box.teeRight}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.teeLeft}${RESET}`);\n\n for (const squad of data.squads) {\n const row = ` ${colors.purple}${box.vertical}${RESET} ` +\n `${colors.cyan}${padEnd(truncate(squad.name, w.squad - 1), w.squad)}${RESET}` +\n `${padEnd(truncate(squad.actions, w.actions - 1), w.actions)}` +\n `${padEnd(truncate(squad.outputs, w.outputs - 1), w.outputs)}` +\n `${colors.purple}${box.vertical}${RESET}`;\n writeLine(row);\n }\n\n writeLine(` ${colors.purple}${box.bottomLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.bottomRight}${RESET}`);\n }\n\n // Decisions\n if (data.decisions && data.decisions.length > 0) {\n writeLine();\n writeLine(` ${bold}Strategic Decisions${RESET}`);\n writeLine();\n\n const w = { question: 16, answer: 50 };\n const tableWidth = w.question + w.answer + 4;\n\n writeLine(` ${colors.purple}${box.topLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.topRight}${RESET}`);\n\n for (const decision of data.decisions) {\n const row = ` ${colors.purple}${box.vertical}${RESET} ` +\n `${colors.yellow}${padEnd(decision.question, w.question)}${RESET}` +\n `${padEnd(decision.answer, w.answer)}` +\n `${colors.purple}${box.vertical}${RESET}`;\n writeLine(row);\n }\n\n writeLine(` ${colors.purple}${box.bottomLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.bottomRight}${RESET}`);\n }\n\n // Target customer\n if (data.customer) {\n writeLine();\n writeLine(` ${bold}Target Customer${RESET}`);\n writeLine();\n writeLine(` ${colors.dim}Vertical:${RESET} ${colors.cyan}${data.customer.vertical}${RESET}`);\n writeLine(` ${colors.dim}Persona:${RESET} ${colors.white}${data.customer.persona}${RESET}`);\n writeLine(` ${colors.dim}Pain:${RESET} ${data.customer.painPoints.join(', ')}`);\n }\n\n // Next actions\n if (data.nextActions && data.nextActions.length > 0) {\n writeLine();\n writeLine(` ${bold}Next Actions${RESET}`);\n writeLine();\n\n for (const action of data.nextActions) {\n writeLine(` ${colors.cyan}${padEnd(action.squad, 14)}${RESET}${colors.dim}→${RESET} ${action.action}`);\n }\n }\n\n // Q1 Targets\n if (data.targets && data.targets.length > 0) {\n writeLine();\n writeLine(` ${bold}Q1 Targets${RESET}`);\n writeLine();\n\n for (const target of data.targets) {\n writeLine(` ${colors.dim}•${RESET} ${target.metric}: ${colors.green}${target.value}${RESET}`);\n }\n }\n\n // Files updated\n if (data.filesUpdated && data.filesUpdated.length > 0) {\n writeLine();\n writeLine(` ${colors.dim}Files updated:${RESET}`);\n for (const file of data.filesUpdated) {\n writeLine(` ${colors.dim} •${RESET} ${colors.cyan}${file}${RESET}`);\n }\n }\n\n writeLine();\n\n // Footer with model attribution\n const modelText = data.model ? data.model : 'Claude';\n const durationText = data.duration ? ` ${colors.dim}(${data.duration})${RESET}` : '';\n writeLine(` ${colors.dim}Generated by${RESET} ${colors.purple}${modelText}${RESET}${durationText}`);\n writeLine();\n}\n\n/**\n * Build summary from current session by detecting recent activity\n */\nexport async function buildCurrentSessionSummary(): Promise<SessionSummaryData> {\n const { existsSync, readdirSync, statSync, readFileSync } = await import('fs');\n const { join } = await import('path');\n const { findMemoryDir } = await import('../lib/memory.js');\n\n const memoryDir = findMemoryDir();\n const squads: SessionSummaryData['squads'] = [];\n const filesUpdated: string[] = [];\n\n // Look for files modified in last 2 hours (current session window)\n const sessionWindow = 2 * 60 * 60 * 1000; // 2 hours\n const now = Date.now();\n\n if (memoryDir && existsSync(memoryDir)) {\n const squadDirs = readdirSync(memoryDir, { withFileTypes: true })\n .filter(d => d.isDirectory());\n\n for (const squadDir of squadDirs) {\n const squadPath = join(memoryDir, squadDir.name);\n let squadModified = false;\n let stateContent = '';\n let executionContent = '';\n\n try {\n const agentDirs = readdirSync(squadPath, { withFileTypes: true })\n .filter(d => d.isDirectory());\n\n for (const agentDir of agentDirs) {\n const agentPath = join(squadPath, agentDir.name);\n const files = readdirSync(agentPath).filter(f => f.endsWith('.md'));\n\n for (const file of files) {\n const filePath = join(agentPath, file);\n const stats = statSync(filePath);\n\n if (now - stats.mtimeMs < sessionWindow) {\n squadModified = true;\n const relativePath = `${squadDir.name}/${agentDir.name}/${file}`;\n filesUpdated.push(relativePath);\n\n // Read content for summary\n if (file === 'state.md') {\n stateContent = readFileSync(filePath, 'utf-8');\n } else if (file === 'executions.md') {\n executionContent = readFileSync(filePath, 'utf-8');\n }\n }\n }\n }\n\n if (squadModified) {\n // Extract summary from state/execution content\n let actions = 'State updated';\n let outputs = 'Memory refreshed';\n\n // Try to extract info from execution log\n if (executionContent) {\n const lines = executionContent.split('\\n').filter(l => l.trim());\n const recentEntry = lines.slice(-10).join(' ');\n if (recentEntry.includes('completed')) {\n actions = 'Execution completed';\n }\n // Extract key points\n const keyMatch = recentEntry.match(/Key (?:findings|decisions|outputs)?:?\\s*([^.]+)/i);\n if (keyMatch) {\n outputs = keyMatch[1].substring(0, 50);\n }\n }\n\n // Try to extract from state header\n if (stateContent) {\n const updatedMatch = stateContent.match(/Updated:\\s*([^\\n]+)/);\n if (updatedMatch) {\n actions = `Updated ${updatedMatch[1]}`;\n }\n }\n\n squads.push({\n name: squadDir.name.charAt(0).toUpperCase() + squadDir.name.slice(1),\n actions,\n outputs: outputs.length > 44 ? outputs.substring(0, 41) + '...' : outputs,\n });\n }\n } catch {\n // Skip if can't read\n }\n }\n }\n\n // If no recent activity found\n if (squads.length === 0) {\n squads.push({\n name: 'No recent activity',\n actions: '—',\n outputs: 'Run squads to see activity here',\n });\n }\n\n return {\n squads,\n filesUpdated: filesUpdated.length > 0 ? filesUpdated : undefined,\n model: process.env.ANTHROPIC_MODEL || 'Claude',\n };\n}\n\n/**\n * Show session history and statistics\n */\nexport async function sessionsHistoryCommand(\n options: HistoryOptions = {}\n): Promise<void> {\n const days = options.days || 7;\n const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000);\n\n const stats = await getSessionHistoryStats({\n since,\n squad: options.squad,\n });\n\n const recentSessions = await getRecentSessions(10);\n\n // JSON output\n if (options.json) {\n console.log(JSON.stringify({ stats, recentSessions }, null, 2));\n return;\n }\n\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}sessions history${RESET} ${colors.dim}(${days}d)${RESET}`);\n writeLine();\n\n if (stats.totalSessions === 0) {\n writeLine(` ${colors.dim}No session history found${RESET}`);\n writeLine();\n writeLine(` ${colors.dim}Session events are logged to .agents/sessions/history.jsonl${RESET}`);\n writeLine();\n return;\n }\n\n // Summary stats\n const avgMinutes = Math.round(stats.avgDurationMs / 60000);\n const totalHours = Math.round(stats.totalDurationMs / 3600000 * 10) / 10;\n\n writeLine(` ${bold}Summary${RESET}`);\n writeLine(` ${colors.cyan}${stats.totalSessions}${RESET} sessions ${colors.dim}│${RESET} ${colors.green}${totalHours}h${RESET} total ${colors.dim}│${RESET} ${colors.yellow}${avgMinutes}m${RESET} avg ${colors.dim}│${RESET} ${colors.purple}${stats.peakConcurrent}${RESET} peak`);\n writeLine();\n\n // By squad table\n const squads = Object.entries(stats.bySquad).sort((a, b) => b[1].count - a[1].count);\n\n if (squads.length > 0) {\n const w = { squad: 16, sessions: 10, duration: 12 };\n const tableWidth = w.squad + w.sessions + w.duration + 4;\n\n writeLine(` ${bold}By Squad${RESET}`);\n writeLine();\n writeLine(` ${colors.purple}${box.topLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.topRight}${RESET}`);\n\n const header = ` ${colors.purple}${box.vertical}${RESET} ` +\n `${bold}${padEnd('SQUAD', w.squad)}${RESET}` +\n `${bold}${padEnd('SESSIONS', w.sessions)}${RESET}` +\n `${bold}DURATION${RESET}` +\n ` ${colors.purple}${box.vertical}${RESET}`;\n writeLine(header);\n\n writeLine(` ${colors.purple}${box.teeRight}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.teeLeft}${RESET}`);\n\n for (const [squad, data] of squads) {\n const hours = Math.round(data.durationMs / 3600000 * 10) / 10;\n\n const row = ` ${colors.purple}${box.vertical}${RESET} ` +\n `${colors.cyan}${padEnd(squad, w.squad)}${RESET}` +\n `${padEnd(String(data.count), w.sessions)}` +\n `${padEnd(`${hours}h`, w.duration)}` +\n `${colors.purple}${box.vertical}${RESET}`;\n\n writeLine(row);\n }\n\n writeLine(` ${colors.purple}${box.bottomLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.bottomRight}${RESET}`);\n }\n\n // Recent sessions\n if (recentSessions.length > 0) {\n writeLine();\n writeLine(` ${bold}Recent Sessions${RESET}`);\n writeLine();\n\n for (const event of recentSessions.slice(0, 5)) {\n const squad = event.squad || 'unknown';\n const date = new Date(event.ts);\n const timeStr = date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });\n const dateStr = date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });\n\n writeLine(` ${colors.dim}${dateStr} ${timeStr}${RESET} ${colors.cyan}${squad}${RESET} ${colors.dim}${event.sessionId.slice(0, 8)}${RESET}`);\n }\n }\n\n // By date (last 7 days)\n const dates = Object.entries(stats.byDate)\n .sort((a, b) => b[0].localeCompare(a[0]))\n .slice(0, 7);\n\n if (dates.length > 1) {\n writeLine();\n writeLine(` ${bold}Daily Activity${RESET}`);\n writeLine();\n\n for (const [date, count] of dates) {\n const bar = '█'.repeat(Math.min(count, 20));\n writeLine(` ${colors.dim}${date}${RESET} ${colors.green}${bar}${RESET} ${count}`);\n }\n }\n\n writeLine();\n writeLine(` ${colors.dim}$${RESET} squads sessions history --days 30 ${colors.dim}Longer history${RESET}`);\n writeLine(` ${colors.dim}$${RESET} squads sessions history -s website ${colors.dim}Filter by squad${RESET}`);\n writeLine();\n}\n"],"mappings":"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","names":[]}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
parseSquadFile,
|
|
14
14
|
resolveExecutionContext,
|
|
15
15
|
updateGoalInSquad
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-LDM62TIX.js";
|
|
17
17
|
import "./chunk-7OCVIDC7.js";
|
|
18
18
|
export {
|
|
19
19
|
addGoalToSquad,
|
|
@@ -30,4 +30,4 @@ export {
|
|
|
30
30
|
resolveExecutionContext,
|
|
31
31
|
updateGoalInSquad
|
|
32
32
|
};
|
|
33
|
-
//# sourceMappingURL=squad-parser-
|
|
33
|
+
//# sourceMappingURL=squad-parser-CM3HOIWM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|