great-cto 2.10.2 → 2.11.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/dist/mcp.js +157 -0
- package/package.json +1 -1
package/dist/mcp.js
CHANGED
|
@@ -126,6 +126,112 @@ function toolQueryDecisions(args) {
|
|
|
126
126
|
}),
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
|
+
// ── Board tools — call the running board HTTP API ─────────────────────────
|
|
130
|
+
// Board port: $GREAT_CTO_PORT (default 3141).
|
|
131
|
+
const BOARD_PORT = parseInt(process.env.GREAT_CTO_PORT ?? "3141", 10);
|
|
132
|
+
const BOARD_BASE = `http://127.0.0.1:${BOARD_PORT}`;
|
|
133
|
+
async function boardFetch(path) {
|
|
134
|
+
try {
|
|
135
|
+
const res = await fetch(`${BOARD_BASE}${path}`);
|
|
136
|
+
if (!res.ok)
|
|
137
|
+
throw new Error(`HTTP ${res.status}`);
|
|
138
|
+
return res.json();
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
throw new Error(`Board unreachable at ${BOARD_BASE} — run \`great-cto board\` first. (${e.message})`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function boardPqs(project) {
|
|
145
|
+
return project ? `?project=${encodeURIComponent(project)}` : "";
|
|
146
|
+
}
|
|
147
|
+
async function toolProjectStatus(args) {
|
|
148
|
+
const qs = boardPqs(args.project);
|
|
149
|
+
const [inbox, metrics] = await Promise.all([
|
|
150
|
+
boardFetch(`/api/inbox${qs}`),
|
|
151
|
+
boardFetch(`/api/metrics${qs}`),
|
|
152
|
+
]);
|
|
153
|
+
const s = inbox.summary ?? {};
|
|
154
|
+
const lines = [
|
|
155
|
+
`## Project status${args.project ? ` — ${args.project}` : ""}`,
|
|
156
|
+
"",
|
|
157
|
+
`**Open gates:** ${s.gates ?? 0}`,
|
|
158
|
+
`**Blocked tasks:** ${s.blocked ?? 0}`,
|
|
159
|
+
`**P0 incidents:** ${s.p0 ?? 0}`,
|
|
160
|
+
`**Stale in-progress:** ${s.stale ?? 0}`,
|
|
161
|
+
];
|
|
162
|
+
if ((inbox.pending_gates ?? []).length > 0) {
|
|
163
|
+
lines.push("", "### Gates awaiting approval");
|
|
164
|
+
for (const g of inbox.pending_gates.slice(0, 5)) {
|
|
165
|
+
lines.push(`- **${g.id}** ${g.title} _(${g.status})_`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if ((inbox.blocked ?? []).length > 0) {
|
|
169
|
+
lines.push("", "### Blocked tasks");
|
|
170
|
+
for (const b of inbox.blocked.slice(0, 5)) {
|
|
171
|
+
lines.push(`- **${b.id}** ${b.title}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (metrics) {
|
|
175
|
+
lines.push("", `**Tasks:** ${metrics.done ?? 0}/${metrics.total ?? 0} done`);
|
|
176
|
+
}
|
|
177
|
+
return lines.join("\n");
|
|
178
|
+
}
|
|
179
|
+
async function toolCostSummary(args) {
|
|
180
|
+
const days = Math.min(365, Math.max(1, args.days ?? 30));
|
|
181
|
+
const qs = boardPqs(args.project);
|
|
182
|
+
const d = await boardFetch(`/api/cost${qs}${qs ? "&" : "?"}days=${days}`);
|
|
183
|
+
const lines = [
|
|
184
|
+
`## Cost summary${args.project ? ` — ${args.project}` : ""} (last ${days} days)`,
|
|
185
|
+
"",
|
|
186
|
+
`**Total LLM spend:** $${(d.total_llm ?? 0).toFixed(2)}`,
|
|
187
|
+
`**Daily burn:** $${(d.daily_avg ?? 0).toFixed(2)}/day`,
|
|
188
|
+
`**Projected monthly:** $${(d.projected_monthly ?? 0).toFixed(0)}`,
|
|
189
|
+
];
|
|
190
|
+
if (d.monthly_budget) {
|
|
191
|
+
const status = d.over_budget ? "⚠️ OVER BUDGET" : "✅ within budget";
|
|
192
|
+
lines.push(`**Budget:** $${d.monthly_budget}/month — ${status}`);
|
|
193
|
+
}
|
|
194
|
+
if (d.savings_x)
|
|
195
|
+
lines.push(`**vs Human team:** ${d.savings_x}× cheaper`);
|
|
196
|
+
if ((d.by_feature ?? []).length > 0) {
|
|
197
|
+
lines.push("", "### Top features by AI spend");
|
|
198
|
+
for (const f of d.by_feature.slice(0, 8)) {
|
|
199
|
+
lines.push(`- **${f.feature}**: $${f.llm.toFixed(2)} (${f.runs} runs)`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return lines.join("\n");
|
|
203
|
+
}
|
|
204
|
+
async function toolPipelineStages(args) {
|
|
205
|
+
const stages = await boardFetch(`/api/pipeline${boardPqs(args.project)}`);
|
|
206
|
+
const lines = [
|
|
207
|
+
`## Pipeline stages${args.project ? ` — ${args.project}` : ""}`,
|
|
208
|
+
"",
|
|
209
|
+
"| Stage | Status | Verdict | Last run |",
|
|
210
|
+
"|---|---|---|---|",
|
|
211
|
+
];
|
|
212
|
+
for (const s of stages ?? []) {
|
|
213
|
+
lines.push(`| ${s.stage} | ${s.status ?? "idle"} | ${s.verdict ?? "—"} | ${(s.last_ts ?? "—").slice(0, 16)} |`);
|
|
214
|
+
}
|
|
215
|
+
return lines.join("\n");
|
|
216
|
+
}
|
|
217
|
+
async function toolRecentVerdicts(args) {
|
|
218
|
+
const limit = Math.min(50, Math.max(1, args.limit ?? 10));
|
|
219
|
+
const data = await boardFetch(`/api/metrics${boardPqs(args.project)}`);
|
|
220
|
+
const verdicts = (data.verdicts ?? []).slice(-limit).reverse();
|
|
221
|
+
if (verdicts.length === 0)
|
|
222
|
+
return "No recent verdicts found.";
|
|
223
|
+
const lines = [
|
|
224
|
+
`## Recent verdicts${args.project ? ` — ${args.project}` : ""} (last ${verdicts.length})`,
|
|
225
|
+
"",
|
|
226
|
+
"| Time | Agent | Verdict | Cost |",
|
|
227
|
+
"|---|---|---|---|",
|
|
228
|
+
];
|
|
229
|
+
for (const v of verdicts) {
|
|
230
|
+
const cost = v.cost_usd != null ? `$${v.cost_usd.toFixed(2)}` : "—";
|
|
231
|
+
lines.push(`| ${(v.ts ?? "").slice(0, 16)} | ${v.agent ?? "—"} | ${v.verdict ?? "—"} | ${cost} |`);
|
|
232
|
+
}
|
|
233
|
+
return lines.join("\n");
|
|
234
|
+
}
|
|
129
235
|
// ── Tool dispatch table ────────────────────────────────────────────────────
|
|
130
236
|
const TOOLS = [
|
|
131
237
|
{
|
|
@@ -194,6 +300,57 @@ const TOOLS = [
|
|
|
194
300
|
},
|
|
195
301
|
handler: toolQueryDecisions,
|
|
196
302
|
},
|
|
303
|
+
// ── Board tools (require running board at $GREAT_CTO_PORT / 3141) ────────
|
|
304
|
+
{
|
|
305
|
+
name: "project_status",
|
|
306
|
+
description: "Get current pipeline status from the great_cto board: open gates awaiting approval, blocked tasks, P0 incidents, and in-progress work. " +
|
|
307
|
+
"Use this before starting expensive agent tasks to check for blockers. Requires `great-cto board` running.",
|
|
308
|
+
inputSchema: {
|
|
309
|
+
type: "object",
|
|
310
|
+
properties: {
|
|
311
|
+
project: { type: "string", description: "Project slug (optional, defaults to board's active project)" },
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
handler: toolProjectStatus,
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
name: "cost_summary",
|
|
318
|
+
description: "Get AI agent LLM spend from the board: total cost, daily burn rate, projected monthly cost, budget status, " +
|
|
319
|
+
"and cost broken down by feature. Use to check budget before spawning resource-intensive agents. Requires `great-cto board` running.",
|
|
320
|
+
inputSchema: {
|
|
321
|
+
type: "object",
|
|
322
|
+
properties: {
|
|
323
|
+
days: { type: "number", description: "Window in days: 1, 7, 30, 90, 365 (default: 30)" },
|
|
324
|
+
project: { type: "string", description: "Project slug (optional)" },
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
handler: toolCostSummary,
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: "pipeline_stages",
|
|
331
|
+
description: "Get full pipeline stage list with status (idle/done/failed) and last agent verdict. " +
|
|
332
|
+
"Shows which stage the current feature is at and what each agent last decided. Requires `great-cto board` running.",
|
|
333
|
+
inputSchema: {
|
|
334
|
+
type: "object",
|
|
335
|
+
properties: {
|
|
336
|
+
project: { type: "string", description: "Project slug (optional)" },
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
handler: toolPipelineStages,
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: "recent_verdicts",
|
|
343
|
+
description: "Get the most recent agent verdict lines from the board: timestamps, agent names, verdict values (APPROVED/DONE/BLOCKED), and costs. " +
|
|
344
|
+
"Quick recap of what agents have done recently. Requires `great-cto board` running.",
|
|
345
|
+
inputSchema: {
|
|
346
|
+
type: "object",
|
|
347
|
+
properties: {
|
|
348
|
+
limit: { type: "number", description: "Number of verdicts to return (1–50, default: 10)" },
|
|
349
|
+
project: { type: "string", description: "Project slug (optional)" },
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
handler: toolRecentVerdicts,
|
|
353
|
+
},
|
|
197
354
|
];
|
|
198
355
|
// ── JSON-RPC handler ───────────────────────────────────────────────────────
|
|
199
356
|
async function handle(req) {
|
package/package.json
CHANGED