great-cto 2.33.1 → 2.35.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.
Files changed (3) hide show
  1. package/dist/adapt.js +122 -1
  2. package/dist/main.js +110 -0
  3. package/package.json +3 -2
package/dist/adapt.js CHANGED
@@ -9,7 +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
- const VALID_AI_TOOLS = ["claude-code", "cursor", "copilot", "windsurf", "aider"];
12
+ const VALID_AI_TOOLS = ["claude-code", "cursor", "copilot", "windsurf", "aider", "codex"];
13
13
  function parseAiTools(text) {
14
14
  const line = text.match(/^ai_tools:\s*(.+)$/m)?.[1] ?? "";
15
15
  // Support: [claude-code, cursor] or claude-code, cursor or claude-code
@@ -311,6 +311,112 @@ auto-commits: false
311
311
  dirty-commits: false
312
312
  `;
313
313
  }
314
+ // ── Codex adapter helpers ──────────────────────────────────────────────────
315
+ /**
316
+ * hooks.json content for ~/.codex/skills/great_cto/hooks.json.
317
+ *
318
+ * Phase 0 findings (2026-06-04, confirmed against Codex Desktop binary):
319
+ * - Hook events: PreToolUse, PostToolUse, SessionStart, SubagentStart,
320
+ * SubagentStop, PreCompact, PostCompact, UserPromptSubmit, PermissionRequest.
321
+ * - stdin payload: same keys as Claude Code (tool_name, tool_input, is_error).
322
+ * - block/deny: hookSpecificOutput.permissionDecision (same struct as CC)
323
+ * confirmed by binary string literals.
324
+ * - Hooks enabled by [features].hooks = true in config.toml.
325
+ *
326
+ * @param skillDir - absolute path to ~/.codex/skills/great_cto (used to build hook commands)
327
+ */
328
+ export function getCodexHooksJson(skillDir) {
329
+ const s = skillDir; // shorthand
330
+ return JSON.stringify({
331
+ "SessionStart": [
332
+ {
333
+ "hooks": [
334
+ { "command": `node "${s}/scripts/hooks/quota-check.mjs" 2>/dev/null || true`, "timeout": 15 }
335
+ ]
336
+ }
337
+ ],
338
+ "PreToolUse": [
339
+ {
340
+ "matcher": "computer|bash|shell",
341
+ "hooks": [
342
+ { "command": `node "${s}/scripts/hooks/orchestrator-check.mjs" 2>/dev/null || true`, "timeout": 5 },
343
+ { "command": `node "${s}/scripts/hooks/cost-guard.mjs" 2>/dev/null || true`, "timeout": 5 }
344
+ ]
345
+ },
346
+ {
347
+ "matcher": "edit|write|str_replace_editor|computer",
348
+ "hooks": [
349
+ { "command": `node "${s}/scripts/hooks/secret-scan.mjs" 2>/dev/null || true`, "timeout": 8 }
350
+ ]
351
+ }
352
+ ],
353
+ "PostToolUse": [
354
+ {
355
+ "matcher": "edit|write|str_replace_editor",
356
+ "hooks": [
357
+ { "command": `node "${s}/scripts/hooks/format-check.mjs" 2>/dev/null; true`, "timeout": 12, "async": true },
358
+ { "command": `node "${s}/scripts/hooks/tool-failure.mjs" 2>/dev/null || true`, "timeout": 3, "async": true }
359
+ ]
360
+ },
361
+ {
362
+ "matcher": "",
363
+ "hooks": [
364
+ { "command": `node "${s}/scripts/hooks/tool-failure.mjs" 2>/dev/null || true`, "timeout": 3, "async": true }
365
+ ]
366
+ }
367
+ ]
368
+ }, null, 2);
369
+ }
370
+ /**
371
+ * config.toml fragment to merge into ~/.codex/config.toml.
372
+ * Adds: [features].hooks=true, [mcp_servers.great_cto], [agents.great_cto_skill].
373
+ * Written as a separate file (.codex/great_cto.toml) since merging TOML is
374
+ * non-trivial; installer prints merge instructions.
375
+ */
376
+ function getCodexConfigFragment(meta) {
377
+ return `# great_cto Codex integration — generated by great-cto adapt
378
+ # Merge this into ~/.codex/config.toml or copy the sections manually.
379
+ # Generated: ${new Date().toISOString().slice(0, 10)}
380
+
381
+ [features]
382
+ hooks = true
383
+
384
+ [mcp_servers.great_cto]
385
+ command = "npx"
386
+ args = ["great-cto@latest", "mcp"]
387
+ # Set startup timeout generously — npx downloads on first run
388
+ startup_timeout_sec = 60
389
+
390
+ [mcp_servers.great_cto.env]
391
+ # Point hooks at the skill dir so hook scripts resolve correctly.
392
+ CODEX_SKILL_DIR = "${process.env.HOME ?? "~"}/.codex/skills/great_cto"
393
+
394
+ # Agents exposed via MCP (great_cto specialist fleet)
395
+ # Codex will use these as subagent personalities via the [agents] table.
396
+ # Full 57-agent routing is handled inside AGENTS.md / SKILL.md.
397
+ [agents.great_cto_architect]
398
+ description = "Deep architectural reasoning, ADRs, cross-cutting design decisions"
399
+
400
+ [agents.great_cto_senior_dev]
401
+ description = "Feature implementation with TDD — RED→GREEN→REFACTOR"
402
+
403
+ [agents.great_cto_qa_engineer]
404
+ description = "QA reports, coverage, regression check after implementation"
405
+
406
+ [agents.great_cto_security_officer]
407
+ description = "Security audit — OWASP Top 10, auth, PII, secrets"
408
+
409
+ [agents.great_cto_devops]
410
+ description = "Deploy, canary rollout, rollback, SLO monitoring"
411
+
412
+ [agents.great_cto_pm]
413
+ description = "Feature decomposition into tasks, timeline, dependency graph"
414
+
415
+ # Archetype: ${meta.archetype}
416
+ # Compliance: ${meta.compliance.join(", ") || "none"}
417
+ # Re-run great-cto adapt --platform codex to refresh.
418
+ `;
419
+ }
314
420
  function getCliVersion() {
315
421
  try {
316
422
  const here = dirname(new URL(import.meta.url).pathname);
@@ -395,6 +501,21 @@ conventions. Generated by \`great-cto adapt\`.
395
501
  out.push(".aider.conf.yml");
396
502
  break;
397
503
  }
504
+ case "codex": {
505
+ // Write hooks.json + config.toml fragment to .codex/ (project-scoped, trusted)
506
+ const defaultSkillDir = `${process.env.HOME ?? "~"}/.codex/skills/great_cto`;
507
+ const hooksPath = join(cwd, ".codex", "hooks.json");
508
+ const configPath = join(cwd, ".codex", "great_cto.toml");
509
+ if (writeFile(hooksPath, getCodexHooksJson(defaultSkillDir), dryRun))
510
+ out.push(".codex/hooks.json");
511
+ if (writeFile(configPath, getCodexConfigFragment(meta), dryRun))
512
+ out.push(".codex/great_cto.toml");
513
+ if (!dryRun) {
514
+ console.log(" ⚠ Codex: merge .codex/great_cto.toml sections into ~/.codex/config.toml");
515
+ console.log(" Then restart Codex to activate hooks and MCP server.");
516
+ }
517
+ break;
518
+ }
398
519
  case "claude-code":
399
520
  // Already handled above (CLAUDE.md + AGENTS.md)
400
521
  break;
package/dist/main.js CHANGED
@@ -49,6 +49,7 @@ function parseArgs(argv) {
49
49
  version: null,
50
50
  useLlm: false,
51
51
  noLlm: false,
52
+ host: null,
52
53
  positional: [],
53
54
  };
54
55
  const rest = [];
@@ -78,6 +79,14 @@ function parseArgs(argv) {
78
79
  args.useLlm = true;
79
80
  else if (a === "--no-llm")
80
81
  args.noLlm = true;
82
+ else if (a === "--host") {
83
+ const v = argv[++i] ?? "";
84
+ args.host = (v === "codex" || v === "claude-code") ? v : null;
85
+ }
86
+ else if (a.startsWith("--host=")) {
87
+ const v = a.slice("--host=".length);
88
+ args.host = (v === "codex" || v === "claude-code") ? v : null;
89
+ }
81
90
  else if (a === "board")
82
91
  args.command = "board";
83
92
  else if (a === "register")
@@ -408,7 +417,108 @@ ${bold("Links:")}
408
417
  github.com/avelikiy/great_cto
409
418
  `);
410
419
  }
420
+ async function runInitCodex(args) {
421
+ const { homedir } = await import("node:os");
422
+ const home = homedir();
423
+ log(bold("great-cto · Codex host install"));
424
+ log("");
425
+ log(`Installing great_cto for ${cyan("OpenAI Codex")} (Desktop + CLI).`);
426
+ log(`This writes hook, MCP, and agent config to your Codex skill directory.`);
427
+ log("");
428
+ if (args.dryRun) {
429
+ log(yellow("dry-run: showing what would be written."));
430
+ log(` would write: ${home}/.codex/skills/great_cto/hooks.json`);
431
+ log(` would write: ${home}/.codex/skills/great_cto/scripts/ (hook .mjs files)`);
432
+ log(` would update: .codex/great_cto.toml (merge into ~/.codex/config.toml)`);
433
+ return 0;
434
+ }
435
+ const { mkdirSync, copyFileSync, existsSync, writeFileSync } = await import("node:fs");
436
+ const { join, dirname } = await import("node:path");
437
+ const { fileURLToPath } = await import("node:url");
438
+ // ── 1. locate the plugin source ──────────────────────────
439
+ // Works whether invoked via npx (global cache) or a local build.
440
+ // - npx run: dist/main.js → dist/ → ../ → package root → scripts/hooks/
441
+ // - dev run from packages/cli/: same as above
442
+ // - repo dev with ts-node: src/main.ts → src/ → ../ → packages/cli/ → ../../scripts/hooks/
443
+ const here = dirname(fileURLToPath(import.meta.url));
444
+ const hooksSearchPaths = [
445
+ join(here, "..", "scripts", "hooks"), // npm install: dist/../scripts/hooks
446
+ join(here, "..", "..", "scripts", "hooks"), // monorepo: packages/cli/dist/../../scripts
447
+ join(here, "..", "..", "..", "scripts", "hooks"), // ts-node: src/../../../scripts
448
+ ];
449
+ const hooksDir = hooksSearchPaths.find(p => existsSync(p));
450
+ if (!hooksDir) {
451
+ error("Could not locate scripts/hooks/. Try: npx great-cto@latest --host codex");
452
+ return 1;
453
+ }
454
+ // ── 2. install skill dir ──────────────────────────────────
455
+ const skillDir = join(home, ".codex", "skills", "great_cto");
456
+ const skillScriptsDir = join(skillDir, "scripts", "hooks");
457
+ mkdirSync(skillScriptsDir, { recursive: true });
458
+ log(dim(` skill dir: ${skillDir}`));
459
+ // Copy hook scripts
460
+ const HOOKS_TO_COPY = [
461
+ "quota-check.mjs",
462
+ "secret-scan.mjs",
463
+ "cost-guard.mjs",
464
+ "orchestrator-check.mjs",
465
+ "format-check.mjs",
466
+ "tool-failure.mjs",
467
+ "summary-enforce.mjs",
468
+ ];
469
+ let copied = 0;
470
+ for (const hook of HOOKS_TO_COPY) {
471
+ const src = join(hooksDir, hook);
472
+ const dst = join(skillScriptsDir, hook);
473
+ if (existsSync(src)) {
474
+ copyFileSync(src, dst);
475
+ copied++;
476
+ }
477
+ }
478
+ log(` ${green("✓")} ${copied} hook scripts → ${skillScriptsDir}`);
479
+ // Write hooks.json into the skill dir
480
+ const { getCodexHooksJson } = await import("./adapt.js");
481
+ const hooksJson = getCodexHooksJson(skillDir);
482
+ writeFileSync(join(skillDir, "hooks.json"), hooksJson);
483
+ log(` ${green("✓")} wrote ~/.codex/skills/great_cto/hooks.json`);
484
+ // ── 3. write project-scoped config fragment ───────────────
485
+ const configFrag = join(args.dir, ".codex", "great_cto.toml");
486
+ mkdirSync(dirname(configFrag), { recursive: true });
487
+ writeFileSync(configFrag, [
488
+ `# great_cto Codex integration — generated ${new Date().toISOString().slice(0, 10)}`,
489
+ `# Add these sections to ~/.codex/config.toml`,
490
+ ``,
491
+ `[features]`,
492
+ `hooks = true`,
493
+ ``,
494
+ `[mcp_servers.great_cto]`,
495
+ `command = "npx"`,
496
+ `args = ["great-cto@latest", "mcp"]`,
497
+ `startup_timeout_sec = 60`,
498
+ ``,
499
+ `[mcp_servers.great_cto.env]`,
500
+ `CODEX_SKILL_DIR = "${skillDir}"`,
501
+ ``,
502
+ `[hooks_files]`,
503
+ `paths = ["${join(skillDir, "hooks.json")}"]`,
504
+ ].join("\n") + "\n");
505
+ log(` ${green("✓")} wrote .codex/great_cto.toml`);
506
+ log("");
507
+ log(bold("Next steps:"));
508
+ log(` 1. Merge ${cyan(".codex/great_cto.toml")} sections into ${cyan("~/.codex/config.toml")}`);
509
+ log(` 2. Add ${cyan(args.dir)} to trusted projects in config.toml if not already:`);
510
+ log(` ${dim(`[projects."${args.dir}"]`)}`);
511
+ log(` ${dim(`trust_level = "trusted"`)}`);
512
+ log(` 3. Restart Codex Desktop / CLI to activate hooks and MCP server.`);
513
+ log(` 4. Verify: run ${cyan("great-cto mcp")} in a terminal — should list great_cto tools.`);
514
+ log("");
515
+ log(`${green("✓")} Codex host install complete.`);
516
+ return 0;
517
+ }
411
518
  async function runInit(args) {
519
+ // Route to Codex-specific install if --host codex
520
+ if (args.host === "codex")
521
+ return runInitCodex(args);
412
522
  banner();
413
523
  // ── 1. detect ────────────────────────────────────────────
414
524
  // Guard: refuse to init in $HOME or other "obviously not a project" locations.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "2.33.1",
3
+ "version": "2.35.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",
@@ -71,7 +71,8 @@
71
71
  "dist/",
72
72
  "assets/",
73
73
  "postinstall.mjs",
74
- "README.md"
74
+ "README.md",
75
+ "scripts/hooks/"
75
76
  ],
76
77
  "type": "module",
77
78
  "scripts": {