great-cto 3.24.0 → 3.25.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 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.24.0",
4
+ "version": "3.25.0",
5
5
  "author": {
6
6
  "name": "Alexander Velikiy",
7
7
  "url": "https://hashnode.com/@Greatcto"
@@ -11,7 +11,7 @@
11
11
  //
12
12
  // Pairs with change-tier.mjs (the tier) + gate-plan.mjs (per-change plan) + ADR-004.
13
13
 
14
- export const DEFAULT_FRONTIER_JUDGE = 'claude-opus-4-8';
14
+ export const DEFAULT_FRONTIER_JUDGE = 'claude-opus-5';
15
15
  export const DEFAULT_CHEAP_JUDGE = 'claude-haiku-4-5';
16
16
 
17
17
  /**
package/dist/adapt.js CHANGED
@@ -9,6 +9,7 @@
9
9
  // great-cto adapt --dry-run Show what would be written
10
10
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
11
11
  import { dirname, join } from "node:path";
12
+ import { codexInstallPlan } from "./codex.js";
12
13
  const VALID_AI_TOOLS = ["claude-code", "cursor", "copilot", "windsurf", "aider", "codex"];
13
14
  function parseAiTools(text) {
14
15
  const line = text.match(/^ai_tools:\s*(.+)$/m)?.[1] ?? "";
@@ -309,134 +310,68 @@ dirty-commits: false
309
310
  `;
310
311
  }
311
312
  // ── Codex adapter helpers ──────────────────────────────────────────────────
313
+ // `getCodexHooksJson` used to live here, and `adapt` wrote its output to
314
+ // `.codex/hooks.json`. Six tests certified its shape — the split between
315
+ // blocking and advisory wrappers, the matchers covering `apply_patch` — and all
316
+ // six passed while the file went to a path Codex does not read.
317
+ //
318
+ // Two upstream issues settle it (openai/codex #16430, #39895): hooks load from
319
+ // the config layer only, a plugin cannot carry them, and the `hooks` field is
320
+ // read by nothing "with no warning, error, or log line". `.codex/hooks.json`,
321
+ // project-scoped, was never even the config layer. See
322
+ // docs/analysis/2026-09-05-codex-phase0-findings.md.
323
+ //
324
+ // So the generator is gone rather than corrected. A tested generator writing to
325
+ // a path nothing reads is the exact defect this repository exists to delete: it
326
+ // looked more finished than an absent one.
312
327
  /**
313
- * hooks.json content for ~/.codex/skills/great_cto/hooks.json.
314
- *
315
- * Phase 0 findings (2026-06-04, confirmed against Codex Desktop binary):
316
- * - Hook events: PreToolUse, PostToolUse, SessionStart, SubagentStart,
317
- * SubagentStop, PreCompact, PostCompact, UserPromptSubmit, PermissionRequest.
318
- * - stdin payload: same keys as Claude Code (tool_name, tool_input, is_error).
319
- * - block/deny: hookSpecificOutput.permissionDecision (same struct as CC)
320
- * confirmed by binary string literals.
321
- * - Hooks enabled by [features].hooks = true in config.toml.
322
- *
323
- * @param skillDir - absolute path to ~/.codex/skills/great_cto (used to build hook commands)
324
- */
325
- /**
326
- * hooks.json for Codex.
328
+ * The config.toml fragment for Codex — only the part that runs.
327
329
  *
328
- * Codex implements our hook contract exactly same events, same wire format,
329
- * and `permissionDecision` takes `allow | deny | ask`, the words we already
330
- * write. No translation layer is needed; see
331
- * docs/analysis/2026-09-05-codex-phase0-findings.md.
330
+ * What this used to emit, and why each line is gone:
332
331
  *
333
- * What needed care is the shell wrapper. Every command here was written as
334
- * `node "…" 2>/dev/null || true`, which swallows the exit code AND the reason.
335
- * On secret-scan a BLOCKING guard — that produced a guard that cannot block
336
- * and cannot say why: it would have reported clean on every write.
332
+ * [features] hooks = true turns on a feature a plugin cannot reach
333
+ * (openai/codex#16430) and which has an open
334
+ * timeout regression on 0.148.0+ (#42279)
335
+ * CODEX_SKILL_DIR = ~/.codex/skills/great_cto
336
+ * a path a working Codex install does not have;
337
+ * Phase 0 checked, the directory is not created
338
+ * [agents.great_cto_*] six role descriptions presented as "the
339
+ * specialist fleet", with a comment claiming
340
+ * "full 57-agent routing" — we ship seventy, and
341
+ * Codex routes none of them
337
342
  *
338
- * So the wrapper is now split by intent, and the test pins both halves:
339
- *
340
- * MATCHERS carry both hosts' tool names. Codex writes through `apply_patch` and
341
- * runs commands through `shell`; the Claude Code names are `edit`/`write`/
342
- * `str_replace_editor`. This was found by running it: Codex wrote a file
343
- * containing an API key and secret-scan never fired — the hook was correct, it
344
- * was never called. A matcher that matches nothing looks exactly like a guard
345
- * that passed.
346
- * blocking (secret-scan) bare, so a non-zero exit reaches Codex
347
- * advisory (format-check, tool-failure) keeps `|| true` — a formatter that
348
- * dies must not stop the user's write
349
- */
350
- export function getCodexHooksJson(skillDir) {
351
- const s = skillDir; // shorthand
352
- return JSON.stringify({
353
- "SessionStart": [
354
- {
355
- "hooks": [
356
- { "command": `node "${s}/scripts/hooks/quota-check.mjs" 2>/dev/null || true`, "timeout": 15 }
357
- ]
358
- }
359
- ],
360
- "PreToolUse": [
361
- {
362
- "matcher": "computer|bash|shell",
363
- "hooks": [
364
- { "command": `node "${s}/scripts/hooks/orchestrator-check.mjs" 2>/dev/null || true`, "timeout": 5 },
365
- { "command": `node "${s}/scripts/hooks/cost-guard.mjs" 2>/dev/null || true`, "timeout": 5 }
366
- ]
367
- },
368
- {
369
- "matcher": "edit|write|str_replace_editor|computer|apply_patch",
370
- "hooks": [
371
- { "command": `node "${s}/scripts/hooks/secret-scan.mjs"`, "timeout": 8 }
372
- ]
373
- }
374
- ],
375
- "PostToolUse": [
376
- {
377
- "matcher": "edit|write|str_replace_editor|apply_patch",
378
- "hooks": [
379
- { "command": `node "${s}/scripts/hooks/format-check.mjs" 2>/dev/null; true`, "timeout": 12, "async": true },
380
- { "command": `node "${s}/scripts/hooks/tool-failure.mjs" 2>/dev/null || true`, "timeout": 3, "async": true }
381
- ]
382
- },
383
- {
384
- "matcher": "",
385
- "hooks": [
386
- { "command": `node "${s}/scripts/hooks/tool-failure.mjs" 2>/dev/null || true`, "timeout": 3, "async": true }
387
- ]
388
- }
389
- ]
390
- }, null, 2);
391
- }
392
- /**
393
- * config.toml fragment to merge into ~/.codex/config.toml.
394
- * Adds: [features].hooks=true, [mcp_servers.great_cto], [agents.great_cto_skill].
395
- * Written as a separate file (.codex/great_cto.toml) since merging TOML is
396
- * non-trivial; installer prints merge instructions.
343
+ * An MCP server is the one thing here Codex actually starts, so it is the one
344
+ * thing left. The rest of the fragment is now a statement of what does NOT come
345
+ * with it, taken from `codexInstallPlan` so the two cannot drift apart again —
346
+ * which is precisely how they drifted the first time.
397
347
  */
398
348
  function getCodexConfigFragment(meta) {
399
- return `# great_cto Codex integration generated by great-cto adapt
400
- # Merge this into ~/.codex/config.toml or copy the sections manually.
349
+ const plan = codexInstallPlan({ repoDir: "<path-to-great_cto>", codexOnPath: true });
350
+ const notes = plan.notSupported.map((n) => `# - ${n}`).join("\n");
351
+ return `# great_cto ⇄ Codex — generated by great-cto adapt
401
352
  # Generated: ${new Date().toISOString().slice(0, 10)}
402
-
403
- [features]
404
- hooks = true
353
+ #
354
+ # This file contains ONE section, because one section is what Codex runs from a
355
+ # config fragment. Merge it into ~/.codex/config.toml.
356
+ #
357
+ # For skills, install the plugin instead of copying anything by hand:
358
+ # ${plan.commands.join("\n# ")}
359
+ #
360
+ # What does NOT come with either, on codex-cli as it stands today:
361
+ ${notes}
362
+ #
363
+ # Details, measured rather than inferred:
364
+ # docs/analysis/2026-09-05-codex-phase0-findings.md
405
365
 
406
366
  [mcp_servers.great_cto]
407
367
  command = "npx"
408
368
  args = ["great-cto@latest", "mcp"]
409
- # Set startup timeout generously — npx downloads on first run
369
+ # Generous: npx downloads on first run.
410
370
  startup_timeout_sec = 60
411
371
 
412
- [mcp_servers.great_cto.env]
413
- # Point hooks at the skill dir so hook scripts resolve correctly.
414
- CODEX_SKILL_DIR = "${process.env.HOME ?? "~"}/.codex/skills/great_cto"
415
-
416
- # Agents exposed via MCP (great_cto specialist fleet)
417
- # Codex will use these as subagent personalities via the [agents] table.
418
- # Full 57-agent routing is handled inside AGENTS.md / SKILL.md.
419
- [agents.great_cto_architect]
420
- description = "Deep architectural reasoning, ADRs, cross-cutting design decisions"
421
-
422
- [agents.great_cto_senior_dev]
423
- description = "Feature implementation with TDD — RED→GREEN→REFACTOR"
424
-
425
- [agents.great_cto_qa_engineer]
426
- description = "QA reports, coverage, regression check after implementation"
427
-
428
- [agents.great_cto_security_officer]
429
- description = "Security audit — OWASP Top 10, auth, PII, secrets"
430
-
431
- [agents.great_cto_devops]
432
- description = "Deploy, canary rollout, rollback, SLO monitoring"
433
-
434
- [agents.great_cto_pm]
435
- description = "Feature decomposition into tasks, timeline, dependency graph"
436
-
437
372
  # Archetype: ${meta.archetype}
438
373
  # Compliance: ${meta.compliance.join(", ") || "none"}
439
- # Re-run great-cto adapt --platform codex to refresh.
374
+ # Re-run great-cto adapt to refresh.
440
375
  `;
441
376
  }
442
377
  function getCliVersion() {
@@ -524,17 +459,30 @@ conventions. Generated by \`great-cto adapt\`.
524
459
  break;
525
460
  }
526
461
  case "codex": {
527
- // Write hooks.json + config.toml fragment to .codex/ (project-scoped, trusted)
528
- const defaultSkillDir = `${process.env.HOME ?? "~"}/.codex/skills/great_cto`;
529
- const hooksPath = join(cwd, ".codex", "hooks.json");
462
+ // One file, and only the MCP section in it. The previous version also
463
+ // wrote `.codex/hooks.json` and then said "restart Codex to activate
464
+ // hooks and MCP server" — half of which was true. A user who followed
465
+ // that line came away believing the gate chain and secret-scan were
466
+ // guarding their session on Codex. They were not, and nothing said so.
530
467
  const configPath = join(cwd, ".codex", "great_cto.toml");
531
- if (writeFile(hooksPath, getCodexHooksJson(defaultSkillDir), dryRun))
532
- out.push(".codex/hooks.json");
533
468
  if (writeFile(configPath, getCodexConfigFragment(meta), dryRun))
534
469
  out.push(".codex/great_cto.toml");
470
+ // A file we used to write and no longer do stays on disk. Say so rather
471
+ // than delete it: it is in the user's project, and it may be theirs now.
472
+ const stale = join(cwd, ".codex", "hooks.json");
535
473
  if (!dryRun) {
536
- console.log(" ⚠ Codex: merge .codex/great_cto.toml sections into ~/.codex/config.toml");
537
- console.log(" Then restart Codex to activate hooks and MCP server.");
474
+ console.log(" ⚠ Codex: merge .codex/great_cto.toml into ~/.codex/config.toml, then restart Codex.");
475
+ console.log(" That gives you the MCP server. For the skills, install the plugin:");
476
+ for (const c of codexInstallPlan({ repoDir: "<path-to-great_cto>", codexOnPath: true }).commands) {
477
+ console.log(` ${c}`);
478
+ }
479
+ console.log(" Hooks, slash commands and the role agents do NOT carry over to Codex today —");
480
+ console.log(" see docs/analysis/2026-09-05-codex-phase0-findings.md.");
481
+ if (existsSync(stale)) {
482
+ console.log("");
483
+ console.log(" ⚠ .codex/hooks.json exists and an older great-cto wrote it. Codex never read it");
484
+ console.log(" (openai/codex#16430) — delete it yourself if it is not yours.");
485
+ }
538
486
  }
539
487
  break;
540
488
  }
@@ -593,7 +541,10 @@ export function nextStepsAfterAdapt(aiTools = []) {
593
541
  out.push(" 1. Restart Claude Code so it picks up the regenerated CLAUDE.md.", " 2. /audit — full analysis of this codebase (existing project)", " /start — scope and build a new feature (greenfield)", " /inbox — what needs your decision right now", " 3. great-cto board — Kanban + CTO dashboard at localhost:3141");
594
542
  }
595
543
  else {
596
- out.push(` Your ${aiTools.join(" / ")} config is live — reload the tool to pick it up.`, " The agent pipeline (architecture review, QA, security gates) runs inside", " Claude Code. To use it here: add claude-code to ai_tools in PROJECT.md,", " then `npx great-cto install`.");
544
+ // "is live" was wrong for Codex, whose fragment the user still has to merge
545
+ // into ~/.codex/config.toml by hand — and a line that says a thing is live
546
+ // is exactly how an unmerged file passes for a working one.
547
+ out.push(` Config written for ${aiTools.join(" / ")}. A fragment that says to merge it is not active`, " until you do — then reload the tool to pick it up.", " The agent pipeline (architecture review, QA, security gates) runs inside", " Claude Code. To use it here: add claude-code to ai_tools in PROJECT.md,", " then `npx great-cto install`.");
597
548
  }
598
549
  return out;
599
550
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "3.24.0",
3
+ "version": "3.25.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",