squads-cli 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +2136 -12600
- 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
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-LDM62TIX.js";
|
|
3
|
+
import {
|
|
4
|
+
findMemoryDir
|
|
5
|
+
} from "./chunk-ZTQ7ISUR.js";
|
|
6
|
+
import {
|
|
7
|
+
RESET,
|
|
8
|
+
bold,
|
|
9
|
+
box,
|
|
10
|
+
colors,
|
|
11
|
+
gradient,
|
|
12
|
+
icons,
|
|
13
|
+
padEnd,
|
|
14
|
+
truncate,
|
|
15
|
+
writeLine
|
|
16
|
+
} from "./chunk-N7KDWU4W.js";
|
|
17
|
+
import "./chunk-7OCVIDC7.js";
|
|
18
|
+
|
|
19
|
+
// src/commands/progress.ts
|
|
20
|
+
import { execSync } from "child_process";
|
|
21
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
22
|
+
import { join } from "path";
|
|
23
|
+
function getTasksFilePath() {
|
|
24
|
+
const memoryDir = findMemoryDir();
|
|
25
|
+
if (!memoryDir) {
|
|
26
|
+
const cwd = process.cwd();
|
|
27
|
+
const agentsDir = join(cwd, ".agents");
|
|
28
|
+
if (!existsSync(agentsDir)) {
|
|
29
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
return join(agentsDir, "tasks.json");
|
|
32
|
+
}
|
|
33
|
+
return join(memoryDir, "..", "tasks.json");
|
|
34
|
+
}
|
|
35
|
+
function loadTasks() {
|
|
36
|
+
const tasksPath = getTasksFilePath();
|
|
37
|
+
if (existsSync(tasksPath)) {
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(readFileSync(tasksPath, "utf-8"));
|
|
40
|
+
} catch {
|
|
41
|
+
return { tasks: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return { tasks: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
45
|
+
}
|
|
46
|
+
function saveTasks(data) {
|
|
47
|
+
const tasksPath = getTasksFilePath();
|
|
48
|
+
data.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
49
|
+
writeFileSync(tasksPath, JSON.stringify(data, null, 2));
|
|
50
|
+
}
|
|
51
|
+
function getRecentActivity() {
|
|
52
|
+
const activity = [];
|
|
53
|
+
const squadKeywords = {
|
|
54
|
+
website: ["website", "web", "homepage", "astro", "page"],
|
|
55
|
+
product: ["cli", "squads-cli", "command"],
|
|
56
|
+
research: ["research", "report", "analysis"],
|
|
57
|
+
engineering: ["infra", "engineering", "build"],
|
|
58
|
+
intelligence: ["intel", "monitor", "competitor"],
|
|
59
|
+
customer: ["lead", "customer", "outreach"],
|
|
60
|
+
finance: ["cost", "finance", "budget"],
|
|
61
|
+
company: ["company", "strategy", "mission"],
|
|
62
|
+
marketing: ["marketing", "content", "social"]
|
|
63
|
+
};
|
|
64
|
+
try {
|
|
65
|
+
const logOutput = execSync(
|
|
66
|
+
'git log --since="24 hours ago" --format="%h|%aI|%s" 2>/dev/null',
|
|
67
|
+
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
68
|
+
).trim();
|
|
69
|
+
if (!logOutput) return activity;
|
|
70
|
+
for (const line of logOutput.split("\n")) {
|
|
71
|
+
const [hash, date, ...msgParts] = line.split("|");
|
|
72
|
+
const message = msgParts.join("|");
|
|
73
|
+
if (!hash || !message) continue;
|
|
74
|
+
const msgLower = message.toLowerCase();
|
|
75
|
+
let detectedSquad = "unknown";
|
|
76
|
+
for (const [squad, keywords] of Object.entries(squadKeywords)) {
|
|
77
|
+
if (keywords.some((k) => msgLower.includes(k))) {
|
|
78
|
+
detectedSquad = squad;
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
activity.push({
|
|
83
|
+
squad: detectedSquad,
|
|
84
|
+
message,
|
|
85
|
+
hash,
|
|
86
|
+
date: date.split("T")[0]
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
}
|
|
91
|
+
return activity;
|
|
92
|
+
}
|
|
93
|
+
async function progressCommand(options = {}) {
|
|
94
|
+
writeLine();
|
|
95
|
+
writeLine(` ${gradient("squads")} ${colors.dim}progress${RESET}`);
|
|
96
|
+
writeLine();
|
|
97
|
+
const tasksData = loadTasks();
|
|
98
|
+
const recentActivity = getRecentActivity();
|
|
99
|
+
const activeTasks = tasksData.tasks.filter((t) => t.status === "active");
|
|
100
|
+
const completedToday = tasksData.tasks.filter(
|
|
101
|
+
(t) => t.status === "completed" && t.completedAt?.startsWith((/* @__PURE__ */ new Date()).toISOString().split("T")[0])
|
|
102
|
+
);
|
|
103
|
+
const stats = [
|
|
104
|
+
`${colors.cyan}${activeTasks.length}${RESET} active`,
|
|
105
|
+
`${colors.green}${completedToday.length}${RESET} done today`,
|
|
106
|
+
`${colors.purple}${recentActivity.length}${RESET} commits (24h)`
|
|
107
|
+
].join(` ${colors.dim}\u2502${RESET} `);
|
|
108
|
+
writeLine(` ${stats}`);
|
|
109
|
+
writeLine();
|
|
110
|
+
if (activeTasks.length > 0) {
|
|
111
|
+
writeLine(` ${bold}Active Tasks${RESET}`);
|
|
112
|
+
writeLine();
|
|
113
|
+
for (const task of activeTasks) {
|
|
114
|
+
const elapsed = getElapsedTime(task.startedAt);
|
|
115
|
+
writeLine(` ${icons.progress} ${colors.cyan}${task.squad}${RESET} ${truncate(task.description, 45)}`);
|
|
116
|
+
writeLine(` ${colors.dim}started ${elapsed} ago${RESET}`);
|
|
117
|
+
}
|
|
118
|
+
writeLine();
|
|
119
|
+
} else {
|
|
120
|
+
writeLine(` ${colors.dim}No active tasks${RESET}`);
|
|
121
|
+
writeLine();
|
|
122
|
+
}
|
|
123
|
+
if (recentActivity.length > 0) {
|
|
124
|
+
writeLine(` ${bold}Recent Activity${RESET} ${colors.dim}(last 24h)${RESET}`);
|
|
125
|
+
writeLine();
|
|
126
|
+
const w = { squad: 12, message: 50 };
|
|
127
|
+
const tableWidth = w.squad + w.message + 4;
|
|
128
|
+
writeLine(` ${colors.purple}${box.topLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.topRight}${RESET}`);
|
|
129
|
+
writeLine(` ${colors.purple}${box.vertical}${RESET} ${bold}${padEnd("SQUAD", w.squad)}${RESET}${bold}COMMIT${RESET}${" ".repeat(w.message - 6)} ${colors.purple}${box.vertical}${RESET}`);
|
|
130
|
+
writeLine(` ${colors.purple}${box.teeRight}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.teeLeft}${RESET}`);
|
|
131
|
+
const maxRows = options.verbose ? 15 : 8;
|
|
132
|
+
for (const act of recentActivity.slice(0, maxRows)) {
|
|
133
|
+
const squadColor = act.squad === "unknown" ? colors.dim : colors.cyan;
|
|
134
|
+
const row = ` ${colors.purple}${box.vertical}${RESET} ${squadColor}${padEnd(act.squad, w.squad)}${RESET}${truncate(act.message, w.message - 2)} ${colors.purple}${box.vertical}${RESET}`;
|
|
135
|
+
writeLine(row);
|
|
136
|
+
}
|
|
137
|
+
writeLine(` ${colors.purple}${box.bottomLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.bottomRight}${RESET}`);
|
|
138
|
+
if (recentActivity.length > maxRows) {
|
|
139
|
+
writeLine(` ${colors.dim}+${recentActivity.length - maxRows} more commits${RESET}`);
|
|
140
|
+
}
|
|
141
|
+
writeLine();
|
|
142
|
+
}
|
|
143
|
+
if (completedToday.length > 0) {
|
|
144
|
+
writeLine(` ${bold}Completed Today${RESET}`);
|
|
145
|
+
writeLine();
|
|
146
|
+
for (const task of completedToday.slice(0, 5)) {
|
|
147
|
+
writeLine(` ${icons.success} ${colors.cyan}${task.squad}${RESET} ${truncate(task.description, 50)}`);
|
|
148
|
+
}
|
|
149
|
+
if (completedToday.length > 5) {
|
|
150
|
+
writeLine(` ${colors.dim}+${completedToday.length - 5} more${RESET}`);
|
|
151
|
+
}
|
|
152
|
+
writeLine();
|
|
153
|
+
}
|
|
154
|
+
writeLine(` ${colors.dim}$${RESET} squads results ${colors.dim}KPI goals vs actuals${RESET}`);
|
|
155
|
+
writeLine(` ${colors.dim}$${RESET} squads dash ${colors.dim}Full dashboard${RESET}`);
|
|
156
|
+
writeLine();
|
|
157
|
+
}
|
|
158
|
+
async function progressStartCommand(squad, description) {
|
|
159
|
+
const tasksData = loadTasks();
|
|
160
|
+
const id = Math.random().toString(36).substring(2, 9);
|
|
161
|
+
tasksData.tasks.push({
|
|
162
|
+
id,
|
|
163
|
+
squad,
|
|
164
|
+
description,
|
|
165
|
+
status: "active",
|
|
166
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
167
|
+
});
|
|
168
|
+
saveTasks(tasksData);
|
|
169
|
+
writeLine(` ${icons.active} Task ${colors.cyan}${id}${RESET} started for ${colors.purple}${squad}${RESET}`);
|
|
170
|
+
}
|
|
171
|
+
async function progressCompleteCommand(taskId, options = {}) {
|
|
172
|
+
const tasksData = loadTasks();
|
|
173
|
+
const task = tasksData.tasks.find((t) => t.id === taskId);
|
|
174
|
+
if (!task) {
|
|
175
|
+
writeLine(` ${icons.error} Task ${colors.red}${taskId}${RESET} not found`);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
task.status = options.failed ? "failed" : "completed";
|
|
179
|
+
task.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
180
|
+
saveTasks(tasksData);
|
|
181
|
+
const icon = options.failed ? icons.error : icons.success;
|
|
182
|
+
const status = options.failed ? "failed" : "completed";
|
|
183
|
+
writeLine(` ${icon} Task ${colors.cyan}${taskId}${RESET} ${status}`);
|
|
184
|
+
}
|
|
185
|
+
function getElapsedTime(startTime) {
|
|
186
|
+
const start = new Date(startTime).getTime();
|
|
187
|
+
const now = Date.now();
|
|
188
|
+
const diffMs = now - start;
|
|
189
|
+
const minutes = Math.floor(diffMs / 6e4);
|
|
190
|
+
const hours = Math.floor(minutes / 60);
|
|
191
|
+
const days = Math.floor(hours / 24);
|
|
192
|
+
if (days > 0) return `${days}d`;
|
|
193
|
+
if (hours > 0) return `${hours}h`;
|
|
194
|
+
if (minutes > 0) return `${minutes}m`;
|
|
195
|
+
return "<1m";
|
|
196
|
+
}
|
|
197
|
+
export {
|
|
198
|
+
progressCommand,
|
|
199
|
+
progressCompleteCommand,
|
|
200
|
+
progressStartCommand
|
|
201
|
+
};
|
|
202
|
+
//# sourceMappingURL=progress-FKG4V2VH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/progress.ts"],"sourcesContent":["import { execSync } from 'child_process';\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport '../lib/squad-parser.js';\nimport { findMemoryDir } from '../lib/memory.js';\nimport {\n colors,\n bold,\n RESET,\n gradient,\n box,\n padEnd,\n truncate,\n icons,\n writeLine,\n} from '../lib/terminal.js';\n\ninterface TaskEntry {\n id: string;\n squad: string;\n description: string;\n status: 'active' | 'completed' | 'failed';\n startedAt: string;\n completedAt?: string;\n commits?: string[];\n}\n\ninterface TasksFile {\n tasks: TaskEntry[];\n lastUpdated: string;\n}\n\nfunction getTasksFilePath(): string {\n const memoryDir = findMemoryDir();\n if (!memoryDir) {\n const cwd = process.cwd();\n const agentsDir = join(cwd, '.agents');\n if (!existsSync(agentsDir)) {\n mkdirSync(agentsDir, { recursive: true });\n }\n return join(agentsDir, 'tasks.json');\n }\n return join(memoryDir, '..', 'tasks.json');\n}\n\nfunction loadTasks(): TasksFile {\n const tasksPath = getTasksFilePath();\n if (existsSync(tasksPath)) {\n try {\n return JSON.parse(readFileSync(tasksPath, 'utf-8'));\n } catch {\n return { tasks: [], lastUpdated: new Date().toISOString() };\n }\n }\n return { tasks: [], lastUpdated: new Date().toISOString() };\n}\n\nfunction saveTasks(data: TasksFile): void {\n const tasksPath = getTasksFilePath();\n data.lastUpdated = new Date().toISOString();\n writeFileSync(tasksPath, JSON.stringify(data, null, 2));\n}\n\n// Get recent commits to infer activity\nfunction getRecentActivity(): { squad: string; message: string; hash: string; date: string }[] {\n const activity: { squad: string; message: string; hash: string; date: string }[] = [];\n\n const squadKeywords: Record<string, string[]> = {\n website: ['website', 'web', 'homepage', 'astro', 'page'],\n product: ['cli', 'squads-cli', 'command'],\n research: ['research', 'report', 'analysis'],\n engineering: ['infra', 'engineering', 'build'],\n intelligence: ['intel', 'monitor', 'competitor'],\n customer: ['lead', 'customer', 'outreach'],\n finance: ['cost', 'finance', 'budget'],\n company: ['company', 'strategy', 'mission'],\n marketing: ['marketing', 'content', 'social'],\n };\n\n try {\n const logOutput = execSync(\n 'git log --since=\"24 hours ago\" --format=\"%h|%aI|%s\" 2>/dev/null',\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }\n ).trim();\n\n if (!logOutput) return activity;\n\n for (const line of logOutput.split('\\n')) {\n const [hash, date, ...msgParts] = line.split('|');\n const message = msgParts.join('|');\n if (!hash || !message) continue;\n\n // Detect squad from commit message\n const msgLower = message.toLowerCase();\n let detectedSquad = 'unknown';\n\n for (const [squad, keywords] of Object.entries(squadKeywords)) {\n if (keywords.some(k => msgLower.includes(k))) {\n detectedSquad = squad;\n break;\n }\n }\n\n activity.push({\n squad: detectedSquad,\n message,\n hash,\n date: date.split('T')[0],\n });\n }\n } catch {\n // Not in git repo\n }\n\n return activity;\n}\n\nexport async function progressCommand(options: { verbose?: boolean } = {}): Promise<void> {\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}progress${RESET}`);\n writeLine();\n\n const tasksData = loadTasks();\n const recentActivity = getRecentActivity();\n\n // Active tasks\n const activeTasks = tasksData.tasks.filter(t => t.status === 'active');\n const completedToday = tasksData.tasks.filter(t =>\n t.status === 'completed' &&\n t.completedAt?.startsWith(new Date().toISOString().split('T')[0])\n );\n\n // Stats row\n const stats = [\n `${colors.cyan}${activeTasks.length}${RESET} active`,\n `${colors.green}${completedToday.length}${RESET} done today`,\n `${colors.purple}${recentActivity.length}${RESET} commits (24h)`,\n ].join(` ${colors.dim}│${RESET} `);\n writeLine(` ${stats}`);\n writeLine();\n\n // Active tasks section\n if (activeTasks.length > 0) {\n writeLine(` ${bold}Active Tasks${RESET}`);\n writeLine();\n\n for (const task of activeTasks) {\n const elapsed = getElapsedTime(task.startedAt);\n writeLine(` ${icons.progress} ${colors.cyan}${task.squad}${RESET} ${truncate(task.description, 45)}`);\n writeLine(` ${colors.dim}started ${elapsed} ago${RESET}`);\n }\n writeLine();\n } else {\n writeLine(` ${colors.dim}No active tasks${RESET}`);\n writeLine();\n }\n\n // Recent activity from git\n if (recentActivity.length > 0) {\n writeLine(` ${bold}Recent Activity${RESET} ${colors.dim}(last 24h)${RESET}`);\n writeLine();\n\n const w = { squad: 12, message: 50 };\n const tableWidth = w.squad + w.message + 4;\n\n writeLine(` ${colors.purple}${box.topLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.topRight}${RESET}`);\n writeLine(` ${colors.purple}${box.vertical}${RESET} ${bold}${padEnd('SQUAD', w.squad)}${RESET}${bold}COMMIT${RESET}${' '.repeat(w.message - 6)} ${colors.purple}${box.vertical}${RESET}`);\n writeLine(` ${colors.purple}${box.teeRight}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.teeLeft}${RESET}`);\n\n const maxRows = options.verbose ? 15 : 8;\n for (const act of recentActivity.slice(0, maxRows)) {\n const squadColor = act.squad === 'unknown' ? colors.dim : colors.cyan;\n const row = ` ${colors.purple}${box.vertical}${RESET} ` +\n `${squadColor}${padEnd(act.squad, w.squad)}${RESET}` +\n `${truncate(act.message, w.message - 2)}` +\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 if (recentActivity.length > maxRows) {\n writeLine(` ${colors.dim}+${recentActivity.length - maxRows} more commits${RESET}`);\n }\n writeLine();\n }\n\n // Completed today\n if (completedToday.length > 0) {\n writeLine(` ${bold}Completed Today${RESET}`);\n writeLine();\n for (const task of completedToday.slice(0, 5)) {\n writeLine(` ${icons.success} ${colors.cyan}${task.squad}${RESET} ${truncate(task.description, 50)}`);\n }\n if (completedToday.length > 5) {\n writeLine(` ${colors.dim}+${completedToday.length - 5} more${RESET}`);\n }\n writeLine();\n }\n\n // Commands\n writeLine(` ${colors.dim}$${RESET} squads results ${colors.dim}KPI goals vs actuals${RESET}`);\n writeLine(` ${colors.dim}$${RESET} squads dash ${colors.dim}Full dashboard${RESET}`);\n writeLine();\n}\n\n// Register a new task (called by agents)\nexport async function progressStartCommand(\n squad: string,\n description: string\n): Promise<void> {\n const tasksData = loadTasks();\n const id = Math.random().toString(36).substring(2, 9);\n\n tasksData.tasks.push({\n id,\n squad,\n description,\n status: 'active',\n startedAt: new Date().toISOString(),\n });\n\n saveTasks(tasksData);\n writeLine(` ${icons.active} Task ${colors.cyan}${id}${RESET} started for ${colors.purple}${squad}${RESET}`);\n}\n\n// Complete a task\nexport async function progressCompleteCommand(\n taskId: string,\n options: { failed?: boolean } = {}\n): Promise<void> {\n const tasksData = loadTasks();\n const task = tasksData.tasks.find(t => t.id === taskId);\n\n if (!task) {\n writeLine(` ${icons.error} Task ${colors.red}${taskId}${RESET} not found`);\n return;\n }\n\n task.status = options.failed ? 'failed' : 'completed';\n task.completedAt = new Date().toISOString();\n\n saveTasks(tasksData);\n\n const icon = options.failed ? icons.error : icons.success;\n const status = options.failed ? 'failed' : 'completed';\n writeLine(` ${icon} Task ${colors.cyan}${taskId}${RESET} ${status}`);\n}\n\nfunction getElapsedTime(startTime: string): string {\n const start = new Date(startTime).getTime();\n const now = Date.now();\n const diffMs = now - start;\n\n const minutes = Math.floor(diffMs / 60000);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) return `${days}d`;\n if (hours > 0) return `${hours}h`;\n if (minutes > 0) return `${minutes}m`;\n return '<1m';\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getAllCLIStatus
|
|
4
|
+
} from "./chunk-QHNUMM4V.js";
|
|
5
|
+
import {
|
|
6
|
+
Events,
|
|
7
|
+
track
|
|
8
|
+
} from "./chunk-L6GQCHDF.js";
|
|
9
|
+
import {
|
|
10
|
+
RESET,
|
|
11
|
+
colors,
|
|
12
|
+
gradient,
|
|
13
|
+
icons,
|
|
14
|
+
writeLine
|
|
15
|
+
} from "./chunk-N7KDWU4W.js";
|
|
16
|
+
import "./chunk-7OCVIDC7.js";
|
|
17
|
+
|
|
18
|
+
// src/commands/providers.ts
|
|
19
|
+
async function providersCommand(options = {}) {
|
|
20
|
+
const statuses = getAllCLIStatus();
|
|
21
|
+
await track(Events.CLI_PROVIDERS, {
|
|
22
|
+
available: statuses.filter((s) => s.available).length,
|
|
23
|
+
total: statuses.length
|
|
24
|
+
});
|
|
25
|
+
if (options.json) {
|
|
26
|
+
console.log(JSON.stringify(statuses, null, 2));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
writeLine();
|
|
30
|
+
writeLine(` ${gradient("squads")} ${colors.dim}providers${RESET}`);
|
|
31
|
+
writeLine();
|
|
32
|
+
writeLine(` ${colors.dim}Provider CLI Status${RESET}`);
|
|
33
|
+
writeLine(` ${colors.dim}${"\u2500".repeat(40)}${RESET}`);
|
|
34
|
+
const ready = [];
|
|
35
|
+
const missing = [];
|
|
36
|
+
for (const status of statuses) {
|
|
37
|
+
const statusText = status.available ? `${colors.green}${icons.success} ready${RESET}` : `${colors.red}${icons.error} not installed${RESET}`;
|
|
38
|
+
const providerCol = status.displayName.padEnd(12);
|
|
39
|
+
const commandCol = status.command.padEnd(9);
|
|
40
|
+
writeLine(` ${colors.cyan}${providerCol}${RESET} ${commandCol} ${statusText}`);
|
|
41
|
+
if (status.available) {
|
|
42
|
+
ready.push(status);
|
|
43
|
+
} else {
|
|
44
|
+
missing.push(status);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
writeLine();
|
|
48
|
+
if (ready.length === statuses.length) {
|
|
49
|
+
writeLine(` ${colors.green}${icons.success}${RESET} All providers ready`);
|
|
50
|
+
} else {
|
|
51
|
+
writeLine(` ${colors.dim}${ready.length}/${statuses.length} providers available${RESET}`);
|
|
52
|
+
}
|
|
53
|
+
if (missing.length > 0) {
|
|
54
|
+
writeLine();
|
|
55
|
+
writeLine(` ${colors.dim}Install missing:${RESET}`);
|
|
56
|
+
for (const status of missing) {
|
|
57
|
+
writeLine(` ${colors.dim}$${RESET} ${status.install}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
writeLine();
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
providersCommand
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=providers-66PDCORB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/providers.ts"],"sourcesContent":["/**\n * squads providers - Show available LLM CLI providers\n *\n * Lists all supported LLM CLIs and their availability status.\n * Provides install instructions for missing CLIs.\n *\n * @see specs/multi-llm.md\n */\n\nimport {\n colors,\n RESET,\n gradient,\n icons,\n writeLine,\n} from '../lib/terminal.js';\nimport { getAllCLIStatus, CLIStatus } from '../lib/llm-clis.js';\nimport { track, Events } from '../lib/telemetry.js';\n\nexport interface ProvidersOptions {\n json?: boolean;\n}\n\n/**\n * Show status of all LLM CLI providers\n */\nexport async function providersCommand(options: ProvidersOptions = {}): Promise<void> {\n const statuses = getAllCLIStatus();\n\n // Track telemetry\n await track(Events.CLI_PROVIDERS, {\n available: statuses.filter((s) => s.available).length,\n total: statuses.length,\n });\n\n // JSON output for programmatic use\n if (options.json) {\n console.log(JSON.stringify(statuses, null, 2));\n return;\n }\n\n // Pretty output\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}providers${RESET}`);\n writeLine();\n\n // Header\n writeLine(` ${colors.dim}Provider CLI Status${RESET}`);\n writeLine(` ${colors.dim}${'─'.repeat(40)}${RESET}`);\n\n // Provider rows\n const ready: CLIStatus[] = [];\n const missing: CLIStatus[] = [];\n\n for (const status of statuses) {\n const statusText = status.available\n ? `${colors.green}${icons.success} ready${RESET}`\n : `${colors.red}${icons.error} not installed${RESET}`;\n\n // Pad columns for alignment\n const providerCol = status.displayName.padEnd(12);\n const commandCol = status.command.padEnd(9);\n\n writeLine(` ${colors.cyan}${providerCol}${RESET} ${commandCol} ${statusText}`);\n\n if (status.available) {\n ready.push(status);\n } else {\n missing.push(status);\n }\n }\n\n writeLine();\n\n // Summary\n if (ready.length === statuses.length) {\n writeLine(` ${colors.green}${icons.success}${RESET} All providers ready`);\n } else {\n writeLine(` ${colors.dim}${ready.length}/${statuses.length} providers available${RESET}`);\n }\n\n // Install instructions for missing\n if (missing.length > 0) {\n writeLine();\n writeLine(` ${colors.dim}Install missing:${RESET}`);\n\n for (const status of missing) {\n writeLine(` ${colors.dim}$${RESET} ${status.install}`);\n }\n }\n\n writeLine();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA0BA,eAAsB,iBAAiB,UAA4B,CAAC,GAAkB;AACpF,QAAM,WAAW,gBAAgB;AAGjC,QAAM,MAAM,OAAO,eAAe;AAAA,IAChC,WAAW,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE;AAAA,IAC/C,OAAO,SAAS;AAAA,EAClB,CAAC;AAGD,MAAI,QAAQ,MAAM;AAChB,YAAQ,IAAI,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAC7C;AAAA,EACF;AAGA,YAAU;AACV,YAAU,KAAK,SAAS,QAAQ,CAAC,IAAI,OAAO,GAAG,YAAY,KAAK,EAAE;AAClE,YAAU;AAGV,YAAU,KAAK,OAAO,GAAG,gCAAgC,KAAK,EAAE;AAChE,YAAU,KAAK,OAAO,GAAG,GAAG,SAAI,OAAO,EAAE,CAAC,GAAG,KAAK,EAAE;AAGpD,QAAM,QAAqB,CAAC;AAC5B,QAAM,UAAuB,CAAC;AAE9B,aAAW,UAAU,UAAU;AAC7B,UAAM,aAAa,OAAO,YACtB,GAAG,OAAO,KAAK,GAAG,MAAM,OAAO,SAAS,KAAK,KAC7C,GAAG,OAAO,GAAG,GAAG,MAAM,KAAK,iBAAiB,KAAK;AAGrD,UAAM,cAAc,OAAO,YAAY,OAAO,EAAE;AAChD,UAAM,aAAa,OAAO,QAAQ,OAAO,CAAC;AAE1C,cAAU,KAAK,OAAO,IAAI,GAAG,WAAW,GAAG,KAAK,IAAI,UAAU,IAAI,UAAU,EAAE;AAE9E,QAAI,OAAO,WAAW;AACpB,YAAM,KAAK,MAAM;AAAA,IACnB,OAAO;AACL,cAAQ,KAAK,MAAM;AAAA,IACrB;AAAA,EACF;AAEA,YAAU;AAGV,MAAI,MAAM,WAAW,SAAS,QAAQ;AACpC,cAAU,KAAK,OAAO,KAAK,GAAG,MAAM,OAAO,GAAG,KAAK,sBAAsB;AAAA,EAC3E,OAAO;AACL,cAAU,KAAK,OAAO,GAAG,GAAG,MAAM,MAAM,IAAI,SAAS,MAAM,uBAAuB,KAAK,EAAE;AAAA,EAC3F;AAGA,MAAI,QAAQ,SAAS,GAAG;AACtB,cAAU;AACV,cAAU,KAAK,OAAO,GAAG,mBAAmB,KAAK,EAAE;AAEnD,eAAW,UAAU,SAAS;AAC5B,gBAAU,OAAO,OAAO,GAAG,IAAI,KAAK,IAAI,OAAO,OAAO,EAAE;AAAA,IAC1D;AAAA,EACF;AAEA,YAAU;AACZ;","names":[]}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
findSquadsDir,
|
|
4
|
+
listSquads,
|
|
5
|
+
loadSquad
|
|
6
|
+
} from "./chunk-LDM62TIX.js";
|
|
7
|
+
import {
|
|
8
|
+
RESET,
|
|
9
|
+
bold,
|
|
10
|
+
box,
|
|
11
|
+
colors,
|
|
12
|
+
gradient,
|
|
13
|
+
icons,
|
|
14
|
+
padEnd,
|
|
15
|
+
truncate,
|
|
16
|
+
writeLine
|
|
17
|
+
} from "./chunk-N7KDWU4W.js";
|
|
18
|
+
import "./chunk-7OCVIDC7.js";
|
|
19
|
+
|
|
20
|
+
// src/commands/results.ts
|
|
21
|
+
import { execSync } from "child_process";
|
|
22
|
+
function getGitStats(days = 7) {
|
|
23
|
+
const stats = /* @__PURE__ */ new Map();
|
|
24
|
+
const squadKeywords = {
|
|
25
|
+
website: ["agents-squads-web", "website", "homepage"],
|
|
26
|
+
product: ["squads-cli", "cli"],
|
|
27
|
+
research: ["research"],
|
|
28
|
+
engineering: ["engineering", ".agents"],
|
|
29
|
+
intelligence: ["intelligence"],
|
|
30
|
+
customer: ["customer"],
|
|
31
|
+
finance: ["finance"],
|
|
32
|
+
company: ["company"],
|
|
33
|
+
marketing: ["marketing"]
|
|
34
|
+
};
|
|
35
|
+
try {
|
|
36
|
+
const logOutput = execSync(
|
|
37
|
+
`git log --since="${days} days ago" --format="%s" --name-only 2>/dev/null`,
|
|
38
|
+
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
39
|
+
).trim();
|
|
40
|
+
if (!logOutput) return stats;
|
|
41
|
+
const entries = logOutput.split("\n\n");
|
|
42
|
+
for (const entry of entries) {
|
|
43
|
+
const lines = entry.split("\n").filter((l) => l.trim());
|
|
44
|
+
if (lines.length === 0) continue;
|
|
45
|
+
const message = lines[0];
|
|
46
|
+
const files = lines.slice(1);
|
|
47
|
+
const msgLower = message.toLowerCase();
|
|
48
|
+
let detectedSquad = "other";
|
|
49
|
+
for (const [squad, keywords] of Object.entries(squadKeywords)) {
|
|
50
|
+
const inMessage = keywords.some((k) => msgLower.includes(k));
|
|
51
|
+
const inFiles = files.some(
|
|
52
|
+
(f) => keywords.some((k) => f.toLowerCase().includes(k))
|
|
53
|
+
);
|
|
54
|
+
if (inMessage || inFiles) {
|
|
55
|
+
detectedSquad = squad;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (!stats.has(detectedSquad)) {
|
|
60
|
+
stats.set(detectedSquad, { commits: 0, files: [] });
|
|
61
|
+
}
|
|
62
|
+
const squadStats = stats.get(detectedSquad);
|
|
63
|
+
squadStats.commits++;
|
|
64
|
+
squadStats.files.push(...files);
|
|
65
|
+
}
|
|
66
|
+
} catch {
|
|
67
|
+
}
|
|
68
|
+
return stats;
|
|
69
|
+
}
|
|
70
|
+
function getGitHubStats(days = 7) {
|
|
71
|
+
const prsOpened = /* @__PURE__ */ new Map();
|
|
72
|
+
const prsMerged = /* @__PURE__ */ new Map();
|
|
73
|
+
const issuesClosed = /* @__PURE__ */ new Map();
|
|
74
|
+
try {
|
|
75
|
+
const prsOutput = execSync(
|
|
76
|
+
`gh pr list --state all --json title,createdAt,mergedAt --limit 50 2>/dev/null`,
|
|
77
|
+
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
78
|
+
);
|
|
79
|
+
const prs = JSON.parse(prsOutput || "[]");
|
|
80
|
+
const since = new Date(Date.now() - days * 24 * 60 * 60 * 1e3);
|
|
81
|
+
for (const pr of prs) {
|
|
82
|
+
const created = new Date(pr.createdAt);
|
|
83
|
+
if (created < since) continue;
|
|
84
|
+
const squad = detectSquadFromTitle(pr.title);
|
|
85
|
+
prsOpened.set(squad, (prsOpened.get(squad) || 0) + 1);
|
|
86
|
+
if (pr.mergedAt) {
|
|
87
|
+
prsMerged.set(squad, (prsMerged.get(squad) || 0) + 1);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const issuesOutput = execSync(
|
|
91
|
+
`gh issue list --state closed --json title,closedAt --limit 50 2>/dev/null`,
|
|
92
|
+
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
93
|
+
);
|
|
94
|
+
const issues = JSON.parse(issuesOutput || "[]");
|
|
95
|
+
for (const issue of issues) {
|
|
96
|
+
const closed = new Date(issue.closedAt);
|
|
97
|
+
if (closed < since) continue;
|
|
98
|
+
const squad = detectSquadFromTitle(issue.title);
|
|
99
|
+
issuesClosed.set(squad, (issuesClosed.get(squad) || 0) + 1);
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
return { prsOpened, prsMerged, issuesClosed };
|
|
104
|
+
}
|
|
105
|
+
function detectSquadFromTitle(title) {
|
|
106
|
+
const lower = title.toLowerCase();
|
|
107
|
+
const mapping = {
|
|
108
|
+
website: ["website", "web", "homepage", "page"],
|
|
109
|
+
product: ["cli", "squads", "command"],
|
|
110
|
+
research: ["research", "report"],
|
|
111
|
+
engineering: ["infra", "build", "ci"],
|
|
112
|
+
intelligence: ["intel", "monitor"],
|
|
113
|
+
customer: ["lead", "customer"],
|
|
114
|
+
finance: ["cost", "finance"],
|
|
115
|
+
marketing: ["marketing", "content"]
|
|
116
|
+
};
|
|
117
|
+
for (const [squad, keywords] of Object.entries(mapping)) {
|
|
118
|
+
if (keywords.some((k) => lower.includes(k))) {
|
|
119
|
+
return squad;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return "other";
|
|
123
|
+
}
|
|
124
|
+
function parseMetrics(goal) {
|
|
125
|
+
const metrics = [];
|
|
126
|
+
if (goal.metrics && goal.metrics.length > 0) {
|
|
127
|
+
return goal.metrics;
|
|
128
|
+
}
|
|
129
|
+
const desc = goal.description.toLowerCase();
|
|
130
|
+
if (desc.includes("revenue")) metrics.push("revenue_usd");
|
|
131
|
+
if (desc.includes("lead")) metrics.push("leads_count");
|
|
132
|
+
if (desc.includes("traffic") || desc.includes("visit")) metrics.push("page_views");
|
|
133
|
+
if (desc.includes("signup") || desc.includes("email")) metrics.push("signups");
|
|
134
|
+
if (desc.includes("cost")) metrics.push("cost_usd");
|
|
135
|
+
if (desc.includes("publish") || desc.includes("launch")) metrics.push("shipped");
|
|
136
|
+
if (desc.includes("demo")) metrics.push("demos_booked");
|
|
137
|
+
return metrics.length > 0 ? metrics : ["progress"];
|
|
138
|
+
}
|
|
139
|
+
async function resultsCommand(options = {}) {
|
|
140
|
+
const squadsDir = findSquadsDir();
|
|
141
|
+
if (!squadsDir) {
|
|
142
|
+
writeLine(`${colors.red}No .agents/squads directory found${RESET}`);
|
|
143
|
+
writeLine(`${colors.dim}Run \`squads init\` to create one.${RESET}`);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const days = parseInt(options.days || "7", 10);
|
|
147
|
+
writeLine();
|
|
148
|
+
writeLine(` ${gradient("squads")} ${colors.dim}results${RESET} ${colors.dim}(${days}d)${RESET}`);
|
|
149
|
+
writeLine();
|
|
150
|
+
const squadNames = options.squad ? [options.squad] : listSquads(squadsDir);
|
|
151
|
+
const gitStats = getGitStats(days);
|
|
152
|
+
const ghStats = getGitHubStats(days);
|
|
153
|
+
const results = [];
|
|
154
|
+
for (const name of squadNames) {
|
|
155
|
+
const squad = loadSquad(name);
|
|
156
|
+
if (!squad) continue;
|
|
157
|
+
const git = gitStats.get(name) || { commits: 0, files: [] };
|
|
158
|
+
const activeGoals = squad.goals.filter((g) => !g.completed);
|
|
159
|
+
results.push({
|
|
160
|
+
name,
|
|
161
|
+
commits: git.commits,
|
|
162
|
+
prsOpened: ghStats.prsOpened.get(name) || 0,
|
|
163
|
+
prsMerged: ghStats.prsMerged.get(name) || 0,
|
|
164
|
+
issuesClosed: ghStats.issuesClosed.get(name) || 0,
|
|
165
|
+
goals: activeGoals.map((g) => ({
|
|
166
|
+
description: g.description,
|
|
167
|
+
metrics: parseMetrics(g),
|
|
168
|
+
progress: g.progress,
|
|
169
|
+
completed: g.completed
|
|
170
|
+
}))
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
const totalCommits = results.reduce((sum, r) => sum + r.commits, 0);
|
|
174
|
+
const totalPRs = results.reduce((sum, r) => sum + r.prsMerged, 0);
|
|
175
|
+
const totalGoals = results.reduce((sum, r) => sum + r.goals.length, 0);
|
|
176
|
+
const stats = [
|
|
177
|
+
`${colors.cyan}${totalCommits}${RESET} commits`,
|
|
178
|
+
`${colors.green}${totalPRs}${RESET} PRs merged`,
|
|
179
|
+
`${colors.purple}${totalGoals}${RESET} active goals`
|
|
180
|
+
].join(` ${colors.dim}\u2502${RESET} `);
|
|
181
|
+
writeLine(` ${stats}`);
|
|
182
|
+
writeLine();
|
|
183
|
+
const w = { squad: 14, commits: 8, prs: 6, goals: 5, kpi: 20 };
|
|
184
|
+
const tableWidth = w.squad + w.commits + w.prs + w.goals + w.kpi + 8;
|
|
185
|
+
writeLine(` ${colors.purple}${box.topLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.topRight}${RESET}`);
|
|
186
|
+
writeLine(` ${colors.purple}${box.vertical}${RESET} ${bold}${padEnd("SQUAD", w.squad)}${RESET}${bold}${padEnd("COMMITS", w.commits)}${RESET}${bold}${padEnd("PRs", w.prs)}${RESET}${bold}${padEnd("GOALS", w.goals)}${RESET}${bold}KEY METRIC${RESET} ${colors.purple}${box.vertical}${RESET}`);
|
|
187
|
+
writeLine(` ${colors.purple}${box.teeRight}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.teeLeft}${RESET}`);
|
|
188
|
+
for (const result of results) {
|
|
189
|
+
const keyMetric = result.goals.length > 0 ? result.goals[0].metrics[0] || "\u2014" : "\u2014";
|
|
190
|
+
const commitColor = result.commits > 0 ? colors.green : colors.dim;
|
|
191
|
+
const prColor = result.prsMerged > 0 ? colors.green : colors.dim;
|
|
192
|
+
const row = ` ${colors.purple}${box.vertical}${RESET} ${colors.cyan}${padEnd(result.name, w.squad)}${RESET}${commitColor}${padEnd(String(result.commits), w.commits)}${RESET}${prColor}${padEnd(String(result.prsMerged), w.prs)}${RESET}${padEnd(String(result.goals.length), w.goals)}${colors.dim}${truncate(keyMetric, w.kpi)}${RESET} ${colors.purple}${box.vertical}${RESET}`;
|
|
193
|
+
writeLine(row);
|
|
194
|
+
}
|
|
195
|
+
writeLine(` ${colors.purple}${box.bottomLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.bottomRight}${RESET}`);
|
|
196
|
+
writeLine();
|
|
197
|
+
if (options.verbose || options.squad) {
|
|
198
|
+
writeLine(` ${bold}Goals & KPIs${RESET}`);
|
|
199
|
+
writeLine();
|
|
200
|
+
for (const result of results) {
|
|
201
|
+
if (result.goals.length === 0) continue;
|
|
202
|
+
writeLine(` ${colors.cyan}${result.name}${RESET}`);
|
|
203
|
+
for (const goal of result.goals) {
|
|
204
|
+
const statusIcon = goal.progress ? icons.progress : icons.empty;
|
|
205
|
+
writeLine(` ${statusIcon} ${truncate(goal.description, 55)}`);
|
|
206
|
+
if (goal.metrics.length > 0) {
|
|
207
|
+
const metricsStr = goal.metrics.map((m) => `${colors.purple}${m}${RESET}`).join(", ");
|
|
208
|
+
writeLine(` ${colors.dim}metrics:${RESET} ${metricsStr}`);
|
|
209
|
+
}
|
|
210
|
+
if (goal.progress) {
|
|
211
|
+
writeLine(` ${colors.dim}progress:${RESET} ${colors.green}${goal.progress}${RESET}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
writeLine();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
writeLine(` ${colors.dim}$${RESET} squads results ${colors.cyan}<squad>${RESET} -v ${colors.dim}Detailed squad KPIs${RESET}`);
|
|
218
|
+
writeLine(` ${colors.dim}$${RESET} squads goal progress ${colors.dim}Update goal progress${RESET}`);
|
|
219
|
+
writeLine();
|
|
220
|
+
}
|
|
221
|
+
export {
|
|
222
|
+
resultsCommand
|
|
223
|
+
};
|
|
224
|
+
//# sourceMappingURL=results-2MJFLWEO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/results.ts"],"sourcesContent":["import { execSync } from 'child_process';\nimport { findSquadsDir, listSquads, loadSquad, Goal } from '../lib/squad-parser.js';\nimport {\n colors,\n bold,\n RESET,\n gradient,\n box,\n padEnd,\n truncate,\n icons,\n writeLine,\n} from '../lib/terminal.js';\n\ninterface SquadResults {\n name: string;\n commits: number;\n prsOpened: number;\n prsMerged: number;\n issuesClosed: number;\n goals: GoalWithMetrics[];\n}\n\ninterface GoalWithMetrics {\n description: string;\n metrics: string[];\n progress?: string;\n completed: boolean;\n actual?: Record<string, number | string>;\n}\n\n// Get git stats for the past week per squad\nfunction getGitStats(days: number = 7): Map<string, { commits: number; files: string[] }> {\n const stats = new Map<string, { commits: number; files: string[] }>();\n\n const squadKeywords: Record<string, string[]> = {\n website: ['agents-squads-web', 'website', 'homepage'],\n product: ['squads-cli', 'cli'],\n research: ['research'],\n engineering: ['engineering', '.agents'],\n intelligence: ['intelligence'],\n customer: ['customer'],\n finance: ['finance'],\n company: ['company'],\n marketing: ['marketing'],\n };\n\n try {\n const logOutput = execSync(\n `git log --since=\"${days} days ago\" --format=\"%s\" --name-only 2>/dev/null`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }\n ).trim();\n\n if (!logOutput) return stats;\n\n const entries = logOutput.split('\\n\\n');\n for (const entry of entries) {\n const lines = entry.split('\\n').filter(l => l.trim());\n if (lines.length === 0) continue;\n\n const message = lines[0];\n const files = lines.slice(1);\n const msgLower = message.toLowerCase();\n\n // Detect squad\n let detectedSquad = 'other';\n for (const [squad, keywords] of Object.entries(squadKeywords)) {\n const inMessage = keywords.some(k => msgLower.includes(k));\n const inFiles = files.some(f =>\n keywords.some(k => f.toLowerCase().includes(k))\n );\n if (inMessage || inFiles) {\n detectedSquad = squad;\n break;\n }\n }\n\n if (!stats.has(detectedSquad)) {\n stats.set(detectedSquad, { commits: 0, files: [] });\n }\n const squadStats = stats.get(detectedSquad)!;\n squadStats.commits++;\n squadStats.files.push(...files);\n }\n } catch {\n // Not in git repo\n }\n\n return stats;\n}\n\n// Get GitHub stats via gh CLI\nfunction getGitHubStats(days: number = 7): {\n prsOpened: Map<string, number>;\n prsMerged: Map<string, number>;\n issuesClosed: Map<string, number>;\n} {\n const prsOpened = new Map<string, number>();\n const prsMerged = new Map<string, number>();\n const issuesClosed = new Map<string, number>();\n\n try {\n // Get PRs opened\n const prsOutput = execSync(\n `gh pr list --state all --json title,createdAt,mergedAt --limit 50 2>/dev/null`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }\n );\n const prs = JSON.parse(prsOutput || '[]');\n const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000);\n\n for (const pr of prs) {\n const created = new Date(pr.createdAt);\n if (created < since) continue;\n\n const squad = detectSquadFromTitle(pr.title);\n prsOpened.set(squad, (prsOpened.get(squad) || 0) + 1);\n\n if (pr.mergedAt) {\n prsMerged.set(squad, (prsMerged.get(squad) || 0) + 1);\n }\n }\n\n // Get issues closed\n const issuesOutput = execSync(\n `gh issue list --state closed --json title,closedAt --limit 50 2>/dev/null`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }\n );\n const issues = JSON.parse(issuesOutput || '[]');\n\n for (const issue of issues) {\n const closed = new Date(issue.closedAt);\n if (closed < since) continue;\n\n const squad = detectSquadFromTitle(issue.title);\n issuesClosed.set(squad, (issuesClosed.get(squad) || 0) + 1);\n }\n } catch {\n // gh not available or not in repo\n }\n\n return { prsOpened, prsMerged, issuesClosed };\n}\n\nfunction detectSquadFromTitle(title: string): string {\n const lower = title.toLowerCase();\n const mapping: Record<string, string[]> = {\n website: ['website', 'web', 'homepage', 'page'],\n product: ['cli', 'squads', 'command'],\n research: ['research', 'report'],\n engineering: ['infra', 'build', 'ci'],\n intelligence: ['intel', 'monitor'],\n customer: ['lead', 'customer'],\n finance: ['cost', 'finance'],\n marketing: ['marketing', 'content'],\n };\n\n for (const [squad, keywords] of Object.entries(mapping)) {\n if (keywords.some(k => lower.includes(k))) {\n return squad;\n }\n }\n return 'other';\n}\n\n// Parse metrics from goal description\nfunction parseMetrics(goal: Goal): string[] {\n const metrics: string[] = [];\n\n // Check for explicit metrics in goal\n if (goal.metrics && goal.metrics.length > 0) {\n return goal.metrics;\n }\n\n // Infer from description\n const desc = goal.description.toLowerCase();\n\n if (desc.includes('revenue')) metrics.push('revenue_usd');\n if (desc.includes('lead')) metrics.push('leads_count');\n if (desc.includes('traffic') || desc.includes('visit')) metrics.push('page_views');\n if (desc.includes('signup') || desc.includes('email')) metrics.push('signups');\n if (desc.includes('cost')) metrics.push('cost_usd');\n if (desc.includes('publish') || desc.includes('launch')) metrics.push('shipped');\n if (desc.includes('demo')) metrics.push('demos_booked');\n\n return metrics.length > 0 ? metrics : ['progress'];\n}\n\nexport async function resultsCommand(options: {\n squad?: string;\n days?: string;\n verbose?: boolean;\n} = {}): Promise<void> {\n const squadsDir = findSquadsDir();\n if (!squadsDir) {\n writeLine(`${colors.red}No .agents/squads directory found${RESET}`);\n writeLine(`${colors.dim}Run \\`squads init\\` to create one.${RESET}`);\n return;\n }\n\n const days = parseInt(options.days || '7', 10);\n\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}results${RESET} ${colors.dim}(${days}d)${RESET}`);\n writeLine();\n\n const squadNames = options.squad ? [options.squad] : listSquads(squadsDir);\n const gitStats = getGitStats(days);\n const ghStats = getGitHubStats(days);\n\n const results: SquadResults[] = [];\n\n for (const name of squadNames) {\n const squad = loadSquad(name);\n if (!squad) continue;\n\n const git = gitStats.get(name) || { commits: 0, files: [] };\n const activeGoals = squad.goals.filter(g => !g.completed);\n\n results.push({\n name,\n commits: git.commits,\n prsOpened: ghStats.prsOpened.get(name) || 0,\n prsMerged: ghStats.prsMerged.get(name) || 0,\n issuesClosed: ghStats.issuesClosed.get(name) || 0,\n goals: activeGoals.map(g => ({\n description: g.description,\n metrics: parseMetrics(g),\n progress: g.progress,\n completed: g.completed,\n })),\n });\n }\n\n // Summary stats\n const totalCommits = results.reduce((sum, r) => sum + r.commits, 0);\n const totalPRs = results.reduce((sum, r) => sum + r.prsMerged, 0);\n const totalGoals = results.reduce((sum, r) => sum + r.goals.length, 0);\n\n const stats = [\n `${colors.cyan}${totalCommits}${RESET} commits`,\n `${colors.green}${totalPRs}${RESET} PRs merged`,\n `${colors.purple}${totalGoals}${RESET} active goals`,\n ].join(` ${colors.dim}│${RESET} `);\n writeLine(` ${stats}`);\n writeLine();\n\n // Results table\n const w = { squad: 14, commits: 8, prs: 6, goals: 5, kpi: 20 };\n const tableWidth = w.squad + w.commits + w.prs + w.goals + w.kpi + 8;\n\n writeLine(` ${colors.purple}${box.topLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.topRight}${RESET}`);\n writeLine(` ${colors.purple}${box.vertical}${RESET} ` +\n `${bold}${padEnd('SQUAD', w.squad)}${RESET}` +\n `${bold}${padEnd('COMMITS', w.commits)}${RESET}` +\n `${bold}${padEnd('PRs', w.prs)}${RESET}` +\n `${bold}${padEnd('GOALS', w.goals)}${RESET}` +\n `${bold}KEY METRIC${RESET}` +\n ` ${colors.purple}${box.vertical}${RESET}`);\n writeLine(` ${colors.purple}${box.teeRight}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.teeLeft}${RESET}`);\n\n for (const result of results) {\n const keyMetric = result.goals.length > 0\n ? result.goals[0].metrics[0] || '—'\n : '—';\n\n const commitColor = result.commits > 0 ? colors.green : colors.dim;\n const prColor = result.prsMerged > 0 ? colors.green : colors.dim;\n\n const row = ` ${colors.purple}${box.vertical}${RESET} ` +\n `${colors.cyan}${padEnd(result.name, w.squad)}${RESET}` +\n `${commitColor}${padEnd(String(result.commits), w.commits)}${RESET}` +\n `${prColor}${padEnd(String(result.prsMerged), w.prs)}${RESET}` +\n `${padEnd(String(result.goals.length), w.goals)}` +\n `${colors.dim}${truncate(keyMetric, w.kpi)}${RESET}` +\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 writeLine();\n\n // Goal details with KPIs\n if (options.verbose || options.squad) {\n writeLine(` ${bold}Goals & KPIs${RESET}`);\n writeLine();\n\n for (const result of results) {\n if (result.goals.length === 0) continue;\n\n writeLine(` ${colors.cyan}${result.name}${RESET}`);\n\n for (const goal of result.goals) {\n const statusIcon = goal.progress ? icons.progress : icons.empty;\n writeLine(` ${statusIcon} ${truncate(goal.description, 55)}`);\n\n // Show metrics\n if (goal.metrics.length > 0) {\n const metricsStr = goal.metrics.map(m => `${colors.purple}${m}${RESET}`).join(', ');\n writeLine(` ${colors.dim}metrics:${RESET} ${metricsStr}`);\n }\n\n // Show progress if any\n if (goal.progress) {\n writeLine(` ${colors.dim}progress:${RESET} ${colors.green}${goal.progress}${RESET}`);\n }\n }\n writeLine();\n }\n }\n\n // Help\n writeLine(` ${colors.dim}$${RESET} squads results ${colors.cyan}<squad>${RESET} -v ${colors.dim}Detailed squad KPIs${RESET}`);\n writeLine(` ${colors.dim}$${RESET} squads goal progress ${colors.dim}Update goal progress${RESET}`);\n writeLine();\n}\n"],"mappings":"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","names":[]}
|