great-cto 3.38.0 → 3.40.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/board/.claude-plugin/plugin.json +1 -1
- package/board/packages/board/lib/data-readers.mjs +1 -1
- package/board/packages/board/public/index.html +11 -7
- package/board/scripts/lib/cost-meter.mjs +23 -5
- package/board/scripts/lib/gate-plan.mjs +1 -1
- package/dist/adapt.js +1 -1
- package/dist/main.js +8 -4
- package/dist/mcp.js +1 -1
- package/package.json +1 -1
|
@@ -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 71 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.40.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Alexander Velikiy",
|
|
7
7
|
"url": "https://hashnode.com/@Greatcto"
|
|
@@ -29,7 +29,7 @@ function getMemory(cwd = process.cwd()) {
|
|
|
29
29
|
{ id: 'skill', scope: 'project', layer: 'L1', name: 'SKILL.md', desc: 'Pipeline skill — synced from plugin', path: path.join(cwd, '.great_cto', 'SKILL.md') },
|
|
30
30
|
{ id: 'codebase', scope: 'project', layer: 'L2', name: 'CODEBASE.md', desc: 'God nodes, entry points, public API, routes', path: path.join(cwd, '.great_cto', 'CODEBASE.md') },
|
|
31
31
|
{ id: 'brain', scope: 'project', layer: 'L3', name: 'brain.md', desc: 'Patterns in use, what failed, team patterns', path: path.join(cwd, '.great_cto', 'brain.md') },
|
|
32
|
-
{ id: 'lessons', scope: 'project', layer: 'L3', name: 'lessons.md', desc: 'Per-project lessons (extracted by /learn)', path: path.join(cwd, '.great_cto', 'lessons.md') },
|
|
32
|
+
{ id: 'lessons', scope: 'project', layer: 'L3', name: 'lessons.md', desc: 'Per-project lessons (extracted by /crystallize learn)', path: path.join(cwd, '.great_cto', 'lessons.md') },
|
|
33
33
|
{ id: 'handoff', scope: 'project', layer: 'L3', name: 'HANDOFF.md', desc: 'Auto-written on context compaction', path: path.join(cwd, '.great_cto', 'HANDOFF.md') },
|
|
34
34
|
{ id: 'local', scope: 'project', layer: 'L3', name: 'local.md', desc: 'Project-local notes (gitignored)', path: path.join(cwd, '.great_cto', 'local.md') },
|
|
35
35
|
// Cross-project (~/.great_cto/) — L4 global memory shared across all projects
|
|
@@ -180,13 +180,17 @@
|
|
|
180
180
|
--accent-soft: rgba(0, 217, 126, 0.12);
|
|
181
181
|
--accent-strong: rgba(0, 168, 98, 0.20);
|
|
182
182
|
--accent-text: #097547;
|
|
183
|
-
/* The light theme's status colours are dark (#0a7d4d, #
|
|
184
|
-
so the ink that reads on the dark theme's bright ones fails here
|
|
185
|
-
|
|
183
|
+
/* The light theme's status colours are dark (#0a7d4d, #a64c08, #c43030),
|
|
184
|
+
so the ink that reads on the dark theme's bright ones fails here. White
|
|
185
|
+
gives 5.18, 5.74, 5.51. --status-progress was #b45309 until 3.40: as ink
|
|
186
|
+
on a tinted panel (#eef2f0, the harness judge scores) it measured 4.45:1,
|
|
187
|
+
under the 4.5 floor; #a64c08 is the --p1-fg ink and gives 5.08 there. */
|
|
186
188
|
--on-status: #fff;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
--status-
|
|
189
|
+
/* #6b7280 until 3.40: the backlog pill tints its own bed (slate at 18%) and
|
|
190
|
+
the grey on it measured 4.17:1. #5f6672 gives 4.99 there, 5.78 on white. */
|
|
191
|
+
--status-backlog: #5f6672;
|
|
192
|
+
--status-todo: #5f6672;
|
|
193
|
+
--status-progress: #a64c08;
|
|
190
194
|
--status-review: #0a7d4d;
|
|
191
195
|
/* Same split as --accent / --accent-text: this colour is a BED for tier
|
|
192
196
|
badges and a dot, and INK for approve buttons and budget chips. As ink it
|
|
@@ -1284,7 +1288,7 @@ h1, h2, h3, h4 { font-weight: 600; font-family: var(--sans); }
|
|
|
1284
1288
|
.pill-gate { background: rgba(124, 58, 237, 0.12); color: var(--status-gate); }
|
|
1285
1289
|
.pill-backlog { background: rgba(148, 163, 184, 0.18); color: var(--status-todo); }
|
|
1286
1290
|
.pill-in_progress { background: rgba(245, 158, 11, 0.16); color: var(--status-progress); }
|
|
1287
|
-
.pill-done { background: rgba(
|
|
1291
|
+
.pill-done { background: rgba(10, 125, 77, 0.12); color: var(--status-review-text); } /* was a blue bed under green ink: 4.26:1 on light; done is green, bed and ink agree now (4.94) */
|
|
1288
1292
|
.pill-blocked { background: rgba(220, 38, 38, 0.12); color: var(--status-blocked); }
|
|
1289
1293
|
.result-box {
|
|
1290
1294
|
margin-top: 14px;
|
|
@@ -161,6 +161,25 @@ export function resolvePrice(model, prices = effectivePrices()) {
|
|
|
161
161
|
*
|
|
162
162
|
* @returns {{usd:number, priced:boolean, assumed:boolean, source:string, model:string}}
|
|
163
163
|
*/
|
|
164
|
+
/**
|
|
165
|
+
* Cache-write dollars. Anthropic bills a 5-minute cache write at 1.25× the input
|
|
166
|
+
* price and a 1-hour write at 2×; `usage.cache_creation` splits the tokens by TTL
|
|
167
|
+
* (`ephemeral_5m_input_tokens` / `ephemeral_1h_input_tokens`). Pricing every write
|
|
168
|
+
* at 1.25× understated long sessions — Claude Code writes the 1-hour cache — which
|
|
169
|
+
* session-shape found on 2026-09-27. Without the split, the flat 1.25× stands.
|
|
170
|
+
*/
|
|
171
|
+
export function cacheWriteUsd(usage, inputPrice) {
|
|
172
|
+
const split = usage?.cache_creation;
|
|
173
|
+
const total = usage?.cache_creation_input_tokens || 0;
|
|
174
|
+
if (split && (split.ephemeral_1h_input_tokens != null || split.ephemeral_5m_input_tokens != null)) {
|
|
175
|
+
const h1 = split.ephemeral_1h_input_tokens || 0;
|
|
176
|
+
const m5 = split.ephemeral_5m_input_tokens || 0;
|
|
177
|
+
const rest = Math.max(0, total - h1 - m5); // any write the split does not name
|
|
178
|
+
return (h1 * 2 + (m5 + rest) * 1.25) * inputPrice;
|
|
179
|
+
}
|
|
180
|
+
return total * 1.25 * inputPrice;
|
|
181
|
+
}
|
|
182
|
+
|
|
164
183
|
export function priceUsage({ model, usage, prices }) {
|
|
165
184
|
const { price, source } = resolvePrice(model, prices || effectivePrices());
|
|
166
185
|
if (!usage || !price) {
|
|
@@ -168,10 +187,9 @@ export function priceUsage({ model, usage, prices }) {
|
|
|
168
187
|
}
|
|
169
188
|
const inTok = usage.input_tokens || 0;
|
|
170
189
|
const outTok = usage.output_tokens || 0;
|
|
171
|
-
const cacheWrite = usage.cache_creation_input_tokens || 0;
|
|
172
190
|
const cacheRead = usage.cache_read_input_tokens || 0;
|
|
173
191
|
const usd = (inTok * price.input + outTok * price.output
|
|
174
|
-
+
|
|
192
|
+
+ cacheWriteUsd(usage, price.input) + cacheRead * price.input * 0.1) / 1_000_000;
|
|
175
193
|
return { usd, priced: true, assumed: source === 'family', source, model: model || '' };
|
|
176
194
|
}
|
|
177
195
|
|
|
@@ -190,13 +208,13 @@ export function costForUsage({ model, usage, prices }) {
|
|
|
190
208
|
const inTok = usage.input_tokens || 0;
|
|
191
209
|
const outTok = usage.output_tokens || 0;
|
|
192
210
|
// Prompt-caching tokens bill at Anthropic's standard multipliers off the base
|
|
193
|
-
// input price: cache WRITE = 1.25× input
|
|
211
|
+
// input price: cache WRITE = 1.25× input (2× for the 1-hour TTL, see
|
|
212
|
+
// cacheWriteUsd), cache READ = 0.1× input. Ignoring
|
|
194
213
|
// them under-counts real spend badly (a cached turn is often 50k+ cache tokens
|
|
195
214
|
// vs a few hundred fresh input tokens).
|
|
196
|
-
const cacheWrite = usage.cache_creation_input_tokens || 0;
|
|
197
215
|
const cacheRead = usage.cache_read_input_tokens || 0;
|
|
198
216
|
return (inTok * p.input + outTok * p.output
|
|
199
|
-
+
|
|
217
|
+
+ cacheWriteUsd(usage, p.input) + cacheRead * p.input * 0.1) / 1_000_000;
|
|
200
218
|
}
|
|
201
219
|
|
|
202
220
|
export function round4(n) { return Math.round(n * 10000) / 10000; }
|
|
@@ -44,7 +44,7 @@ export function parseProject(text) {
|
|
|
44
44
|
// (qa runs tests, security runs secret/CVE scans, ship gates on CI green).
|
|
45
45
|
// R1 = text-only judgment — a human/reviewer reads and approves the direction.
|
|
46
46
|
// R2 gates are the moat: an enforced control, not a vibe. Surfacing the split lets
|
|
47
|
-
// /gov
|
|
47
|
+
// /digest gov measure how much of the pipeline is actually enforced vs prose.
|
|
48
48
|
const R2_GATES = new Set(['qa', 'security', 'ship']);
|
|
49
49
|
export function regimeOfGate(gate) { return R2_GATES.has(gate) ? 'R2' : 'R1'; }
|
|
50
50
|
|
package/dist/adapt.js
CHANGED
|
@@ -424,7 +424,7 @@ conventions. Generated by \`great-cto adapt\`.
|
|
|
424
424
|
- \`/spec\` — interview → requirements.md + design.md + tasks.md
|
|
425
425
|
- \`/start "..."\` — kick off a feature pipeline
|
|
426
426
|
- \`/inbox\` — see what needs your decision
|
|
427
|
-
- \`/agent
|
|
427
|
+
- \`/agent review\` — performance scorecard for agents
|
|
428
428
|
|
|
429
429
|
`;
|
|
430
430
|
if (writeFile(join(cwd, "AGENTS.md"), agentsBody, dryRun))
|
package/dist/main.js
CHANGED
|
@@ -154,9 +154,9 @@ function parseArgs(argv) {
|
|
|
154
154
|
// instead of a confusing usage error. These work only in the chat plugin.
|
|
155
155
|
else if (a === "start" || a === "audit" || a === "inbox" || a === "digest" ||
|
|
156
156
|
a === "review" || a === "doctor" || a === "burn" || a === "save" ||
|
|
157
|
-
a === "resume" || a === "learn" || a === "agent
|
|
158
|
-
a === "rfc" || a === "release" || a === "ownership" ||
|
|
159
|
-
a === "sec" || a === "poc" || a === "
|
|
157
|
+
a === "resume" || a === "learn" || a === "agent" ||
|
|
158
|
+
a === "rfc" || a === "release" || a === "ownership" ||
|
|
159
|
+
a === "sec" || a === "poc" || a === "crystallize" ||
|
|
160
160
|
a === "migrate") {
|
|
161
161
|
args.command = "chat-only-hint";
|
|
162
162
|
// Stash which command they tried so we can quote it back
|
|
@@ -1538,12 +1538,16 @@ async function main() {
|
|
|
1538
1538
|
}
|
|
1539
1539
|
if (args.command === "chat-only-hint") {
|
|
1540
1540
|
const tried = args._slashTried || "<command>";
|
|
1541
|
+
// 3.40 folded these into modes of another command — quote the command that
|
|
1542
|
+
// does the job now, not one the plugin no longer ships.
|
|
1543
|
+
const folded = { burn: "digest slo", learn: "crystallize learn", migrate: "doctor --fix" };
|
|
1544
|
+
const slash = folded[tried] ?? tried;
|
|
1541
1545
|
error(`'${tried}' is a chat slash command, not a CLI subcommand.`);
|
|
1542
1546
|
log("");
|
|
1543
1547
|
log(`To run it, open Claude Code, Cursor, or any AI assistant that has`);
|
|
1544
1548
|
log(`great_cto installed and type:`);
|
|
1545
1549
|
log("");
|
|
1546
|
-
log(` ${cyan("/" +
|
|
1550
|
+
log(` ${cyan("/" + slash)} ${dim("[args]")}`);
|
|
1547
1551
|
log("");
|
|
1548
1552
|
log(`The CLI surface (this command) only exposes:`);
|
|
1549
1553
|
log(` ${cyan("init")} · ${cyan("ci")} · ${cyan("mcp")} · ${cyan("adapt")} ·`);
|
package/dist/mcp.js
CHANGED
|
@@ -46,7 +46,7 @@ async function toolDetectArchetype(args) {
|
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
async function toolEstimateCost(args) {
|
|
49
|
-
// Rough heuristic — for production, agents call /cost feature directly.
|
|
49
|
+
// Rough heuristic — for production, agents call /digest cost feature directly.
|
|
50
50
|
// This is the LLM-host-friendly summary.
|
|
51
51
|
const scale = args.scale ?? "standard";
|
|
52
52
|
const minutesByScale = {
|
package/package.json
CHANGED