oh-my-customcode 0.69.0 → 0.71.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/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  **[한국어 문서 (Korean)](./README_ko.md)**
15
15
 
16
- 46 agents. 100 skills. 21 rules. One command.
16
+ 46 agents. 99 skills. 21 rules. One command.
17
17
 
18
18
  ```bash
19
19
  npm install -g oh-my-customcode && cd your-project && omcustom init
@@ -146,20 +146,20 @@ Each agent declares its tools, model, memory scope, and limitations in YAML fron
146
146
 
147
147
  ---
148
148
 
149
- ### Skills (100)
149
+ ### Skills (99)
150
150
 
151
151
  | Category | Count | Includes |
152
152
  |----------|-------|----------|
153
153
  | Best Practices | 24 | Go, Python, TypeScript, Kotlin, Rust, React, FastAPI, Spring Boot, Django, Flutter, Docker, AWS, Postgres, Redis, Kafka, dbt, Spark, Snowflake, Airflow, pipeline-architecture-patterns, alembic, and more |
154
154
  | Routing | 4 | secretary, dev-lead, de-lead, qa-lead |
155
- | Workflow | 15 | structured-dev-cycle, deep-plan, research, evaluator-optimizer, dag-orchestration, worker-reviewer-pipeline, reasoning-sandwich, workflow, workflow-runner, workflow-resume, and more |
155
+ | Workflow | 13 | structured-dev-cycle, deep-plan, research, evaluator-optimizer, dag-orchestration, worker-reviewer-pipeline, reasoning-sandwich, pipeline, and more |
156
156
  | Development | 7 | dev-review, dev-refactor, analysis, create-agent, intent-detection, web-design-guidelines, omcustom-takeover |
157
157
  | Operations | 9 | update-docs, audit-agents, sauron-watch, monitoring-setup, fix-refs, release-notes, and more |
158
158
  | Memory | 3 | memory-save, memory-recall, memory-management |
159
159
  | Package | 3 | npm-publish, npm-version, npm-audit |
160
160
  | Optimization | 3 | optimize-analyze, optimize-bundle, optimize-report |
161
161
  | Security | 3 | adversarial-review, cve-triage, jinja2-prompts |
162
- | Other | 8 | codex-exec, vercel-deploy, skills-sh-search, result-aggregation, writing-clearly-and-concisely, and more |
162
+ | Other | 9 | codex-exec, claude-native, vercel-deploy, skills-sh-search, result-aggregation, writing-clearly-and-concisely, and more |
163
163
 
164
164
  Skills use a 3-tier scope system: `core` (universal), `harness` (agent/skill maintenance), `package` (project-specific).
165
165
 
@@ -181,8 +181,8 @@ All commands are invoked inside the Claude Code conversation.
181
181
  | `/sdd-dev` | Spec-Driven Development workflow |
182
182
  | `/ambiguity-gate` | Pre-routing ambiguity analysis |
183
183
  | `/adversarial-review` | Attacker-mindset security code review |
184
- | `/workflow` | Execute YAML-defined workflow pipelines |
185
- | `/workflow:resume` | Resume a halted workflow from last failure point |
184
+ | `/pipeline` | Execute YAML-defined pipelines |
185
+ | `/pipeline resume` | Resume a halted pipeline from last failure point |
186
186
 
187
187
  ### Agent Management
188
188
 
@@ -282,7 +282,7 @@ your-project/
282
282
  ├── CLAUDE.md # Entry point
283
283
  ├── .claude/
284
284
  │ ├── agents/ # 46 agent definitions
285
- │ ├── skills/ # 100 skill modules
285
+ │ ├── skills/ # 99 skill modules
286
286
  │ ├── rules/ # 21 governance rules (R000-R021)
287
287
  │ ├── hooks/ # 15 lifecycle hook scripts
288
288
  │ ├── schemas/ # Tool input validation schemas
package/dist/cli/index.js CHANGED
@@ -9325,7 +9325,7 @@ var init_package = __esm(() => {
9325
9325
  workspaces: [
9326
9326
  "packages/*"
9327
9327
  ],
9328
- version: "0.69.0",
9328
+ version: "0.71.0",
9329
9329
  description: "Batteries-included agent harness for Claude Code",
9330
9330
  type: "module",
9331
9331
  bin: {
@@ -24826,7 +24826,9 @@ var en_default = {
24826
24826
  projectLatestSuffix: "(latest)",
24827
24827
  newVersionAvailable: "[Info] oh-my-customcode v{{latest}} available (current: v{{current}}). Run 'npm i -g oh-my-customcode' to upgrade.",
24828
24828
  rtkMissing: "[RTK] RTK is not installed. Attempting installation...",
24829
- rtkInstalled: "[RTK] ✓ RTK installed — 60-90% token savings activated"
24829
+ rtkInstalled: "[RTK] ✓ RTK installed — 60-90% token savings activated",
24830
+ codexMissing: "[Codex] Codex CLI is not installed. Attempting installation...",
24831
+ codexInstalled: "[Codex] ✓ Codex CLI installed"
24830
24832
  },
24831
24833
  list: {
24832
24834
  description: "List installed components",
@@ -24930,6 +24932,10 @@ var en_default = {
24930
24932
  rtk: {
24931
24933
  pass: "RTK installed",
24932
24934
  warn: "RTK not installed — token savings unavailable"
24935
+ },
24936
+ codex: {
24937
+ pass: "Codex CLI installed",
24938
+ warn: "Codex CLI not installed — AI-assisted development unavailable"
24933
24939
  }
24934
24940
  }
24935
24941
  },
@@ -24993,7 +24999,11 @@ var en_default = {
24993
24999
  rtk_installing: "Installing RTK...",
24994
25000
  rtk_success: "RTK installed successfully",
24995
25001
  rtk_already: "RTK already installed",
24996
- rtk_install_failed: "RTK installation failed"
25002
+ rtk_install_failed: "RTK installation failed",
25003
+ codex_installing: "Installing Codex CLI...",
25004
+ codex_success: "Codex CLI installed successfully",
25005
+ codex_already: "Codex CLI already installed",
25006
+ codex_install_failed: "Codex CLI installation failed"
24997
25007
  },
24998
25008
  init: {
24999
25009
  description: "Initialize oh-my-customcode in the current directory",
@@ -25223,7 +25233,9 @@ var ko_default = {
25223
25233
  projectLatestSuffix: "(최신)",
25224
25234
  newVersionAvailable: "[정보] oh-my-customcode v{{latest}} 사용 가능 (현재: v{{current}}). 'npm i -g oh-my-customcode'를 실행하여 업그레이드하세요.",
25225
25235
  rtkMissing: "[RTK] RTK가 설치되지 않았습니다. 설치를 시도합니다...",
25226
- rtkInstalled: "[RTK] ✓ RTK 설치 완료 — 토큰 60-90% 절감 활성화"
25236
+ rtkInstalled: "[RTK] ✓ RTK 설치 완료 — 토큰 60-90% 절감 활성화",
25237
+ codexMissing: "[Codex] Codex CLI가 설치되지 않았습니다. 설치를 시도합니다...",
25238
+ codexInstalled: "[Codex] ✓ Codex CLI 설치 완료"
25227
25239
  },
25228
25240
  list: {
25229
25241
  description: "설치된 컴포넌트 목록 표시",
@@ -25327,6 +25339,10 @@ var ko_default = {
25327
25339
  rtk: {
25328
25340
  pass: "RTK 설치됨",
25329
25341
  warn: "RTK 미설치 — 토큰 절감 불가"
25342
+ },
25343
+ codex: {
25344
+ pass: "Codex CLI 설치됨",
25345
+ warn: "Codex CLI 미설치 — AI 개발 지원 불가"
25330
25346
  }
25331
25347
  }
25332
25348
  },
@@ -25390,7 +25406,11 @@ var ko_default = {
25390
25406
  rtk_installing: "RTK 설치 중...",
25391
25407
  rtk_success: "RTK 설치 완료",
25392
25408
  rtk_already: "RTK 이미 설치됨",
25393
- rtk_install_failed: "RTK 설치 실패"
25409
+ rtk_install_failed: "RTK 설치 실패",
25410
+ codex_installing: "Codex CLI 설치 중...",
25411
+ codex_success: "Codex CLI 설치 완료",
25412
+ codex_already: "Codex CLI 이미 설치됨",
25413
+ codex_install_failed: "Codex CLI 설치 실패"
25394
25414
  },
25395
25415
  init: {
25396
25416
  description: "현재 디렉토리에 oh-my-customcode 초기화",
@@ -25820,9 +25840,9 @@ var $stringify = publicApi.stringify;
25820
25840
  var $visit = visit.visit;
25821
25841
  var $visitAsync = visit.visitAsync;
25822
25842
 
25823
- // src/core/config.ts
25824
- init_fs();
25825
- import { join as join3 } from "node:path";
25843
+ // src/core/codex-installer.ts
25844
+ import { execSync as execSync3 } from "node:child_process";
25845
+ import { platform } from "node:os";
25826
25846
 
25827
25847
  // src/utils/logger.ts
25828
25848
  var currentOptions = {
@@ -26043,7 +26063,77 @@ function success(messageKey, params) {
26043
26063
  }
26044
26064
  }
26045
26065
 
26066
+ // src/core/codex-installer.ts
26067
+ var defaultDeps = {
26068
+ exec: execSync3,
26069
+ getPlatform: platform
26070
+ };
26071
+ function isCodexInstalled(deps = defaultDeps) {
26072
+ try {
26073
+ deps.exec("which codex", { stdio: "pipe", timeout: 3000 });
26074
+ return true;
26075
+ } catch {
26076
+ return false;
26077
+ }
26078
+ }
26079
+ function getCodexVersion(deps = defaultDeps) {
26080
+ try {
26081
+ return deps.exec("codex --version", {
26082
+ encoding: "utf-8",
26083
+ stdio: "pipe",
26084
+ timeout: 3000
26085
+ }).trim();
26086
+ } catch {
26087
+ return null;
26088
+ }
26089
+ }
26090
+ function installCodex(deps = defaultDeps) {
26091
+ if (process.env.CI || false || false) {
26092
+ return false;
26093
+ }
26094
+ if (isCodexInstalled(deps)) {
26095
+ info("codex.already_installed");
26096
+ return true;
26097
+ }
26098
+ const os = deps.getPlatform();
26099
+ try {
26100
+ if (os === "darwin") {
26101
+ try {
26102
+ info("codex.installing_brew");
26103
+ deps.exec("brew install openai-codex", {
26104
+ stdio: "inherit",
26105
+ timeout: 120000
26106
+ });
26107
+ return isCodexInstalled(deps);
26108
+ } catch {
26109
+ info("codex.installing_npm");
26110
+ deps.exec("npm install -g @openai/codex", {
26111
+ stdio: "inherit",
26112
+ timeout: 120000
26113
+ });
26114
+ return isCodexInstalled(deps);
26115
+ }
26116
+ } else if (os === "linux") {
26117
+ info("codex.installing_npm");
26118
+ deps.exec("npm install -g @openai/codex", {
26119
+ stdio: "inherit",
26120
+ timeout: 120000
26121
+ });
26122
+ return isCodexInstalled(deps);
26123
+ } else {
26124
+ warn("codex.unsupported_os", { os });
26125
+ return false;
26126
+ }
26127
+ } catch (err) {
26128
+ const message = err instanceof Error ? err.message : String(err);
26129
+ warn("codex.install_failed", { error: message });
26130
+ return false;
26131
+ }
26132
+ }
26133
+
26046
26134
  // src/core/config.ts
26135
+ init_fs();
26136
+ import { join as join3 } from "node:path";
26047
26137
  var CONFIG_FILE = ".omcustomrc.json";
26048
26138
  var CURRENT_CONFIG_VERSION = 1;
26049
26139
  function getDefaultConfig() {
@@ -26403,56 +26493,60 @@ async function generateAndWriteLockfileForDir(targetDir) {
26403
26493
  }
26404
26494
 
26405
26495
  // src/core/rtk-installer.ts
26406
- import { execSync as execSync3 } from "node:child_process";
26407
- import { platform } from "node:os";
26408
- function isRtkInstalled() {
26496
+ import { execSync as execSync4 } from "node:child_process";
26497
+ import { platform as platform2 } from "node:os";
26498
+ var defaultDeps2 = {
26499
+ exec: execSync4,
26500
+ getPlatform: platform2
26501
+ };
26502
+ function isRtkInstalled(deps = defaultDeps2) {
26409
26503
  try {
26410
- execSync3("which rtk", { stdio: "pipe", timeout: 3000 });
26504
+ deps.exec("which rtk", { stdio: "pipe", timeout: 3000 });
26411
26505
  return true;
26412
26506
  } catch {
26413
26507
  return false;
26414
26508
  }
26415
26509
  }
26416
- function getRtkVersion() {
26510
+ function getRtkVersion(deps = defaultDeps2) {
26417
26511
  try {
26418
- return execSync3("rtk --version", { encoding: "utf-8", stdio: "pipe", timeout: 3000 }).trim();
26512
+ return deps.exec("rtk --version", { encoding: "utf-8", stdio: "pipe", timeout: 3000 }).trim();
26419
26513
  } catch {
26420
26514
  return null;
26421
26515
  }
26422
26516
  }
26423
- function installRtk() {
26517
+ function installRtk(deps = defaultDeps2) {
26424
26518
  if (process.env.CI || false || false) {
26425
26519
  return false;
26426
26520
  }
26427
- if (isRtkInstalled()) {
26521
+ if (isRtkInstalled(deps)) {
26428
26522
  info("rtk.already_installed");
26429
26523
  return true;
26430
26524
  }
26431
- const os = platform();
26525
+ const os = deps.getPlatform();
26432
26526
  try {
26433
26527
  if (os === "darwin") {
26434
26528
  try {
26435
26529
  info("rtk.installing_brew");
26436
- execSync3("brew install rtk-ai/tap/rtk", {
26530
+ deps.exec("brew install rtk-ai/tap/rtk", {
26437
26531
  stdio: "inherit",
26438
26532
  timeout: 120000
26439
26533
  });
26440
26534
  return true;
26441
26535
  } catch {
26442
26536
  info("rtk.installing_curl");
26443
- execSync3("curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh", {
26537
+ deps.exec("curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh", {
26444
26538
  stdio: "inherit",
26445
26539
  timeout: 120000
26446
26540
  });
26447
- return isRtkInstalled();
26541
+ return isRtkInstalled(deps);
26448
26542
  }
26449
26543
  } else if (os === "linux") {
26450
26544
  info("rtk.installing_curl");
26451
- execSync3("curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh", {
26545
+ deps.exec("curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh", {
26452
26546
  stdio: "inherit",
26453
26547
  timeout: 120000
26454
26548
  });
26455
- return isRtkInstalled();
26549
+ return isRtkInstalled(deps);
26456
26550
  } else {
26457
26551
  warn("rtk.unsupported_os", { os });
26458
26552
  return false;
@@ -26780,6 +26874,23 @@ async function checkRtk() {
26780
26874
  fixable: false
26781
26875
  };
26782
26876
  }
26877
+ async function checkCodex() {
26878
+ if (!isCodexInstalled()) {
26879
+ return {
26880
+ name: "Codex",
26881
+ status: "warn",
26882
+ message: "Codex CLI not installed — install manually: npm install -g @openai/codex",
26883
+ fixable: true
26884
+ };
26885
+ }
26886
+ const version = getCodexVersion();
26887
+ return {
26888
+ name: "Codex",
26889
+ status: "pass",
26890
+ message: `Codex CLI OK (${version ?? "unknown version"})`,
26891
+ fixable: false
26892
+ };
26893
+ }
26783
26894
  async function checkContexts(targetDir, rootDir = ".claude") {
26784
26895
  const contextsDir = path.join(targetDir, rootDir, "contexts");
26785
26896
  const exists2 = await isDirectory(contextsDir);
@@ -26883,7 +26994,8 @@ async function fixSingleIssue(check, targetDir, rootDir = ".claude") {
26883
26994
  const fixedCount = await fixBrokenSymlinks(targetDir, fullPaths);
26884
26995
  return fixedCount > 0;
26885
26996
  },
26886
- RTK: async () => Promise.resolve(installRtk())
26997
+ RTK: async () => Promise.resolve(installRtk()),
26998
+ Codex: async () => Promise.resolve(installCodex())
26887
26999
  };
26888
27000
  const fixer = fixMap[check.name];
26889
27001
  return fixer ? fixer() : false;
@@ -27032,7 +27144,8 @@ async function runAllChecks(targetDir, layout, packageVersion, includeUpdates) {
27032
27144
  checkHooks(targetDir, layout.rootDir),
27033
27145
  checkContexts(targetDir, layout.rootDir),
27034
27146
  checkCustomComponents(targetDir, layout.rootDir),
27035
- checkRtk()
27147
+ checkRtk(),
27148
+ checkCodex()
27036
27149
  ]);
27037
27150
  const frameworkCheck = await checkFrameworkDrift(targetDir, packageVersion);
27038
27151
  const checksWithFramework = frameworkCheck ? [...baseChecks, frameworkCheck] : baseChecks;
@@ -27693,6 +27806,19 @@ function installRtkIfNeeded(result) {
27693
27806
  info("install.rtk_already");
27694
27807
  }
27695
27808
  }
27809
+ function installCodexIfNeeded(result) {
27810
+ if (!isCodexInstalled()) {
27811
+ info("install.codex_installing");
27812
+ const codexInstalled = installCodex();
27813
+ if (codexInstalled) {
27814
+ info("install.codex_success");
27815
+ } else {
27816
+ result.warnings.push("Codex CLI installation failed — install manually: npm install -g @openai/codex");
27817
+ }
27818
+ } else {
27819
+ info("install.codex_already");
27820
+ }
27821
+ }
27696
27822
  async function install(options) {
27697
27823
  const result = createInstallResult(options.targetDir);
27698
27824
  try {
@@ -27731,6 +27857,7 @@ async function install(options) {
27731
27857
  info("install.lockfile_generated", { files: String(lockfileResult.fileCount) });
27732
27858
  }
27733
27859
  installRtkIfNeeded(result);
27860
+ installCodexIfNeeded(result);
27734
27861
  result.success = true;
27735
27862
  success("install.success");
27736
27863
  } catch (err) {
@@ -27914,7 +28041,7 @@ async function backupExistingInstallation(targetDir) {
27914
28041
 
27915
28042
  // src/core/mcp-config.ts
27916
28043
  init_fs();
27917
- import { execSync as execSync4 } from "node:child_process";
28044
+ import { execSync as execSync5 } from "node:child_process";
27918
28045
  import { writeFile } from "node:fs/promises";
27919
28046
  import { join as join8 } from "node:path";
27920
28047
  async function generateMCPConfig(targetDir) {
@@ -27926,15 +28053,15 @@ async function generateMCPConfig(targetDir) {
27926
28053
  return;
27927
28054
  }
27928
28055
  try {
27929
- execSync4("uv --version", { stdio: "pipe" });
28056
+ execSync5("uv --version", { stdio: "pipe" });
27930
28057
  } catch {
27931
28058
  warn("uv (Python package manager) not found. Install it with: curl -LsSf https://astral.sh/uv/install.sh | sh");
27932
28059
  warn("Skipping ontology-rag MCP configuration. You can set it up manually later.");
27933
28060
  return;
27934
28061
  }
27935
28062
  try {
27936
- execSync4("uv venv .venv", { cwd: targetDir, stdio: "pipe" });
27937
- execSync4('uv pip install "ontology-rag @ git+https://github.com/baekenough/oh-my-customcode.git#subdirectory=packages/ontology-rag"', { cwd: targetDir, stdio: "pipe" });
28063
+ execSync5("uv venv .venv", { cwd: targetDir, stdio: "pipe" });
28064
+ execSync5('uv pip install "ontology-rag @ git+https://github.com/baekenough/oh-my-customcode.git#subdirectory=packages/ontology-rag"', { cwd: targetDir, stdio: "pipe" });
27938
28065
  } catch (error2) {
27939
28066
  const msg = error2 instanceof Error ? error2.message : String(error2);
27940
28067
  warn(`Failed to setup ontology-rag: ${msg}`);
@@ -27977,7 +28104,7 @@ async function generateMCPConfig(targetDir) {
27977
28104
  }
27978
28105
  async function checkUvAvailable() {
27979
28106
  try {
27980
- execSync4("uv --version", { stdio: "pipe" });
28107
+ execSync5("uv --version", { stdio: "pipe" });
27981
28108
  return true;
27982
28109
  } catch {
27983
28110
  return false;
@@ -30306,6 +30433,16 @@ function checkAndInstallRtkAfterUpdate() {
30306
30433
  }
30307
30434
  }
30308
30435
  }
30436
+ function checkAndInstallCodexAfterUpdate() {
30437
+ if (!isCodexInstalled()) {
30438
+ warn("update.codex_missing");
30439
+ console.log(i18n.t("cli.update.codexMissing"));
30440
+ const codexInstalled = installCodex();
30441
+ if (codexInstalled) {
30442
+ console.log(i18n.t("cli.update.codexInstalled"));
30443
+ }
30444
+ }
30445
+ }
30309
30446
  async function update(options) {
30310
30447
  const result = createUpdateResult();
30311
30448
  try {
@@ -30354,6 +30491,7 @@ async function update(options) {
30354
30491
  });
30355
30492
  }
30356
30493
  checkAndInstallRtkAfterUpdate();
30494
+ checkAndInstallCodexAfterUpdate();
30357
30495
  } catch (err) {
30358
30496
  const message = err instanceof Error ? err.message : String(err);
30359
30497
  result.error = message;
package/dist/index.js CHANGED
@@ -914,6 +914,65 @@ import {
914
914
  } from "node:fs/promises";
915
915
  import { basename as basename2, join as join5 } from "node:path";
916
916
 
917
+ // src/core/codex-installer.ts
918
+ import { execSync } from "node:child_process";
919
+ import { platform } from "node:os";
920
+ var defaultDeps = {
921
+ exec: execSync,
922
+ getPlatform: platform
923
+ };
924
+ function isCodexInstalled(deps = defaultDeps) {
925
+ try {
926
+ deps.exec("which codex", { stdio: "pipe", timeout: 3000 });
927
+ return true;
928
+ } catch {
929
+ return false;
930
+ }
931
+ }
932
+ function installCodex(deps = defaultDeps) {
933
+ if (process.env.CI || false || false) {
934
+ return false;
935
+ }
936
+ if (isCodexInstalled(deps)) {
937
+ info("codex.already_installed");
938
+ return true;
939
+ }
940
+ const os = deps.getPlatform();
941
+ try {
942
+ if (os === "darwin") {
943
+ try {
944
+ info("codex.installing_brew");
945
+ deps.exec("brew install openai-codex", {
946
+ stdio: "inherit",
947
+ timeout: 120000
948
+ });
949
+ return isCodexInstalled(deps);
950
+ } catch {
951
+ info("codex.installing_npm");
952
+ deps.exec("npm install -g @openai/codex", {
953
+ stdio: "inherit",
954
+ timeout: 120000
955
+ });
956
+ return isCodexInstalled(deps);
957
+ }
958
+ } else if (os === "linux") {
959
+ info("codex.installing_npm");
960
+ deps.exec("npm install -g @openai/codex", {
961
+ stdio: "inherit",
962
+ timeout: 120000
963
+ });
964
+ return isCodexInstalled(deps);
965
+ } else {
966
+ warn("codex.unsupported_os", { os });
967
+ return false;
968
+ }
969
+ } catch (err) {
970
+ const message = err instanceof Error ? err.message : String(err);
971
+ warn("codex.install_failed", { error: message });
972
+ return false;
973
+ }
974
+ }
975
+
917
976
  // src/core/file-preservation.ts
918
977
  init_fs();
919
978
  import { basename, join as join3 } from "node:path";
@@ -1249,49 +1308,53 @@ async function generateAndWriteLockfileForDir(targetDir) {
1249
1308
  }
1250
1309
 
1251
1310
  // src/core/rtk-installer.ts
1252
- import { execSync } from "node:child_process";
1253
- import { platform } from "node:os";
1254
- function isRtkInstalled() {
1311
+ import { execSync as execSync2 } from "node:child_process";
1312
+ import { platform as platform2 } from "node:os";
1313
+ var defaultDeps2 = {
1314
+ exec: execSync2,
1315
+ getPlatform: platform2
1316
+ };
1317
+ function isRtkInstalled(deps = defaultDeps2) {
1255
1318
  try {
1256
- execSync("which rtk", { stdio: "pipe", timeout: 3000 });
1319
+ deps.exec("which rtk", { stdio: "pipe", timeout: 3000 });
1257
1320
  return true;
1258
1321
  } catch {
1259
1322
  return false;
1260
1323
  }
1261
1324
  }
1262
- function installRtk() {
1325
+ function installRtk(deps = defaultDeps2) {
1263
1326
  if (process.env.CI || false || false) {
1264
1327
  return false;
1265
1328
  }
1266
- if (isRtkInstalled()) {
1329
+ if (isRtkInstalled(deps)) {
1267
1330
  info("rtk.already_installed");
1268
1331
  return true;
1269
1332
  }
1270
- const os = platform();
1333
+ const os = deps.getPlatform();
1271
1334
  try {
1272
1335
  if (os === "darwin") {
1273
1336
  try {
1274
1337
  info("rtk.installing_brew");
1275
- execSync("brew install rtk-ai/tap/rtk", {
1338
+ deps.exec("brew install rtk-ai/tap/rtk", {
1276
1339
  stdio: "inherit",
1277
1340
  timeout: 120000
1278
1341
  });
1279
1342
  return true;
1280
1343
  } catch {
1281
1344
  info("rtk.installing_curl");
1282
- execSync("curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh", {
1345
+ deps.exec("curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh", {
1283
1346
  stdio: "inherit",
1284
1347
  timeout: 120000
1285
1348
  });
1286
- return isRtkInstalled();
1349
+ return isRtkInstalled(deps);
1287
1350
  }
1288
1351
  } else if (os === "linux") {
1289
1352
  info("rtk.installing_curl");
1290
- execSync("curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh", {
1353
+ deps.exec("curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh", {
1291
1354
  stdio: "inherit",
1292
1355
  timeout: 120000
1293
1356
  });
1294
- return isRtkInstalled();
1357
+ return isRtkInstalled(deps);
1295
1358
  } else {
1296
1359
  warn("rtk.unsupported_os", { os });
1297
1360
  return false;
@@ -1492,6 +1555,19 @@ function installRtkIfNeeded(result) {
1492
1555
  info("install.rtk_already");
1493
1556
  }
1494
1557
  }
1558
+ function installCodexIfNeeded(result) {
1559
+ if (!isCodexInstalled()) {
1560
+ info("install.codex_installing");
1561
+ const codexInstalled = installCodex();
1562
+ if (codexInstalled) {
1563
+ info("install.codex_success");
1564
+ } else {
1565
+ result.warnings.push("Codex CLI installation failed — install manually: npm install -g @openai/codex");
1566
+ }
1567
+ } else {
1568
+ info("install.codex_already");
1569
+ }
1570
+ }
1495
1571
  async function install(options) {
1496
1572
  const result = createInstallResult(options.targetDir);
1497
1573
  try {
@@ -1530,6 +1606,7 @@ async function install(options) {
1530
1606
  info("install.lockfile_generated", { files: String(lockfileResult.fileCount) });
1531
1607
  }
1532
1608
  installRtkIfNeeded(result);
1609
+ installCodexIfNeeded(result);
1533
1610
  result.success = true;
1534
1611
  success("install.success");
1535
1612
  } catch (err) {
@@ -1743,7 +1820,7 @@ var package_default = {
1743
1820
  workspaces: [
1744
1821
  "packages/*"
1745
1822
  ],
1746
- version: "0.69.0",
1823
+ version: "0.71.0",
1747
1824
  description: "Batteries-included agent harness for Claude Code",
1748
1825
  type: "module",
1749
1826
  bin: {
@@ -4588,6 +4665,16 @@ function checkAndInstallRtkAfterUpdate() {
4588
4665
  }
4589
4666
  }
4590
4667
  }
4668
+ function checkAndInstallCodexAfterUpdate() {
4669
+ if (!isCodexInstalled()) {
4670
+ warn("update.codex_missing");
4671
+ console.log(i18n.t("cli.update.codexMissing"));
4672
+ const codexInstalled = installCodex();
4673
+ if (codexInstalled) {
4674
+ console.log(i18n.t("cli.update.codexInstalled"));
4675
+ }
4676
+ }
4677
+ }
4591
4678
  async function update(options) {
4592
4679
  const result = createUpdateResult();
4593
4680
  try {
@@ -4636,6 +4723,7 @@ async function update(options) {
4636
4723
  });
4637
4724
  }
4638
4725
  checkAndInstallRtkAfterUpdate();
4726
+ checkAndInstallCodexAfterUpdate();
4639
4727
  } catch (err) {
4640
4728
  const message = err instanceof Error ? err.message : String(err);
4641
4729
  result.error = message;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "workspaces": [
4
4
  "packages/*"
5
5
  ],
6
- "version": "0.69.0",
6
+ "version": "0.71.0",
7
7
  "description": "Batteries-included agent harness for Claude Code",
8
8
  "type": "module",
9
9
  "bin": {
@@ -116,6 +116,16 @@
116
116
  }
117
117
  ],
118
118
  "SessionStart": [
119
+ {
120
+ "matcher": "*",
121
+ "hooks": [
122
+ {
123
+ "type": "command",
124
+ "command": ".claude/hooks/scripts/omcustom-auto-update.sh"
125
+ }
126
+ ],
127
+ "description": "Interactive oh-my-customcode update check at session start (#752)"
128
+ },
119
129
  {
120
130
  "matcher": "*",
121
131
  "hooks": [