squads-cli 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +196 -1152
- package/dist/auth-YW3UPFSB.js +23 -0
- package/dist/autonomy-BWTVDEAT.js +102 -0
- package/dist/autonomy-BWTVDEAT.js.map +1 -0
- package/dist/chunk-3KCWNZWW.js +401 -0
- package/dist/chunk-3KCWNZWW.js.map +1 -0
- package/dist/chunk-67RO2HKR.js +174 -0
- package/dist/chunk-67RO2HKR.js.map +1 -0
- package/dist/chunk-7JVD7RD4.js +275 -0
- package/dist/chunk-7JVD7RD4.js.map +1 -0
- package/dist/chunk-BODLDQY7.js +452 -0
- package/dist/chunk-BODLDQY7.js.map +1 -0
- package/dist/chunk-FFFCFZ6A.js +121 -0
- package/dist/chunk-FFFCFZ6A.js.map +1 -0
- package/dist/chunk-FIWT2NMM.js +165 -0
- package/dist/chunk-FIWT2NMM.js.map +1 -0
- package/dist/chunk-L6GQCHDF.js +222 -0
- package/dist/chunk-L6GQCHDF.js.map +1 -0
- package/dist/{chunk-O7UV3FWI.js → chunk-LDM62TIX.js} +2 -2
- package/dist/chunk-LDM62TIX.js.map +1 -0
- package/dist/chunk-LOA3KWYJ.js +294 -0
- package/dist/chunk-LOA3KWYJ.js.map +1 -0
- package/dist/chunk-NA45DFXY.js +616 -0
- package/dist/chunk-NA45DFXY.js.map +1 -0
- package/dist/{chunk-4CMAEQQY.js → chunk-NQN6JPI7.js} +4 -3
- package/dist/chunk-NQN6JPI7.js.map +1 -0
- package/dist/chunk-OQJHPULO.js +103 -0
- package/dist/chunk-OQJHPULO.js.map +1 -0
- package/dist/chunk-QHNUMM4V.js +87 -0
- package/dist/chunk-QHNUMM4V.js.map +1 -0
- package/dist/chunk-RM6BWILN.js +74 -0
- package/dist/chunk-RM6BWILN.js.map +1 -0
- package/dist/chunk-WBR5J7EX.js +90 -0
- package/dist/chunk-WBR5J7EX.js.map +1 -0
- package/dist/chunk-Z2UKDBNL.js +162 -0
- package/dist/chunk-Z2UKDBNL.js.map +1 -0
- package/dist/cli.js +2151 -12594
- package/dist/cli.js.map +1 -1
- package/dist/context-M2A2DOFV.js +291 -0
- package/dist/context-M2A2DOFV.js.map +1 -0
- package/dist/context-feed-JMNW4GAM.js +391 -0
- package/dist/context-feed-JMNW4GAM.js.map +1 -0
- package/dist/cost-N37I4UTA.js +274 -0
- package/dist/cost-N37I4UTA.js.map +1 -0
- package/dist/create-554W5HNU.js +286 -0
- package/dist/create-554W5HNU.js.map +1 -0
- package/dist/daemon-XWPQPPPN.js +546 -0
- package/dist/daemon-XWPQPPPN.js.map +1 -0
- package/dist/dashboard-L7YKVQEB.js +945 -0
- package/dist/dashboard-L7YKVQEB.js.map +1 -0
- package/dist/dashboard-MFNRLCEE.js +794 -0
- package/dist/dashboard-MFNRLCEE.js.map +1 -0
- package/dist/doctor-RG75M5RO.js +346 -0
- package/dist/doctor-RG75M5RO.js.map +1 -0
- package/dist/env-config-KCLDBKYX.js +21 -0
- package/dist/exec-JQKBF7BL.js +197 -0
- package/dist/exec-JQKBF7BL.js.map +1 -0
- package/dist/feedback-KA2UYBZG.js +229 -0
- package/dist/feedback-KA2UYBZG.js.map +1 -0
- package/dist/github-UQTM5KMS.js +23 -0
- package/dist/goal-EOPC5ZCD.js +168 -0
- package/dist/goal-EOPC5ZCD.js.map +1 -0
- package/dist/health-3FZDOSR5.js +209 -0
- package/dist/health-3FZDOSR5.js.map +1 -0
- package/dist/history-TFVXJEDH.js +229 -0
- package/dist/history-TFVXJEDH.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/init-UOWTNMIE.js +747 -0
- package/dist/init-UOWTNMIE.js.map +1 -0
- package/dist/kpi-2SQ2WCVT.js +413 -0
- package/dist/kpi-2SQ2WCVT.js.map +1 -0
- package/dist/learn-6ERTERAO.js +269 -0
- package/dist/learn-6ERTERAO.js.map +1 -0
- package/dist/list-KSOMUBMB.js +92 -0
- package/dist/list-KSOMUBMB.js.map +1 -0
- package/dist/login-ST6PAXYE.js +155 -0
- package/dist/login-ST6PAXYE.js.map +1 -0
- package/dist/memory-3CSNKXIL.js +562 -0
- package/dist/memory-3CSNKXIL.js.map +1 -0
- package/dist/progress-FKG4V2VH.js +202 -0
- package/dist/progress-FKG4V2VH.js.map +1 -0
- package/dist/providers-66PDCORB.js +65 -0
- package/dist/providers-66PDCORB.js.map +1 -0
- package/dist/results-2MJFLWEO.js +224 -0
- package/dist/results-2MJFLWEO.js.map +1 -0
- package/dist/run-72OQLH5A.js +2685 -0
- package/dist/run-72OQLH5A.js.map +1 -0
- package/dist/session-6H67XPAQ.js +64 -0
- package/dist/session-6H67XPAQ.js.map +1 -0
- package/dist/{chunk-NHGLXN2F.js → sessions-GVQIMN4W.js} +23 -459
- package/dist/sessions-GVQIMN4W.js.map +1 -0
- package/dist/{squad-parser-4BI3G4RS.js → squad-parser-CM3HOIWM.js} +2 -2
- package/dist/squad-parser-CM3HOIWM.js.map +1 -0
- package/dist/stats-ONZI557Q.js +335 -0
- package/dist/stats-ONZI557Q.js.map +1 -0
- package/dist/status-FYH42FTB.js +346 -0
- package/dist/status-FYH42FTB.js.map +1 -0
- package/dist/sync-HJZJNXHW.js +800 -0
- package/dist/sync-HJZJNXHW.js.map +1 -0
- package/dist/update-B4WMUOPO.js +83 -0
- package/dist/update-B4WMUOPO.js.map +1 -0
- package/dist/{update-ALJKFFM7.js → update-L7FGHN6W.js} +2 -2
- package/dist/update-L7FGHN6W.js.map +1 -0
- package/package.json +18 -10
- package/dist/chunk-4CMAEQQY.js.map +0 -1
- package/dist/chunk-NHGLXN2F.js.map +0 -1
- package/dist/chunk-O7UV3FWI.js.map +0 -1
- package/dist/sessions-6PB7ALCE.js +0 -16
- /package/dist/{sessions-6PB7ALCE.js.map → auth-YW3UPFSB.js.map} +0 -0
- /package/dist/{squad-parser-4BI3G4RS.js.map → env-config-KCLDBKYX.js.map} +0 -0
- /package/dist/{update-ALJKFFM7.js.map → github-UQTM5KMS.js.map} +0 -0
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
computeAllScorecards,
|
|
4
|
+
getOutcomeScoreModifier,
|
|
5
|
+
pollOutcomes,
|
|
6
|
+
recordArtifacts
|
|
7
|
+
} from "./chunk-7JVD7RD4.js";
|
|
8
|
+
import {
|
|
9
|
+
pushCognitionSignal
|
|
10
|
+
} from "./chunk-WBR5J7EX.js";
|
|
11
|
+
import {
|
|
12
|
+
getBotGhEnv
|
|
13
|
+
} from "./chunk-FIWT2NMM.js";
|
|
14
|
+
import "./chunk-Z2UKDBNL.js";
|
|
15
|
+
import "./chunk-OQJHPULO.js";
|
|
16
|
+
import {
|
|
17
|
+
findSquadsDir,
|
|
18
|
+
listSquads
|
|
19
|
+
} from "./chunk-LDM62TIX.js";
|
|
20
|
+
import {
|
|
21
|
+
findMemoryDir
|
|
22
|
+
} from "./chunk-ZTQ7ISUR.js";
|
|
23
|
+
import {
|
|
24
|
+
RESET,
|
|
25
|
+
bold,
|
|
26
|
+
colors,
|
|
27
|
+
icons,
|
|
28
|
+
writeLine
|
|
29
|
+
} from "./chunk-N7KDWU4W.js";
|
|
30
|
+
import "./chunk-7OCVIDC7.js";
|
|
31
|
+
|
|
32
|
+
// src/commands/daemon.ts
|
|
33
|
+
import { execSync, spawn } from "child_process";
|
|
34
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
35
|
+
import { join } from "path";
|
|
36
|
+
import { homedir } from "os";
|
|
37
|
+
var botGhEnv = {};
|
|
38
|
+
var STATE_DIR = join(homedir(), ".squads", "daemon");
|
|
39
|
+
var STATE_FILE = join(STATE_DIR, "state.json");
|
|
40
|
+
function defaultState() {
|
|
41
|
+
return {
|
|
42
|
+
lastCycle: "",
|
|
43
|
+
dailyCost: 0,
|
|
44
|
+
dailyCostDate: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
45
|
+
recentRuns: [],
|
|
46
|
+
failCounts: {}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function loadState() {
|
|
50
|
+
if (!existsSync(STATE_DIR)) mkdirSync(STATE_DIR, { recursive: true });
|
|
51
|
+
if (!existsSync(STATE_FILE)) return defaultState();
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(readFileSync(STATE_FILE, "utf-8"));
|
|
54
|
+
} catch {
|
|
55
|
+
return defaultState();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function saveState(state) {
|
|
59
|
+
if (!existsSync(STATE_DIR)) mkdirSync(STATE_DIR, { recursive: true });
|
|
60
|
+
writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
61
|
+
}
|
|
62
|
+
function getOpenIssues(repo) {
|
|
63
|
+
try {
|
|
64
|
+
const raw = execSync(
|
|
65
|
+
`gh issue list -R ${repo} --state open --json number,title,labels --limit 20`,
|
|
66
|
+
{ encoding: "utf-8", timeout: 15e3, stdio: ["pipe", "pipe", "pipe"], env: { ...process.env, ...botGhEnv } }
|
|
67
|
+
);
|
|
68
|
+
const issues = JSON.parse(raw);
|
|
69
|
+
return issues.map((i) => ({
|
|
70
|
+
number: i.number,
|
|
71
|
+
title: i.title,
|
|
72
|
+
labels: i.labels.map((l) => l.name),
|
|
73
|
+
repo
|
|
74
|
+
}));
|
|
75
|
+
} catch {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function getLastRunAge(squad, agent) {
|
|
80
|
+
const memDir = findMemoryDir();
|
|
81
|
+
if (!memDir) return null;
|
|
82
|
+
const execPath = join(memDir, squad, agent, "executions.md");
|
|
83
|
+
if (!existsSync(execPath)) return null;
|
|
84
|
+
try {
|
|
85
|
+
const content = readFileSync(execPath, "utf-8");
|
|
86
|
+
const timestamps = content.match(/\*\*(\d{4}-\d{2}-\d{2}T[\d:.]+Z?)\*\*/g);
|
|
87
|
+
if (!timestamps || timestamps.length === 0) return null;
|
|
88
|
+
const last = timestamps[timestamps.length - 1].replace(/\*\*/g, "");
|
|
89
|
+
const lastDate = new Date(last);
|
|
90
|
+
return Date.now() - lastDate.getTime();
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function getSquadRepos() {
|
|
96
|
+
const repos = {};
|
|
97
|
+
const squadsDir = findSquadsDir();
|
|
98
|
+
if (!squadsDir) return repos;
|
|
99
|
+
try {
|
|
100
|
+
const squads = listSquads(squadsDir);
|
|
101
|
+
for (const squad of squads) {
|
|
102
|
+
const squadMd = join(squadsDir, squad, "SQUAD.md");
|
|
103
|
+
if (!existsSync(squadMd)) continue;
|
|
104
|
+
const content = readFileSync(squadMd, "utf-8");
|
|
105
|
+
const repoMatch = content.match(/^repo:\s*(.+)/m);
|
|
106
|
+
if (repoMatch) {
|
|
107
|
+
repos[squad] = repoMatch[1].trim();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
return repos;
|
|
113
|
+
}
|
|
114
|
+
function scoreSquads(state, squadRepos) {
|
|
115
|
+
const signals = [];
|
|
116
|
+
const squadsDir = findSquadsDir();
|
|
117
|
+
if (!squadsDir) return signals;
|
|
118
|
+
let squads;
|
|
119
|
+
try {
|
|
120
|
+
squads = listSquads(squadsDir);
|
|
121
|
+
} catch {
|
|
122
|
+
return signals;
|
|
123
|
+
}
|
|
124
|
+
for (const squadName of squads) {
|
|
125
|
+
try {
|
|
126
|
+
const repo = squadRepos[squadName];
|
|
127
|
+
if (!repo) continue;
|
|
128
|
+
const issues = getOpenIssues(repo);
|
|
129
|
+
let score = 0;
|
|
130
|
+
let reason = "";
|
|
131
|
+
const targetAgent = "issue-solver";
|
|
132
|
+
const p0Issues = issues.filter(
|
|
133
|
+
(i) => i.labels.some((l) => l.includes("P0") || l.includes("priority:P0"))
|
|
134
|
+
);
|
|
135
|
+
const p1Issues = issues.filter(
|
|
136
|
+
(i) => i.labels.some((l) => l.includes("P1") || l.includes("priority:P1"))
|
|
137
|
+
);
|
|
138
|
+
if (p0Issues.length > 0) {
|
|
139
|
+
score += 80;
|
|
140
|
+
reason = `${p0Issues.length} P0 issues: ${p0Issues[0].title}`;
|
|
141
|
+
} else if (p1Issues.length > 0) {
|
|
142
|
+
score += 60;
|
|
143
|
+
reason = `${p1Issues.length} P1 issues: ${p1Issues[0].title}`;
|
|
144
|
+
} else if (issues.length > 0) {
|
|
145
|
+
score += 30;
|
|
146
|
+
reason = `${issues.length} open issues`;
|
|
147
|
+
}
|
|
148
|
+
const lastAge = getLastRunAge(squadName, targetAgent);
|
|
149
|
+
if (lastAge !== null) {
|
|
150
|
+
const hoursAgo = lastAge / (1e3 * 60 * 60);
|
|
151
|
+
if (hoursAgo > 48) {
|
|
152
|
+
score += 20;
|
|
153
|
+
reason += ` (stale: ${Math.floor(hoursAgo)}h since last run)`;
|
|
154
|
+
} else if (hoursAgo > 24) {
|
|
155
|
+
score += 10;
|
|
156
|
+
reason += ` (${Math.floor(hoursAgo)}h since last run)`;
|
|
157
|
+
} else if (hoursAgo < 2) {
|
|
158
|
+
score -= 30;
|
|
159
|
+
reason += ` (ran ${Math.floor(hoursAgo * 60)}m ago)`;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const failKey = `${squadName}:${targetAgent}`;
|
|
163
|
+
const failures = state.failCounts[failKey] || 0;
|
|
164
|
+
if (failures >= 3) {
|
|
165
|
+
score -= 40;
|
|
166
|
+
reason += ` (${failures} consecutive failures \u2014 needs human)`;
|
|
167
|
+
} else if (failures >= 1) {
|
|
168
|
+
score -= 10 * failures;
|
|
169
|
+
}
|
|
170
|
+
const outcomeModifier = getOutcomeScoreModifier(squadName, targetAgent);
|
|
171
|
+
if (outcomeModifier !== 0) {
|
|
172
|
+
score += outcomeModifier;
|
|
173
|
+
reason += ` (outcome: ${outcomeModifier > 0 ? "+" : ""}${outcomeModifier})`;
|
|
174
|
+
}
|
|
175
|
+
if (score > 0 && issues.length > 0) {
|
|
176
|
+
signals.push({ squad: squadName, score, reason, agent: targetAgent, issues });
|
|
177
|
+
}
|
|
178
|
+
} catch {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
signals.sort((a, b) => b.score - a.score);
|
|
183
|
+
return signals;
|
|
184
|
+
}
|
|
185
|
+
function dispatchAgent(squad, agent, task) {
|
|
186
|
+
const args = ["run", squad, "-a", agent];
|
|
187
|
+
if (task) args.push("--task", task);
|
|
188
|
+
const proc = spawn("squads", args, {
|
|
189
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
190
|
+
detached: false
|
|
191
|
+
});
|
|
192
|
+
return {
|
|
193
|
+
squad,
|
|
194
|
+
agent,
|
|
195
|
+
pid: proc.pid || 0,
|
|
196
|
+
startedAt: Date.now(),
|
|
197
|
+
process: proc
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function waitForJob(job, timeoutMs = 20 * 60 * 1e3) {
|
|
201
|
+
return new Promise((resolve) => {
|
|
202
|
+
let settled = false;
|
|
203
|
+
const timer = setTimeout(() => {
|
|
204
|
+
if (!settled) {
|
|
205
|
+
settled = true;
|
|
206
|
+
try {
|
|
207
|
+
job.process.kill("SIGTERM");
|
|
208
|
+
} catch {
|
|
209
|
+
}
|
|
210
|
+
resolve("timeout");
|
|
211
|
+
}
|
|
212
|
+
}, timeoutMs);
|
|
213
|
+
job.process.on("close", (code) => {
|
|
214
|
+
if (!settled) {
|
|
215
|
+
settled = true;
|
|
216
|
+
clearTimeout(timer);
|
|
217
|
+
resolve(code === 0 ? "completed" : "failed");
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
job.process.on("error", () => {
|
|
221
|
+
if (!settled) {
|
|
222
|
+
settled = true;
|
|
223
|
+
clearTimeout(timer);
|
|
224
|
+
resolve("failed");
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function checkNewPRs(repo, sinceMins = 30) {
|
|
230
|
+
try {
|
|
231
|
+
const raw = execSync(
|
|
232
|
+
`gh pr list -R ${repo} --state open --json number,title,createdAt --limit 5`,
|
|
233
|
+
{ encoding: "utf-8", timeout: 15e3, stdio: ["pipe", "pipe", "pipe"], env: { ...process.env, ...botGhEnv } }
|
|
234
|
+
);
|
|
235
|
+
const prs = JSON.parse(raw);
|
|
236
|
+
const cutoff = Date.now() - sinceMins * 60 * 1e3;
|
|
237
|
+
return prs.filter((pr) => new Date(pr.createdAt).getTime() > cutoff);
|
|
238
|
+
} catch {
|
|
239
|
+
return [];
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function getPRsWithReviewFeedback(repo) {
|
|
243
|
+
try {
|
|
244
|
+
const prsRaw = execSync(
|
|
245
|
+
`gh pr list -R ${repo} --state open --author "agents-squads[bot]" --json number,title,headRefName --limit 10`,
|
|
246
|
+
{ encoding: "utf-8", timeout: 15e3, stdio: ["pipe", "pipe", "pipe"], env: { ...process.env, ...botGhEnv } }
|
|
247
|
+
);
|
|
248
|
+
const prs = JSON.parse(prsRaw);
|
|
249
|
+
const results = [];
|
|
250
|
+
for (const pr of prs) {
|
|
251
|
+
try {
|
|
252
|
+
const reviewsRaw = execSync(
|
|
253
|
+
`gh api repos/${repo}/pulls/${pr.number}/comments --jq '.[] | {author: .user.login, body: .body, path: .path, createdAt: .created_at}'`,
|
|
254
|
+
{ encoding: "utf-8", timeout: 15e3, stdio: ["pipe", "pipe", "pipe"], env: { ...process.env, ...botGhEnv } }
|
|
255
|
+
);
|
|
256
|
+
const issueCommentsRaw = execSync(
|
|
257
|
+
`gh api repos/${repo}/issues/${pr.number}/comments --jq '.[] | {author: .user.login, body: .body, createdAt: .created_at}'`,
|
|
258
|
+
{ encoding: "utf-8", timeout: 15e3, stdio: ["pipe", "pipe", "pipe"], env: { ...process.env, ...botGhEnv } }
|
|
259
|
+
);
|
|
260
|
+
const comments = [];
|
|
261
|
+
for (const line of [...reviewsRaw.split("\n"), ...issueCommentsRaw.split("\n")]) {
|
|
262
|
+
if (!line.trim()) continue;
|
|
263
|
+
try {
|
|
264
|
+
const comment = JSON.parse(line);
|
|
265
|
+
if (comment.author === "agents-squads[bot]") continue;
|
|
266
|
+
comments.push(comment);
|
|
267
|
+
} catch {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (comments.length > 0) {
|
|
272
|
+
results.push({
|
|
273
|
+
number: pr.number,
|
|
274
|
+
title: pr.title,
|
|
275
|
+
branch: pr.headRefName,
|
|
276
|
+
repo,
|
|
277
|
+
comments
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
} catch {
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return results;
|
|
285
|
+
} catch {
|
|
286
|
+
return [];
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function buildReviewTask(pr) {
|
|
290
|
+
const commentSummary = pr.comments.map((c) => {
|
|
291
|
+
const location = c.path ? ` (${c.path})` : "";
|
|
292
|
+
return `- ${c.author}${location}: ${c.body.slice(0, 300)}`;
|
|
293
|
+
}).join("\n");
|
|
294
|
+
return [
|
|
295
|
+
`Address review feedback on PR #${pr.number}: ${pr.title}`,
|
|
296
|
+
`Branch: ${pr.branch}`,
|
|
297
|
+
``,
|
|
298
|
+
`Review comments to address:`,
|
|
299
|
+
commentSummary,
|
|
300
|
+
``,
|
|
301
|
+
`Checkout the branch, fix the issues, commit, and push.`
|
|
302
|
+
].join("\n");
|
|
303
|
+
}
|
|
304
|
+
async function slackNotify(message) {
|
|
305
|
+
try {
|
|
306
|
+
const envPath = join(homedir(), "agents-squads", "hq", ".env");
|
|
307
|
+
if (!existsSync(envPath)) return;
|
|
308
|
+
const env = readFileSync(envPath, "utf-8");
|
|
309
|
+
const tokenMatch = env.match(/SLACK_BOT_TOKEN=(.+)/);
|
|
310
|
+
if (!tokenMatch) return;
|
|
311
|
+
const token = tokenMatch[1].trim();
|
|
312
|
+
const founderId = "U0A6NQ3U0JG";
|
|
313
|
+
await fetch("https://slack.com/api/chat.postMessage", {
|
|
314
|
+
method: "POST",
|
|
315
|
+
headers: {
|
|
316
|
+
"Authorization": `Bearer ${token}`,
|
|
317
|
+
"Content-Type": "application/json"
|
|
318
|
+
},
|
|
319
|
+
body: JSON.stringify({ channel: founderId, text: message }),
|
|
320
|
+
signal: AbortSignal.timeout(1e4)
|
|
321
|
+
});
|
|
322
|
+
} catch {
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
async function runCycle(options) {
|
|
326
|
+
botGhEnv = await getBotGhEnv();
|
|
327
|
+
const state = loadState();
|
|
328
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
329
|
+
const result = {
|
|
330
|
+
dispatched: [],
|
|
331
|
+
completed: [],
|
|
332
|
+
failed: [],
|
|
333
|
+
skipped: [],
|
|
334
|
+
costEstimate: 0
|
|
335
|
+
};
|
|
336
|
+
if (state.dailyCostDate !== today) {
|
|
337
|
+
state.dailyCost = 0;
|
|
338
|
+
state.dailyCostDate = today;
|
|
339
|
+
}
|
|
340
|
+
if (options.budget > 0 && state.dailyCost >= options.budget) {
|
|
341
|
+
writeLine(` ${icons.warning} ${colors.yellow}Daily budget reached ($${state.dailyCost.toFixed(2)}/$${options.budget})${RESET}`);
|
|
342
|
+
saveState(state);
|
|
343
|
+
return result;
|
|
344
|
+
}
|
|
345
|
+
const pollResult = pollOutcomes(botGhEnv);
|
|
346
|
+
if (pollResult.polled > 0) {
|
|
347
|
+
writeLine(` ${colors.dim}Polled ${pollResult.polled} artifact(s), ${pollResult.settled} newly settled${RESET}`);
|
|
348
|
+
}
|
|
349
|
+
computeAllScorecards("7d");
|
|
350
|
+
writeLine(` ${colors.dim}Scanning org state...${RESET}`);
|
|
351
|
+
const squadRepos = getSquadRepos();
|
|
352
|
+
const signals = scoreSquads(state, squadRepos);
|
|
353
|
+
if (signals.length === 0) {
|
|
354
|
+
writeLine(` ${colors.dim}No squads need attention${RESET}`);
|
|
355
|
+
saveState(state);
|
|
356
|
+
return result;
|
|
357
|
+
}
|
|
358
|
+
if (options.verbose) {
|
|
359
|
+
writeLine(` ${colors.dim}Scored ${signals.length} squads${RESET}`);
|
|
360
|
+
}
|
|
361
|
+
writeLine(` ${bold}Signals:${RESET}`);
|
|
362
|
+
for (const sig of signals.slice(0, 8)) {
|
|
363
|
+
const scoreColor = sig.score >= 60 ? colors.red : sig.score >= 30 ? colors.yellow : colors.dim;
|
|
364
|
+
writeLine(` ${scoreColor}[${sig.score}]${RESET} ${colors.cyan}${sig.squad}${RESET} ${colors.dim}${sig.reason}${RESET}`);
|
|
365
|
+
}
|
|
366
|
+
writeLine();
|
|
367
|
+
const toDispatch = signals.filter((s) => s.score > 0).slice(0, options.maxParallel);
|
|
368
|
+
if (toDispatch.length === 0) {
|
|
369
|
+
writeLine(` ${colors.dim}All signals below threshold${RESET}`);
|
|
370
|
+
saveState(state);
|
|
371
|
+
return result;
|
|
372
|
+
}
|
|
373
|
+
if (options.dryRun) {
|
|
374
|
+
writeLine(` ${colors.yellow}[DRY RUN] Would dispatch:${RESET}`);
|
|
375
|
+
for (const sig of toDispatch) {
|
|
376
|
+
writeLine(` ${colors.cyan}${sig.squad}/${sig.agent}${RESET} \u2014 ${sig.reason}`);
|
|
377
|
+
}
|
|
378
|
+
saveState(state);
|
|
379
|
+
return result;
|
|
380
|
+
}
|
|
381
|
+
const jobs = [];
|
|
382
|
+
for (const sig of toDispatch) {
|
|
383
|
+
const topIssue = sig.issues[0];
|
|
384
|
+
const task = topIssue ? `Fix issue #${topIssue.number}: ${topIssue.title}` : void 0;
|
|
385
|
+
writeLine(` ${icons.running} Dispatching ${colors.cyan}${sig.squad}/${sig.agent}${RESET}${task ? ` \u2192 #${topIssue?.number}` : ""}`);
|
|
386
|
+
const job = dispatchAgent(sig.squad, sig.agent || "issue-solver", task);
|
|
387
|
+
jobs.push(job);
|
|
388
|
+
result.dispatched.push(`${sig.squad}/${sig.agent}`);
|
|
389
|
+
}
|
|
390
|
+
writeLine(` ${colors.dim}${jobs.length} agents running. Waiting...${RESET}`);
|
|
391
|
+
writeLine();
|
|
392
|
+
const outcomes = await Promise.all(
|
|
393
|
+
jobs.map(async (job) => {
|
|
394
|
+
const outcome = await waitForJob(job);
|
|
395
|
+
const durationMs = Date.now() - job.startedAt;
|
|
396
|
+
const durationMin = Math.floor(durationMs / 6e4);
|
|
397
|
+
const key = `${job.squad}:${job.agent}`;
|
|
398
|
+
state.recentRuns.push({
|
|
399
|
+
squad: job.squad,
|
|
400
|
+
agent: job.agent,
|
|
401
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
402
|
+
result: outcome,
|
|
403
|
+
durationMs
|
|
404
|
+
});
|
|
405
|
+
if (outcome === "failed" || outcome === "timeout") {
|
|
406
|
+
state.failCounts[key] = (state.failCounts[key] || 0) + 1;
|
|
407
|
+
result.failed.push(`${job.squad}/${job.agent}`);
|
|
408
|
+
writeLine(` ${icons.error} ${colors.red}${job.squad}/${job.agent}${RESET} ${outcome} (${durationMin}m)`);
|
|
409
|
+
} else {
|
|
410
|
+
state.failCounts[key] = 0;
|
|
411
|
+
result.completed.push(`${job.squad}/${job.agent}`);
|
|
412
|
+
writeLine(` ${icons.success} ${colors.green}${job.squad}/${job.agent}${RESET} completed (${durationMin}m)`);
|
|
413
|
+
}
|
|
414
|
+
const estimatedCost = 0.5;
|
|
415
|
+
state.dailyCost += estimatedCost;
|
|
416
|
+
result.costEstimate += estimatedCost;
|
|
417
|
+
if (outcome === "completed") {
|
|
418
|
+
const repo = squadRepos[job.squad];
|
|
419
|
+
if (repo) {
|
|
420
|
+
recordArtifacts({
|
|
421
|
+
executionId: `daemon_${job.squad}_${job.agent}_${job.startedAt}`,
|
|
422
|
+
squad: job.squad,
|
|
423
|
+
agent: job.agent,
|
|
424
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
425
|
+
costUsd: estimatedCost,
|
|
426
|
+
repo
|
|
427
|
+
}, botGhEnv);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
pushCognitionSignal({
|
|
431
|
+
source: "execution",
|
|
432
|
+
signal_type: outcome === "completed" ? "agent_completed" : "agent_failed",
|
|
433
|
+
value: outcome === "completed" ? 1 : 0,
|
|
434
|
+
unit: "completion",
|
|
435
|
+
data: { outcome, durationMs, cost_usd: estimatedCost },
|
|
436
|
+
entity_type: "agent",
|
|
437
|
+
entity_id: `${job.squad}/${job.agent}`,
|
|
438
|
+
confidence: 0.95
|
|
439
|
+
});
|
|
440
|
+
return { job, outcome, durationMs };
|
|
441
|
+
})
|
|
442
|
+
);
|
|
443
|
+
state.recentRuns = state.recentRuns.slice(-50);
|
|
444
|
+
state.lastCycle = (/* @__PURE__ */ new Date()).toISOString();
|
|
445
|
+
saveState(state);
|
|
446
|
+
writeLine();
|
|
447
|
+
for (const { job, outcome } of outcomes) {
|
|
448
|
+
if (outcome !== "completed") continue;
|
|
449
|
+
const repo = squadRepos[job.squad];
|
|
450
|
+
if (!repo) continue;
|
|
451
|
+
const newPRs = checkNewPRs(repo, 30);
|
|
452
|
+
if (newPRs.length > 0) {
|
|
453
|
+
writeLine(` ${icons.success} ${colors.cyan}${job.squad}${RESET} created ${newPRs.length} PR(s):`);
|
|
454
|
+
for (const pr of newPRs) {
|
|
455
|
+
writeLine(` ${colors.dim}#${pr.number} ${pr.title}${RESET}`);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
if (!options.dryRun) {
|
|
460
|
+
const reviewJobs = [];
|
|
461
|
+
for (const repo of Object.values(squadRepos)) {
|
|
462
|
+
const prsWithFeedback = getPRsWithReviewFeedback(repo);
|
|
463
|
+
for (const pr of prsWithFeedback) {
|
|
464
|
+
const squad = Object.entries(squadRepos).find(([, r]) => r === repo)?.[0];
|
|
465
|
+
if (!squad) continue;
|
|
466
|
+
if (options.budget > 0 && state.dailyCost >= options.budget) break;
|
|
467
|
+
const task = buildReviewTask(pr);
|
|
468
|
+
writeLine(` ${icons.running} Addressing ${pr.comments.length} review comment(s) on ${colors.cyan}${squad}${RESET} PR #${pr.number}`);
|
|
469
|
+
const job = dispatchAgent(squad, "issue-solver", task);
|
|
470
|
+
reviewJobs.push(job);
|
|
471
|
+
result.dispatched.push(`${squad}/issue-solver (review #${pr.number})`);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (reviewJobs.length > 0) {
|
|
475
|
+
writeLine(` ${colors.dim}${reviewJobs.length} review-fix agent(s) running...${RESET}`);
|
|
476
|
+
for (const job of reviewJobs) {
|
|
477
|
+
const outcome = await waitForJob(job);
|
|
478
|
+
const durationMs = Date.now() - job.startedAt;
|
|
479
|
+
const durationMin = Math.floor(durationMs / 6e4);
|
|
480
|
+
if (outcome === "completed") {
|
|
481
|
+
result.completed.push(`${job.squad}/review-fix`);
|
|
482
|
+
writeLine(` ${icons.success} ${colors.green}${job.squad}/review-fix${RESET} completed (${durationMin}m)`);
|
|
483
|
+
} else {
|
|
484
|
+
result.failed.push(`${job.squad}/review-fix`);
|
|
485
|
+
writeLine(` ${icons.error} ${colors.red}${job.squad}/review-fix${RESET} ${outcome} (${durationMin}m)`);
|
|
486
|
+
}
|
|
487
|
+
state.dailyCost += 0.5;
|
|
488
|
+
result.costEstimate += 0.5;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
saveState(state);
|
|
493
|
+
if (result.completed.length > 0 || result.failed.length > 0) {
|
|
494
|
+
const summary = [
|
|
495
|
+
`*Daemon cycle complete*`,
|
|
496
|
+
result.completed.length > 0 ? `Completed: ${result.completed.join(", ")}` : "",
|
|
497
|
+
result.failed.length > 0 ? `Failed: ${result.failed.join(", ")}` : "",
|
|
498
|
+
`Est. cost: $${result.costEstimate.toFixed(2)} (daily: $${state.dailyCost.toFixed(2)}${options.budget > 0 ? "/$" + options.budget : ""})`
|
|
499
|
+
].filter(Boolean).join("\n");
|
|
500
|
+
slackNotify(summary);
|
|
501
|
+
}
|
|
502
|
+
for (const [key, count] of Object.entries(state.failCounts)) {
|
|
503
|
+
if (count >= 3) {
|
|
504
|
+
slackNotify(`*Escalation*: ${key} has failed ${count} times consecutively. Needs human attention.`);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return result;
|
|
508
|
+
}
|
|
509
|
+
async function daemonCommand(options) {
|
|
510
|
+
const config = {
|
|
511
|
+
interval: parseInt(options.interval || "30", 10),
|
|
512
|
+
maxParallel: parseInt(options.parallel || "2", 10),
|
|
513
|
+
dryRun: options.dryRun || false,
|
|
514
|
+
verbose: options.verbose || false,
|
|
515
|
+
once: options.once || false,
|
|
516
|
+
budget: parseFloat(options.budget || "0")
|
|
517
|
+
};
|
|
518
|
+
writeLine();
|
|
519
|
+
writeLine(` ${bold}squads daemon${RESET}`);
|
|
520
|
+
const budgetLabel = config.budget > 0 ? `Budget: $${config.budget}/day` : "Subscription (no budget limit)";
|
|
521
|
+
writeLine(` ${colors.dim}Interval: ${config.interval}m | Parallel: ${config.maxParallel} | ${budgetLabel}${config.dryRun ? " | DRY RUN" : ""}${RESET}`);
|
|
522
|
+
writeLine();
|
|
523
|
+
const result = await runCycle(config);
|
|
524
|
+
if (config.once) {
|
|
525
|
+
writeLine();
|
|
526
|
+
writeLine(` ${colors.dim}Single cycle complete. Dispatched: ${result.dispatched.length}, Completed: ${result.completed.length}, Failed: ${result.failed.length}${RESET}`);
|
|
527
|
+
writeLine();
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
writeLine();
|
|
531
|
+
writeLine(` ${colors.dim}Next cycle in ${config.interval} minutes. Ctrl+C to stop.${RESET}`);
|
|
532
|
+
const loop = async () => {
|
|
533
|
+
while (true) {
|
|
534
|
+
await new Promise((resolve) => setTimeout(resolve, config.interval * 60 * 1e3));
|
|
535
|
+
writeLine();
|
|
536
|
+
writeLine(` ${colors.dim}\u2500\u2500\u2500 Cycle ${(/* @__PURE__ */ new Date()).toISOString()} \u2500\u2500\u2500${RESET}`);
|
|
537
|
+
await runCycle(config);
|
|
538
|
+
writeLine(` ${colors.dim}Next cycle in ${config.interval} minutes.${RESET}`);
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
await loop();
|
|
542
|
+
}
|
|
543
|
+
export {
|
|
544
|
+
daemonCommand
|
|
545
|
+
};
|
|
546
|
+
//# sourceMappingURL=daemon-XWPQPPPN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/daemon.ts"],"sourcesContent":["/**\n * squads daemon — persistent intelligence loop.\n *\n * Watches the org, decides what to run, dispatches agents,\n * monitors results, and reacts (merge, retry, escalate).\n *\n * This is the product: incremental smartness, not 200 agents.\n */\n\nimport { execSync, spawn } from 'child_process';\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport {\n findSquadsDir,\n listSquads,\n} from '../lib/squad-parser.js';\nimport { findMemoryDir } from '../lib/memory.js';\nimport { getBotGhEnv } from '../lib/github.js';\nimport {\n recordArtifacts,\n pollOutcomes,\n computeAllScorecards,\n getOutcomeScoreModifier,\n} from '../lib/outcomes.js';\nimport { pushCognitionSignal } from '../lib/api-client.js';\nimport {\n colors,\n bold,\n RESET,\n icons,\n writeLine,\n} from '../lib/terminal.js';\n\n// Bot environment for gh CLI commands (populated on first cycle)\nlet botGhEnv: Record<string, string> = {};\n\n// ── Types ────────────────────────────────────────────────────────────\n\ninterface DaemonOptions {\n interval: number; // minutes between cycles\n maxParallel: number;\n dryRun: boolean;\n verbose: boolean;\n once: boolean; // run one cycle and exit\n budget: number; // max $/day\n}\n\ninterface SquadSignal {\n squad: string;\n score: number; // 0-100 urgency\n reason: string;\n agent?: string; // specific agent to run, or undefined for squad conversation\n issues: GhIssue[];\n}\n\ninterface GhIssue {\n number: number;\n title: string;\n labels: string[];\n repo: string;\n}\n\ninterface RunningJob {\n squad: string;\n agent: string;\n pid: number;\n startedAt: number;\n process: ReturnType<typeof spawn>;\n}\n\ninterface CycleResult {\n dispatched: string[];\n completed: string[];\n failed: string[];\n skipped: string[];\n costEstimate: number;\n}\n\n// ── State file ───────────────────────────────────────────────────────\n\nconst STATE_DIR = join(homedir(), '.squads', 'daemon');\nconst STATE_FILE = join(STATE_DIR, 'state.json');\n\ninterface DaemonState {\n lastCycle: string;\n dailyCost: number;\n dailyCostDate: string;\n recentRuns: Array<{\n squad: string;\n agent: string;\n at: string;\n result: 'completed' | 'failed' | 'timeout';\n durationMs: number;\n }>;\n failCounts: Record<string, number>; // squad:agent → consecutive failures\n}\n\nfunction defaultState(): DaemonState {\n return {\n lastCycle: '',\n dailyCost: 0,\n dailyCostDate: new Date().toISOString().slice(0, 10),\n recentRuns: [],\n failCounts: {},\n };\n}\n\nfunction loadState(): DaemonState {\n if (!existsSync(STATE_DIR)) mkdirSync(STATE_DIR, { recursive: true });\n if (!existsSync(STATE_FILE)) return defaultState();\n try {\n return JSON.parse(readFileSync(STATE_FILE, 'utf-8'));\n } catch {\n return defaultState();\n }\n}\n\nfunction saveState(state: DaemonState): void {\n if (!existsSync(STATE_DIR)) mkdirSync(STATE_DIR, { recursive: true });\n writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));\n}\n\n// ── Intelligence: Gather signals ─────────────────────────────────────\n\nfunction getOpenIssues(repo: string): GhIssue[] {\n try {\n const raw = execSync(\n `gh issue list -R ${repo} --state open --json number,title,labels --limit 20`,\n { encoding: 'utf-8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, ...botGhEnv } },\n );\n const issues = JSON.parse(raw) as Array<{\n number: number;\n title: string;\n labels: Array<{ name: string }>;\n }>;\n return issues.map(i => ({\n number: i.number,\n title: i.title,\n labels: i.labels.map(l => l.name),\n repo,\n }));\n } catch {\n return [];\n }\n}\n\nfunction getOpenPRs(repo: string): Array<{ number: number; title: string; branch: string; checks: string }> {\n try {\n const raw = execSync(\n `gh pr list -R ${repo} --state open --json number,title,headRefName,statusCheckRollup --limit 10`,\n { encoding: 'utf-8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, ...botGhEnv } },\n );\n const prs = JSON.parse(raw) as Array<{\n number: number;\n title: string;\n headRefName: string;\n statusCheckRollup: Array<{ conclusion: string }> | null;\n }>;\n return prs.map(pr => ({\n number: pr.number,\n title: pr.title,\n branch: pr.headRefName,\n checks: pr.statusCheckRollup?.every(c => c.conclusion === 'SUCCESS') ? 'passing' : 'pending',\n }));\n } catch {\n return [];\n }\n}\n\nfunction getLastRunAge(squad: string, agent: string): number | null {\n const memDir = findMemoryDir();\n if (!memDir) return null;\n\n const execPath = join(memDir, squad, agent, 'executions.md');\n if (!existsSync(execPath)) return null;\n\n try {\n const content = readFileSync(execPath, 'utf-8');\n // Find the last timestamp\n const timestamps = content.match(/\\*\\*(\\d{4}-\\d{2}-\\d{2}T[\\d:.]+Z?)\\*\\*/g);\n if (!timestamps || timestamps.length === 0) return null;\n\n const last = timestamps[timestamps.length - 1].replace(/\\*\\*/g, '');\n const lastDate = new Date(last);\n return Date.now() - lastDate.getTime();\n } catch {\n return null;\n }\n}\n\n// ── Intelligence: Score squads ───────────────────────────────────────\n\n/**\n * Build squad→repo mapping dynamically from SQUAD.md `repo:` fields.\n * Falls back to detecting org from git remote + squad name conventions.\n */\nfunction getSquadRepos(): Record<string, string> {\n const repos: Record<string, string> = {};\n const squadsDir = findSquadsDir();\n if (!squadsDir) return repos;\n\n try {\n const squads = listSquads(squadsDir);\n for (const squad of squads) {\n const squadMd = join(squadsDir, squad, 'SQUAD.md');\n if (!existsSync(squadMd)) continue;\n\n const content = readFileSync(squadMd, 'utf-8');\n const repoMatch = content.match(/^repo:\\s*(.+)/m);\n if (repoMatch) {\n repos[squad] = repoMatch[1].trim();\n }\n }\n } catch {\n // Fall back to empty — scoring will skip squads without repos\n }\n\n return repos;\n}\n\nfunction scoreSquads(state: DaemonState, squadRepos: Record<string, string>): SquadSignal[] {\n const signals: SquadSignal[] = [];\n const squadsDir = findSquadsDir();\n if (!squadsDir) return signals;\n\n let squads: string[];\n try {\n squads = listSquads(squadsDir);\n } catch {\n return signals;\n }\n\n for (const squadName of squads) {\n try {\n const repo = squadRepos[squadName];\n if (!repo) continue; // Only score squads with repos we can check\n\n const issues = getOpenIssues(repo);\n\n // Score based on signals\n let score = 0;\n let reason = '';\n const targetAgent = 'issue-solver'; // default worker\n\n // P0/P1 issues = highest priority\n const p0Issues = issues.filter(i =>\n i.labels.some(l => l.includes('P0') || l.includes('priority:P0')),\n );\n const p1Issues = issues.filter(i =>\n i.labels.some(l => l.includes('P1') || l.includes('priority:P1')),\n );\n\n if (p0Issues.length > 0) {\n score += 80;\n reason = `${p0Issues.length} P0 issues: ${p0Issues[0].title}`;\n } else if (p1Issues.length > 0) {\n score += 60;\n reason = `${p1Issues.length} P1 issues: ${p1Issues[0].title}`;\n } else if (issues.length > 0) {\n score += 30;\n reason = `${issues.length} open issues`;\n }\n\n // Staleness bonus: haven't run recently\n const lastAge = getLastRunAge(squadName, targetAgent);\n if (lastAge !== null) {\n const hoursAgo = lastAge / (1000 * 60 * 60);\n if (hoursAgo > 48) {\n score += 20;\n reason += ` (stale: ${Math.floor(hoursAgo)}h since last run)`;\n } else if (hoursAgo > 24) {\n score += 10;\n reason += ` (${Math.floor(hoursAgo)}h since last run)`;\n } else if (hoursAgo < 2) {\n // Recently ran — penalize\n score -= 30;\n reason += ` (ran ${Math.floor(hoursAgo * 60)}m ago)`;\n }\n }\n\n // Consecutive failure penalty\n const failKey = `${squadName}:${targetAgent}`;\n const failures = state.failCounts[failKey] || 0;\n if (failures >= 3) {\n score -= 40;\n reason += ` (${failures} consecutive failures — needs human)`;\n } else if (failures >= 1) {\n score -= 10 * failures;\n }\n\n // Outcome-based modifier (needs 3+ executions for data)\n const outcomeModifier = getOutcomeScoreModifier(squadName, targetAgent);\n if (outcomeModifier !== 0) {\n score += outcomeModifier;\n reason += ` (outcome: ${outcomeModifier > 0 ? '+' : ''}${outcomeModifier})`;\n }\n\n // Only include squads with positive scores and actual work\n if (score > 0 && issues.length > 0) {\n signals.push({ squad: squadName, score, reason, agent: targetAgent, issues });\n }\n } catch {\n // Skip squads that error during scoring\n continue;\n }\n }\n\n // Sort by score descending\n signals.sort((a, b) => b.score - a.score);\n return signals;\n}\n\n// ── Dispatch: Run agents ─────────────────────────────────────────────\n\nfunction dispatchAgent(\n squad: string,\n agent: string,\n task?: string,\n): RunningJob {\n const args = ['run', squad, '-a', agent];\n if (task) args.push('--task', task);\n\n const proc = spawn('squads', args, {\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: false,\n });\n\n return {\n squad,\n agent,\n pid: proc.pid || 0,\n startedAt: Date.now(),\n process: proc,\n };\n}\n\nfunction waitForJob(job: RunningJob, timeoutMs: number = 20 * 60 * 1000): Promise<'completed' | 'failed' | 'timeout'> {\n return new Promise((resolve) => {\n let settled = false;\n\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true;\n try { job.process.kill('SIGTERM'); } catch { /* ignore */ }\n resolve('timeout');\n }\n }, timeoutMs);\n\n job.process.on('close', (code) => {\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n resolve(code === 0 ? 'completed' : 'failed');\n }\n });\n\n job.process.on('error', () => {\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n resolve('failed');\n }\n });\n });\n}\n\n// ── React: Post-run actions ──────────────────────────────────────────\n\nfunction checkNewPRs(repo: string, sinceMins: number = 30): Array<{ number: number; title: string }> {\n try {\n const raw = execSync(\n `gh pr list -R ${repo} --state open --json number,title,createdAt --limit 5`,\n { encoding: 'utf-8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, ...botGhEnv } },\n );\n const prs = JSON.parse(raw) as Array<{ number: number; title: string; createdAt: string }>;\n const cutoff = Date.now() - sinceMins * 60 * 1000;\n return prs.filter(pr => new Date(pr.createdAt).getTime() > cutoff);\n } catch {\n return [];\n }\n}\n\ninterface ReviewComment {\n author: string;\n body: string;\n path?: string;\n createdAt: string;\n}\n\ninterface PRWithReviews {\n number: number;\n title: string;\n branch: string;\n repo: string;\n comments: ReviewComment[];\n}\n\n/**\n * Get open PRs with unaddressed review comments (from Gemini, humans, etc).\n * Skips comments from our own bot to avoid feedback loops.\n */\nfunction getPRsWithReviewFeedback(repo: string): PRWithReviews[] {\n try {\n // Get open PRs authored by the bot\n const prsRaw = execSync(\n `gh pr list -R ${repo} --state open --author \"agents-squads[bot]\" --json number,title,headRefName --limit 10`,\n { encoding: 'utf-8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, ...botGhEnv } },\n );\n const prs = JSON.parse(prsRaw) as Array<{ number: number; title: string; headRefName: string }>;\n\n const results: PRWithReviews[] = [];\n\n for (const pr of prs) {\n try {\n // Get review comments (inline code review comments)\n const reviewsRaw = execSync(\n `gh api repos/${repo}/pulls/${pr.number}/comments --jq '.[] | {author: .user.login, body: .body, path: .path, createdAt: .created_at}'`,\n { encoding: 'utf-8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, ...botGhEnv } },\n );\n\n // Get issue comments (top-level PR comments like Gemini summaries)\n const issueCommentsRaw = execSync(\n `gh api repos/${repo}/issues/${pr.number}/comments --jq '.[] | {author: .user.login, body: .body, createdAt: .created_at}'`,\n { encoding: 'utf-8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, ...botGhEnv } },\n );\n\n const comments: ReviewComment[] = [];\n\n // Parse JSONL output (one JSON object per line)\n for (const line of [...reviewsRaw.split('\\n'), ...issueCommentsRaw.split('\\n')]) {\n if (!line.trim()) continue;\n try {\n const comment = JSON.parse(line) as ReviewComment;\n // Skip our own bot's comments to avoid loops\n if (comment.author === 'agents-squads[bot]') continue;\n comments.push(comment);\n } catch {\n continue;\n }\n }\n\n if (comments.length > 0) {\n results.push({\n number: pr.number,\n title: pr.title,\n branch: pr.headRefName,\n repo,\n comments,\n });\n }\n } catch {\n continue;\n }\n }\n\n return results;\n } catch {\n return [];\n }\n}\n\n/**\n * Build a task directive from review feedback for an agent to address.\n */\nfunction buildReviewTask(pr: PRWithReviews): string {\n const commentSummary = pr.comments\n .map(c => {\n const location = c.path ? ` (${c.path})` : '';\n return `- ${c.author}${location}: ${c.body.slice(0, 300)}`;\n })\n .join('\\n');\n\n return [\n `Address review feedback on PR #${pr.number}: ${pr.title}`,\n `Branch: ${pr.branch}`,\n ``,\n `Review comments to address:`,\n commentSummary,\n ``,\n `Checkout the branch, fix the issues, commit, and push.`,\n ].join('\\n');\n}\n\nasync function slackNotify(message: string): Promise<void> {\n try {\n const envPath = join(homedir(), 'agents-squads', 'hq', '.env');\n if (!existsSync(envPath)) return;\n\n const env = readFileSync(envPath, 'utf-8');\n const tokenMatch = env.match(/SLACK_BOT_TOKEN=(.+)/);\n if (!tokenMatch) return;\n\n const token = tokenMatch[1].trim();\n const founderId = 'U0A6NQ3U0JG';\n\n await fetch('https://slack.com/api/chat.postMessage', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ channel: founderId, text: message }),\n signal: AbortSignal.timeout(10000),\n });\n } catch {\n // Silent — Slack is best-effort\n }\n}\n\n// ── Main cycle ───────────────────────────────────────────────────────\n\nasync function runCycle(options: DaemonOptions): Promise<CycleResult> {\n // Refresh bot token for gh CLI calls\n botGhEnv = await getBotGhEnv();\n\n const state = loadState();\n const today = new Date().toISOString().slice(0, 10);\n const result: CycleResult = {\n dispatched: [],\n completed: [],\n failed: [],\n skipped: [],\n costEstimate: 0,\n };\n\n // Reset daily cost counter\n if (state.dailyCostDate !== today) {\n state.dailyCost = 0;\n state.dailyCostDate = today;\n }\n\n // Check budget (0 = unlimited, subscription mode)\n if (options.budget > 0 && state.dailyCost >= options.budget) {\n writeLine(` ${icons.warning} ${colors.yellow}Daily budget reached ($${state.dailyCost.toFixed(2)}/$${options.budget})${RESET}`);\n saveState(state);\n return result;\n }\n\n // Poll outcomes for unsettled records\n const pollResult = pollOutcomes(botGhEnv);\n if (pollResult.polled > 0) {\n writeLine(` ${colors.dim}Polled ${pollResult.polled} artifact(s), ${pollResult.settled} newly settled${RESET}`);\n }\n\n // Recompute scorecards\n computeAllScorecards('7d');\n\n // Gather intelligence\n writeLine(` ${colors.dim}Scanning org state...${RESET}`);\n const squadRepos = getSquadRepos();\n const signals = scoreSquads(state, squadRepos);\n\n if (signals.length === 0) {\n writeLine(` ${colors.dim}No squads need attention${RESET}`);\n saveState(state);\n return result;\n }\n\n if (options.verbose) {\n writeLine(` ${colors.dim}Scored ${signals.length} squads${RESET}`);\n }\n\n // Show what we found\n writeLine(` ${bold}Signals:${RESET}`);\n for (const sig of signals.slice(0, 8)) {\n const scoreColor = sig.score >= 60 ? colors.red : sig.score >= 30 ? colors.yellow : colors.dim;\n writeLine(` ${scoreColor}[${sig.score}]${RESET} ${colors.cyan}${sig.squad}${RESET} ${colors.dim}${sig.reason}${RESET}`);\n }\n writeLine();\n\n // Pick top N to dispatch\n const toDispatch = signals\n .filter(s => s.score > 0)\n .slice(0, options.maxParallel);\n\n if (toDispatch.length === 0) {\n writeLine(` ${colors.dim}All signals below threshold${RESET}`);\n saveState(state);\n return result;\n }\n\n if (options.dryRun) {\n writeLine(` ${colors.yellow}[DRY RUN] Would dispatch:${RESET}`);\n for (const sig of toDispatch) {\n writeLine(` ${colors.cyan}${sig.squad}/${sig.agent}${RESET} — ${sig.reason}`);\n }\n saveState(state);\n return result;\n }\n\n // Dispatch agents\n const jobs: RunningJob[] = [];\n for (const sig of toDispatch) {\n // Build task from top issue\n const topIssue = sig.issues[0];\n const task = topIssue\n ? `Fix issue #${topIssue.number}: ${topIssue.title}`\n : undefined;\n\n writeLine(` ${icons.running} Dispatching ${colors.cyan}${sig.squad}/${sig.agent}${RESET}${task ? ` → #${topIssue?.number}` : ''}`);\n const job = dispatchAgent(sig.squad, sig.agent || 'issue-solver', task);\n jobs.push(job);\n result.dispatched.push(`${sig.squad}/${sig.agent}`);\n }\n\n writeLine(` ${colors.dim}${jobs.length} agents running. Waiting...${RESET}`);\n writeLine();\n\n // Wait for all jobs (parallel)\n const outcomes = await Promise.all(\n jobs.map(async (job) => {\n const outcome = await waitForJob(job);\n const durationMs = Date.now() - job.startedAt;\n const durationMin = Math.floor(durationMs / 60000);\n const key = `${job.squad}:${job.agent}`;\n\n // Update state\n state.recentRuns.push({\n squad: job.squad,\n agent: job.agent,\n at: new Date().toISOString(),\n result: outcome,\n durationMs,\n });\n\n // Track failures\n if (outcome === 'failed' || outcome === 'timeout') {\n state.failCounts[key] = (state.failCounts[key] || 0) + 1;\n result.failed.push(`${job.squad}/${job.agent}`);\n writeLine(` ${icons.error} ${colors.red}${job.squad}/${job.agent}${RESET} ${outcome} (${durationMin}m)`);\n } else {\n state.failCounts[key] = 0; // Reset on success\n result.completed.push(`${job.squad}/${job.agent}`);\n writeLine(` ${icons.success} ${colors.green}${job.squad}/${job.agent}${RESET} completed (${durationMin}m)`);\n }\n\n // Estimate cost (~$0.50 per agent run average)\n const estimatedCost = 0.50;\n state.dailyCost += estimatedCost;\n result.costEstimate += estimatedCost;\n\n // Record artifacts for outcome tracking\n if (outcome === 'completed') {\n const repo = squadRepos[job.squad];\n if (repo) {\n recordArtifacts({\n executionId: `daemon_${job.squad}_${job.agent}_${job.startedAt}`,\n squad: job.squad,\n agent: job.agent,\n completedAt: new Date().toISOString(),\n costUsd: estimatedCost,\n repo,\n }, botGhEnv);\n }\n }\n\n // Push execution signal to cognition engine (fire-and-forget)\n pushCognitionSignal({\n source: 'execution',\n signal_type: outcome === 'completed' ? 'agent_completed' : 'agent_failed',\n value: outcome === 'completed' ? 1 : 0,\n unit: 'completion',\n data: { outcome, durationMs, cost_usd: estimatedCost },\n entity_type: 'agent',\n entity_id: `${job.squad}/${job.agent}`,\n confidence: 0.95,\n });\n\n return { job, outcome, durationMs };\n }),\n );\n\n // Trim recent runs to last 50\n state.recentRuns = state.recentRuns.slice(-50);\n state.lastCycle = new Date().toISOString();\n saveState(state);\n\n // React: check for new PRs\n writeLine();\n for (const { job, outcome } of outcomes) {\n if (outcome !== 'completed') continue;\n const repo = squadRepos[job.squad];\n if (!repo) continue;\n const newPRs = checkNewPRs(repo, 30);\n if (newPRs.length > 0) {\n writeLine(` ${icons.success} ${colors.cyan}${job.squad}${RESET} created ${newPRs.length} PR(s):`);\n for (const pr of newPRs) {\n writeLine(` ${colors.dim}#${pr.number} ${pr.title}${RESET}`);\n }\n }\n }\n\n // React: check for review feedback on bot PRs (Gemini, humans, etc.)\n if (!options.dryRun) {\n const reviewJobs: RunningJob[] = [];\n\n for (const repo of Object.values(squadRepos)) {\n const prsWithFeedback = getPRsWithReviewFeedback(repo);\n for (const pr of prsWithFeedback) {\n // Find which squad owns this repo\n const squad = Object.entries(squadRepos).find(([, r]) => r === repo)?.[0];\n if (!squad) continue;\n\n // Check budget (0 = unlimited)\n if (options.budget > 0 && state.dailyCost >= options.budget) break;\n\n const task = buildReviewTask(pr);\n writeLine(` ${icons.running} Addressing ${pr.comments.length} review comment(s) on ${colors.cyan}${squad}${RESET} PR #${pr.number}`);\n\n const job = dispatchAgent(squad, 'issue-solver', task);\n reviewJobs.push(job);\n result.dispatched.push(`${squad}/issue-solver (review #${pr.number})`);\n }\n }\n\n // Wait for review-fix jobs\n if (reviewJobs.length > 0) {\n writeLine(` ${colors.dim}${reviewJobs.length} review-fix agent(s) running...${RESET}`);\n for (const job of reviewJobs) {\n const outcome = await waitForJob(job);\n const durationMs = Date.now() - job.startedAt;\n const durationMin = Math.floor(durationMs / 60000);\n\n if (outcome === 'completed') {\n result.completed.push(`${job.squad}/review-fix`);\n writeLine(` ${icons.success} ${colors.green}${job.squad}/review-fix${RESET} completed (${durationMin}m)`);\n } else {\n result.failed.push(`${job.squad}/review-fix`);\n writeLine(` ${icons.error} ${colors.red}${job.squad}/review-fix${RESET} ${outcome} (${durationMin}m)`);\n }\n\n state.dailyCost += 0.50;\n result.costEstimate += 0.50;\n }\n }\n }\n\n saveState(state);\n\n // Slack summary\n if (result.completed.length > 0 || result.failed.length > 0) {\n const summary = [\n `*Daemon cycle complete*`,\n result.completed.length > 0 ? `Completed: ${result.completed.join(', ')}` : '',\n result.failed.length > 0 ? `Failed: ${result.failed.join(', ')}` : '',\n `Est. cost: $${result.costEstimate.toFixed(2)} (daily: $${state.dailyCost.toFixed(2)}${options.budget > 0 ? '/$' + options.budget : ''})`,\n ].filter(Boolean).join('\\n');\n slackNotify(summary);\n }\n\n // Escalate persistent failures\n for (const [key, count] of Object.entries(state.failCounts)) {\n if (count >= 3) {\n slackNotify(`*Escalation*: ${key} has failed ${count} times consecutively. Needs human attention.`);\n }\n }\n\n return result;\n}\n\n// ── Command ──────────────────────────────────────────────────────────\n\nexport async function daemonCommand(options: {\n interval?: string;\n parallel?: string;\n dryRun?: boolean;\n verbose?: boolean;\n once?: boolean;\n budget?: string;\n}): Promise<void> {\n const config: DaemonOptions = {\n interval: parseInt(options.interval || '30', 10),\n maxParallel: parseInt(options.parallel || '2', 10),\n dryRun: options.dryRun || false,\n verbose: options.verbose || false,\n once: options.once || false,\n budget: parseFloat(options.budget || '0'),\n };\n\n writeLine();\n writeLine(` ${bold}squads daemon${RESET}`);\n const budgetLabel = config.budget > 0 ? `Budget: $${config.budget}/day` : 'Subscription (no budget limit)';\n writeLine(` ${colors.dim}Interval: ${config.interval}m | Parallel: ${config.maxParallel} | ${budgetLabel}${config.dryRun ? ' | DRY RUN' : ''}${RESET}`);\n writeLine();\n\n // First cycle\n const result = await runCycle(config);\n\n if (config.once) {\n writeLine();\n writeLine(` ${colors.dim}Single cycle complete. Dispatched: ${result.dispatched.length}, Completed: ${result.completed.length}, Failed: ${result.failed.length}${RESET}`);\n writeLine();\n return;\n }\n\n // Continuous loop\n writeLine();\n writeLine(` ${colors.dim}Next cycle in ${config.interval} minutes. Ctrl+C to stop.${RESET}`);\n\n const loop = async () => {\n while (true) {\n await new Promise(resolve => setTimeout(resolve, config.interval * 60 * 1000));\n writeLine();\n writeLine(` ${colors.dim}─── Cycle ${new Date().toISOString()} ───${RESET}`);\n await runCycle(config);\n writeLine(` ${colors.dim}Next cycle in ${config.interval} minutes.${RESET}`);\n }\n };\n\n await loop();\n}\n"],"mappings":"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","names":[]}
|