oh-my-customcode 0.68.0 → 0.68.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.
package/README.md CHANGED
@@ -294,15 +294,15 @@ your-project/
294
294
 
295
295
  ---
296
296
 
297
- ## Optional External Tools
297
+ ## External Tool Integrations
298
298
 
299
- oh-my-customcode works fully without any external tools. These optional integrations provide additional capabilities when installed:
299
+ RTK is automatically installed during `omcustom init` for 60-90% token savings. Other tools are optional:
300
300
 
301
- | Tool | Purpose | Install | Skill |
302
- |------|---------|---------|-------|
303
- | [RTK](https://github.com/rtk-ai/rtk) | 60-90% token savings on CLI output | `brew install rtk` | `/rtk-exec` |
304
- | [Codex CLI](https://github.com/openai/codex) | OpenAI Codex hybrid workflows | `npm i -g @openai/codex` | `/codex-exec` |
305
- | [Gemini CLI](https://github.com/google-gemini/gemini-cli) | Google Gemini hybrid workflows | `npm i -g @anthropic-ai/gemini-cli` | `/gemini-exec` |
301
+ | Tool | Purpose | Install | Status |
302
+ |------|---------|---------|--------|
303
+ | [RTK](https://github.com/rtk-ai/rtk) | 60-90% token savings on CLI output | Auto-installed via `omcustom init` | **Recommended** |
304
+ | [Codex CLI](https://github.com/openai/codex) | OpenAI Codex hybrid workflows | `npm i -g @openai/codex` | Optional |
305
+ | [Gemini CLI](https://github.com/google-gemini/gemini-cli) | Google Gemini hybrid workflows | `npm i -g @google/gemini-cli` | Optional |
306
306
 
307
307
  When installed, each tool is **auto-detected** at session start and its features become available. When not installed, all commands gracefully fall back to Claude-native alternatives.
308
308
 
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.68.0",
9328
+ version: "0.68.2",
9329
9329
  description: "Batteries-included agent harness for Claude Code",
9330
9330
  type: "module",
9331
9331
  bin: {
@@ -24824,7 +24824,9 @@ var en_default = {
24824
24824
  interactiveNoneSelected: "No projects selected. Exiting.",
24825
24825
  interactiveUpdating: "Updating selected projects...",
24826
24826
  projectLatestSuffix: "(latest)",
24827
- newVersionAvailable: "[Info] oh-my-customcode v{{latest}} available (current: v{{current}}). Run 'npm i -g oh-my-customcode' to upgrade."
24827
+ newVersionAvailable: "[Info] oh-my-customcode v{{latest}} available (current: v{{current}}). Run 'npm i -g oh-my-customcode' to upgrade.",
24828
+ rtkMissing: "[RTK] RTK is not installed. Attempting installation...",
24829
+ rtkInstalled: "[RTK] ✓ RTK installed — 60-90% token savings activated"
24828
24830
  },
24829
24831
  list: {
24830
24832
  description: "List installed components",
@@ -24924,6 +24926,10 @@ var en_default = {
24924
24926
  framework: {
24925
24927
  pass: "Framework is up to date (v{{version}})",
24926
24928
  warn: "Framework is outdated: installed v{{installed}}, latest v{{latest}} ({{behind}} version(s) behind). Run 'omcustom update' to sync."
24929
+ },
24930
+ rtk: {
24931
+ pass: "RTK installed",
24932
+ warn: "RTK not installed — token savings unavailable"
24927
24933
  }
24928
24934
  }
24929
24935
  },
@@ -24983,6 +24989,12 @@ var en_default = {
24983
24989
  }
24984
24990
  }
24985
24991
  },
24992
+ install: {
24993
+ rtk_installing: "Installing RTK...",
24994
+ rtk_success: "RTK installed successfully",
24995
+ rtk_already: "RTK already installed",
24996
+ rtk_install_failed: "RTK installation failed"
24997
+ },
24986
24998
  init: {
24987
24999
  description: "Initialize oh-my-customcode in the current directory",
24988
25000
  starting: "Initializing oh-my-customcode...",
@@ -25209,7 +25221,9 @@ var ko_default = {
25209
25221
  interactiveNoneSelected: "선택된 프로젝트가 없습니다. 종료합니다.",
25210
25222
  interactiveUpdating: "선택된 프로젝트 업데이트 중...",
25211
25223
  projectLatestSuffix: "(최신)",
25212
- newVersionAvailable: "[정보] oh-my-customcode v{{latest}} 사용 가능 (현재: v{{current}}). 'npm i -g oh-my-customcode'를 실행하여 업그레이드하세요."
25224
+ newVersionAvailable: "[정보] oh-my-customcode v{{latest}} 사용 가능 (현재: v{{current}}). 'npm i -g oh-my-customcode'를 실행하여 업그레이드하세요.",
25225
+ rtkMissing: "[RTK] RTK가 설치되지 않았습니다. 설치를 시도합니다...",
25226
+ rtkInstalled: "[RTK] ✓ RTK 설치 완료 — 토큰 60-90% 절감 활성화"
25213
25227
  },
25214
25228
  list: {
25215
25229
  description: "설치된 컴포넌트 목록 표시",
@@ -25309,6 +25323,10 @@ var ko_default = {
25309
25323
  framework: {
25310
25324
  pass: "프레임워크가 최신 상태입니다 (v{{version}})",
25311
25325
  warn: "프레임워크가 구버전입니다: 설치됨 v{{installed}}, 최신 v{{latest}} ({{behind}}개 버전 뒤처짐). 'omcustom update'를 실행하여 동기화하세요."
25326
+ },
25327
+ rtk: {
25328
+ pass: "RTK 설치됨",
25329
+ warn: "RTK 미설치 — 토큰 절감 불가"
25312
25330
  }
25313
25331
  }
25314
25332
  },
@@ -25368,6 +25386,12 @@ var ko_default = {
25368
25386
  }
25369
25387
  }
25370
25388
  },
25389
+ install: {
25390
+ rtk_installing: "RTK 설치 중...",
25391
+ rtk_success: "RTK 설치 완료",
25392
+ rtk_already: "RTK 이미 설치됨",
25393
+ rtk_install_failed: "RTK 설치 실패"
25394
+ },
25371
25395
  init: {
25372
25396
  description: "현재 디렉토리에 oh-my-customcode 초기화",
25373
25397
  starting: "oh-my-customcode 초기화 중...",
@@ -25513,6 +25537,19 @@ function compareSemver(a, b) {
25513
25537
  }
25514
25538
  return 0;
25515
25539
  }
25540
+ function isVersionPlausible(currentVersion, candidateVersion) {
25541
+ const current = normalizeVersion(currentVersion).split(".").map((n) => parseInt(n, 10) || 0);
25542
+ const candidate = normalizeVersion(candidateVersion).split(".").map((n) => parseInt(n, 10) || 0);
25543
+ const majorDiff = (candidate[0] ?? 0) - (current[0] ?? 0);
25544
+ const minorDiff = (candidate[1] ?? 0) - (current[1] ?? 0);
25545
+ if (majorDiff >= 1) {
25546
+ return false;
25547
+ }
25548
+ if (majorDiff === 0 && minorDiff >= 10) {
25549
+ return false;
25550
+ }
25551
+ return true;
25552
+ }
25516
25553
  function isInteractiveSession(stdin = process.stdin, stdout = process.stdout) {
25517
25554
  return Boolean(stdin.isTTY && stdout.isTTY);
25518
25555
  }
@@ -25639,12 +25676,16 @@ function checkSelfUpdate(options) {
25639
25676
  let usedCache = false;
25640
25677
  const cache = readCache(cachePath);
25641
25678
  if (cache && isCacheFresh(cache, now, cacheTtlMs)) {
25642
- latestVersion = normalizeVersion(cache.latestVersion);
25643
- usedCache = true;
25679
+ const cachedVersion = normalizeVersion(cache.latestVersion);
25680
+ if (isVersionPlausible(currentVersion, cachedVersion)) {
25681
+ latestVersion = cachedVersion;
25682
+ usedCache = true;
25683
+ }
25644
25684
  }
25645
25685
  if (!latestVersion) {
25646
- latestVersion = fetchLatestVersion(packageName);
25647
- if (latestVersion) {
25686
+ const fetched = fetchLatestVersion(packageName);
25687
+ if (fetched && isVersionPlausible(currentVersion, fetched)) {
25688
+ latestVersion = fetched;
25648
25689
  writeCache(cachePath, latestVersion, now);
25649
25690
  }
25650
25691
  }
@@ -26361,6 +26402,68 @@ async function generateAndWriteLockfileForDir(targetDir) {
26361
26402
  }
26362
26403
  }
26363
26404
 
26405
+ // src/core/rtk-installer.ts
26406
+ import { execSync as execSync3 } from "node:child_process";
26407
+ import { platform } from "node:os";
26408
+ function isRtkInstalled() {
26409
+ try {
26410
+ execSync3("which rtk", { stdio: "pipe", timeout: 3000 });
26411
+ return true;
26412
+ } catch {
26413
+ return false;
26414
+ }
26415
+ }
26416
+ function getRtkVersion() {
26417
+ try {
26418
+ return execSync3("rtk --version", { encoding: "utf-8", stdio: "pipe", timeout: 3000 }).trim();
26419
+ } catch {
26420
+ return null;
26421
+ }
26422
+ }
26423
+ function installRtk() {
26424
+ if (process.env.CI || false || false) {
26425
+ return false;
26426
+ }
26427
+ if (isRtkInstalled()) {
26428
+ info("rtk.already_installed");
26429
+ return true;
26430
+ }
26431
+ const os = platform();
26432
+ try {
26433
+ if (os === "darwin") {
26434
+ try {
26435
+ info("rtk.installing_brew");
26436
+ execSync3("brew install rtk-ai/tap/rtk", {
26437
+ stdio: "inherit",
26438
+ timeout: 120000
26439
+ });
26440
+ return true;
26441
+ } catch {
26442
+ info("rtk.installing_curl");
26443
+ execSync3("curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh", {
26444
+ stdio: "inherit",
26445
+ timeout: 120000
26446
+ });
26447
+ return isRtkInstalled();
26448
+ }
26449
+ } else if (os === "linux") {
26450
+ info("rtk.installing_curl");
26451
+ execSync3("curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh", {
26452
+ stdio: "inherit",
26453
+ timeout: 120000
26454
+ });
26455
+ return isRtkInstalled();
26456
+ } else {
26457
+ warn("rtk.unsupported_os", { os });
26458
+ return false;
26459
+ }
26460
+ } catch (err) {
26461
+ const message = err instanceof Error ? err.message : String(err);
26462
+ warn("rtk.install_failed", { error: message });
26463
+ return false;
26464
+ }
26465
+ }
26466
+
26364
26467
  // src/cli/doctor.ts
26365
26468
  async function pathExists(targetPath) {
26366
26469
  try {
@@ -26660,6 +26763,23 @@ async function checkHooks(targetDir, rootDir = ".claude") {
26660
26763
  fixable: false
26661
26764
  };
26662
26765
  }
26766
+ async function checkRtk() {
26767
+ if (!isRtkInstalled()) {
26768
+ return {
26769
+ name: "RTK",
26770
+ status: "warn",
26771
+ message: "RTK not installed — token savings unavailable (brew install rtk-ai/tap/rtk)",
26772
+ fixable: true
26773
+ };
26774
+ }
26775
+ const version = getRtkVersion();
26776
+ return {
26777
+ name: "RTK",
26778
+ status: "pass",
26779
+ message: `RTK OK (${version ?? "unknown version"})`,
26780
+ fixable: false
26781
+ };
26782
+ }
26663
26783
  async function checkContexts(targetDir, rootDir = ".claude") {
26664
26784
  const contextsDir = path.join(targetDir, rootDir, "contexts");
26665
26785
  const exists2 = await isDirectory(contextsDir);
@@ -26762,7 +26882,8 @@ async function fixSingleIssue(check, targetDir, rootDir = ".claude") {
26762
26882
  const fullPaths = check.details.map((d) => path.join(targetDir, d));
26763
26883
  const fixedCount = await fixBrokenSymlinks(targetDir, fullPaths);
26764
26884
  return fixedCount > 0;
26765
- }
26885
+ },
26886
+ RTK: async () => Promise.resolve(installRtk())
26766
26887
  };
26767
26888
  const fixer = fixMap[check.name];
26768
26889
  return fixer ? fixer() : false;
@@ -26910,7 +27031,8 @@ async function runAllChecks(targetDir, layout, packageVersion, includeUpdates) {
26910
27031
  checkGuides(targetDir),
26911
27032
  checkHooks(targetDir, layout.rootDir),
26912
27033
  checkContexts(targetDir, layout.rootDir),
26913
- checkCustomComponents(targetDir, layout.rootDir)
27034
+ checkCustomComponents(targetDir, layout.rootDir),
27035
+ checkRtk()
26914
27036
  ]);
26915
27037
  const frameworkCheck = await checkFrameworkDrift(targetDir, packageVersion);
26916
27038
  const checksWithFramework = frameworkCheck ? [...baseChecks, frameworkCheck] : baseChecks;
@@ -27558,6 +27680,19 @@ async function updateInstallConfig(targetDir, options, installedComponents) {
27558
27680
  config.installedComponents = installedComponents;
27559
27681
  await saveConfig(targetDir, config);
27560
27682
  }
27683
+ function installRtkIfNeeded(result) {
27684
+ if (!isRtkInstalled()) {
27685
+ info("install.rtk_installing");
27686
+ const rtkInstalled = installRtk();
27687
+ if (rtkInstalled) {
27688
+ info("install.rtk_success");
27689
+ } else {
27690
+ result.warnings.push("RTK installation failed — install manually: brew install rtk-ai/tap/rtk");
27691
+ }
27692
+ } else {
27693
+ info("install.rtk_already");
27694
+ }
27695
+ }
27561
27696
  async function install(options) {
27562
27697
  const result = createInstallResult(options.targetDir);
27563
27698
  try {
@@ -27595,6 +27730,7 @@ async function install(options) {
27595
27730
  } else {
27596
27731
  info("install.lockfile_generated", { files: String(lockfileResult.fileCount) });
27597
27732
  }
27733
+ installRtkIfNeeded(result);
27598
27734
  result.success = true;
27599
27735
  success("install.success");
27600
27736
  } catch (err) {
@@ -27778,7 +27914,7 @@ async function backupExistingInstallation(targetDir) {
27778
27914
 
27779
27915
  // src/core/mcp-config.ts
27780
27916
  init_fs();
27781
- import { execSync as execSync3 } from "node:child_process";
27917
+ import { execSync as execSync4 } from "node:child_process";
27782
27918
  import { writeFile } from "node:fs/promises";
27783
27919
  import { join as join8 } from "node:path";
27784
27920
  async function generateMCPConfig(targetDir) {
@@ -27790,15 +27926,15 @@ async function generateMCPConfig(targetDir) {
27790
27926
  return;
27791
27927
  }
27792
27928
  try {
27793
- execSync3("uv --version", { stdio: "pipe" });
27929
+ execSync4("uv --version", { stdio: "pipe" });
27794
27930
  } catch {
27795
27931
  warn("uv (Python package manager) not found. Install it with: curl -LsSf https://astral.sh/uv/install.sh | sh");
27796
27932
  warn("Skipping ontology-rag MCP configuration. You can set it up manually later.");
27797
27933
  return;
27798
27934
  }
27799
27935
  try {
27800
- execSync3("uv venv .venv", { cwd: targetDir, stdio: "pipe" });
27801
- execSync3('uv pip install "ontology-rag @ git+https://github.com/baekenough/oh-my-customcode.git#subdirectory=packages/ontology-rag"', { cwd: targetDir, stdio: "pipe" });
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" });
27802
27938
  } catch (error2) {
27803
27939
  const msg = error2 instanceof Error ? error2.message : String(error2);
27804
27940
  warn(`Failed to setup ontology-rag: ${msg}`);
@@ -27841,7 +27977,7 @@ async function generateMCPConfig(targetDir) {
27841
27977
  }
27842
27978
  async function checkUvAvailable() {
27843
27979
  try {
27844
- execSync3("uv --version", { stdio: "pipe" });
27980
+ execSync4("uv --version", { stdio: "pipe" });
27845
27981
  return true;
27846
27982
  } catch {
27847
27983
  return false;
@@ -29836,8 +29972,8 @@ init_package();
29836
29972
 
29837
29973
  // src/core/updater.ts
29838
29974
  init_package();
29839
- init_fs();
29840
29975
  import { join as join14 } from "node:path";
29976
+ init_fs();
29841
29977
 
29842
29978
  // src/core/entry-merger.ts
29843
29979
  var MANAGED_START = "<!-- omcustom:start -->";
@@ -30160,6 +30296,16 @@ function compareSemver2(a, b) {
30160
30296
  }
30161
30297
  return 0;
30162
30298
  }
30299
+ function checkAndInstallRtkAfterUpdate() {
30300
+ if (!isRtkInstalled()) {
30301
+ warn("update.rtk_missing");
30302
+ console.log(i18n.t("cli.update.rtkMissing"));
30303
+ const rtkInstalled = installRtk();
30304
+ if (rtkInstalled) {
30305
+ console.log(i18n.t("cli.update.rtkInstalled"));
30306
+ }
30307
+ }
30308
+ }
30163
30309
  async function update(options) {
30164
30310
  const result = createUpdateResult();
30165
30311
  try {
@@ -30207,6 +30353,7 @@ async function update(options) {
30207
30353
  files: String(lockfileResult.fileCount)
30208
30354
  });
30209
30355
  }
30356
+ checkAndInstallRtkAfterUpdate();
30210
30357
  } catch (err) {
30211
30358
  const message = err instanceof Error ? err.message : String(err);
30212
30359
  result.error = message;