great-cto 2.33.1 → 2.34.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/dist/adapt.js +122 -1
- package/dist/main.js +110 -0
- 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.
|
|
3
|
+
"version": "2.34.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": {
|