oh-my-customcodex 0.5.0 → 0.5.2

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 (52) hide show
  1. package/README.md +6 -6
  2. package/dist/cli/index.js +168 -13
  3. package/dist/index.js +150 -8
  4. package/package.json +1 -1
  5. package/templates/.claude/agents/qa-engineer.md +7 -0
  6. package/templates/.claude/hooks/hooks.json +28 -0
  7. package/templates/.claude/hooks/scripts/agent-capability-precheck.sh +99 -0
  8. package/templates/.claude/hooks/scripts/agent-mode-guard.sh +14 -3
  9. package/templates/.claude/hooks/scripts/git-delegation-guard.sh +14 -5
  10. package/templates/.claude/hooks/scripts/plugin-cache-check.sh +42 -0
  11. package/templates/.claude/hooks/scripts/session-reflection.sh +106 -0
  12. package/templates/.claude/output-styles/korean-engineer.md +4 -0
  13. package/templates/.claude/rules/MUST-agent-identification.md +50 -22
  14. package/templates/.claude/rules/MUST-agent-teams.md +6 -2
  15. package/templates/.claude/rules/MUST-completion-verification.md +11 -0
  16. package/templates/.claude/rules/MUST-continuous-improvement.md +15 -1
  17. package/templates/.claude/rules/MUST-intent-transparency.md +29 -0
  18. package/templates/.claude/rules/MUST-language-policy.md +7 -0
  19. package/templates/.claude/rules/MUST-orchestrator-coordination.md +62 -0
  20. package/templates/.claude/rules/MUST-tool-identification.md +19 -0
  21. package/templates/.claude/rules/SHOULD-memory-integration.md +27 -12
  22. package/templates/.claude/skills/adversarial-review/SKILL.md +10 -0
  23. package/templates/.claude/skills/dev-review/SKILL.md +15 -5
  24. package/templates/.claude/skills/harness-export/SKILL.md +46 -0
  25. package/templates/.claude/skills/instinct-extractor/SKILL.md +54 -0
  26. package/templates/.claude/skills/manifest-install/SKILL.md +53 -0
  27. package/templates/.claude/skills/memory-management/SKILL.md +71 -12
  28. package/templates/.claude/skills/memory-recall/SKILL.md +6 -4
  29. package/templates/.claude/skills/memory-save/SKILL.md +8 -5
  30. package/templates/.claude/skills/pipeline/labels.md +55 -0
  31. package/templates/.claude/skills/sec-agentshield-wrapper/SKILL.md +49 -0
  32. package/templates/.claude/skills/systematic-debugging/SKILL.md +44 -0
  33. package/templates/.claude/skills/systematic-debugging/phases/amplification-detection.md +25 -0
  34. package/templates/.claude/skills/systematic-debugging/phases/fault-injection.md +31 -0
  35. package/templates/.claude/skills/systematic-debugging/phases/retry-cache-timeout-audit.md +27 -0
  36. package/templates/.claude/skills/systematic-debugging/phases/timeline-correlation.md +26 -0
  37. package/templates/.claude/statusline.sh +40 -9
  38. package/templates/AGENTS.md.en +6 -2
  39. package/templates/AGENTS.md.ko +6 -2
  40. package/templates/CLAUDE.md +6 -2
  41. package/templates/CLAUDE.md.en +6 -2
  42. package/templates/CLAUDE.md.ko +6 -2
  43. package/templates/README.md +110 -0
  44. package/templates/guides/agent-teams/troubleshooting.md +53 -0
  45. package/templates/guides/autonomous-challenge-lessons/README.md +43 -0
  46. package/templates/guides/claude-code/14-token-efficiency.md +6 -1
  47. package/templates/guides/claude-code/15-version-compatibility.md +86 -0
  48. package/templates/guides/claude-code-tracking.md +51 -0
  49. package/templates/guides/index.yaml +12 -0
  50. package/templates/manifest.json +4 -4
  51. package/templates/tests/tsconfig.json +7 -0
  52. package/templates/workflows/auto-dev.yaml +80 -5
package/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  **[한국어 문서 (Korean)](./README_ko.md)**
15
15
 
16
- 49 agents. 119 skills. 22 rules. One command.
16
+ 49 agents. 123 skills. 22 rules. One command.
17
17
 
18
18
  ```bash
19
19
  npm install -g oh-my-customcodex && cd your-project && omcustomcodex init
@@ -134,7 +134,7 @@ Each agent declares its tools, model, memory scope, and limitations in YAML fron
134
134
 
135
135
  ---
136
136
 
137
- ### Skills (119)
137
+ ### Skills (123)
138
138
 
139
139
  | Category | Count | Includes |
140
140
  |----------|-------|----------|
@@ -228,7 +228,7 @@ Key rules: R010 (orchestrator never writes files), R009 (parallel execution mand
228
228
 
229
229
  ---
230
230
 
231
- ### Guides (48)
231
+ ### Guides (50)
232
232
 
233
233
  Reference documentation covering best practices, architecture decisions, and integration patterns. Located in `guides/` at project root, covering topics from agent design to CI/CD to observability.
234
234
 
@@ -287,8 +287,8 @@ your-project/
287
287
  │ ├── contexts/ # 4 shared context files
288
288
  │ └── ontology/ # Knowledge graph for RAG
289
289
  ├── .agents/
290
- │ └── skills/ # 119 installed skill modules
291
- └── guides/ # 48 reference documents
290
+ │ └── skills/ # 123 installed skill modules
291
+ └── guides/ # 50 reference documents
292
292
  ```
293
293
 
294
294
  ### Source Repository And Compatibility Surfaces
@@ -325,7 +325,7 @@ bun test # Run tests
325
325
  bun run build # Production build
326
326
  ```
327
327
 
328
- Requirements: Node.js >= 18.0.0, Codex CLI.
328
+ Requirements: Node.js >= 18.0.0, Bun, Codex CLI. GitHub CLI (`gh`) and `jq` are recommended for release automation and local hook validation.
329
329
 
330
330
  ---
331
331
 
package/dist/cli/index.js CHANGED
@@ -3091,7 +3091,7 @@ var init_package = __esm(() => {
3091
3091
  workspaces: [
3092
3092
  "packages/*"
3093
3093
  ],
3094
- version: "0.5.0",
3094
+ version: "0.5.2",
3095
3095
  requiresCC: ">=2.1.121",
3096
3096
  claudeCode: {
3097
3097
  minimumVersion: "2.1.121",
@@ -26977,6 +26977,7 @@ init_lockfile();
26977
26977
  init_logger();
26978
26978
  import { execSync as execSync4 } from "node:child_process";
26979
26979
  import { platform as platform2 } from "node:os";
26980
+ var MINIMUM_OMX_VERSION = "0.18.0";
26980
26981
  var defaultDeps2 = {
26981
26982
  exec: execSync4,
26982
26983
  getPlatform: platform2
@@ -27000,11 +27001,116 @@ function getOmxVersion(deps = defaultDeps2) {
27000
27001
  return null;
27001
27002
  }
27002
27003
  }
27004
+ function parseOmxVersion(versionOutput) {
27005
+ if (!versionOutput) {
27006
+ return null;
27007
+ }
27008
+ const match = versionOutput.match(/\bv?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)\b/);
27009
+ return match ? match[1] : null;
27010
+ }
27011
+ function parseVersionParts(version) {
27012
+ const [withoutBuild] = version.split("+");
27013
+ const [coreText, prerelease = null] = withoutBuild.split("-", 2);
27014
+ const coreParts = coreText.split(".").map((part) => Number.parseInt(part, 10));
27015
+ return {
27016
+ core: [coreParts[0] ?? 0, coreParts[1] ?? 0, coreParts[2] ?? 0],
27017
+ prerelease
27018
+ };
27019
+ }
27020
+ function compareOmxVersions(left, right) {
27021
+ const a = parseVersionParts(left);
27022
+ const b = parseVersionParts(right);
27023
+ for (let index = 0;index < 3; index += 1) {
27024
+ const diff = a.core[index] - b.core[index];
27025
+ if (diff !== 0) {
27026
+ return diff > 0 ? 1 : -1;
27027
+ }
27028
+ }
27029
+ if (a.prerelease === b.prerelease) {
27030
+ return 0;
27031
+ }
27032
+ if (a.prerelease === null) {
27033
+ return 1;
27034
+ }
27035
+ if (b.prerelease === null) {
27036
+ return -1;
27037
+ }
27038
+ return a.prerelease.localeCompare(b.prerelease, undefined, { numeric: true });
27039
+ }
27040
+ function hasOmxApiCommand(deps = defaultDeps2) {
27041
+ try {
27042
+ deps.exec("omx api --help", {
27043
+ encoding: "utf-8",
27044
+ stdio: "pipe",
27045
+ timeout: 3000
27046
+ });
27047
+ return true;
27048
+ } catch {
27049
+ return false;
27050
+ }
27051
+ }
27052
+ function assessOmxInstallation(deps = defaultDeps2) {
27053
+ if (!isOmxInstalled(deps)) {
27054
+ return {
27055
+ status: "missing",
27056
+ installed: false,
27057
+ version: null,
27058
+ parsedVersion: null,
27059
+ minimumVersion: MINIMUM_OMX_VERSION,
27060
+ hasApiCommand: false
27061
+ };
27062
+ }
27063
+ const version = getOmxVersion(deps);
27064
+ const parsedVersion = parseOmxVersion(version);
27065
+ if (parsedVersion && compareOmxVersions(parsedVersion, MINIMUM_OMX_VERSION) < 0) {
27066
+ return {
27067
+ status: "stale",
27068
+ installed: true,
27069
+ version,
27070
+ parsedVersion,
27071
+ minimumVersion: MINIMUM_OMX_VERSION,
27072
+ hasApiCommand: false
27073
+ };
27074
+ }
27075
+ const hasApi = hasOmxApiCommand(deps);
27076
+ if (parsedVersion && !hasApi) {
27077
+ return {
27078
+ status: "api-missing",
27079
+ installed: true,
27080
+ version,
27081
+ parsedVersion,
27082
+ minimumVersion: MINIMUM_OMX_VERSION,
27083
+ hasApiCommand: false
27084
+ };
27085
+ }
27086
+ if (!parsedVersion && !hasApi) {
27087
+ return {
27088
+ status: "unknown-version",
27089
+ installed: true,
27090
+ version,
27091
+ parsedVersion: null,
27092
+ minimumVersion: MINIMUM_OMX_VERSION,
27093
+ hasApiCommand: false
27094
+ };
27095
+ }
27096
+ return {
27097
+ status: "ready",
27098
+ installed: true,
27099
+ version,
27100
+ parsedVersion,
27101
+ minimumVersion: MINIMUM_OMX_VERSION,
27102
+ hasApiCommand: hasApi
27103
+ };
27104
+ }
27105
+ function isOmxReady(deps = defaultDeps2) {
27106
+ return assessOmxInstallation(deps).status === "ready";
27107
+ }
27003
27108
  function installOmx(deps = defaultDeps2) {
27004
27109
  if (process.env.CI || false || false) {
27005
27110
  return false;
27006
27111
  }
27007
- if (isOmxInstalled(deps)) {
27112
+ const current = assessOmxInstallation(deps);
27113
+ if (current.status === "ready") {
27008
27114
  info("install.omx_already");
27009
27115
  return true;
27010
27116
  }
@@ -27015,11 +27121,11 @@ function installOmx(deps = defaultDeps2) {
27015
27121
  }
27016
27122
  try {
27017
27123
  info("install.omx_installing");
27018
- deps.exec("npm install -g oh-my-codex", {
27124
+ deps.exec("npm install -g oh-my-codex@latest", {
27019
27125
  stdio: "inherit",
27020
27126
  timeout: 120000
27021
27127
  });
27022
- return isOmxInstalled(deps);
27128
+ return isOmxReady(deps);
27023
27129
  } catch (err) {
27024
27130
  const message = err instanceof Error ? err.message : String(err);
27025
27131
  warn("install.omx_install_failed", { error: message });
@@ -27428,7 +27534,8 @@ async function checkCodex() {
27428
27534
  };
27429
27535
  }
27430
27536
  async function checkOmx() {
27431
- if (!isOmxInstalled()) {
27537
+ const omx = assessOmxInstallation();
27538
+ if (omx.status === "missing") {
27432
27539
  return {
27433
27540
  name: "OMX",
27434
27541
  status: "warn",
@@ -27436,11 +27543,34 @@ async function checkOmx() {
27436
27543
  fixable: true
27437
27544
  };
27438
27545
  }
27439
- const version = getOmxVersion();
27546
+ if (omx.status === "stale") {
27547
+ return {
27548
+ name: "OMX",
27549
+ status: "warn",
27550
+ message: `OMX stale (${omx.version ?? "unknown version"}) — requires oh-my-codex v${MINIMUM_OMX_VERSION}+ with omx api`,
27551
+ fixable: true
27552
+ };
27553
+ }
27554
+ if (omx.status === "api-missing") {
27555
+ return {
27556
+ name: "OMX",
27557
+ status: "warn",
27558
+ message: `OMX missing required omx api command (${omx.version ?? "unknown version"}) — install oh-my-codex v${MINIMUM_OMX_VERSION}+`,
27559
+ fixable: true
27560
+ };
27561
+ }
27562
+ if (omx.status === "unknown-version") {
27563
+ return {
27564
+ name: "OMX",
27565
+ status: "warn",
27566
+ message: `OMX version could not be verified — requires oh-my-codex v${MINIMUM_OMX_VERSION}+ with omx api`,
27567
+ fixable: true
27568
+ };
27569
+ }
27440
27570
  return {
27441
27571
  name: "OMX",
27442
27572
  status: "pass",
27443
- message: `OMX OK (${version ?? "unknown version"})`,
27573
+ message: `OMX OK (${omx.version ?? "unknown version"}, omx api available)`,
27444
27574
  fixable: false
27445
27575
  };
27446
27576
  }
@@ -27557,7 +27687,7 @@ async function fixSingleIssue(check, targetDir, rootDir = ".codex") {
27557
27687
  async function fixIssues(checks, targetDir, rootDir = ".codex") {
27558
27688
  const fixedChecks = [];
27559
27689
  for (const check of checks) {
27560
- if (check.status !== "fail" || !check.fixable) {
27690
+ if (check.status === "pass" || !check.fixable) {
27561
27691
  fixedChecks.push(check);
27562
27692
  continue;
27563
27693
  }
@@ -27717,7 +27847,7 @@ async function doctorCommand(options = {}) {
27717
27847
  const checksWithUpdate = await runAllChecks(targetDir, layout, packageVersion, options.updates ?? false);
27718
27848
  let checks = checksWithUpdate;
27719
27849
  if (options.fix) {
27720
- const hasFixableIssues = checksWithUpdate.some((c) => c.status === "fail" && c.fixable);
27850
+ const hasFixableIssues = checksWithUpdate.some((c) => c.status !== "pass" && c.fixable);
27721
27851
  if (hasFixableIssues) {
27722
27852
  console.log(i18n.t("cli.doctor.applyingFixes"));
27723
27853
  console.log("");
@@ -28306,6 +28436,22 @@ async function installStatusline(targetDir, options, _result) {
28306
28436
  await fs2.chmod(destPath, 493);
28307
28437
  debug("install.statusline_installed", {});
28308
28438
  }
28439
+ async function installTestsConfig(targetDir, options, _result) {
28440
+ const srcPath = resolveTemplatePath(join7("tests", "tsconfig.json"));
28441
+ const destPath = join7(targetDir, "tests", "tsconfig.json");
28442
+ if (!await fileExists(srcPath)) {
28443
+ debug("install.tests_config_not_found", { path: srcPath });
28444
+ return;
28445
+ }
28446
+ if (await fileExists(destPath)) {
28447
+ if (!options.force && !options.backup) {
28448
+ debug("install.tests_config_skipped", { reason: "exists" });
28449
+ return;
28450
+ }
28451
+ }
28452
+ await copyFile(srcPath, destPath);
28453
+ debug("install.tests_config_installed", {});
28454
+ }
28309
28455
  async function installSettingsLocal(targetDir, result) {
28310
28456
  const layout = getProviderLayout();
28311
28457
  const settingsPath = join7(targetDir, layout.rootDir, "settings.local.json");
@@ -28382,13 +28528,15 @@ function installCodexIfNeeded(result) {
28382
28528
  }
28383
28529
  }
28384
28530
  function installOmxIfNeeded(result) {
28385
- if (!isOmxInstalled()) {
28531
+ const omx = assessOmxInstallation();
28532
+ if (omx.status !== "ready") {
28386
28533
  info("install.omx_installing");
28387
28534
  const omxInstalled = installOmx();
28388
28535
  if (omxInstalled) {
28389
28536
  info("install.omx_success");
28390
28537
  } else {
28391
- result.warnings.push("OMX installation failed install manually: npm install -g oh-my-codex");
28538
+ const versionDetail = omx.version ? ` (found ${omx.version})` : "";
28539
+ result.warnings.push(`OMX installation/upgrade failed${versionDetail} — install oh-my-codex >= v${MINIMUM_OMX_VERSION} manually: npm install -g oh-my-codex@latest`);
28392
28540
  }
28393
28541
  } else {
28394
28542
  info("install.omx_already");
@@ -28404,6 +28552,7 @@ async function install(options) {
28404
28552
  await verifyTemplateDirectory();
28405
28553
  await installAllComponents(options.targetDir, options, result);
28406
28554
  await installStatusline(options.targetDir, options, result);
28555
+ await installTestsConfig(options.targetDir, options, result);
28407
28556
  await installSettingsLocal(options.targetDir, result);
28408
28557
  await installEntryDocWithTracking(options.targetDir, options, result);
28409
28558
  if (preservation) {
@@ -31529,9 +31678,15 @@ function checkAndInstallCodexAfterUpdate() {
31529
31678
  }
31530
31679
  }
31531
31680
  function checkAndInstallOmxAfterUpdate() {
31532
- if (!isOmxInstalled()) {
31681
+ const omx = assessOmxInstallation();
31682
+ if (omx.status !== "ready") {
31533
31683
  warn("update.omx_missing");
31534
- console.log(i18n.t("cli.update.omxMissing"));
31684
+ if (omx.status === "missing") {
31685
+ console.log(i18n.t("cli.update.omxMissing"));
31686
+ } else {
31687
+ const versionDetail = omx.version ? ` (${omx.version})` : "";
31688
+ console.log(`OMX${versionDetail} does not meet the oh-my-codex v${MINIMUM_OMX_VERSION} baseline. Attempting upgrade...`);
31689
+ }
31535
31690
  const omxInstalled = installOmx();
31536
31691
  if (omxInstalled) {
31537
31692
  console.log(i18n.t("cli.update.omxInstalled"));
package/dist/index.js CHANGED
@@ -1569,6 +1569,7 @@ init_lockfile();
1569
1569
  init_logger();
1570
1570
  import { execSync as execSync2 } from "node:child_process";
1571
1571
  import { platform as platform2 } from "node:os";
1572
+ var MINIMUM_OMX_VERSION = "0.18.0";
1572
1573
  var defaultDeps2 = {
1573
1574
  exec: execSync2,
1574
1575
  getPlatform: platform2
@@ -1581,11 +1582,127 @@ function isOmxInstalled(deps = defaultDeps2) {
1581
1582
  return false;
1582
1583
  }
1583
1584
  }
1585
+ function getOmxVersion(deps = defaultDeps2) {
1586
+ try {
1587
+ return deps.exec("omx --version", {
1588
+ encoding: "utf-8",
1589
+ stdio: "pipe",
1590
+ timeout: 3000
1591
+ }).trim();
1592
+ } catch {
1593
+ return null;
1594
+ }
1595
+ }
1596
+ function parseOmxVersion(versionOutput) {
1597
+ if (!versionOutput) {
1598
+ return null;
1599
+ }
1600
+ const match = versionOutput.match(/\bv?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)\b/);
1601
+ return match ? match[1] : null;
1602
+ }
1603
+ function parseVersionParts(version) {
1604
+ const [withoutBuild] = version.split("+");
1605
+ const [coreText, prerelease = null] = withoutBuild.split("-", 2);
1606
+ const coreParts = coreText.split(".").map((part) => Number.parseInt(part, 10));
1607
+ return {
1608
+ core: [coreParts[0] ?? 0, coreParts[1] ?? 0, coreParts[2] ?? 0],
1609
+ prerelease
1610
+ };
1611
+ }
1612
+ function compareOmxVersions(left, right) {
1613
+ const a = parseVersionParts(left);
1614
+ const b = parseVersionParts(right);
1615
+ for (let index = 0;index < 3; index += 1) {
1616
+ const diff = a.core[index] - b.core[index];
1617
+ if (diff !== 0) {
1618
+ return diff > 0 ? 1 : -1;
1619
+ }
1620
+ }
1621
+ if (a.prerelease === b.prerelease) {
1622
+ return 0;
1623
+ }
1624
+ if (a.prerelease === null) {
1625
+ return 1;
1626
+ }
1627
+ if (b.prerelease === null) {
1628
+ return -1;
1629
+ }
1630
+ return a.prerelease.localeCompare(b.prerelease, undefined, { numeric: true });
1631
+ }
1632
+ function hasOmxApiCommand(deps = defaultDeps2) {
1633
+ try {
1634
+ deps.exec("omx api --help", {
1635
+ encoding: "utf-8",
1636
+ stdio: "pipe",
1637
+ timeout: 3000
1638
+ });
1639
+ return true;
1640
+ } catch {
1641
+ return false;
1642
+ }
1643
+ }
1644
+ function assessOmxInstallation(deps = defaultDeps2) {
1645
+ if (!isOmxInstalled(deps)) {
1646
+ return {
1647
+ status: "missing",
1648
+ installed: false,
1649
+ version: null,
1650
+ parsedVersion: null,
1651
+ minimumVersion: MINIMUM_OMX_VERSION,
1652
+ hasApiCommand: false
1653
+ };
1654
+ }
1655
+ const version = getOmxVersion(deps);
1656
+ const parsedVersion = parseOmxVersion(version);
1657
+ if (parsedVersion && compareOmxVersions(parsedVersion, MINIMUM_OMX_VERSION) < 0) {
1658
+ return {
1659
+ status: "stale",
1660
+ installed: true,
1661
+ version,
1662
+ parsedVersion,
1663
+ minimumVersion: MINIMUM_OMX_VERSION,
1664
+ hasApiCommand: false
1665
+ };
1666
+ }
1667
+ const hasApi = hasOmxApiCommand(deps);
1668
+ if (parsedVersion && !hasApi) {
1669
+ return {
1670
+ status: "api-missing",
1671
+ installed: true,
1672
+ version,
1673
+ parsedVersion,
1674
+ minimumVersion: MINIMUM_OMX_VERSION,
1675
+ hasApiCommand: false
1676
+ };
1677
+ }
1678
+ if (!parsedVersion && !hasApi) {
1679
+ return {
1680
+ status: "unknown-version",
1681
+ installed: true,
1682
+ version,
1683
+ parsedVersion: null,
1684
+ minimumVersion: MINIMUM_OMX_VERSION,
1685
+ hasApiCommand: false
1686
+ };
1687
+ }
1688
+ return {
1689
+ status: "ready",
1690
+ installed: true,
1691
+ version,
1692
+ parsedVersion,
1693
+ minimumVersion: MINIMUM_OMX_VERSION,
1694
+ hasApiCommand: hasApi
1695
+ };
1696
+ }
1697
+ function isOmxReady(deps = defaultDeps2) {
1698
+ return assessOmxInstallation(deps).status === "ready";
1699
+ }
1584
1700
  function installOmx(deps = defaultDeps2) {
1585
1701
  if (process.env.CI || false || false) {
1586
1702
  return false;
1587
1703
  }
1588
- if (isOmxInstalled(deps)) {
1704
+ const current = assessOmxInstallation(deps);
1705
+ if (current.status === "ready") {
1589
1706
  info("install.omx_already");
1590
1707
  return true;
1591
1708
  }
@@ -1596,11 +1713,11 @@ function installOmx(deps = defaultDeps2) {
1596
1713
  }
1597
1714
  try {
1598
1715
  info("install.omx_installing");
1599
- deps.exec("npm install -g oh-my-codex", {
1716
+ deps.exec("npm install -g oh-my-codex@latest", {
1600
1717
  stdio: "inherit",
1601
1718
  timeout: 120000
1602
1719
  });
1603
- return isOmxInstalled(deps);
1720
+ return isOmxReady(deps);
1604
1721
  } catch (err) {
1605
1722
  const message = err instanceof Error ? err.message : String(err);
1606
1723
  warn("install.omx_install_failed", { error: message });
@@ -1796,6 +1913,22 @@ async function installStatusline(targetDir, options, _result) {
1796
1913
  await fs.chmod(destPath, 493);
1797
1914
  debug("install.statusline_installed", {});
1798
1915
  }
1916
+ async function installTestsConfig(targetDir, options, _result) {
1917
+ const srcPath = resolveTemplatePath(join5("tests", "tsconfig.json"));
1918
+ const destPath = join5(targetDir, "tests", "tsconfig.json");
1919
+ if (!await fileExists(srcPath)) {
1920
+ debug("install.tests_config_not_found", { path: srcPath });
1921
+ return;
1922
+ }
1923
+ if (await fileExists(destPath)) {
1924
+ if (!options.force && !options.backup) {
1925
+ debug("install.tests_config_skipped", { reason: "exists" });
1926
+ return;
1927
+ }
1928
+ }
1929
+ await copyFile(srcPath, destPath);
1930
+ debug("install.tests_config_installed", {});
1931
+ }
1799
1932
  async function installSettingsLocal(targetDir, result) {
1800
1933
  const layout = getProviderLayout();
1801
1934
  const settingsPath = join5(targetDir, layout.rootDir, "settings.local.json");
@@ -1872,13 +2005,15 @@ function installCodexIfNeeded(result) {
1872
2005
  }
1873
2006
  }
1874
2007
  function installOmxIfNeeded(result) {
1875
- if (!isOmxInstalled()) {
2008
+ const omx = assessOmxInstallation();
2009
+ if (omx.status !== "ready") {
1876
2010
  info("install.omx_installing");
1877
2011
  const omxInstalled = installOmx();
1878
2012
  if (omxInstalled) {
1879
2013
  info("install.omx_success");
1880
2014
  } else {
1881
- result.warnings.push("OMX installation failed install manually: npm install -g oh-my-codex");
2015
+ const versionDetail = omx.version ? ` (found ${omx.version})` : "";
2016
+ result.warnings.push(`OMX installation/upgrade failed${versionDetail} — install oh-my-codex >= v${MINIMUM_OMX_VERSION} manually: npm install -g oh-my-codex@latest`);
1882
2017
  }
1883
2018
  } else {
1884
2019
  info("install.omx_already");
@@ -1894,6 +2029,7 @@ async function install(options) {
1894
2029
  await verifyTemplateDirectory();
1895
2030
  await installAllComponents(options.targetDir, options, result);
1896
2031
  await installStatusline(options.targetDir, options, result);
2032
+ await installTestsConfig(options.targetDir, options, result);
1897
2033
  await installSettingsLocal(options.targetDir, result);
1898
2034
  await installEntryDocWithTracking(options.targetDir, options, result);
1899
2035
  if (preservation) {
@@ -2180,7 +2316,7 @@ var package_default = {
2180
2316
  workspaces: [
2181
2317
  "packages/*"
2182
2318
  ],
2183
- version: "0.5.0",
2319
+ version: "0.5.2",
2184
2320
  requiresCC: ">=2.1.121",
2185
2321
  claudeCode: {
2186
2322
  minimumVersion: "2.1.121",
@@ -5124,9 +5260,15 @@ function checkAndInstallCodexAfterUpdate() {
5124
5260
  }
5125
5261
  }
5126
5262
  function checkAndInstallOmxAfterUpdate() {
5127
- if (!isOmxInstalled()) {
5263
+ const omx = assessOmxInstallation();
5264
+ if (omx.status !== "ready") {
5128
5265
  warn("update.omx_missing");
5129
- console.log(i18n.t("cli.update.omxMissing"));
5266
+ if (omx.status === "missing") {
5267
+ console.log(i18n.t("cli.update.omxMissing"));
5268
+ } else {
5269
+ const versionDetail = omx.version ? ` (${omx.version})` : "";
5270
+ console.log(`OMX${versionDetail} does not meet the oh-my-codex v${MINIMUM_OMX_VERSION} baseline. Attempting upgrade...`);
5271
+ }
5130
5272
  const omxInstalled = installOmx();
5131
5273
  if (omxInstalled) {
5132
5274
  console.log(i18n.t("cli.update.omxInstalled"));
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "workspaces": [
4
4
  "packages/*"
5
5
  ],
6
- "version": "0.5.0",
6
+ "version": "0.5.2",
7
7
  "requiresCC": ">=2.1.121",
8
8
  "claudeCode": {
9
9
  "minimumVersion": "2.1.121",
@@ -31,6 +31,13 @@ You are a QA execution specialist that runs tests, identifies defects, and valid
31
31
 
32
32
  Jest, Vitest, pytest, go test, JUnit, Playwright, Cypress
33
33
 
34
+ ## Evidence Requirements
35
+
36
+ - Before citing selectors, test IDs, CLI flags, mappings, function names, or config keys, read or grep the target code and quote the exact identifier.
37
+ - Do not invent `data-testid`, route, mapping, or flag names from memory.
38
+ - UI verification requires browser or screenshot evidence when a renderer is available; typecheck alone is not sufficient for visual completion.
39
+ - If only indirect evidence is available, label it as indirect and state the missing direct check.
40
+
34
41
  ## Collaboration
35
42
 
36
43
  Receives from: qa-writer (test cases), qa-planner (priorities). Outputs to: dev-lead (defects), qa-writer (results).
@@ -129,6 +129,10 @@
129
129
  "type": "command",
130
130
  "command": "bash .codex/hooks/scripts/agent-mode-guard.sh"
131
131
  },
132
+ {
133
+ "type": "command",
134
+ "command": "bash .codex/hooks/scripts/agent-capability-precheck.sh"
135
+ },
132
136
  {
133
137
  "type": "command",
134
138
  "command": "#!/bin/bash\ninput=$(cat)\nagent_type=$(echo \"$input\" | jq -r '.tool_input.subagent_type // \"unknown\"')\nmodel=$(echo \"$input\" | jq -r '.tool_input.model // \"inherit\"')\ndesc=$(echo \"$input\" | jq -r '.tool_input.description // \"\"' | head -c 40)\nresume=$(echo \"$input\" | jq -r '.tool_input.resume // empty')\nif [ -n \"$resume\" ]; then\n echo \"─── [Resume] ${agent_type}:${model} | ${desc} ───\" >&2\nelse\n echo \"─── [Spawn] ${agent_type}:${model} | ${desc} ───\" >&2\nfi\necho \"$input\""
@@ -199,6 +203,16 @@
199
203
  }
200
204
  ],
201
205
  "description": "Auto-detect and fix previous session issues at start (#838)"
206
+ },
207
+ {
208
+ "matcher": "*",
209
+ "hooks": [
210
+ {
211
+ "type": "command",
212
+ "command": "bash .codex/hooks/scripts/plugin-cache-check.sh"
213
+ }
214
+ ],
215
+ "description": "Advisory check for plugin cache directories missing node_modules (#1366)"
202
216
  }
203
217
  ],
204
218
  "UserPromptSubmit": [
@@ -255,6 +269,10 @@
255
269
  "type": "command",
256
270
  "command": "bash .codex/hooks/scripts/auto-continue-guard.sh"
257
271
  },
272
+ {
273
+ "type": "command",
274
+ "command": "bash .codex/hooks/scripts/session-reflection.sh"
275
+ },
258
276
  {
259
277
  "type": "prompt",
260
278
  "prompt": "A background subagent just completed. Check if there are pending workflow steps that depend on this result. If the previous subagent FAILED, do NOT auto-continue — report the failure and wait for user input. If the previous step succeeded and there are pending steps, proceed automatically. If no pending steps, report results and wait. Safety: The file /tmp/.codex-loop-count-$PPID tracks auto-continue count. After 3 consecutive auto-continues without user interaction, pause and ask the user before proceeding."
@@ -555,6 +573,16 @@
555
573
  ],
556
574
  "description": "Batch-save agent outcomes to eval-core DB on session end (advisory, exit 0)"
557
575
  },
576
+ {
577
+ "matcher": "*",
578
+ "hooks": [
579
+ {
580
+ "type": "command",
581
+ "command": "bash .codex/hooks/scripts/session-reflection.sh"
582
+ }
583
+ ],
584
+ "description": "Capture session-end reflection from transcript, background_tasks, and session_crons (advisory, exit 0)"
585
+ },
558
586
  {
559
587
  "matcher": "*",
560
588
  "hooks": [