great-cto 3.37.1 → 3.39.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
- "description": "You already have the agent. This is everything around it. great_cto runs Claude Code as a pipeline of 70 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.37.1",
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.39.0",
5
5
  "author": {
6
6
  "name": "Alexander Velikiy",
7
7
  "url": "https://hashnode.com/@Greatcto"
@@ -159,9 +159,9 @@
159
159
  },
160
160
  {
161
161
  "type": "command",
162
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; INPUT=$(cat 2>/dev/null); if [ -z \"$INPUT\" ]; then exit 0; fi; CMD=$(echo \"$INPUT\" | python3 -c \"import sys,json; d=json.load(sys.stdin); print(d.get('command',''))\" 2>/dev/null); if [ -z \"$CMD\" ]; then exit 0; fi; if echo \"$CMD\" | grep -qiE '(^|[;&|[:space:]])rm[[:space:]]+(-[a-zA-Z]*r[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*r|--recursive)|(^|[;&|[:space:]])git[[:space:]]+(push[[:space:]].*(--force(-with-lease)?|-f([[:space:]]|$))|reset[[:space:]]+--hard)|(DROP[[:space:]]+(TABLE|DATABASE|SCHEMA))|(^|[;&|[:space:]])truncate[[:space:]]+--all|(^|[;&|[:space:]])(mkfs|dd)[[:space:]]|(^|[;&|[:space:]])chmod[[:space:]]+[0-7]*0{3}[[:space:]]|curl[[:space:]]+.*[|][[:space:]]*(sudo|sh|bash|zsh|python[23]?|perl|ruby)'; then echo \"BLOCKED: Dangerous command pattern detected.\"; exit 2; fi; exit 0",
162
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/destructive-guard.mjs\"; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
163
163
  "timeout": 5,
164
- "statusMessage": "Safety check..."
164
+ "statusMessage": "Destructive-command check..."
165
165
  }
166
166
  ]
167
167
  },
@@ -201,7 +201,7 @@
201
201
  "hooks": [
202
202
  {
203
203
  "type": "command",
204
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; INPUT=$(cat 2>/dev/null); FILE=$(echo \"$INPUT\" | python3 -c \"import sys,json; d=json.load(sys.stdin); print(d.get('file_path',''))\" 2>/dev/null); TOOL=$(echo \"$INPUT\" | python3 -c \"import sys,json; d=json.load(sys.stdin); print(d.get('tool_name',''))\" 2>/dev/null); if [ -n \"$FILE\" ]; then mkdir -p .great_cto 2>/dev/null; printf '%s %s %s\\n' \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" \"$TOOL\" \"$FILE\" >> .great_cto/agent-writes.log 2>/dev/null; fi; true",
204
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; INPUT=$(cat 2>/dev/null); FILE=$(echo \"$INPUT\" | python3 -c \"import sys,json; d=json.load(sys.stdin); print((d.get('tool_input') or {}).get('file_path') or d.get('file_path',''))\" 2>/dev/null); TOOL=$(echo \"$INPUT\" | python3 -c \"import sys,json; d=json.load(sys.stdin); print(d.get('tool_name',''))\" 2>/dev/null); if [ -n \"$FILE\" ]; then mkdir -p .great_cto 2>/dev/null; printf '%s %s %s\\n' \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" \"$TOOL\" \"$FILE\" >> .great_cto/agent-writes.log 2>/dev/null; fi; true",
205
205
  "timeout": 3,
206
206
  "async": true
207
207
  },
@@ -211,6 +211,11 @@
211
211
  "timeout": 12,
212
212
  "async": true
213
213
  },
214
+ {
215
+ "type": "command",
216
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/typecheck-accumulate.mjs\" 2>/dev/null; true",
217
+ "timeout": 5
218
+ },
214
219
  {
215
220
  "type": "command",
216
221
  "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/summary-enforce.mjs\" 2>/dev/null; true",
@@ -244,6 +249,11 @@
244
249
  "timeout": 3,
245
250
  "statusMessage": "Capturing tool failure...",
246
251
  "async": true
252
+ },
253
+ {
254
+ "type": "command",
255
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/loop-detector.mjs\" 2>/dev/null || true",
256
+ "timeout": 3
247
257
  }
248
258
  ]
249
259
  },
@@ -327,6 +337,11 @@
327
337
  "type": "command",
328
338
  "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/cross-review-gate.mjs\" 2>/dev/null || true"
329
339
  },
340
+ {
341
+ "type": "command",
342
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/stop-typecheck.mjs\" 2>/dev/null || true",
343
+ "timeout": 90
344
+ },
330
345
  {
331
346
  "type": "command",
332
347
  "async": true,
@@ -370,6 +385,7 @@
370
385
  "./agents-full/app-scaffolder.md",
371
386
  "./agents-full/architect.md",
372
387
  "./agents-full/auth-engineer.md",
388
+ "./agents-full/ci-resolver.md",
373
389
  "./agents-full/cli-reviewer.md",
374
390
  "./agents-full/cmmc-reviewer.md",
375
391
  "./agents-full/cms-reviewer.md",
@@ -5929,7 +5929,7 @@ async function renderHarnesses() {
5929
5929
 
5930
5930
  body.innerHTML = `
5931
5931
  <div class="mp-card harness-hosts">
5932
- <div><span class="dot ok"></span><b>Claude Code</b> <span class="mono cap muted">host · v${esc(h.claude_code?.version || '')}</span><span class="cap muted" style="margin-left:auto" title="70 agents · commands · skills · hooks">full pipeline</span></div>
5932
+ <div><span class="dot ok"></span><b>Claude Code</b> <span class="mono cap muted">host · v${esc(h.claude_code?.version || '')}</span><span class="cap muted" style="margin-left:auto" title="71 agents · commands · skills · hooks">full pipeline</span></div>
5933
5933
  <div><span class="${codexDot}"></span><b>OpenAI Codex</b> <span class="mono cap">${codexState}</span>${cx.version ? `<span class="mono cap muted">${esc(cx.version)}</span>` : ''}${cx.model ? `<span class="mono cap muted" style="margin-left:auto">${esc(cx.model)}</span>` : ''}</div>
5934
5934
  </div>
5935
5935
  <div class="mp-card" style="margin-top:12px">
@@ -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; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "3.37.1",
3
+ "version": "3.39.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",