squads-cli 0.2.0 → 0.2.1
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 +521 -288
- package/dist/auth-YW3UPFSB.js +23 -0
- package/dist/auth-YW3UPFSB.js.map +1 -0
- package/dist/autonomy-PSVZVX7A.js +105 -0
- package/dist/autonomy-PSVZVX7A.js.map +1 -0
- package/dist/chunk-67RO2HKR.js +174 -0
- package/dist/chunk-67RO2HKR.js.map +1 -0
- package/dist/chunk-7OCVIDC7.js +12 -0
- package/dist/chunk-7OCVIDC7.js.map +1 -0
- package/dist/chunk-BODLDQY7.js +452 -0
- package/dist/chunk-BODLDQY7.js.map +1 -0
- package/dist/chunk-EHQJHRIW.js +103 -0
- package/dist/chunk-EHQJHRIW.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-HF4WR7RA.js +154 -0
- package/dist/chunk-HF4WR7RA.js.map +1 -0
- package/dist/chunk-J6QF4ZQX.js +230 -0
- package/dist/chunk-J6QF4ZQX.js.map +1 -0
- package/dist/chunk-LOA3KWYJ.js +294 -0
- package/dist/chunk-LOA3KWYJ.js.map +1 -0
- package/dist/chunk-M5FXNY6Y.js +384 -0
- package/dist/chunk-M5FXNY6Y.js.map +1 -0
- package/dist/chunk-QHNUMM4V.js +87 -0
- package/dist/chunk-QHNUMM4V.js.map +1 -0
- package/dist/chunk-QJ7C7CMB.js +223 -0
- package/dist/chunk-QJ7C7CMB.js.map +1 -0
- package/dist/chunk-RM6BWILN.js +74 -0
- package/dist/chunk-RM6BWILN.js.map +1 -0
- package/dist/chunk-TYFTF53O.js +613 -0
- package/dist/chunk-TYFTF53O.js.map +1 -0
- package/dist/chunk-TZXD6WFN.js +420 -0
- package/dist/chunk-TZXD6WFN.js.map +1 -0
- package/dist/chunk-WVOIY5GW.js +621 -0
- package/dist/chunk-WVOIY5GW.js.map +1 -0
- package/dist/chunk-Z2UKDBNL.js +162 -0
- package/dist/chunk-Z2UKDBNL.js.map +1 -0
- package/dist/chunk-ZTQ7ISUR.js +338 -0
- package/dist/chunk-ZTQ7ISUR.js.map +1 -0
- package/dist/cli.js +2483 -5902
- package/dist/cli.js.map +1 -1
- package/dist/context-GWPF4SEY.js +291 -0
- package/dist/context-GWPF4SEY.js.map +1 -0
- package/dist/context-feed-AJGVAR6H.js +394 -0
- package/dist/context-feed-AJGVAR6H.js.map +1 -0
- package/dist/cost-XBCDJ7XC.js +275 -0
- package/dist/cost-XBCDJ7XC.js.map +1 -0
- package/dist/create-BLFGG6PF.js +286 -0
- package/dist/create-BLFGG6PF.js.map +1 -0
- package/dist/dashboard-LGT2B2BL.js +951 -0
- package/dist/dashboard-LGT2B2BL.js.map +1 -0
- package/dist/dashboard-RMK2BOD2.js +794 -0
- package/dist/dashboard-RMK2BOD2.js.map +1 -0
- package/dist/doctor-XPUIIBHJ.js +374 -0
- package/dist/doctor-XPUIIBHJ.js.map +1 -0
- package/dist/env-config-SQEI3Y7Y.js +21 -0
- package/dist/env-config-SQEI3Y7Y.js.map +1 -0
- package/dist/exec-OUXM7JBF.js +223 -0
- package/dist/exec-OUXM7JBF.js.map +1 -0
- package/dist/feedback-KNAOG5QK.js +229 -0
- package/dist/feedback-KNAOG5QK.js.map +1 -0
- package/dist/github-UQTM5KMS.js +23 -0
- package/dist/github-UQTM5KMS.js.map +1 -0
- package/dist/goal-BVHV5573.js +168 -0
- package/dist/goal-BVHV5573.js.map +1 -0
- package/dist/health-4UXN44PF.js +218 -0
- package/dist/health-4UXN44PF.js.map +1 -0
- package/dist/history-ILH3SWHB.js +232 -0
- package/dist/history-ILH3SWHB.js.map +1 -0
- package/dist/index.d.ts +736 -8
- package/dist/index.js +1312 -6
- package/dist/index.js.map +1 -1
- package/dist/init-XQZ7BOGT.js +812 -0
- package/dist/init-XQZ7BOGT.js.map +1 -0
- package/dist/kpi-RQIU7WGK.js +413 -0
- package/dist/kpi-RQIU7WGK.js.map +1 -0
- package/dist/learn-OIFUVZAS.js +269 -0
- package/dist/learn-OIFUVZAS.js.map +1 -0
- package/dist/login-DXZANWZY.js +155 -0
- package/dist/login-DXZANWZY.js.map +1 -0
- package/dist/memory-T3ACCS7E.js +560 -0
- package/dist/memory-T3ACCS7E.js.map +1 -0
- package/dist/memory-VNF2VFRB.js +23 -0
- package/dist/memory-VNF2VFRB.js.map +1 -0
- package/dist/progress-DAUZMT3N.js +202 -0
- package/dist/progress-DAUZMT3N.js.map +1 -0
- package/dist/providers-3P5D2XL5.js +65 -0
- package/dist/providers-3P5D2XL5.js.map +1 -0
- package/dist/results-UECWGLTB.js +224 -0
- package/dist/results-UECWGLTB.js.map +1 -0
- package/dist/run-I6KAXU6U.js +4049 -0
- package/dist/run-I6KAXU6U.js.map +1 -0
- package/dist/session-HBU6KZOD.js +64 -0
- package/dist/session-HBU6KZOD.js.map +1 -0
- package/dist/sessions-CK25VGPL.js +333 -0
- package/dist/sessions-CK25VGPL.js.map +1 -0
- package/dist/squad-parser-DCG65BJS.js +35 -0
- package/dist/squad-parser-DCG65BJS.js.map +1 -0
- package/dist/stats-G6NAU5BD.js +334 -0
- package/dist/stats-G6NAU5BD.js.map +1 -0
- package/dist/status-AQNLDZVN.js +352 -0
- package/dist/status-AQNLDZVN.js.map +1 -0
- package/dist/sync-ZI3MHA4G.js +836 -0
- package/dist/sync-ZI3MHA4G.js.map +1 -0
- package/dist/templates/core/AGENTS.md.template +51 -0
- package/dist/templates/core/BUSINESS_BRIEF.md.template +29 -0
- package/dist/templates/core/CLAUDE.md.template +48 -0
- package/dist/templates/core/provider.yaml.template +5 -0
- package/dist/templates/first-squad/SQUAD.md.template +23 -0
- package/dist/templates/first-squad/lead.md.template +44 -0
- package/dist/templates/memory/getting-started/state.md.template +19 -0
- package/dist/templates/seed/BUSINESS_BRIEF.md.template +27 -0
- package/dist/templates/seed/CLAUDE.md.template +119 -0
- package/dist/templates/seed/README.md.template +42 -0
- package/dist/templates/seed/config/SYSTEM.md +52 -0
- package/dist/templates/seed/config/provider.yaml +4 -0
- package/dist/templates/seed/hooks/settings.json.template +31 -0
- package/dist/templates/seed/memory/company/directives.md +37 -0
- package/dist/templates/seed/memory/company/manager/state.md +16 -0
- package/dist/templates/seed/memory/engineering/issue-solver/state.md +12 -0
- package/dist/templates/seed/memory/intelligence/intel-lead/state.md +9 -0
- package/dist/templates/seed/memory/marketing/content-drafter/state.md +12 -0
- package/dist/templates/seed/memory/operations/ops-lead/state.md +12 -0
- package/dist/templates/seed/memory/product/lead/state.md +14 -0
- package/dist/templates/seed/memory/research/lead/state.md +14 -0
- package/dist/templates/seed/skills/gh/SKILL.md +57 -0
- package/dist/templates/seed/skills/squads-cli/SKILL.md +84 -0
- package/dist/templates/seed/squads/company/SQUAD.md +51 -0
- package/dist/templates/seed/squads/company/company-critic.md +49 -0
- package/dist/templates/seed/squads/company/company-eval.md +49 -0
- package/dist/templates/seed/squads/company/event-dispatcher.md +43 -0
- package/dist/templates/seed/squads/company/goal-tracker.md +43 -0
- package/dist/templates/seed/squads/company/manager.md +54 -0
- package/dist/templates/seed/squads/engineering/SQUAD.md +48 -0
- package/dist/templates/seed/squads/engineering/code-reviewer.md +57 -0
- package/dist/templates/seed/squads/engineering/issue-solver.md +58 -0
- package/dist/templates/seed/squads/engineering/test-writer.md +50 -0
- package/dist/templates/seed/squads/intelligence/SQUAD.md +38 -0
- package/dist/templates/seed/squads/intelligence/intel-critic.md +36 -0
- package/dist/templates/seed/squads/intelligence/intel-eval.md +31 -0
- package/dist/templates/seed/squads/intelligence/intel-lead.md +71 -0
- package/dist/templates/seed/squads/marketing/SQUAD.md +47 -0
- package/dist/templates/seed/squads/marketing/content-drafter.md +71 -0
- package/dist/templates/seed/squads/marketing/growth-analyst.md +49 -0
- package/dist/templates/seed/squads/marketing/social-poster.md +44 -0
- package/dist/templates/seed/squads/operations/SQUAD.md +45 -0
- package/dist/templates/seed/squads/operations/finance-tracker.md +47 -0
- package/dist/templates/seed/squads/operations/goal-tracker.md +48 -0
- package/dist/templates/seed/squads/operations/ops-lead.md +58 -0
- package/dist/templates/seed/squads/product/SQUAD.md +41 -0
- package/dist/templates/seed/squads/product/lead.md +56 -0
- package/dist/templates/seed/squads/product/scanner.md +50 -0
- package/dist/templates/seed/squads/product/worker.md +55 -0
- package/dist/templates/seed/squads/research/SQUAD.md +38 -0
- package/dist/templates/seed/squads/research/analyst.md +50 -0
- package/dist/templates/seed/squads/research/lead.md +52 -0
- package/dist/templates/seed/squads/research/synthesizer.md +59 -0
- package/dist/templates/skills/squads-learn/SKILL.md +86 -0
- package/dist/templates/skills/squads-workflow/instruction.md +70 -0
- package/dist/terminal-FBQFQTKZ.js +55 -0
- package/dist/terminal-FBQFQTKZ.js.map +1 -0
- package/dist/update-D7CGIZ3M.js +18 -0
- package/dist/update-D7CGIZ3M.js.map +1 -0
- package/dist/update-STU276HR.js +83 -0
- package/dist/update-STU276HR.js.map +1 -0
- package/package.json +31 -13
- package/templates/core/AGENTS.md.template +51 -0
- package/templates/core/BUSINESS_BRIEF.md.template +29 -0
- package/templates/core/CLAUDE.md.template +48 -0
- package/templates/core/provider.yaml.template +5 -0
- package/templates/first-squad/SQUAD.md.template +23 -0
- package/templates/first-squad/lead.md.template +44 -0
- package/templates/memory/getting-started/state.md.template +19 -0
- package/templates/seed/BUSINESS_BRIEF.md.template +27 -0
- package/templates/seed/CLAUDE.md.template +119 -0
- package/templates/seed/README.md.template +42 -0
- package/templates/seed/config/SYSTEM.md +52 -0
- package/templates/seed/config/provider.yaml +4 -0
- package/templates/seed/hooks/settings.json.template +31 -0
- package/templates/seed/memory/company/directives.md +37 -0
- package/templates/seed/memory/company/manager/state.md +16 -0
- package/templates/seed/memory/engineering/issue-solver/state.md +12 -0
- package/templates/seed/memory/intelligence/intel-lead/state.md +9 -0
- package/templates/seed/memory/marketing/content-drafter/state.md +12 -0
- package/templates/seed/memory/operations/ops-lead/state.md +12 -0
- package/templates/seed/memory/product/lead/state.md +14 -0
- package/templates/seed/memory/research/lead/state.md +14 -0
- package/templates/seed/skills/gh/SKILL.md +57 -0
- package/templates/seed/skills/squads-cli/SKILL.md +84 -0
- package/templates/seed/squads/company/SQUAD.md +51 -0
- package/templates/seed/squads/company/company-critic.md +49 -0
- package/templates/seed/squads/company/company-eval.md +49 -0
- package/templates/seed/squads/company/event-dispatcher.md +43 -0
- package/templates/seed/squads/company/goal-tracker.md +43 -0
- package/templates/seed/squads/company/manager.md +54 -0
- package/templates/seed/squads/engineering/SQUAD.md +48 -0
- package/templates/seed/squads/engineering/code-reviewer.md +57 -0
- package/templates/seed/squads/engineering/issue-solver.md +58 -0
- package/templates/seed/squads/engineering/test-writer.md +50 -0
- package/templates/seed/squads/intelligence/SQUAD.md +38 -0
- package/templates/seed/squads/intelligence/intel-critic.md +36 -0
- package/templates/seed/squads/intelligence/intel-eval.md +31 -0
- package/templates/seed/squads/intelligence/intel-lead.md +71 -0
- package/templates/seed/squads/marketing/SQUAD.md +47 -0
- package/templates/seed/squads/marketing/content-drafter.md +71 -0
- package/templates/seed/squads/marketing/growth-analyst.md +49 -0
- package/templates/seed/squads/marketing/social-poster.md +44 -0
- package/templates/seed/squads/operations/SQUAD.md +45 -0
- package/templates/seed/squads/operations/finance-tracker.md +47 -0
- package/templates/seed/squads/operations/goal-tracker.md +48 -0
- package/templates/seed/squads/operations/ops-lead.md +58 -0
- package/templates/seed/squads/product/SQUAD.md +41 -0
- package/templates/seed/squads/product/lead.md +56 -0
- package/templates/seed/squads/product/scanner.md +50 -0
- package/templates/seed/squads/product/worker.md +55 -0
- package/templates/seed/squads/research/SQUAD.md +38 -0
- package/templates/seed/squads/research/analyst.md +50 -0
- package/templates/seed/squads/research/lead.md +52 -0
- package/templates/seed/squads/research/synthesizer.md +59 -0
- package/templates/skills/squads-learn/SKILL.md +86 -0
- package/templates/skills/squads-workflow/instruction.md +70 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
Events,
|
|
4
|
+
track
|
|
5
|
+
} from "./chunk-QJ7C7CMB.js";
|
|
6
|
+
import {
|
|
7
|
+
addGoalToSquad,
|
|
8
|
+
findSquadsDir,
|
|
9
|
+
listSquads,
|
|
10
|
+
loadSquad,
|
|
11
|
+
updateGoalInSquad
|
|
12
|
+
} from "./chunk-TYFTF53O.js";
|
|
13
|
+
import {
|
|
14
|
+
RESET,
|
|
15
|
+
bold,
|
|
16
|
+
colors,
|
|
17
|
+
gradient,
|
|
18
|
+
icons,
|
|
19
|
+
truncate,
|
|
20
|
+
writeLine
|
|
21
|
+
} from "./chunk-M5FXNY6Y.js";
|
|
22
|
+
import "./chunk-7OCVIDC7.js";
|
|
23
|
+
|
|
24
|
+
// src/commands/goal.ts
|
|
25
|
+
async function goalSetCommand(squadName, description, options) {
|
|
26
|
+
await track(Events.CLI_GOAL_SET, { squad: squadName });
|
|
27
|
+
const squad = loadSquad(squadName);
|
|
28
|
+
if (!squad) {
|
|
29
|
+
writeLine(` ${colors.red}Squad "${squadName}" not found${RESET}`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
let goalText = description;
|
|
33
|
+
if (options.metric && options.metric.length > 0) {
|
|
34
|
+
goalText += ` [metrics: ${options.metric.join(", ")}]`;
|
|
35
|
+
}
|
|
36
|
+
const success = addGoalToSquad(squadName, goalText);
|
|
37
|
+
writeLine();
|
|
38
|
+
if (success) {
|
|
39
|
+
writeLine(` ${icons.success} Goal added to ${colors.cyan}${squadName}${RESET}`);
|
|
40
|
+
writeLine(` ${bold}${description}${RESET}`);
|
|
41
|
+
if (options.metric && options.metric.length > 0) {
|
|
42
|
+
writeLine(` ${colors.dim}Metrics: ${options.metric.join(", ")}${RESET}`);
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
writeLine(` ${colors.red}Failed to add goal${RESET}`);
|
|
46
|
+
}
|
|
47
|
+
writeLine();
|
|
48
|
+
}
|
|
49
|
+
async function goalListCommand(squadName, options = {}) {
|
|
50
|
+
await track(Events.CLI_GOAL_LIST, { squad: squadName || "all" });
|
|
51
|
+
const squadsDir = findSquadsDir();
|
|
52
|
+
if (!squadsDir) {
|
|
53
|
+
writeLine(` ${colors.red}No .agents/squads directory found${RESET}`);
|
|
54
|
+
writeLine(` ${colors.dim}Run \`squads init\` to create one.${RESET}`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const squadsToCheck = squadName ? [squadName] : listSquads(squadsDir);
|
|
58
|
+
let totalActive = 0;
|
|
59
|
+
let totalCompleted = 0;
|
|
60
|
+
let hasGoals = false;
|
|
61
|
+
writeLine();
|
|
62
|
+
writeLine(` ${gradient("squads")} ${colors.dim}goal list${RESET}`);
|
|
63
|
+
writeLine();
|
|
64
|
+
for (const name of squadsToCheck) {
|
|
65
|
+
const squad = loadSquad(name);
|
|
66
|
+
if (!squad || squad.goals.length === 0) {
|
|
67
|
+
if (squadName) {
|
|
68
|
+
writeLine(` ${colors.yellow}No goals set for ${name}${RESET}`);
|
|
69
|
+
}
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
hasGoals = true;
|
|
73
|
+
const activeGoals = squad.goals.filter((g) => !g.completed);
|
|
74
|
+
const completedGoals = squad.goals.filter((g) => g.completed);
|
|
75
|
+
totalActive += activeGoals.length;
|
|
76
|
+
totalCompleted += completedGoals.length;
|
|
77
|
+
if (activeGoals.length === 0 && !options.all) continue;
|
|
78
|
+
writeLine(` ${colors.cyan}${name}${RESET}`);
|
|
79
|
+
if (squad.mission) {
|
|
80
|
+
writeLine(` ${colors.dim}${truncate(squad.mission, 60)}${RESET}`);
|
|
81
|
+
}
|
|
82
|
+
writeLine();
|
|
83
|
+
for (const goal of activeGoals) {
|
|
84
|
+
const globalIdx = squad.goals.indexOf(goal) + 1;
|
|
85
|
+
writeLine(` ${icons.active} ${colors.dim}[${globalIdx}]${RESET} ${goal.description}`);
|
|
86
|
+
if (goal.progress) {
|
|
87
|
+
writeLine(` ${colors.dim}\u2514 ${goal.progress}${RESET}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (options.all && completedGoals.length > 0) {
|
|
91
|
+
for (const goal of completedGoals) {
|
|
92
|
+
const globalIdx = squad.goals.indexOf(goal) + 1;
|
|
93
|
+
writeLine(` ${icons.success} ${colors.dim}[${globalIdx}] ${goal.description}${RESET}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
writeLine();
|
|
97
|
+
}
|
|
98
|
+
if (hasGoals) {
|
|
99
|
+
writeLine(` ${colors.green}${totalActive}${RESET} active ${colors.dim}\u2502${RESET} ${colors.dim}${totalCompleted} completed${RESET}`);
|
|
100
|
+
} else if (!squadName) {
|
|
101
|
+
writeLine(` ${colors.yellow}No goals defined yet${RESET}`);
|
|
102
|
+
writeLine();
|
|
103
|
+
writeLine(` ${colors.dim}$${RESET} squads goal set ${colors.cyan}<squad>${RESET} ${colors.cyan}"<goal>"${RESET}`);
|
|
104
|
+
}
|
|
105
|
+
writeLine();
|
|
106
|
+
}
|
|
107
|
+
async function goalCompleteCommand(squadName, goalIndex) {
|
|
108
|
+
await track(Events.CLI_GOAL_COMPLETE, { squad: squadName });
|
|
109
|
+
const squad = loadSquad(squadName);
|
|
110
|
+
if (!squad) {
|
|
111
|
+
writeLine(` ${colors.red}Squad "${squadName}" not found${RESET}`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const idx = parseInt(goalIndex) - 1;
|
|
115
|
+
if (isNaN(idx) || idx < 0 || idx >= squad.goals.length) {
|
|
116
|
+
writeLine(` ${colors.red}Invalid goal index: ${goalIndex}${RESET}`);
|
|
117
|
+
if (squad.goals.length === 0) {
|
|
118
|
+
writeLine(` ${colors.dim}Squad has no goals${RESET}`);
|
|
119
|
+
} else {
|
|
120
|
+
writeLine(` ${colors.dim}Valid indexes: 1-${squad.goals.length}${RESET}`);
|
|
121
|
+
writeLine(` ${colors.dim}Tip: Run 'squads goal list ${squadName}' to see goals with indexes${RESET}`);
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const success = updateGoalInSquad(squadName, idx, { completed: true });
|
|
126
|
+
writeLine();
|
|
127
|
+
if (success) {
|
|
128
|
+
writeLine(` ${icons.success} Goal completed: ${colors.cyan}${squad.goals[idx].description}${RESET}`);
|
|
129
|
+
} else {
|
|
130
|
+
writeLine(` ${colors.red}Failed to update goal${RESET}`);
|
|
131
|
+
}
|
|
132
|
+
writeLine();
|
|
133
|
+
}
|
|
134
|
+
async function goalProgressCommand(squadName, goalIndex, progress) {
|
|
135
|
+
await track(Events.CLI_GOAL_PROGRESS, { squad: squadName });
|
|
136
|
+
const squad = loadSquad(squadName);
|
|
137
|
+
if (!squad) {
|
|
138
|
+
writeLine(` ${colors.red}Squad "${squadName}" not found${RESET}`);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const idx = parseInt(goalIndex) - 1;
|
|
142
|
+
if (isNaN(idx) || idx < 0 || idx >= squad.goals.length) {
|
|
143
|
+
writeLine(` ${colors.red}Invalid goal index: ${goalIndex}${RESET}`);
|
|
144
|
+
if (squad.goals.length === 0) {
|
|
145
|
+
writeLine(` ${colors.dim}Squad has no goals${RESET}`);
|
|
146
|
+
} else {
|
|
147
|
+
writeLine(` ${colors.dim}Valid indexes: 1-${squad.goals.length}${RESET}`);
|
|
148
|
+
writeLine(` ${colors.dim}Tip: Run 'squads goal list ${squadName}' to see goals with indexes${RESET}`);
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const success = updateGoalInSquad(squadName, idx, { progress });
|
|
153
|
+
writeLine();
|
|
154
|
+
if (success) {
|
|
155
|
+
writeLine(` ${icons.success} Progress updated: ${colors.cyan}${squad.goals[idx].description}${RESET}`);
|
|
156
|
+
writeLine(` ${colors.dim}${progress}${RESET}`);
|
|
157
|
+
} else {
|
|
158
|
+
writeLine(` ${colors.red}Failed to update progress${RESET}`);
|
|
159
|
+
}
|
|
160
|
+
writeLine();
|
|
161
|
+
}
|
|
162
|
+
export {
|
|
163
|
+
goalCompleteCommand,
|
|
164
|
+
goalListCommand,
|
|
165
|
+
goalProgressCommand,
|
|
166
|
+
goalSetCommand
|
|
167
|
+
};
|
|
168
|
+
//# sourceMappingURL=goal-BVHV5573.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/goal.ts"],"sourcesContent":["import {\n loadSquad,\n findSquadsDir,\n listSquads,\n addGoalToSquad,\n updateGoalInSquad,\n} from '../lib/squad-parser.js';\nimport {\n colors,\n bold,\n RESET,\n gradient,\n truncate,\n icons,\n writeLine,\n} from '../lib/terminal.js';\nimport { track, Events } from '../lib/telemetry.js';\n\nexport async function goalSetCommand(\n squadName: string,\n description: string,\n options: { metric?: string[] }\n): Promise<void> {\n await track(Events.CLI_GOAL_SET, { squad: squadName });\n const squad = loadSquad(squadName);\n if (!squad) {\n writeLine(` ${colors.red}Squad \"${squadName}\" not found${RESET}`);\n return;\n }\n\n // Add metric annotations if provided\n let goalText = description;\n if (options.metric && options.metric.length > 0) {\n goalText += ` [metrics: ${options.metric.join(', ')}]`;\n }\n\n const success = addGoalToSquad(squadName, goalText);\n\n writeLine();\n if (success) {\n writeLine(` ${icons.success} Goal added to ${colors.cyan}${squadName}${RESET}`);\n writeLine(` ${bold}${description}${RESET}`);\n if (options.metric && options.metric.length > 0) {\n writeLine(` ${colors.dim}Metrics: ${options.metric.join(', ')}${RESET}`);\n }\n } else {\n writeLine(` ${colors.red}Failed to add goal${RESET}`);\n }\n writeLine();\n}\n\nexport async function goalListCommand(\n squadName?: string,\n options: { all?: boolean } = {}\n): Promise<void> {\n await track(Events.CLI_GOAL_LIST, { squad: squadName || 'all' });\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 squadsToCheck = squadName ? [squadName] : listSquads(squadsDir);\n\n let totalActive = 0;\n let totalCompleted = 0;\n let hasGoals = false;\n\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}goal list${RESET}`);\n writeLine();\n\n for (const name of squadsToCheck) {\n const squad = loadSquad(name);\n if (!squad || squad.goals.length === 0) {\n if (squadName) {\n writeLine(` ${colors.yellow}No goals set for ${name}${RESET}`);\n }\n continue;\n }\n\n hasGoals = true;\n const activeGoals = squad.goals.filter(g => !g.completed);\n const completedGoals = squad.goals.filter(g => g.completed);\n\n totalActive += activeGoals.length;\n totalCompleted += completedGoals.length;\n\n if (activeGoals.length === 0 && !options.all) continue;\n\n writeLine(` ${colors.cyan}${name}${RESET}`);\n if (squad.mission) {\n writeLine(` ${colors.dim}${truncate(squad.mission, 60)}${RESET}`);\n }\n writeLine();\n\n for (const goal of activeGoals) {\n const globalIdx = squad.goals.indexOf(goal) + 1;\n writeLine(` ${icons.active} ${colors.dim}[${globalIdx}]${RESET} ${goal.description}`);\n if (goal.progress) {\n writeLine(` ${colors.dim}└ ${goal.progress}${RESET}`);\n }\n }\n\n if (options.all && completedGoals.length > 0) {\n for (const goal of completedGoals) {\n const globalIdx = squad.goals.indexOf(goal) + 1;\n writeLine(` ${icons.success} ${colors.dim}[${globalIdx}] ${goal.description}${RESET}`);\n }\n }\n writeLine();\n }\n\n if (hasGoals) {\n writeLine(` ${colors.green}${totalActive}${RESET} active ${colors.dim}│${RESET} ${colors.dim}${totalCompleted} completed${RESET}`);\n } else if (!squadName) {\n writeLine(` ${colors.yellow}No goals defined yet${RESET}`);\n writeLine();\n writeLine(` ${colors.dim}$${RESET} squads goal set ${colors.cyan}<squad>${RESET} ${colors.cyan}\"<goal>\"${RESET}`);\n }\n writeLine();\n}\n\nexport async function goalCompleteCommand(\n squadName: string,\n goalIndex: string\n): Promise<void> {\n await track(Events.CLI_GOAL_COMPLETE, { squad: squadName });\n const squad = loadSquad(squadName);\n if (!squad) {\n writeLine(` ${colors.red}Squad \"${squadName}\" not found${RESET}`);\n return;\n }\n\n const idx = parseInt(goalIndex) - 1;\n if (isNaN(idx) || idx < 0 || idx >= squad.goals.length) {\n writeLine(` ${colors.red}Invalid goal index: ${goalIndex}${RESET}`);\n if (squad.goals.length === 0) {\n writeLine(` ${colors.dim}Squad has no goals${RESET}`);\n } else {\n writeLine(` ${colors.dim}Valid indexes: 1-${squad.goals.length}${RESET}`);\n writeLine(` ${colors.dim}Tip: Run 'squads goal list ${squadName}' to see goals with indexes${RESET}`);\n }\n return;\n }\n\n const success = updateGoalInSquad(squadName, idx, { completed: true });\n\n writeLine();\n if (success) {\n writeLine(` ${icons.success} Goal completed: ${colors.cyan}${squad.goals[idx].description}${RESET}`);\n } else {\n writeLine(` ${colors.red}Failed to update goal${RESET}`);\n }\n writeLine();\n}\n\nexport async function goalProgressCommand(\n squadName: string,\n goalIndex: string,\n progress: string\n): Promise<void> {\n await track(Events.CLI_GOAL_PROGRESS, { squad: squadName });\n const squad = loadSquad(squadName);\n if (!squad) {\n writeLine(` ${colors.red}Squad \"${squadName}\" not found${RESET}`);\n return;\n }\n\n const idx = parseInt(goalIndex) - 1;\n if (isNaN(idx) || idx < 0 || idx >= squad.goals.length) {\n writeLine(` ${colors.red}Invalid goal index: ${goalIndex}${RESET}`);\n if (squad.goals.length === 0) {\n writeLine(` ${colors.dim}Squad has no goals${RESET}`);\n } else {\n writeLine(` ${colors.dim}Valid indexes: 1-${squad.goals.length}${RESET}`);\n writeLine(` ${colors.dim}Tip: Run 'squads goal list ${squadName}' to see goals with indexes${RESET}`);\n }\n return;\n }\n\n const success = updateGoalInSquad(squadName, idx, { progress });\n\n writeLine();\n if (success) {\n writeLine(` ${icons.success} Progress updated: ${colors.cyan}${squad.goals[idx].description}${RESET}`);\n writeLine(` ${colors.dim}${progress}${RESET}`);\n } else {\n writeLine(` ${colors.red}Failed to update progress${RESET}`);\n }\n writeLine();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAkBA,eAAsB,eACpB,WACA,aACA,SACe;AACf,QAAM,MAAM,OAAO,cAAc,EAAE,OAAO,UAAU,CAAC;AACrD,QAAM,QAAQ,UAAU,SAAS;AACjC,MAAI,CAAC,OAAO;AACV,cAAU,KAAK,OAAO,GAAG,UAAU,SAAS,cAAc,KAAK,EAAE;AACjE;AAAA,EACF;AAGA,MAAI,WAAW;AACf,MAAI,QAAQ,UAAU,QAAQ,OAAO,SAAS,GAAG;AAC/C,gBAAY,cAAc,QAAQ,OAAO,KAAK,IAAI,CAAC;AAAA,EACrD;AAEA,QAAM,UAAU,eAAe,WAAW,QAAQ;AAElD,YAAU;AACV,MAAI,SAAS;AACX,cAAU,KAAK,MAAM,OAAO,kBAAkB,OAAO,IAAI,GAAG,SAAS,GAAG,KAAK,EAAE;AAC/E,cAAU,KAAK,IAAI,GAAG,WAAW,GAAG,KAAK,EAAE;AAC3C,QAAI,QAAQ,UAAU,QAAQ,OAAO,SAAS,GAAG;AAC/C,gBAAU,KAAK,OAAO,GAAG,YAAY,QAAQ,OAAO,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE;AAAA,IAC1E;AAAA,EACF,OAAO;AACL,cAAU,KAAK,OAAO,GAAG,qBAAqB,KAAK,EAAE;AAAA,EACvD;AACA,YAAU;AACZ;AAEA,eAAsB,gBACpB,WACA,UAA6B,CAAC,GACf;AACf,QAAM,MAAM,OAAO,eAAe,EAAE,OAAO,aAAa,MAAM,CAAC;AAC/D,QAAM,YAAY,cAAc;AAChC,MAAI,CAAC,WAAW;AACd,cAAU,KAAK,OAAO,GAAG,oCAAoC,KAAK,EAAE;AACpE,cAAU,KAAK,OAAO,GAAG,qCAAqC,KAAK,EAAE;AACrE;AAAA,EACF;AAEA,QAAM,gBAAgB,YAAY,CAAC,SAAS,IAAI,WAAW,SAAS;AAEpE,MAAI,cAAc;AAClB,MAAI,iBAAiB;AACrB,MAAI,WAAW;AAEf,YAAU;AACV,YAAU,KAAK,SAAS,QAAQ,CAAC,IAAI,OAAO,GAAG,YAAY,KAAK,EAAE;AAClE,YAAU;AAEV,aAAW,QAAQ,eAAe;AAChC,UAAM,QAAQ,UAAU,IAAI;AAC5B,QAAI,CAAC,SAAS,MAAM,MAAM,WAAW,GAAG;AACtC,UAAI,WAAW;AACb,kBAAU,KAAK,OAAO,MAAM,oBAAoB,IAAI,GAAG,KAAK,EAAE;AAAA,MAChE;AACA;AAAA,IACF;AAEA,eAAW;AACX,UAAM,cAAc,MAAM,MAAM,OAAO,OAAK,CAAC,EAAE,SAAS;AACxD,UAAM,iBAAiB,MAAM,MAAM,OAAO,OAAK,EAAE,SAAS;AAE1D,mBAAe,YAAY;AAC3B,sBAAkB,eAAe;AAEjC,QAAI,YAAY,WAAW,KAAK,CAAC,QAAQ,IAAK;AAE9C,cAAU,KAAK,OAAO,IAAI,GAAG,IAAI,GAAG,KAAK,EAAE;AAC3C,QAAI,MAAM,SAAS;AACjB,gBAAU,KAAK,OAAO,GAAG,GAAG,SAAS,MAAM,SAAS,EAAE,CAAC,GAAG,KAAK,EAAE;AAAA,IACnE;AACA,cAAU;AAEV,eAAW,QAAQ,aAAa;AAC9B,YAAM,YAAY,MAAM,MAAM,QAAQ,IAAI,IAAI;AAC9C,gBAAU,KAAK,MAAM,MAAM,IAAI,OAAO,GAAG,IAAI,SAAS,IAAI,KAAK,IAAI,KAAK,WAAW,EAAE;AACrF,UAAI,KAAK,UAAU;AACjB,kBAAU,OAAO,OAAO,GAAG,UAAK,KAAK,QAAQ,GAAG,KAAK,EAAE;AAAA,MACzD;AAAA,IACF;AAEA,QAAI,QAAQ,OAAO,eAAe,SAAS,GAAG;AAC5C,iBAAW,QAAQ,gBAAgB;AACjC,cAAM,YAAY,MAAM,MAAM,QAAQ,IAAI,IAAI;AAC9C,kBAAU,KAAK,MAAM,OAAO,IAAI,OAAO,GAAG,IAAI,SAAS,KAAK,KAAK,WAAW,GAAG,KAAK,EAAE;AAAA,MACxF;AAAA,IACF;AACA,cAAU;AAAA,EACZ;AAEA,MAAI,UAAU;AACZ,cAAU,KAAK,OAAO,KAAK,GAAG,WAAW,GAAG,KAAK,YAAY,OAAO,GAAG,SAAI,KAAK,KAAK,OAAO,GAAG,GAAG,cAAc,aAAa,KAAK,EAAE;AAAA,EACtI,WAAW,CAAC,WAAW;AACrB,cAAU,KAAK,OAAO,MAAM,uBAAuB,KAAK,EAAE;AAC1D,cAAU;AACV,cAAU,KAAK,OAAO,GAAG,IAAI,KAAK,oBAAoB,OAAO,IAAI,UAAU,KAAK,IAAI,OAAO,IAAI,WAAW,KAAK,EAAE;AAAA,EACnH;AACA,YAAU;AACZ;AAEA,eAAsB,oBACpB,WACA,WACe;AACf,QAAM,MAAM,OAAO,mBAAmB,EAAE,OAAO,UAAU,CAAC;AAC1D,QAAM,QAAQ,UAAU,SAAS;AACjC,MAAI,CAAC,OAAO;AACV,cAAU,KAAK,OAAO,GAAG,UAAU,SAAS,cAAc,KAAK,EAAE;AACjE;AAAA,EACF;AAEA,QAAM,MAAM,SAAS,SAAS,IAAI;AAClC,MAAI,MAAM,GAAG,KAAK,MAAM,KAAK,OAAO,MAAM,MAAM,QAAQ;AACtD,cAAU,KAAK,OAAO,GAAG,uBAAuB,SAAS,GAAG,KAAK,EAAE;AACnE,QAAI,MAAM,MAAM,WAAW,GAAG;AAC5B,gBAAU,KAAK,OAAO,GAAG,qBAAqB,KAAK,EAAE;AAAA,IACvD,OAAO;AACL,gBAAU,KAAK,OAAO,GAAG,oBAAoB,MAAM,MAAM,MAAM,GAAG,KAAK,EAAE;AACzE,gBAAU,KAAK,OAAO,GAAG,8BAA8B,SAAS,8BAA8B,KAAK,EAAE;AAAA,IACvG;AACA;AAAA,EACF;AAEA,QAAM,UAAU,kBAAkB,WAAW,KAAK,EAAE,WAAW,KAAK,CAAC;AAErE,YAAU;AACV,MAAI,SAAS;AACX,cAAU,KAAK,MAAM,OAAO,oBAAoB,OAAO,IAAI,GAAG,MAAM,MAAM,GAAG,EAAE,WAAW,GAAG,KAAK,EAAE;AAAA,EACtG,OAAO;AACL,cAAU,KAAK,OAAO,GAAG,wBAAwB,KAAK,EAAE;AAAA,EAC1D;AACA,YAAU;AACZ;AAEA,eAAsB,oBACpB,WACA,WACA,UACe;AACf,QAAM,MAAM,OAAO,mBAAmB,EAAE,OAAO,UAAU,CAAC;AAC1D,QAAM,QAAQ,UAAU,SAAS;AACjC,MAAI,CAAC,OAAO;AACV,cAAU,KAAK,OAAO,GAAG,UAAU,SAAS,cAAc,KAAK,EAAE;AACjE;AAAA,EACF;AAEA,QAAM,MAAM,SAAS,SAAS,IAAI;AAClC,MAAI,MAAM,GAAG,KAAK,MAAM,KAAK,OAAO,MAAM,MAAM,QAAQ;AACtD,cAAU,KAAK,OAAO,GAAG,uBAAuB,SAAS,GAAG,KAAK,EAAE;AACnE,QAAI,MAAM,MAAM,WAAW,GAAG;AAC5B,gBAAU,KAAK,OAAO,GAAG,qBAAqB,KAAK,EAAE;AAAA,IACvD,OAAO;AACL,gBAAU,KAAK,OAAO,GAAG,oBAAoB,MAAM,MAAM,MAAM,GAAG,KAAK,EAAE;AACzE,gBAAU,KAAK,OAAO,GAAG,8BAA8B,SAAS,8BAA8B,KAAK,EAAE;AAAA,IACvG;AACA;AAAA,EACF;AAEA,QAAM,UAAU,kBAAkB,WAAW,KAAK,EAAE,SAAS,CAAC;AAE9D,YAAU;AACV,MAAI,SAAS;AACX,cAAU,KAAK,MAAM,OAAO,sBAAsB,OAAO,IAAI,GAAG,MAAM,MAAM,GAAG,EAAE,WAAW,GAAG,KAAK,EAAE;AACtG,cAAU,KAAK,OAAO,GAAG,GAAG,QAAQ,GAAG,KAAK,EAAE;AAAA,EAChD,OAAO;AACL,cAAU,KAAK,OAAO,GAAG,4BAA4B,KAAK,EAAE;AAAA,EAC9D;AACA,YAAU;AACZ;","names":[]}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getEnv
|
|
4
|
+
} from "./chunk-EHQJHRIW.js";
|
|
5
|
+
import {
|
|
6
|
+
RESET,
|
|
7
|
+
colors,
|
|
8
|
+
gradient,
|
|
9
|
+
icons,
|
|
10
|
+
padEnd,
|
|
11
|
+
writeLine
|
|
12
|
+
} from "./chunk-M5FXNY6Y.js";
|
|
13
|
+
import "./chunk-7OCVIDC7.js";
|
|
14
|
+
|
|
15
|
+
// src/commands/health.ts
|
|
16
|
+
var FETCH_TIMEOUT_MS = 2e3;
|
|
17
|
+
function getServiceChecks() {
|
|
18
|
+
const env = getEnv();
|
|
19
|
+
const checks = [];
|
|
20
|
+
if (env.api_url) {
|
|
21
|
+
checks.push({
|
|
22
|
+
name: "API",
|
|
23
|
+
url: `${env.api_url}/health`,
|
|
24
|
+
optional: true,
|
|
25
|
+
fix: "squads login"
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
if (env.bridge_url) {
|
|
29
|
+
checks.push({
|
|
30
|
+
name: "Bridge",
|
|
31
|
+
url: `${env.bridge_url}/health`,
|
|
32
|
+
optional: true,
|
|
33
|
+
fix: "squads login"
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (process.env.LANGFUSE_HOST) {
|
|
37
|
+
checks.push({
|
|
38
|
+
name: "Traces",
|
|
39
|
+
url: `${process.env.LANGFUSE_HOST}/api/public/health`,
|
|
40
|
+
optional: true,
|
|
41
|
+
fix: "squads login"
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return checks;
|
|
45
|
+
}
|
|
46
|
+
async function fetchWithTimeout(url, timeoutMs = FETCH_TIMEOUT_MS) {
|
|
47
|
+
const controller = new AbortController();
|
|
48
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
49
|
+
try {
|
|
50
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
51
|
+
clearTimeout(timeoutId);
|
|
52
|
+
return response;
|
|
53
|
+
} catch {
|
|
54
|
+
clearTimeout(timeoutId);
|
|
55
|
+
throw new Error("timeout");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function checkService(service) {
|
|
59
|
+
const start = Date.now();
|
|
60
|
+
try {
|
|
61
|
+
const response = await fetchWithTimeout(service.url);
|
|
62
|
+
const latencyMs = Date.now() - start;
|
|
63
|
+
if (response.ok) {
|
|
64
|
+
return {
|
|
65
|
+
name: service.name,
|
|
66
|
+
status: "healthy",
|
|
67
|
+
latencyMs,
|
|
68
|
+
optional: service.optional
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
name: service.name,
|
|
73
|
+
status: "degraded",
|
|
74
|
+
latencyMs,
|
|
75
|
+
error: `HTTP ${response.status}`,
|
|
76
|
+
optional: service.optional,
|
|
77
|
+
fix: service.fix
|
|
78
|
+
};
|
|
79
|
+
} catch (error) {
|
|
80
|
+
return {
|
|
81
|
+
name: service.name,
|
|
82
|
+
status: "down",
|
|
83
|
+
error: error instanceof Error ? error.message : "unknown",
|
|
84
|
+
optional: service.optional,
|
|
85
|
+
fix: service.fix
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function getTriggerStats() {
|
|
90
|
+
try {
|
|
91
|
+
const env = getEnv();
|
|
92
|
+
const apiUrl = env.api_url;
|
|
93
|
+
if (!apiUrl) return null;
|
|
94
|
+
const response = await fetchWithTimeout(`${apiUrl}/api/triggers/stats`);
|
|
95
|
+
if (!response.ok) return null;
|
|
96
|
+
const data = await response.json();
|
|
97
|
+
return {
|
|
98
|
+
active: data.active || 0,
|
|
99
|
+
disabled: data.disabled || 0,
|
|
100
|
+
lastFire: data.last_fire ? {
|
|
101
|
+
name: data.last_fire.name || "unknown",
|
|
102
|
+
ago: formatTimeAgo(new Date(data.last_fire.fired_at || Date.now()))
|
|
103
|
+
} : void 0
|
|
104
|
+
};
|
|
105
|
+
} catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function formatTimeAgo(date) {
|
|
110
|
+
const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
|
|
111
|
+
if (seconds < 60) return `${seconds}s ago`;
|
|
112
|
+
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;
|
|
113
|
+
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;
|
|
114
|
+
return `${Math.floor(seconds / 86400)}d ago`;
|
|
115
|
+
}
|
|
116
|
+
function formatLatency(ms) {
|
|
117
|
+
if (!ms) return "\u2014";
|
|
118
|
+
return `${ms}ms`;
|
|
119
|
+
}
|
|
120
|
+
async function healthCommand(_options = {}) {
|
|
121
|
+
writeLine();
|
|
122
|
+
writeLine(` ${gradient("squads")} ${colors.dim}health${RESET}`);
|
|
123
|
+
writeLine();
|
|
124
|
+
const SERVICES = getServiceChecks();
|
|
125
|
+
if (SERVICES.length === 0) {
|
|
126
|
+
writeLine(` ${colors.yellow}${icons.warning} No services configured${RESET}`);
|
|
127
|
+
writeLine(` ${colors.dim}Run ${RESET}${colors.cyan}squads login${RESET}${colors.dim} to connect to cloud services${RESET}`);
|
|
128
|
+
writeLine();
|
|
129
|
+
writeLine(` ${colors.cyan}${icons.progress}${RESET} Running in local mode ${colors.dim}(no cloud services required)${RESET}`);
|
|
130
|
+
writeLine(` Core commands work without cloud services: ${colors.cyan}init${RESET}, ${colors.cyan}run${RESET}, ${colors.cyan}status${RESET}, ${colors.cyan}eval${RESET}`);
|
|
131
|
+
writeLine(` Memory uses local ${colors.dim}.agents/memory/${RESET} files.`);
|
|
132
|
+
writeLine();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const results = await Promise.all(SERVICES.map(checkService));
|
|
136
|
+
writeLine(` ${colors.purple}\u250C${"\u2500".repeat(48)}\u2510${RESET}`);
|
|
137
|
+
writeLine(` ${colors.purple}\u2502${RESET} ${padEnd("SERVICE", 18)}${padEnd("STATUS", 14)}${padEnd("LATENCY", 12)}${colors.purple}\u2502${RESET}`);
|
|
138
|
+
writeLine(` ${colors.purple}\u251C${"\u2500".repeat(48)}\u2524${RESET}`);
|
|
139
|
+
const issues = [];
|
|
140
|
+
const optionalDown = [];
|
|
141
|
+
for (const result of results) {
|
|
142
|
+
let statusIcon;
|
|
143
|
+
let statusColor;
|
|
144
|
+
let statusText;
|
|
145
|
+
switch (result.status) {
|
|
146
|
+
case "healthy":
|
|
147
|
+
statusIcon = icons.success;
|
|
148
|
+
statusColor = colors.green;
|
|
149
|
+
statusText = "healthy";
|
|
150
|
+
break;
|
|
151
|
+
case "degraded":
|
|
152
|
+
statusIcon = icons.warning;
|
|
153
|
+
statusColor = colors.yellow;
|
|
154
|
+
statusText = "degraded";
|
|
155
|
+
issues.push(result);
|
|
156
|
+
break;
|
|
157
|
+
case "down":
|
|
158
|
+
statusIcon = icons.error;
|
|
159
|
+
statusColor = colors.red;
|
|
160
|
+
statusText = "down";
|
|
161
|
+
if (!result.optional) {
|
|
162
|
+
issues.push(result);
|
|
163
|
+
} else {
|
|
164
|
+
optionalDown.push(result);
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
const nameDisplay = result.optional ? `${result.name} ${colors.dim}(opt)${RESET}` : result.name;
|
|
169
|
+
const latency = formatLatency(result.latencyMs);
|
|
170
|
+
writeLine(` ${colors.purple}\u2502${RESET} ${padEnd(nameDisplay, 18)}${statusColor}${statusIcon} ${padEnd(statusText, 11)}${RESET}${padEnd(latency, 12)}${colors.purple}\u2502${RESET}`);
|
|
171
|
+
}
|
|
172
|
+
writeLine(` ${colors.purple}\u2514${"\u2500".repeat(48)}\u2518${RESET}`);
|
|
173
|
+
writeLine();
|
|
174
|
+
const apiUp = results.find((r) => r.name === "API")?.status === "healthy";
|
|
175
|
+
if (apiUp) {
|
|
176
|
+
const stats = await getTriggerStats();
|
|
177
|
+
if (stats) {
|
|
178
|
+
const lastFireText = stats.lastFire ? `${colors.dim}Last fire:${RESET} ${stats.lastFire.ago} (${stats.lastFire.name})` : `${colors.dim}No recent fires${RESET}`;
|
|
179
|
+
writeLine(` ${colors.cyan}Triggers:${RESET} ${stats.active} active, ${stats.disabled} disabled`);
|
|
180
|
+
writeLine(` ${lastFireText}`);
|
|
181
|
+
writeLine();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (issues.length > 0) {
|
|
185
|
+
writeLine(` ${colors.red}${icons.warning} ${issues.length} service(s) need attention${RESET}`);
|
|
186
|
+
for (const issue of issues) {
|
|
187
|
+
writeLine(` ${colors.dim}\u2022${RESET} ${issue.name}: ${issue.error || "not responding"}`);
|
|
188
|
+
if (issue.fix) {
|
|
189
|
+
writeLine(` ${colors.cyan}Fix:${RESET} ${issue.fix}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
writeLine();
|
|
193
|
+
} else if (optionalDown.length > 0) {
|
|
194
|
+
writeLine(` ${colors.green}${icons.success} Core ready${RESET} ${colors.dim}(no required services are down)${RESET}`);
|
|
195
|
+
writeLine(` ${colors.dim}\u25CB ${optionalDown.length} optional service(s) offline \u2014 run ${RESET}${colors.cyan}squads login${RESET}${colors.dim} to connect${RESET}`);
|
|
196
|
+
writeLine();
|
|
197
|
+
} else {
|
|
198
|
+
writeLine(` ${colors.green}${icons.success} All services healthy${RESET}`);
|
|
199
|
+
writeLine();
|
|
200
|
+
}
|
|
201
|
+
const allDown = results.every((r) => r.status === "down");
|
|
202
|
+
if (allDown) {
|
|
203
|
+
writeLine(` ${colors.cyan}${icons.progress}${RESET} Running in local mode ${colors.dim}(no cloud services required)${RESET}`);
|
|
204
|
+
writeLine(` Core commands work without cloud services: ${colors.cyan}init${RESET}, ${colors.cyan}run${RESET}, ${colors.cyan}status${RESET}, ${colors.cyan}eval${RESET}`);
|
|
205
|
+
writeLine(` Memory uses local ${colors.dim}.agents/memory/${RESET} files.`);
|
|
206
|
+
writeLine();
|
|
207
|
+
writeLine(` ${colors.dim}To enable scheduling and telemetry:${RESET} squads login`);
|
|
208
|
+
writeLine();
|
|
209
|
+
} else if (!apiUp) {
|
|
210
|
+
writeLine(` ${colors.yellow}${icons.warning} API not reachable - triggers won't auto-fire${RESET}`);
|
|
211
|
+
writeLine(` ${colors.dim}Check connection:${RESET} squads login`);
|
|
212
|
+
writeLine();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
export {
|
|
216
|
+
healthCommand
|
|
217
|
+
};
|
|
218
|
+
//# sourceMappingURL=health-4UXN44PF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/health.ts"],"sourcesContent":["/**\n * squads health - Quick infrastructure health check\n *\n * Lightweight check that pings configured service endpoints\n */\n\nimport {\n colors,\n RESET,\n gradient,\n icons,\n writeLine,\n padEnd,\n} from '../lib/terminal.js';\nimport { getEnv } from '../lib/env-config.js';\n\nconst FETCH_TIMEOUT_MS = 2000;\n\ninterface ServiceCheck {\n name: string;\n url: string;\n optional?: boolean;\n fix?: string;\n}\n\ninterface ServiceResult {\n name: string;\n status: 'healthy' | 'down' | 'degraded';\n latencyMs?: number;\n error?: string;\n optional?: boolean;\n fix?: string;\n}\n\ninterface TriggerStats {\n active: number;\n disabled: number;\n lastFire?: {\n name: string;\n ago: string;\n };\n}\n\nfunction getServiceChecks(): ServiceCheck[] {\n const env = getEnv();\n\n const checks: ServiceCheck[] = [];\n\n if (env.api_url) {\n checks.push({\n name: 'API',\n url: `${env.api_url}/health`,\n optional: true,\n fix: 'squads login',\n });\n }\n\n if (env.bridge_url) {\n checks.push({\n name: 'Bridge',\n url: `${env.bridge_url}/health`,\n optional: true,\n fix: 'squads login',\n });\n }\n\n if (process.env.LANGFUSE_HOST) {\n checks.push({\n name: 'Traces',\n url: `${process.env.LANGFUSE_HOST}/api/public/health`,\n optional: true,\n fix: 'squads login',\n });\n }\n\n return checks;\n}\n\n/**\n * Fetch with timeout\n */\nasync function fetchWithTimeout(url: string, timeoutMs = FETCH_TIMEOUT_MS): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await fetch(url, { signal: controller.signal });\n clearTimeout(timeoutId);\n return response;\n } catch {\n clearTimeout(timeoutId);\n throw new Error('timeout');\n }\n}\n\n/**\n * Check a single service\n */\nasync function checkService(service: ServiceCheck): Promise<ServiceResult> {\n const start = Date.now();\n\n try {\n const response = await fetchWithTimeout(service.url);\n const latencyMs = Date.now() - start;\n\n if (response.ok) {\n return {\n name: service.name,\n status: 'healthy',\n latencyMs,\n optional: service.optional,\n };\n }\n\n return {\n name: service.name,\n status: 'degraded',\n latencyMs,\n error: `HTTP ${response.status}`,\n optional: service.optional,\n fix: service.fix,\n };\n } catch (error) {\n return {\n name: service.name,\n status: 'down',\n error: error instanceof Error ? error.message : 'unknown',\n optional: service.optional,\n fix: service.fix,\n };\n }\n}\n\n/**\n * Get trigger stats from API\n */\nasync function getTriggerStats(): Promise<TriggerStats | null> {\n try {\n const env = getEnv();\n const apiUrl = env.api_url;\n if (!apiUrl) return null;\n\n const response = await fetchWithTimeout(`${apiUrl}/api/triggers/stats`);\n\n if (!response.ok) return null;\n\n interface StatsResponse {\n active?: number;\n disabled?: number;\n last_fire?: {\n name?: string;\n fired_at?: string;\n };\n }\n\n const data = await response.json() as StatsResponse;\n return {\n active: data.active || 0,\n disabled: data.disabled || 0,\n lastFire: data.last_fire ? {\n name: data.last_fire.name || 'unknown',\n ago: formatTimeAgo(new Date(data.last_fire.fired_at || Date.now())),\n } : undefined,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Format time ago\n */\nfunction formatTimeAgo(date: Date): string {\n const seconds = Math.floor((Date.now() - date.getTime()) / 1000);\n\n if (seconds < 60) return `${seconds}s ago`;\n if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;\n if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;\n return `${Math.floor(seconds / 86400)}d ago`;\n}\n\n/**\n * Format latency\n */\nfunction formatLatency(ms?: number): string {\n if (!ms) return '—';\n return `${ms}ms`;\n}\n\nexport interface HealthOptions {\n verbose?: boolean;\n}\n\nexport async function healthCommand(_options: HealthOptions = {}): Promise<void> {\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}health${RESET}`);\n writeLine();\n\n const SERVICES = getServiceChecks();\n\n if (SERVICES.length === 0) {\n writeLine(` ${colors.yellow}${icons.warning} No services configured${RESET}`);\n writeLine(` ${colors.dim}Run ${RESET}${colors.cyan}squads login${RESET}${colors.dim} to connect to cloud services${RESET}`);\n writeLine();\n writeLine(` ${colors.cyan}${icons.progress}${RESET} Running in local mode ${colors.dim}(no cloud services required)${RESET}`);\n writeLine(` Core commands work without cloud services: ${colors.cyan}init${RESET}, ${colors.cyan}run${RESET}, ${colors.cyan}status${RESET}, ${colors.cyan}eval${RESET}`);\n writeLine(` Memory uses local ${colors.dim}.agents/memory/${RESET} files.`);\n writeLine();\n return;\n }\n\n // Check all services in parallel\n const results = await Promise.all(SERVICES.map(checkService));\n\n // Display table\n writeLine(` ${colors.purple}┌${'─'.repeat(48)}┐${RESET}`);\n writeLine(` ${colors.purple}│${RESET} ${padEnd('SERVICE', 18)}${padEnd('STATUS', 14)}${padEnd('LATENCY', 12)}${colors.purple}│${RESET}`);\n writeLine(` ${colors.purple}├${'─'.repeat(48)}┤${RESET}`);\n\n const issues: ServiceResult[] = [];\n const optionalDown: ServiceResult[] = [];\n\n for (const result of results) {\n let statusIcon: string;\n let statusColor: string;\n let statusText: string;\n\n switch (result.status) {\n case 'healthy':\n statusIcon = icons.success;\n statusColor = colors.green;\n statusText = 'healthy';\n break;\n case 'degraded':\n statusIcon = icons.warning;\n statusColor = colors.yellow;\n statusText = 'degraded';\n issues.push(result);\n break;\n case 'down':\n statusIcon = icons.error;\n statusColor = colors.red;\n statusText = 'down';\n if (!result.optional) {\n issues.push(result);\n } else {\n optionalDown.push(result);\n }\n break;\n }\n\n const nameDisplay = result.optional ? `${result.name} ${colors.dim}(opt)${RESET}` : result.name;\n const latency = formatLatency(result.latencyMs);\n\n writeLine(` ${colors.purple}│${RESET} ${padEnd(nameDisplay, 18)}${statusColor}${statusIcon} ${padEnd(statusText, 11)}${RESET}${padEnd(latency, 12)}${colors.purple}│${RESET}`);\n }\n\n writeLine(` ${colors.purple}└${'─'.repeat(48)}┘${RESET}`);\n writeLine();\n\n // Get trigger stats if API is up\n const apiUp = results.find(r => r.name === 'API')?.status === 'healthy';\n if (apiUp) {\n const stats = await getTriggerStats();\n if (stats) {\n const lastFireText = stats.lastFire\n ? `${colors.dim}Last fire:${RESET} ${stats.lastFire.ago} (${stats.lastFire.name})`\n : `${colors.dim}No recent fires${RESET}`;\n\n writeLine(` ${colors.cyan}Triggers:${RESET} ${stats.active} active, ${stats.disabled} disabled`);\n writeLine(` ${lastFireText}`);\n writeLine();\n }\n }\n\n // Show issues and fixes\n if (issues.length > 0) {\n writeLine(` ${colors.red}${icons.warning} ${issues.length} service(s) need attention${RESET}`);\n for (const issue of issues) {\n writeLine(` ${colors.dim}•${RESET} ${issue.name}: ${issue.error || 'not responding'}`);\n if (issue.fix) {\n writeLine(` ${colors.cyan}Fix:${RESET} ${issue.fix}`);\n }\n }\n writeLine();\n } else if (optionalDown.length > 0) {\n writeLine(` ${colors.green}${icons.success} Core ready${RESET} ${colors.dim}(no required services are down)${RESET}`);\n writeLine(` ${colors.dim}○ ${optionalDown.length} optional service(s) offline — run ${RESET}${colors.cyan}squads login${RESET}${colors.dim} to connect${RESET}`);\n writeLine();\n } else {\n writeLine(` ${colors.green}${icons.success} All services healthy${RESET}`);\n writeLine();\n }\n\n // Show mode info\n const allDown = results.every(r => r.status === 'down');\n if (allDown) {\n writeLine(` ${colors.cyan}${icons.progress}${RESET} Running in local mode ${colors.dim}(no cloud services required)${RESET}`);\n writeLine(` Core commands work without cloud services: ${colors.cyan}init${RESET}, ${colors.cyan}run${RESET}, ${colors.cyan}status${RESET}, ${colors.cyan}eval${RESET}`);\n writeLine(` Memory uses local ${colors.dim}.agents/memory/${RESET} files.`);\n writeLine();\n writeLine(` ${colors.dim}To enable scheduling and telemetry:${RESET} squads login`);\n writeLine();\n } else if (!apiUp) {\n writeLine(` ${colors.yellow}${icons.warning} API not reachable - triggers won't auto-fire${RESET}`);\n writeLine(` ${colors.dim}Check connection:${RESET} squads login`);\n writeLine();\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getEnv
|
|
4
|
+
} from "./chunk-EHQJHRIW.js";
|
|
5
|
+
import {
|
|
6
|
+
RESET,
|
|
7
|
+
bold,
|
|
8
|
+
colors,
|
|
9
|
+
gradient,
|
|
10
|
+
icons,
|
|
11
|
+
padEnd,
|
|
12
|
+
truncate,
|
|
13
|
+
writeLine
|
|
14
|
+
} from "./chunk-M5FXNY6Y.js";
|
|
15
|
+
import "./chunk-7OCVIDC7.js";
|
|
16
|
+
|
|
17
|
+
// src/commands/history.ts
|
|
18
|
+
import { existsSync, readFileSync } from "fs";
|
|
19
|
+
import { join } from "path";
|
|
20
|
+
var BRIDGE_URL = getEnv().bridge_url;
|
|
21
|
+
var FETCH_TIMEOUT_MS = 3e3;
|
|
22
|
+
async function fetchWithTimeout(url, timeoutMs = FETCH_TIMEOUT_MS) {
|
|
23
|
+
const controller = new AbortController();
|
|
24
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
25
|
+
try {
|
|
26
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
27
|
+
clearTimeout(timeoutId);
|
|
28
|
+
return response;
|
|
29
|
+
} catch {
|
|
30
|
+
clearTimeout(timeoutId);
|
|
31
|
+
throw new Error("Request timed out");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function fetchFromBridge(days, squad) {
|
|
35
|
+
try {
|
|
36
|
+
const params = new URLSearchParams({
|
|
37
|
+
days: String(days),
|
|
38
|
+
...squad && { squad }
|
|
39
|
+
});
|
|
40
|
+
const response = await fetchWithTimeout(`${BRIDGE_URL}/api/executions?${params}`);
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const data = await response.json();
|
|
45
|
+
return (data.executions || []).map((e) => ({
|
|
46
|
+
id: e.id || "",
|
|
47
|
+
squad: e.squad || "unknown",
|
|
48
|
+
agent: e.agent || "unknown",
|
|
49
|
+
startedAt: new Date(e.started_at || Date.now()),
|
|
50
|
+
endedAt: e.ended_at ? new Date(e.ended_at) : void 0,
|
|
51
|
+
durationMs: e.duration_ms,
|
|
52
|
+
status: e.status || "success",
|
|
53
|
+
cost: e.cost_usd,
|
|
54
|
+
tokens: e.total_tokens,
|
|
55
|
+
error: e.error
|
|
56
|
+
}));
|
|
57
|
+
} catch {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function fetchFromLocal(days, squad) {
|
|
62
|
+
const executions = [];
|
|
63
|
+
const historyPaths = [
|
|
64
|
+
join(process.cwd(), ".agents/sessions/history.jsonl"),
|
|
65
|
+
join(process.env.HOME || "", "agents-squads/hq/.agents/sessions/history.jsonl")
|
|
66
|
+
];
|
|
67
|
+
let historyPath;
|
|
68
|
+
for (const path of historyPaths) {
|
|
69
|
+
if (existsSync(path)) {
|
|
70
|
+
historyPath = path;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (!historyPath) {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const content = readFileSync(historyPath, "utf-8");
|
|
79
|
+
const lines = content.trim().split("\n").filter(Boolean);
|
|
80
|
+
const cutoff = Date.now() - days * 24 * 60 * 60 * 1e3;
|
|
81
|
+
for (const line of lines) {
|
|
82
|
+
try {
|
|
83
|
+
const event = JSON.parse(line);
|
|
84
|
+
const timestamp = new Date(event.timestamp || 0);
|
|
85
|
+
if (timestamp.getTime() < cutoff) continue;
|
|
86
|
+
if (squad && event.squad !== squad) continue;
|
|
87
|
+
if (event.type === "session_end" || event.type === "agent_complete") {
|
|
88
|
+
executions.push({
|
|
89
|
+
id: event.sessionId || `local-${Date.now()}`,
|
|
90
|
+
squad: event.squad || "unknown",
|
|
91
|
+
agent: event.agent || "unknown",
|
|
92
|
+
startedAt: timestamp,
|
|
93
|
+
durationMs: event.duration,
|
|
94
|
+
status: event.status === "error" ? "error" : "success",
|
|
95
|
+
cost: event.cost,
|
|
96
|
+
tokens: event.tokens
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} catch {
|
|
103
|
+
}
|
|
104
|
+
return executions;
|
|
105
|
+
}
|
|
106
|
+
function formatDuration(ms) {
|
|
107
|
+
if (!ms) return "\u2014";
|
|
108
|
+
const seconds = Math.floor(ms / 1e3);
|
|
109
|
+
if (seconds < 60) return `${seconds}s`;
|
|
110
|
+
const minutes = Math.floor(seconds / 60);
|
|
111
|
+
const remainingSeconds = seconds % 60;
|
|
112
|
+
if (minutes < 60) return `${minutes}m ${remainingSeconds}s`;
|
|
113
|
+
const hours = Math.floor(minutes / 60);
|
|
114
|
+
const remainingMinutes = minutes % 60;
|
|
115
|
+
return `${hours}h ${remainingMinutes}m`;
|
|
116
|
+
}
|
|
117
|
+
function groupByDate(executions) {
|
|
118
|
+
const groups = /* @__PURE__ */ new Map();
|
|
119
|
+
for (const exec of executions) {
|
|
120
|
+
const dateKey = exec.startedAt.toISOString().split("T")[0];
|
|
121
|
+
if (!groups.has(dateKey)) {
|
|
122
|
+
groups.set(dateKey, []);
|
|
123
|
+
}
|
|
124
|
+
groups.get(dateKey).push(exec);
|
|
125
|
+
}
|
|
126
|
+
return groups;
|
|
127
|
+
}
|
|
128
|
+
function formatDateHeader(dateStr) {
|
|
129
|
+
const date = new Date(dateStr);
|
|
130
|
+
const today = /* @__PURE__ */ new Date();
|
|
131
|
+
const yesterday = new Date(today);
|
|
132
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
133
|
+
if (dateStr === today.toISOString().split("T")[0]) {
|
|
134
|
+
return `Today (${date.toLocaleDateString("en-US", { month: "short", day: "numeric" })})`;
|
|
135
|
+
}
|
|
136
|
+
if (dateStr === yesterday.toISOString().split("T")[0]) {
|
|
137
|
+
return `Yesterday (${date.toLocaleDateString("en-US", { month: "short", day: "numeric" })})`;
|
|
138
|
+
}
|
|
139
|
+
return date.toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric" });
|
|
140
|
+
}
|
|
141
|
+
async function historyCommand(options = {}) {
|
|
142
|
+
const days = options.days || 7;
|
|
143
|
+
const squad = options.squad;
|
|
144
|
+
const verbose = options.verbose || false;
|
|
145
|
+
const jsonOutput = options.json || false;
|
|
146
|
+
writeLine();
|
|
147
|
+
writeLine(` ${gradient("squads")} ${colors.dim}history${RESET}`);
|
|
148
|
+
writeLine();
|
|
149
|
+
const [bridgeExecs, localExecs] = await Promise.all([
|
|
150
|
+
fetchFromBridge(days, squad),
|
|
151
|
+
Promise.resolve(fetchFromLocal(days, squad))
|
|
152
|
+
]);
|
|
153
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
154
|
+
const allExecutions = [];
|
|
155
|
+
for (const exec of bridgeExecs) {
|
|
156
|
+
seenIds.add(exec.id);
|
|
157
|
+
allExecutions.push(exec);
|
|
158
|
+
}
|
|
159
|
+
for (const exec of localExecs) {
|
|
160
|
+
if (!seenIds.has(exec.id)) {
|
|
161
|
+
allExecutions.push(exec);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
allExecutions.sort((a, b) => b.startedAt.getTime() - a.startedAt.getTime());
|
|
165
|
+
if (jsonOutput) {
|
|
166
|
+
console.log(JSON.stringify(allExecutions, null, 2));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (allExecutions.length === 0) {
|
|
170
|
+
writeLine(` ${colors.dim}No executions found in the last ${days} day(s)${RESET}`);
|
|
171
|
+
writeLine();
|
|
172
|
+
writeLine(` ${colors.dim}Tip: Run agents with 'squads run <squad>' to see history${RESET}`);
|
|
173
|
+
writeLine();
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const grouped = groupByDate(allExecutions);
|
|
177
|
+
const source = bridgeExecs.length > 0 ? "postgres" : "local";
|
|
178
|
+
writeLine(` ${colors.dim}${allExecutions.length} executions (last ${days}d, source: ${source})${RESET}`);
|
|
179
|
+
writeLine();
|
|
180
|
+
for (const [dateStr, execs] of grouped) {
|
|
181
|
+
writeLine(` ${bold}${formatDateHeader(dateStr)}${RESET}`);
|
|
182
|
+
writeLine(` ${colors.purple}\u250C${"\u2500".repeat(60)}\u2510${RESET}`);
|
|
183
|
+
writeLine(` ${colors.purple}\u2502${RESET} ${padEnd("TIME", 7)}${padEnd("SQUAD", 13)}${padEnd("AGENT", 16)}${padEnd("DURATION", 10)}${padEnd("STATUS", 8)}${colors.purple}\u2502${RESET}`);
|
|
184
|
+
writeLine(` ${colors.purple}\u251C${"\u2500".repeat(60)}\u2524${RESET}`);
|
|
185
|
+
for (const exec of execs) {
|
|
186
|
+
const time = exec.startedAt.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false });
|
|
187
|
+
const squadName = truncate(exec.squad, 11);
|
|
188
|
+
const agentName = truncate(exec.agent, 14);
|
|
189
|
+
const duration = formatDuration(exec.durationMs);
|
|
190
|
+
let statusIcon;
|
|
191
|
+
let statusColor;
|
|
192
|
+
switch (exec.status) {
|
|
193
|
+
case "success":
|
|
194
|
+
statusIcon = icons.success;
|
|
195
|
+
statusColor = colors.green;
|
|
196
|
+
break;
|
|
197
|
+
case "error":
|
|
198
|
+
statusIcon = icons.error;
|
|
199
|
+
statusColor = colors.red;
|
|
200
|
+
break;
|
|
201
|
+
case "running":
|
|
202
|
+
statusIcon = icons.progress;
|
|
203
|
+
statusColor = colors.cyan;
|
|
204
|
+
break;
|
|
205
|
+
default:
|
|
206
|
+
statusIcon = icons.empty;
|
|
207
|
+
statusColor = colors.dim;
|
|
208
|
+
}
|
|
209
|
+
writeLine(` ${colors.purple}\u2502${RESET} ${colors.dim}${time}${RESET} ${colors.cyan}${padEnd(squadName, 12)}${RESET}${padEnd(agentName, 16)}${padEnd(duration, 10)}${statusColor}${statusIcon}${RESET} ${colors.purple}\u2502${RESET}`);
|
|
210
|
+
if (verbose && (exec.cost || exec.tokens)) {
|
|
211
|
+
const costStr = exec.cost ? `$${exec.cost.toFixed(2)}` : "";
|
|
212
|
+
const tokenStr = exec.tokens ? `${exec.tokens.toLocaleString()} tokens` : "";
|
|
213
|
+
const details = [costStr, tokenStr].filter(Boolean).join(" \u2502 ");
|
|
214
|
+
writeLine(` ${colors.purple}\u2502${RESET} ${colors.dim}\u2514 ${details}${RESET}${" ".repeat(Math.max(0, 45 - details.length))}${colors.purple}\u2502${RESET}`);
|
|
215
|
+
}
|
|
216
|
+
if (exec.error) {
|
|
217
|
+
writeLine(` ${colors.purple}\u2502${RESET} ${colors.red}\u2514 ${truncate(exec.error, 45)}${RESET}${" ".repeat(Math.max(0, 45 - exec.error.length))}${colors.purple}\u2502${RESET}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
writeLine(` ${colors.purple}\u2514${"\u2500".repeat(60)}\u2518${RESET}`);
|
|
221
|
+
writeLine();
|
|
222
|
+
}
|
|
223
|
+
const successCount = allExecutions.filter((e) => e.status === "success").length;
|
|
224
|
+
const errorCount = allExecutions.filter((e) => e.status === "error").length;
|
|
225
|
+
const totalCost = allExecutions.reduce((sum, e) => sum + (e.cost || 0), 0);
|
|
226
|
+
writeLine(` ${colors.dim}Summary:${RESET} ${colors.green}${successCount} success${RESET} ${errorCount > 0 ? `${colors.red}${errorCount} errors${RESET} ` : ""}${totalCost > 0 ? `${colors.cyan}$${totalCost.toFixed(2)} total${RESET}` : ""}`);
|
|
227
|
+
writeLine();
|
|
228
|
+
}
|
|
229
|
+
export {
|
|
230
|
+
historyCommand
|
|
231
|
+
};
|
|
232
|
+
//# sourceMappingURL=history-ILH3SWHB.js.map
|