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.
@@ -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.38.0",
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, #b45309, #c43030),
184
- so the ink that reads on the dark theme's bright ones fails here: 3.45,
185
- 3.56, 3.24. White gives 5.18, 5.02, 5.51. */
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
- --status-backlog: #6b7280;
188
- --status-todo: #6b7280;
189
- --status-progress: #b45309;
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(37, 99, 235, 0.14); color: var(--status-done); }
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
- + cacheWrite * price.input * 1.25 + cacheRead * price.input * 0.1) / 1_000_000;
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, cache READ = 0.1× input. Ignoring
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
- + cacheWrite * p.input * 1.25 + cacheRead * p.input * 0.1) / 1_000_000;
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-metrics measure how much of the pipeline is actually enforced vs prose.
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-review\` — performance scorecard for agents
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-review" || a === "agent-retire" ||
158
- a === "rfc" || a === "release" || a === "ownership" || a === "oncall" ||
159
- a === "sec" || a === "poc" || a === "promote" || a === "crystallize" ||
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("/" + tried)} ${dim("[args]")}`);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "3.38.0",
3
+ "version": "3.40.0",
4
4
  "description": "One command install for the great_cto Claude Code plugin. Auto-detects your stack, picks the right archetype, bootstraps PROJECT.md.",
5
5
  "keywords": [
6
6
  "claude-code",