oh-my-customcode 0.12.0 → 0.12.1

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 (67) hide show
  1. package/dist/cli/index.js +326 -53
  2. package/package.json +1 -1
  3. package/templates/.codex/agents/arch-documenter.md +1 -1
  4. package/templates/.codex/agents/arch-speckit-agent.md +2 -2
  5. package/templates/.codex/agents/be-express-expert.md +1 -1
  6. package/templates/.codex/agents/be-fastapi-expert.md +1 -1
  7. package/templates/.codex/agents/be-go-backend-expert.md +1 -1
  8. package/templates/.codex/agents/be-nestjs-expert.md +1 -1
  9. package/templates/.codex/agents/be-springboot-expert.md +1 -1
  10. package/templates/.codex/agents/db-postgres-expert.md +1 -1
  11. package/templates/.codex/agents/db-redis-expert.md +1 -1
  12. package/templates/.codex/agents/db-supabase-expert.md +1 -1
  13. package/templates/.codex/agents/de-airflow-expert.md +1 -1
  14. package/templates/.codex/agents/de-dbt-expert.md +1 -1
  15. package/templates/.codex/agents/de-kafka-expert.md +1 -1
  16. package/templates/.codex/agents/de-pipeline-expert.md +1 -1
  17. package/templates/.codex/agents/de-snowflake-expert.md +1 -1
  18. package/templates/.codex/agents/de-spark-expert.md +1 -1
  19. package/templates/.codex/agents/fe-svelte-agent.md +1 -1
  20. package/templates/.codex/agents/fe-vercel-agent.md +1 -1
  21. package/templates/.codex/agents/fe-vuejs-agent.md +1 -1
  22. package/templates/.codex/agents/infra-aws-expert.md +2 -2
  23. package/templates/.codex/agents/infra-docker-expert.md +2 -2
  24. package/templates/.codex/agents/lang-golang-expert.md +1 -1
  25. package/templates/.codex/agents/lang-java21-expert.md +1 -1
  26. package/templates/.codex/agents/lang-kotlin-expert.md +1 -1
  27. package/templates/.codex/agents/lang-python-expert.md +1 -1
  28. package/templates/.codex/agents/lang-rust-expert.md +1 -1
  29. package/templates/.codex/agents/lang-typescript-expert.md +1 -1
  30. package/templates/.codex/agents/mgr-claude-code-bible.md +25 -28
  31. package/templates/.codex/agents/mgr-creator.md +3 -3
  32. package/templates/.codex/agents/mgr-gitnerd.md +1 -1
  33. package/templates/.codex/agents/mgr-sauron.md +11 -11
  34. package/templates/.codex/agents/mgr-supplier.md +1 -1
  35. package/templates/.codex/agents/mgr-sync-checker.md +4 -4
  36. package/templates/.codex/agents/mgr-updater.md +2 -2
  37. package/templates/.codex/agents/qa-engineer.md +1 -1
  38. package/templates/.codex/agents/qa-planner.md +1 -1
  39. package/templates/.codex/agents/qa-writer.md +1 -1
  40. package/templates/.codex/agents/sys-memory-keeper.md +2 -2
  41. package/templates/.codex/agents/sys-naggy.md +1 -1
  42. package/templates/.codex/agents/tool-bun-expert.md +1 -1
  43. package/templates/.codex/agents/tool-npm-expert.md +1 -1
  44. package/templates/.codex/agents/tool-optimizer.md +1 -1
  45. package/templates/.codex/codex-native-hash.txt +1 -1
  46. package/templates/.codex/contexts/index.yaml +2 -2
  47. package/templates/.codex/hooks/hooks.json +3 -4
  48. package/templates/.codex/install-hooks.sh +16 -16
  49. package/templates/.codex/rules/MUST-agent-design.md +7 -7
  50. package/templates/.codex/rules/MUST-agent-identification.md +2 -2
  51. package/templates/.codex/rules/MUST-intent-transparency.md +1 -1
  52. package/templates/.codex/rules/MUST-orchestrator-coordination.md +12 -12
  53. package/templates/.codex/rules/MUST-parallel-execution.md +4 -4
  54. package/templates/.codex/rules/MUST-sync-verification.md +18 -18
  55. package/templates/.codex/rules/MUST-tool-identification.md +15 -15
  56. package/templates/.codex/rules/SHOULD-hud-statusline.md +3 -3
  57. package/templates/.codex/rules/SHOULD-memory-integration.md +4 -4
  58. package/templates/.codex/skills/claude-code-bible/SKILL.md +63 -143
  59. package/templates/.codex/skills/claude-code-bible/scripts/fetch-docs.js +182 -154
  60. package/templates/.codex/skills/de-lead-routing/SKILL.md +19 -19
  61. package/templates/.codex/skills/dev-lead-routing/SKILL.md +3 -3
  62. package/templates/.codex/skills/intent-detection/patterns/agent-triggers.yaml +1 -1
  63. package/templates/.codex/skills/monitoring-setup/SKILL.md +3 -3
  64. package/templates/.codex/skills/qa-lead-routing/SKILL.md +21 -21
  65. package/templates/.codex/skills/secretary-routing/SKILL.md +22 -22
  66. package/templates/.codex/uninstall-hooks.sh +9 -9
  67. package/templates/.codex/skills/go-best-practices/CLAUDE.md +0 -9
package/dist/cli/index.js CHANGED
@@ -9241,6 +9241,13 @@ function formatPreflightWarnings(result) {
9241
9241
  `);
9242
9242
  }
9243
9243
 
9244
+ // src/core/self-update.ts
9245
+ import { execSync as execSync2, spawnSync } from "node:child_process";
9246
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
9247
+ import { homedir } from "node:os";
9248
+ import { dirname, join } from "node:path";
9249
+ import { createInterface } from "node:readline/promises";
9250
+
9244
9251
  // node_modules/i18next/dist/esm/i18next.js
9245
9252
  var isString = (obj) => typeof obj === "string";
9246
9253
  var defer = () => {
@@ -11656,7 +11663,7 @@ var en_default = {
11656
11663
  unknownError: "An unknown error occurred"
11657
11664
  },
11658
11665
  cli: {
11659
- description: "Batteries-included agent harness for Claude Code",
11666
+ description: "Batteries-included agent harness for Claude Code and OpenAI Codex",
11660
11667
  versionOption: "Show version number",
11661
11668
  usage: "Usage: omcustom <command> [options]",
11662
11669
  commands: "Commands",
@@ -11680,6 +11687,18 @@ var en_default = {
11680
11687
  homebrewNotFound: "Homebrew not found, skipping version check",
11681
11688
  timeout: "Version check timed out, continuing..."
11682
11689
  },
11690
+ selfUpdate: {
11691
+ checking: "Checking for oh-my-customcode updates...",
11692
+ available: "📦 New version available: v{{current}} → v{{latest}}",
11693
+ prompt: "Would you like to update oh-my-customcode first? (Y/n): ",
11694
+ updatingGlobal: "⬆️ Updating oh-my-customcode globally to v{{version}}...",
11695
+ updatingNpx: "⬆️ Launching latest version via npx (v{{version}})...",
11696
+ updated: "✅ Updated to v{{version}}",
11697
+ declined: "Continuing with current version.",
11698
+ failed: "Self-update failed: {{error}}",
11699
+ relaunchFailed: "Failed to launch latest version via npx (status: {{status}}).",
11700
+ continueAfterFailure: "Continuing init with current version."
11701
+ },
11683
11702
  init: {
11684
11703
  description: "Initialize oh-my-customcode in the current directory",
11685
11704
  langOption: "Language for templates (en or ko)",
@@ -11940,7 +11959,7 @@ var ko_default = {
11940
11959
  unknownError: "알 수 없는 오류가 발생했습니다"
11941
11960
  },
11942
11961
  cli: {
11943
- description: "Claude Code를 위한 올인원 에이전트 하네스",
11962
+ description: "Claude Code와 OpenAI Codex를 위한 올인원 에이전트 하네스",
11944
11963
  versionOption: "버전 번호 표시",
11945
11964
  usage: "사용법: omcustom <명령어> [옵션]",
11946
11965
  commands: "명령어",
@@ -11964,6 +11983,18 @@ var ko_default = {
11964
11983
  homebrewNotFound: "Homebrew를 찾을 수 없어 버전 확인을 건너뜁니다",
11965
11984
  timeout: "버전 확인 시간 초과, 계속 진행합니다..."
11966
11985
  },
11986
+ selfUpdate: {
11987
+ checking: "oh-my-customcode 업데이트 확인 중...",
11988
+ available: "📦 새 버전 사용 가능: v{{current}} → v{{latest}}",
11989
+ prompt: "먼저 oh-my-customcode를 업데이트할까요? (Y/n): ",
11990
+ updatingGlobal: "⬆️ oh-my-customcode를 전역으로 v{{version}}로 업데이트 중...",
11991
+ updatingNpx: "⬆️ npx로 최신 버전(v{{version}})을 실행합니다...",
11992
+ updated: "✅ v{{version}}로 업데이트되었습니다",
11993
+ declined: "현재 버전으로 계속 진행합니다.",
11994
+ failed: "자체 업데이트 실패: {{error}}",
11995
+ relaunchFailed: "npx 최신 버전 실행 실패 (status: {{status}}).",
11996
+ continueAfterFailure: "현재 버전으로 init을 계속 진행합니다."
11997
+ },
11967
11998
  init: {
11968
11999
  description: "현재 디렉토리에 oh-my-customcode 초기화",
11969
12000
  langOption: "템플릿 언어 (en 또는 ko)",
@@ -12247,6 +12278,242 @@ var i18n = {
12247
12278
  }
12248
12279
  };
12249
12280
 
12281
+ // src/core/self-update.ts
12282
+ var DEFAULT_PACKAGE_NAME = "oh-my-customcode";
12283
+ var DEFAULT_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
12284
+ var DEFAULT_CACHE_PATH = join(homedir(), ".oh-my-customcode", "self-update-cache.json");
12285
+ function normalizeVersion(version) {
12286
+ return version.trim().replace(/^v/i, "").split("-")[0] || "";
12287
+ }
12288
+ function compareSemver(a, b) {
12289
+ const left = normalizeVersion(a).split(".").map((n) => Number.parseInt(n, 10) || 0);
12290
+ const right = normalizeVersion(b).split(".").map((n) => Number.parseInt(n, 10) || 0);
12291
+ const maxLen = Math.max(left.length, right.length, 3);
12292
+ for (let i = 0;i < maxLen; i += 1) {
12293
+ const l = left[i] ?? 0;
12294
+ const r = right[i] ?? 0;
12295
+ if (l < r)
12296
+ return -1;
12297
+ if (l > r)
12298
+ return 1;
12299
+ }
12300
+ return 0;
12301
+ }
12302
+ function isInteractiveSession(stdin = process.stdin, stdout = process.stdout) {
12303
+ return Boolean(stdin.isTTY && stdout.isTTY);
12304
+ }
12305
+ function isNpxInvocation(argv = process.argv, env = process.env) {
12306
+ const argv1 = argv[1] || "";
12307
+ const npmExecPath = env.npm_execpath || "";
12308
+ const npmCommand = env.npm_command || "";
12309
+ return argv1.includes("/_npx/") || argv1.includes("\\_npx\\") || npmExecPath.includes("npx") || npmCommand === "exec" || env.npm_lifecycle_event === "npx";
12310
+ }
12311
+ function readCache(cachePath) {
12312
+ if (!existsSync(cachePath)) {
12313
+ return null;
12314
+ }
12315
+ try {
12316
+ const parsed = JSON.parse(readFileSync(cachePath, "utf-8"));
12317
+ if (!parsed.checkedAt || !parsed.latestVersion) {
12318
+ return null;
12319
+ }
12320
+ return {
12321
+ checkedAt: parsed.checkedAt,
12322
+ latestVersion: parsed.latestVersion
12323
+ };
12324
+ } catch {
12325
+ return null;
12326
+ }
12327
+ }
12328
+ function writeCache(cachePath, latestVersion, now) {
12329
+ const dir2 = dirname(cachePath);
12330
+ if (!existsSync(dir2)) {
12331
+ mkdirSync(dir2, { recursive: true });
12332
+ }
12333
+ const payload = {
12334
+ checkedAt: new Date(now).toISOString(),
12335
+ latestVersion
12336
+ };
12337
+ writeFileSync(cachePath, `${JSON.stringify(payload, null, 2)}
12338
+ `, "utf-8");
12339
+ }
12340
+ function isCacheFresh(cache, now, cacheTtlMs) {
12341
+ const checkedAt = new Date(cache.checkedAt).getTime();
12342
+ if (Number.isNaN(checkedAt)) {
12343
+ return false;
12344
+ }
12345
+ return now - checkedAt < cacheTtlMs;
12346
+ }
12347
+ function fetchLatestVersionFromNpm(packageName = DEFAULT_PACKAGE_NAME) {
12348
+ try {
12349
+ const output = execSync2(`npm view ${packageName} version --json`, {
12350
+ encoding: "utf-8",
12351
+ stdio: "pipe",
12352
+ timeout: 3000
12353
+ }).trim();
12354
+ if (!output) {
12355
+ return null;
12356
+ }
12357
+ let version;
12358
+ if (output.startsWith('"')) {
12359
+ version = JSON.parse(output);
12360
+ } else {
12361
+ version = output;
12362
+ }
12363
+ const normalized = normalizeVersion(version);
12364
+ return normalized || null;
12365
+ } catch {
12366
+ return null;
12367
+ }
12368
+ }
12369
+ function printContinuationSpacing() {
12370
+ console.log("");
12371
+ }
12372
+ function printContinueCurrentVersion() {
12373
+ console.warn(i18n.t("cli.selfUpdate.continueAfterFailure"));
12374
+ printContinuationSpacing();
12375
+ }
12376
+ function runNpxRelaunch(packageName, latestVersion, argv, env) {
12377
+ console.log(i18n.t("cli.selfUpdate.updatingNpx", { version: latestVersion }));
12378
+ const forwardedArgs = argv.slice(2);
12379
+ const child = spawnSync("npx", ["-y", `${packageName}@${latestVersion}`, ...forwardedArgs], {
12380
+ stdio: "inherit",
12381
+ env: {
12382
+ ...env,
12383
+ OMCUSTOM_SKIP_SELF_UPDATE: "true"
12384
+ }
12385
+ });
12386
+ if ((child.status ?? 1) === 0) {
12387
+ process.exit(0);
12388
+ }
12389
+ const status = child.status ?? -1;
12390
+ console.warn(i18n.t("cli.selfUpdate.relaunchFailed", { status }));
12391
+ printContinueCurrentVersion();
12392
+ }
12393
+ function runGlobalUpdate(packageName, latestVersion) {
12394
+ try {
12395
+ console.log(i18n.t("cli.selfUpdate.updatingGlobal", { version: latestVersion }));
12396
+ execSync2(`npm install -g ${packageName}@${latestVersion}`, {
12397
+ stdio: "inherit",
12398
+ timeout: 60000
12399
+ });
12400
+ console.log(i18n.t("cli.selfUpdate.updated", { version: latestVersion }));
12401
+ printContinuationSpacing();
12402
+ } catch (error) {
12403
+ const errorMessage = error instanceof Error ? error.message : String(error);
12404
+ console.warn(i18n.t("cli.selfUpdate.failed", { error: errorMessage }));
12405
+ printContinueCurrentVersion();
12406
+ }
12407
+ }
12408
+ function checkSelfUpdate(options) {
12409
+ const packageName = options.packageName || DEFAULT_PACKAGE_NAME;
12410
+ const cachePath = options.cachePath || DEFAULT_CACHE_PATH;
12411
+ const cacheTtlMs = options.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;
12412
+ const fetchLatestVersion = options.fetchLatestVersion || fetchLatestVersionFromNpm;
12413
+ const now = options.now ?? Date.now();
12414
+ const currentVersion = normalizeVersion(options.currentVersion);
12415
+ if (!currentVersion) {
12416
+ return {
12417
+ checked: false,
12418
+ updateAvailable: false,
12419
+ latestVersion: null,
12420
+ usedCache: false,
12421
+ reason: "invalid-current-version"
12422
+ };
12423
+ }
12424
+ let latestVersion = null;
12425
+ let usedCache = false;
12426
+ const cache = readCache(cachePath);
12427
+ if (cache && isCacheFresh(cache, now, cacheTtlMs)) {
12428
+ latestVersion = normalizeVersion(cache.latestVersion);
12429
+ usedCache = true;
12430
+ }
12431
+ if (!latestVersion) {
12432
+ latestVersion = fetchLatestVersion(packageName);
12433
+ if (latestVersion) {
12434
+ writeCache(cachePath, latestVersion, now);
12435
+ }
12436
+ }
12437
+ if (!latestVersion) {
12438
+ return {
12439
+ checked: false,
12440
+ updateAvailable: false,
12441
+ latestVersion: null,
12442
+ usedCache,
12443
+ reason: "lookup-failed"
12444
+ };
12445
+ }
12446
+ return {
12447
+ checked: true,
12448
+ updateAvailable: compareSemver(currentVersion, latestVersion) < 0,
12449
+ latestVersion,
12450
+ usedCache
12451
+ };
12452
+ }
12453
+ async function promptForSelfUpdate() {
12454
+ const rl = createInterface({
12455
+ input: process.stdin,
12456
+ output: process.stdout
12457
+ });
12458
+ try {
12459
+ const answer = await rl.question(i18n.t("cli.selfUpdate.prompt"));
12460
+ const normalized = answer.trim().toLowerCase();
12461
+ return normalized === "" || normalized === "y" || normalized === "yes";
12462
+ } finally {
12463
+ rl.close();
12464
+ }
12465
+ }
12466
+ function shouldSkipSelfUpdate(options) {
12467
+ const env = options.env || process.env;
12468
+ const argv = options.argv || process.argv;
12469
+ if (options.skip) {
12470
+ return true;
12471
+ }
12472
+ if (argv.includes("--skip-version-check")) {
12473
+ return true;
12474
+ }
12475
+ if (env.OMCUSTOM_SKIP_SELF_UPDATE === "true") {
12476
+ return true;
12477
+ }
12478
+ if (env.CI === "true" || env.GITHUB_ACTIONS === "true") {
12479
+ return true;
12480
+ }
12481
+ if (!isInteractiveSession()) {
12482
+ return true;
12483
+ }
12484
+ return false;
12485
+ }
12486
+ async function maybeHandleSelfUpdateForInit(options) {
12487
+ if (shouldSkipSelfUpdate(options)) {
12488
+ return;
12489
+ }
12490
+ const packageName = options.packageName || DEFAULT_PACKAGE_NAME;
12491
+ const currentVersion = normalizeVersion(options.currentVersion);
12492
+ const argv = options.argv || process.argv;
12493
+ const env = options.env || process.env;
12494
+ if (!currentVersion) {
12495
+ return;
12496
+ }
12497
+ console.log(i18n.t("cli.selfUpdate.checking"));
12498
+ const result = checkSelfUpdate(options);
12499
+ if (!result.checked || !result.updateAvailable || !result.latestVersion) {
12500
+ return;
12501
+ }
12502
+ const latestVersion = result.latestVersion;
12503
+ console.log(i18n.t("cli.selfUpdate.available", { current: currentVersion, latest: latestVersion }));
12504
+ const wantsUpdate = await promptForSelfUpdate();
12505
+ if (!wantsUpdate) {
12506
+ console.log(i18n.t("cli.selfUpdate.declined"));
12507
+ printContinuationSpacing();
12508
+ return;
12509
+ }
12510
+ if (isNpxInvocation(argv, env)) {
12511
+ runNpxRelaunch(packageName, latestVersion, argv, env);
12512
+ return;
12513
+ }
12514
+ runGlobalUpdate(packageName, latestVersion);
12515
+ }
12516
+
12250
12517
  // src/cli/doctor.ts
12251
12518
  import { constants, promises as fs } from "node:fs";
12252
12519
  import path from "node:path";
@@ -12298,10 +12565,10 @@ var $visit = visit.visit;
12298
12565
  var $visitAsync = visit.visitAsync;
12299
12566
 
12300
12567
  // src/core/config.ts
12301
- import { join as join2 } from "node:path";
12568
+ import { join as join3 } from "node:path";
12302
12569
 
12303
12570
  // src/utils/fs.ts
12304
- import { dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
12571
+ import { dirname as dirname2, isAbsolute, join as join2, normalize, relative, resolve, sep } from "node:path";
12305
12572
  import { fileURLToPath } from "node:url";
12306
12573
  function validatePreserveFilePath(filePath, projectRoot) {
12307
12574
  if (!filePath || filePath.trim() === "") {
@@ -12454,17 +12721,17 @@ async function readTextFile(path) {
12454
12721
  }
12455
12722
  async function writeTextFile(path, content) {
12456
12723
  const fs = await import("node:fs/promises");
12457
- await ensureDirectory(dirname(path));
12724
+ await ensureDirectory(dirname2(path));
12458
12725
  await fs.writeFile(path, content, "utf-8");
12459
12726
  }
12460
12727
  function getPackageRoot() {
12461
12728
  const currentFile = fileURLToPath(import.meta.url);
12462
- const currentDir = dirname(currentFile);
12729
+ const currentDir = dirname2(currentFile);
12463
12730
  return resolve(currentDir, "..", "..");
12464
12731
  }
12465
12732
  function resolveTemplatePath(relativePath) {
12466
12733
  const packageRoot = getPackageRoot();
12467
- return join(packageRoot, "templates", relativePath);
12734
+ return join2(packageRoot, "templates", relativePath);
12468
12735
  }
12469
12736
  async function listFiles(dir2, options = {}) {
12470
12737
  const fs = await import("node:fs/promises");
@@ -12716,7 +12983,7 @@ function getDefaultPreferences() {
12716
12983
  };
12717
12984
  }
12718
12985
  function getConfigPath(targetDir) {
12719
- return join2(targetDir, CONFIG_FILE);
12986
+ return join3(targetDir, CONFIG_FILE);
12720
12987
  }
12721
12988
  async function loadConfig(targetDir) {
12722
12989
  const configPath = getConfigPath(targetDir);
@@ -12870,7 +13137,7 @@ function getDefaultProvider() {
12870
13137
  }
12871
13138
 
12872
13139
  // src/core/provider.ts
12873
- import { join as join3 } from "node:path";
13140
+ import { join as join4 } from "node:path";
12874
13141
  var ENV_SIGNALS = {
12875
13142
  claude: [
12876
13143
  "ANTHROPIC_API_KEY",
@@ -12926,8 +13193,8 @@ function detectFromEnv(env) {
12926
13193
  return null;
12927
13194
  }
12928
13195
  async function detectFromProject(targetDir) {
12929
- const claudeMarkers = [join3(targetDir, "CLAUDE.md"), join3(targetDir, ".claude")];
12930
- const codexMarkers = [join3(targetDir, "AGENTS.md"), join3(targetDir, ".codex")];
13196
+ const claudeMarkers = [join4(targetDir, "CLAUDE.md"), join4(targetDir, ".claude")];
13197
+ const codexMarkers = [join4(targetDir, "AGENTS.md"), join4(targetDir, ".codex")];
12931
13198
  const claudeFound = await Promise.all(claudeMarkers.map((path) => fileExists(path)));
12932
13199
  const codexFound = await Promise.all(codexMarkers.map((path) => fileExists(path)));
12933
13200
  const hasClaude = claudeFound.some(Boolean);
@@ -12951,7 +13218,7 @@ async function detectFromProject(targetDir) {
12951
13218
  return null;
12952
13219
  }
12953
13220
  async function detectFromConfig(targetDir) {
12954
- const configPath = join3(targetDir, ".omcustomrc.json");
13221
+ const configPath = join4(targetDir, ".omcustomrc.json");
12955
13222
  if (!await fileExists(configPath)) {
12956
13223
  return null;
12957
13224
  }
@@ -13517,11 +13784,11 @@ async function doctorCommand(options = {}) {
13517
13784
  }
13518
13785
 
13519
13786
  // src/cli/init.ts
13520
- import { join as join6 } from "node:path";
13787
+ import { join as join7 } from "node:path";
13521
13788
 
13522
13789
  // src/core/installer.ts
13523
13790
  import { readFile as fsReadFile, writeFile as fsWriteFile, rename } from "node:fs/promises";
13524
- import { basename, join as join4 } from "node:path";
13791
+ import { basename, join as join5 } from "node:path";
13525
13792
 
13526
13793
  // src/core/git-workflow.ts
13527
13794
  import { execFileSync } from "node:child_process";
@@ -13777,7 +14044,7 @@ function getDefaultWorkflow() {
13777
14044
  var DEFAULT_LANGUAGE2 = "en";
13778
14045
  function getTemplateDir() {
13779
14046
  const packageRoot = getPackageRoot();
13780
- return join4(packageRoot, "templates");
14047
+ return join5(packageRoot, "templates");
13781
14048
  }
13782
14049
  function createInstallResult(targetDir) {
13783
14050
  return {
@@ -13889,7 +14156,7 @@ async function installComponent(targetDir, provider, component, options) {
13889
14156
  if (!templatePath) {
13890
14157
  return false;
13891
14158
  }
13892
- const destPath = join4(targetDir, templatePath);
14159
+ const destPath = join5(targetDir, templatePath);
13893
14160
  const destExists = await fileExists(destPath);
13894
14161
  if (destExists && !options.force && !options.backup) {
13895
14162
  debug("install.component_skipped", { component });
@@ -13917,7 +14184,7 @@ async function installEntryDoc(targetDir, provider, language, overwrite = false)
13917
14184
  const layout = getProviderLayout(provider);
13918
14185
  const templateFile = getEntryTemplateName(provider, language);
13919
14186
  const srcPath = resolveTemplatePath(templateFile);
13920
- const destPath = join4(targetDir, layout.entryFile);
14187
+ const destPath = join5(targetDir, layout.entryFile);
13921
14188
  if (!await fileExists(srcPath)) {
13922
14189
  warn("install.entry_md_not_found", { language, path: srcPath, entry: layout.entryFile });
13923
14190
  return false;
@@ -13938,7 +14205,7 @@ async function installEntryDoc(targetDir, provider, language, overwrite = false)
13938
14205
  }
13939
14206
  async function backupExisting(sourcePath, backupDir) {
13940
14207
  const name = basename(sourcePath);
13941
- const backupPath = join4(backupDir, name);
14208
+ const backupPath = join5(backupDir, name);
13942
14209
  await rename(sourcePath, backupPath);
13943
14210
  return backupPath;
13944
14211
  }
@@ -13947,7 +14214,7 @@ async function checkExistingPaths(targetDir, provider) {
13947
14214
  const pathsToCheck = [layout.entryFile, layout.rootDir, "guides"];
13948
14215
  const existingPaths = [];
13949
14216
  for (const relativePath of pathsToCheck) {
13950
- const fullPath = join4(targetDir, relativePath);
14217
+ const fullPath = join5(targetDir, relativePath);
13951
14218
  if (await fileExists(fullPath)) {
13952
14219
  existingPaths.push(relativePath);
13953
14220
  }
@@ -13961,11 +14228,11 @@ async function backupExistingInstallation(targetDir, provider) {
13961
14228
  return [];
13962
14229
  }
13963
14230
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
13964
- const backupDir = join4(targetDir, `${layout.backupDirPrefix}${timestamp}`);
14231
+ const backupDir = join5(targetDir, `${layout.backupDirPrefix}${timestamp}`);
13965
14232
  await ensureDirectory(backupDir);
13966
14233
  const backedUpPaths = [];
13967
14234
  for (const relativePath of existingPaths) {
13968
- const fullPath = join4(targetDir, relativePath);
14235
+ const fullPath = join5(targetDir, relativePath);
13969
14236
  try {
13970
14237
  const backupPath = await backupExisting(fullPath, backupDir);
13971
14238
  backedUpPaths.push(backupPath);
@@ -13979,14 +14246,14 @@ async function backupExistingInstallation(targetDir, provider) {
13979
14246
  }
13980
14247
 
13981
14248
  // src/core/mcp-config.ts
13982
- import { execSync as execSync2 } from "node:child_process";
14249
+ import { execSync as execSync3 } from "node:child_process";
13983
14250
  import { writeFile } from "node:fs/promises";
13984
- import { join as join5 } from "node:path";
14251
+ import { join as join6 } from "node:path";
13985
14252
  async function generateMCPConfig(targetDir, provider) {
13986
14253
  const layout = getProviderLayout(provider);
13987
- const mcpConfigPath = join5(targetDir, ".mcp.json");
13988
- const ontologyDir = join5(layout.rootDir, "ontology");
13989
- const ontologyExists = await fileExists(join5(targetDir, ontologyDir));
14254
+ const mcpConfigPath = join6(targetDir, ".mcp.json");
14255
+ const ontologyDir = join6(layout.rootDir, "ontology");
14256
+ const ontologyExists = await fileExists(join6(targetDir, ontologyDir));
13990
14257
  if (!ontologyExists) {
13991
14258
  return;
13992
14259
  }
@@ -14025,7 +14292,7 @@ async function generateMCPConfig(targetDir, provider) {
14025
14292
  }
14026
14293
  async function checkPythonAvailable() {
14027
14294
  try {
14028
- execSync2("python --version", { stdio: "pipe" });
14295
+ execSync3("python --version", { stdio: "pipe" });
14029
14296
  return true;
14030
14297
  } catch {
14031
14298
  return false;
@@ -14035,20 +14302,20 @@ async function checkPythonAvailable() {
14035
14302
  // src/cli/init.ts
14036
14303
  async function checkExistingInstallation(targetDir, provider) {
14037
14304
  const layout = getProviderLayout(provider);
14038
- const rootDir = join6(targetDir, layout.rootDir);
14305
+ const rootDir = join7(targetDir, layout.rootDir);
14039
14306
  return fileExists(rootDir);
14040
14307
  }
14041
14308
  var PROVIDER_SUBDIR_COMPONENTS = new Set(["rules", "hooks", "contexts", "agents", "skills"]);
14042
14309
  function componentToPath(targetDir, provider, component) {
14043
14310
  if (component === "entry-md") {
14044
14311
  const layout = getProviderLayout(provider);
14045
- return join6(targetDir, layout.entryFile);
14312
+ return join7(targetDir, layout.entryFile);
14046
14313
  }
14047
14314
  if (PROVIDER_SUBDIR_COMPONENTS.has(component)) {
14048
14315
  const layout = getProviderLayout(provider);
14049
- return join6(targetDir, layout.rootDir, component);
14316
+ return join7(targetDir, layout.rootDir, component);
14050
14317
  }
14051
- return join6(targetDir, component);
14318
+ return join7(targetDir, component);
14052
14319
  }
14053
14320
  function buildInstalledPaths(targetDir, provider, components) {
14054
14321
  return components.map((component) => componentToPath(targetDir, provider, component));
@@ -14130,7 +14397,7 @@ async function initCommand(options) {
14130
14397
  }
14131
14398
 
14132
14399
  // src/cli/list.ts
14133
- import { basename as basename2, dirname as dirname2, join as join7, relative as relative2 } from "node:path";
14400
+ import { basename as basename2, dirname as dirname3, join as join8, relative as relative2 } from "node:path";
14134
14401
  var ALLOWED_TOP_LEVEL_KEYS = new Set(["name", "type", "description", "version", "category"]);
14135
14402
  function parseKeyValue(line) {
14136
14403
  const colonIndex = line.indexOf(":");
@@ -14194,12 +14461,12 @@ function extractAgentTypeFromFilename(filename) {
14194
14461
  return prefixMap[prefix] || "unknown";
14195
14462
  }
14196
14463
  function extractSkillCategoryFromPath(skillPath, baseDir, rootDir) {
14197
- const relativePath = relative2(join7(baseDir, rootDir, "skills"), skillPath);
14464
+ const relativePath = relative2(join8(baseDir, rootDir, "skills"), skillPath);
14198
14465
  const parts = relativePath.split("/").filter(Boolean);
14199
14466
  return parts[0] || "unknown";
14200
14467
  }
14201
14468
  function extractGuideCategoryFromPath(guidePath, baseDir) {
14202
- const relativePath = relative2(join7(baseDir, "guides"), guidePath);
14469
+ const relativePath = relative2(join8(baseDir, "guides"), guidePath);
14203
14470
  const parts = relativePath.split("/").filter(Boolean);
14204
14471
  return parts[0] || "unknown";
14205
14472
  }
@@ -14293,7 +14560,7 @@ async function tryExtractMarkdownDescription(mdPath, options = {}) {
14293
14560
  }
14294
14561
  }
14295
14562
  async function getAgents(targetDir, rootDir = ".claude", config) {
14296
- const agentsDir = join7(targetDir, rootDir, "agents");
14563
+ const agentsDir = join8(targetDir, rootDir, "agents");
14297
14564
  if (!await fileExists(agentsDir))
14298
14565
  return [];
14299
14566
  try {
@@ -14321,7 +14588,7 @@ async function getAgents(targetDir, rootDir = ".claude", config) {
14321
14588
  }
14322
14589
  }
14323
14590
  async function getSkills(targetDir, rootDir = ".claude", config) {
14324
- const skillsDir = join7(targetDir, rootDir, "skills");
14591
+ const skillsDir = join8(targetDir, rootDir, "skills");
14325
14592
  if (!await fileExists(skillsDir))
14326
14593
  return [];
14327
14594
  try {
@@ -14330,8 +14597,8 @@ async function getSkills(targetDir, rootDir = ".claude", config) {
14330
14597
  const customSkillPaths = new Set(customComponents.filter((c) => c.type === "skill").map((c) => c.path));
14331
14598
  const skillMdFiles = await listFiles(skillsDir, { recursive: true, pattern: "SKILL.md" });
14332
14599
  const skills = await Promise.all(skillMdFiles.map(async (skillMdPath) => {
14333
- const skillDir = dirname2(skillMdPath);
14334
- const indexYamlPath = join7(skillDir, "index.yaml");
14600
+ const skillDir = dirname3(skillMdPath);
14601
+ const indexYamlPath = join8(skillDir, "index.yaml");
14335
14602
  const { description, version } = await tryReadIndexYamlMetadata(indexYamlPath);
14336
14603
  const relativePath = relative2(targetDir, skillDir);
14337
14604
  return {
@@ -14350,7 +14617,7 @@ async function getSkills(targetDir, rootDir = ".claude", config) {
14350
14617
  }
14351
14618
  }
14352
14619
  async function getGuides(targetDir, config) {
14353
- const guidesDir = join7(targetDir, "guides");
14620
+ const guidesDir = join8(targetDir, "guides");
14354
14621
  if (!await fileExists(guidesDir))
14355
14622
  return [];
14356
14623
  try {
@@ -14377,7 +14644,7 @@ async function getGuides(targetDir, config) {
14377
14644
  }
14378
14645
  var RULE_PRIORITY_ORDER = { MUST: 0, SHOULD: 1, MAY: 2 };
14379
14646
  async function getRules(targetDir, rootDir = ".claude", config) {
14380
- const rulesDir = join7(targetDir, rootDir, "rules");
14647
+ const rulesDir = join8(targetDir, rootDir, "rules");
14381
14648
  if (!await fileExists(rulesDir))
14382
14649
  return [];
14383
14650
  try {
@@ -14449,7 +14716,7 @@ function formatAsJson(components) {
14449
14716
  console.log(JSON.stringify(components, null, 2));
14450
14717
  }
14451
14718
  async function getHooks(targetDir, rootDir = ".claude") {
14452
- const hooksDir = join7(targetDir, rootDir, "hooks");
14719
+ const hooksDir = join8(targetDir, rootDir, "hooks");
14453
14720
  if (!await fileExists(hooksDir))
14454
14721
  return [];
14455
14722
  try {
@@ -14467,7 +14734,7 @@ async function getHooks(targetDir, rootDir = ".claude") {
14467
14734
  }
14468
14735
  }
14469
14736
  async function getContexts(targetDir, rootDir = ".claude") {
14470
- const contextsDir = join7(targetDir, rootDir, "contexts");
14737
+ const contextsDir = join8(targetDir, rootDir, "contexts");
14471
14738
  if (!await fileExists(contextsDir))
14472
14739
  return [];
14473
14740
  try {
@@ -14552,7 +14819,7 @@ async function listCommand(type = "all", options = {}) {
14552
14819
  }
14553
14820
 
14554
14821
  // src/core/updater.ts
14555
- import { join as join8 } from "node:path";
14822
+ import { join as join9 } from "node:path";
14556
14823
 
14557
14824
  // src/core/entry-merger.ts
14558
14825
  var MANAGED_START = "<!-- omcustom:start -->";
@@ -14804,7 +15071,7 @@ function resolveCustomizations(customizations, configPreserveFiles, targetDir) {
14804
15071
  }
14805
15072
  async function updateEntryDoc(targetDir, provider, config, options) {
14806
15073
  const layout = getProviderLayout(provider);
14807
- const entryPath = join8(targetDir, layout.entryFile);
15074
+ const entryPath = join9(targetDir, layout.entryFile);
14808
15075
  const templateName = getEntryTemplateName2(provider, config.language);
14809
15076
  const templatePath = resolveTemplatePath(templateName);
14810
15077
  if (!await fileExists(templatePath)) {
@@ -14927,7 +15194,7 @@ async function updateComponent(targetDir, provider, component, customizations, o
14927
15194
  const preservedFiles = [];
14928
15195
  const componentPath = getComponentPath2(provider, component);
14929
15196
  const srcPath = resolveTemplatePath(componentPath);
14930
- const destPath = join8(targetDir, componentPath);
15197
+ const destPath = join9(targetDir, componentPath);
14931
15198
  const customComponents = config.customComponents || [];
14932
15199
  const skipPaths = [];
14933
15200
  if (customizations && !options.forceOverwriteAll) {
@@ -14941,7 +15208,7 @@ async function updateComponent(targetDir, provider, component, customizations, o
14941
15208
  }
14942
15209
  }
14943
15210
  const path2 = await import("node:path");
14944
- const normalizedSkipPaths = skipPaths.map((p) => path2.relative(destPath, join8(targetDir, p)));
15211
+ const normalizedSkipPaths = skipPaths.map((p) => path2.relative(destPath, join9(targetDir, p)));
14945
15212
  await copyDirectory(srcPath, destPath, {
14946
15213
  overwrite: true,
14947
15214
  skipPaths: normalizedSkipPaths.length > 0 ? normalizedSkipPaths : undefined
@@ -14961,26 +15228,26 @@ function getComponentPath2(provider, component) {
14961
15228
  }
14962
15229
  async function backupInstallation(targetDir, provider) {
14963
15230
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
14964
- const backupDir = join8(targetDir, `.omcustom-backup-${timestamp}`);
15231
+ const backupDir = join9(targetDir, `.omcustom-backup-${timestamp}`);
14965
15232
  const fs2 = await import("node:fs/promises");
14966
15233
  await ensureDirectory(backupDir);
14967
15234
  const layout = getProviderLayout(provider);
14968
15235
  const dirsToBackup = [layout.rootDir, "guides"];
14969
15236
  for (const dir2 of dirsToBackup) {
14970
- const srcPath = join8(targetDir, dir2);
15237
+ const srcPath = join9(targetDir, dir2);
14971
15238
  if (await fileExists(srcPath)) {
14972
- const destPath = join8(backupDir, dir2);
15239
+ const destPath = join9(backupDir, dir2);
14973
15240
  await copyDirectory(srcPath, destPath, { overwrite: true });
14974
15241
  }
14975
15242
  }
14976
- const entryPath = join8(targetDir, layout.entryFile);
15243
+ const entryPath = join9(targetDir, layout.entryFile);
14977
15244
  if (await fileExists(entryPath)) {
14978
- await fs2.copyFile(entryPath, join8(backupDir, layout.entryFile));
15245
+ await fs2.copyFile(entryPath, join9(backupDir, layout.entryFile));
14979
15246
  }
14980
15247
  return backupDir;
14981
15248
  }
14982
15249
  async function loadCustomizationManifest(targetDir) {
14983
- const manifestPath = join8(targetDir, CUSTOMIZATION_MANIFEST_FILE);
15250
+ const manifestPath = join9(targetDir, CUSTOMIZATION_MANIFEST_FILE);
14984
15251
  if (await fileExists(manifestPath)) {
14985
15252
  return readJsonFile(manifestPath);
14986
15253
  }
@@ -15093,9 +15360,15 @@ function createProgram() {
15093
15360
  program2.command("doctor").description(i18n.t("cli.doctor.description")).option("--fix", i18n.t("cli.doctor.fixOption")).option("-p, --provider <provider>", i18n.t("cli.doctor.providerOption"), "auto").action(async (options) => {
15094
15361
  await doctorCommand(options);
15095
15362
  });
15096
- program2.hook("preAction", async (thisCommand) => {
15363
+ program2.hook("preAction", async (thisCommand, actionCommand) => {
15097
15364
  const opts = thisCommand.optsWithGlobals();
15098
15365
  const skipCheck = opts.skipVersionCheck || false;
15366
+ if (actionCommand.name() === "init") {
15367
+ await maybeHandleSelfUpdateForInit({
15368
+ currentVersion: packageJson.version,
15369
+ skip: skipCheck
15370
+ });
15371
+ }
15099
15372
  const result = await runPreflightCheck({ skip: skipCheck });
15100
15373
  if (result.hasUpdates) {
15101
15374
  const warnings = formatPreflightWarnings(result);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-customcode",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Batteries-included agent harness for Claude Code and OpenAI Codex",
5
5
  "type": "module",
6
6
  "bin": {