great-cto 3.55.0 → 3.56.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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "great-cto",
|
|
3
3
|
"description": "You already have the agent. This is everything around it. great_cto runs Claude Code as a pipeline of 72 specialist agents \u2014 an independent model checks each stage before the next builds on it, spending caps refuse rather than warn, and three decisions stay yours: what gets built, how, and whether it ships.",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.56.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Alexander Velikiy",
|
|
7
7
|
"url": "https://hashnode.com/@Greatcto"
|
|
@@ -6296,16 +6296,19 @@ function usageAgentsCard(d) {
|
|
|
6296
6296
|
const rate = a.stopRate == null ? absent('none', 'no run of this agent reached a conclusion in this period') : `<span class="usage-rate" aria-hidden="true"><span style="width:${Math.round(a.stopRate * 100)}%"></span></span>${Math.round(a.stopRate * 100)}%`;
|
|
6297
6297
|
const disp = dispatched[a.agent];
|
|
6298
6298
|
const gap = disp != null && disp > a.runs ? ` title="${esc(`dispatched ${disp} times in Claude Code, ${a.runs} verdicts recorded — the rest ran without one`)}"` : '';
|
|
6299
|
-
|
|
6299
|
+
const nv = a.noVerdictTotal || 0;
|
|
6300
|
+
const why = Object.entries(a.noVerdict || {}).map(([k, n]) => `${n} ${k === 'reported' ? 'finished without recording one' : k === 'cut-off' ? 'cut off mid-run' : 'ended, shape unknown'}`).join(', ');
|
|
6301
|
+
const noVerdict = nv ? `<span title="${esc(why)}">${nv}</span>` : '0';
|
|
6302
|
+
return `<tr><td>${esc(a.agent)}</td><td class="num">${a.runs}</td><td class="num">${a.pass}</td><td class="num">${a.stopped}</td><td class="num">${a.failed}</td><td class="num">${rate}</td><td class="num">${noVerdict}</td><td class="num"${gap}>${disp == null ? '—' : disp}</td></tr>`;
|
|
6300
6303
|
}).join('');
|
|
6301
6304
|
const notes = [];
|
|
6302
6305
|
if (A.agents.some((a) => a.unknown)) notes.push(`${A.agents.reduce((n, a) => n + a.unknown, 0)} verdicts used a word no rule classifies — counted as runs, not as passes.`);
|
|
6303
6306
|
if (A.other && A.other.runs) notes.push(`${A.other.runs} verdicts from names outside great_cto's roster (${esc(A.other.names.slice(0, 4).join(', '))}) are not shown.`);
|
|
6304
6307
|
if (A.unreadable) notes.push(`${A.unreadable} verdict files could not be read.`);
|
|
6305
6308
|
return `<section class="usage-card" data-outcomes="agents">${head}<div class="usage-table-wrap"><table class="usage-table">
|
|
6306
|
-
<thead><tr><th>Agent</th><th class="num">Verdicts</th><th class="num">Pass</th><th class="num">Stopped</th><th class="num">Failed</th><th class="num">Stop rate</th><th class="num" title="Agent dispatches seen in Claude Code's logs in the same period">Dispatched</th></tr></thead>
|
|
6309
|
+
<thead><tr><th>Agent</th><th class="num">Verdicts</th><th class="num">Pass</th><th class="num">Stopped</th><th class="num">Failed</th><th class="num">Stop rate</th><th class="num" title="Runs the completion check saw end with no verdict — hover a number for how they ended">No verdict</th><th class="num" title="Agent dispatches seen in Claude Code's logs in the same period">Dispatched</th></tr></thead>
|
|
6307
6310
|
<tbody>${rows}</tbody></table></div>
|
|
6308
|
-
<p class="usage-sub">Stopped = BLOCKED, REWORK, REJECTED, ESCALATED — the pipeline halted on the agent's word. Stop rate is of the verdicts that concluded.${notes.length ? ` ${notes.join(' ')}` : ''}</p></section>`;
|
|
6311
|
+
<p class="usage-sub">Stopped = BLOCKED, REWORK, REJECTED, ESCALATED — the pipeline halted on the agent's word. Stop rate is of the verdicts that concluded. No verdict counts runs that ended without one, as the completion check recorded them (from 3.56).${notes.length ? ` ${notes.join(' ')}` : ''}</p></section>`;
|
|
6309
6312
|
}
|
|
6310
6313
|
|
|
6311
6314
|
function usageFindingsCard(d) {
|
|
@@ -85,7 +85,7 @@ export function agentOutcomes({ projects, globalDir = path.join(os.homedir(), '.
|
|
|
85
85
|
seen.add(key);
|
|
86
86
|
const agent = verdictAgent(rec.agent || fileAgent) || fileAgent;
|
|
87
87
|
if (known.size && !known.has(agent)) { other.runs++; other.names.add(agent); continue; }
|
|
88
|
-
const a = agents[agent] || (agents[agent] =
|
|
88
|
+
const a = agents[agent] || (agents[agent] = blankAgent(agent));
|
|
89
89
|
a.runs++;
|
|
90
90
|
a[outcomeOf(rec.verdict)]++;
|
|
91
91
|
if (rec.meta?.need === 'implementer') a.needImplementer++;
|
|
@@ -96,15 +96,39 @@ export function agentOutcomes({ projects, globalDir = path.join(os.homedir(), '.
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
+
// How runs ENDED, from the completion hook's agent-stop events: a run that
|
|
100
|
+
// recorded nothing leaves no verdict line, so only these can count it.
|
|
101
|
+
for (const p of projects) {
|
|
102
|
+
let text = '';
|
|
103
|
+
try { text = fs.readFileSync(path.join(p.path, '.great_cto', 'events.jsonl'), 'utf8'); } catch { continue; }
|
|
104
|
+
for (const line of text.split('\n')) {
|
|
105
|
+
if (!line.includes('"agent-stop"') || !line.includes('no-verdict')) continue;
|
|
106
|
+
let e;
|
|
107
|
+
try { e = JSON.parse(line); } catch { continue; }
|
|
108
|
+
const t = Date.parse(e.ts);
|
|
109
|
+
if (!Number.isFinite(t) || t < from || t > now || !/^no-verdict-/.test(e.outcome || '')) continue;
|
|
110
|
+
const agent = verdictAgent(e.agent);
|
|
111
|
+
if (!agent || (known.size && !known.has(agent))) continue;
|
|
112
|
+
const a = agents[agent] || (agents[agent] = blankAgent(agent));
|
|
113
|
+
const why = e.outcome.slice('no-verdict-'.length);
|
|
114
|
+
a.noVerdict[why] = (a.noVerdict[why] || 0) + 1;
|
|
115
|
+
a.noVerdictTotal++;
|
|
116
|
+
a.projects.add(p.name);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
99
119
|
const rows = Object.values(agents).map((a) => ({
|
|
100
120
|
...a,
|
|
101
121
|
projects: a.projects.size,
|
|
102
122
|
// Of the runs that reached a conclusion, how many stopped the pipeline.
|
|
103
123
|
stopRate: a.pass + a.stopped + a.failed ? (a.stopped + a.failed) / (a.pass + a.stopped + a.failed) : null,
|
|
104
|
-
})).sort((x, y) => y.runs - x.runs);
|
|
124
|
+
})).sort((x, y) => (y.runs + y.noVerdictTotal) - (x.runs + x.noVerdictTotal));
|
|
105
125
|
return { agents: rows, other: { runs: other.runs, names: [...other.names].sort().slice(0, 20) }, unreadable };
|
|
106
126
|
}
|
|
107
127
|
|
|
128
|
+
function blankAgent(agent) {
|
|
129
|
+
return { agent, runs: 0, pass: 0, stopped: 0, failed: 0, skipped: 0, unknown: 0, needImplementer: 0, needDecision: 0, noVerdict: {}, noVerdictTotal: 0, last: null, projects: new Set() };
|
|
130
|
+
}
|
|
131
|
+
|
|
108
132
|
/** Run `bd` in a project; resolves to parsed JSON or a reason it could not. */
|
|
109
133
|
function bdJson(cwd, args, { timeoutMs = 20000, bin = 'bd' } = {}) {
|
|
110
134
|
return new Promise((resolve) => {
|
package/package.json
CHANGED