oh-my-customcode 0.12.0 → 0.12.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 (131) hide show
  1. package/README.md +4 -8
  2. package/dist/cli/index.js +382 -308
  3. package/dist/index.js +99 -260
  4. package/package.json +2 -4
  5. package/templates/.codex/agents/arch-documenter.md +0 -33
  6. package/templates/.codex/agents/arch-speckit-agent.md +0 -47
  7. package/templates/.codex/agents/be-express-expert.md +0 -30
  8. package/templates/.codex/agents/be-fastapi-expert.md +0 -43
  9. package/templates/.codex/agents/be-go-backend-expert.md +0 -43
  10. package/templates/.codex/agents/be-nestjs-expert.md +0 -28
  11. package/templates/.codex/agents/be-springboot-expert.md +0 -40
  12. package/templates/.codex/agents/db-postgres-expert.md +0 -36
  13. package/templates/.codex/agents/db-redis-expert.md +0 -36
  14. package/templates/.codex/agents/db-supabase-expert.md +0 -35
  15. package/templates/.codex/agents/de-airflow-expert.md +0 -34
  16. package/templates/.codex/agents/de-dbt-expert.md +0 -34
  17. package/templates/.codex/agents/de-kafka-expert.md +0 -81
  18. package/templates/.codex/agents/de-pipeline-expert.md +0 -32
  19. package/templates/.codex/agents/de-snowflake-expert.md +0 -36
  20. package/templates/.codex/agents/de-spark-expert.md +0 -36
  21. package/templates/.codex/agents/fe-svelte-agent.md +0 -29
  22. package/templates/.codex/agents/fe-vercel-agent.md +0 -37
  23. package/templates/.codex/agents/fe-vuejs-agent.md +0 -30
  24. package/templates/.codex/agents/infra-aws-expert.md +0 -47
  25. package/templates/.codex/agents/infra-docker-expert.md +0 -47
  26. package/templates/.codex/agents/lang-golang-expert.md +0 -43
  27. package/templates/.codex/agents/lang-java21-expert.md +0 -39
  28. package/templates/.codex/agents/lang-kotlin-expert.md +0 -43
  29. package/templates/.codex/agents/lang-python-expert.md +0 -43
  30. package/templates/.codex/agents/lang-rust-expert.md +0 -43
  31. package/templates/.codex/agents/lang-typescript-expert.md +0 -43
  32. package/templates/.codex/agents/mgr-claude-code-bible.md +0 -61
  33. package/templates/.codex/agents/mgr-creator.md +0 -39
  34. package/templates/.codex/agents/mgr-gitnerd.md +0 -45
  35. package/templates/.codex/agents/mgr-sauron.md +0 -161
  36. package/templates/.codex/agents/mgr-supplier.md +0 -35
  37. package/templates/.codex/agents/mgr-sync-checker.md +0 -38
  38. package/templates/.codex/agents/mgr-updater.md +0 -33
  39. package/templates/.codex/agents/qa-engineer.md +0 -32
  40. package/templates/.codex/agents/qa-planner.md +0 -73
  41. package/templates/.codex/agents/qa-writer.md +0 -27
  42. package/templates/.codex/agents/sys-memory-keeper.md +0 -43
  43. package/templates/.codex/agents/sys-naggy.md +0 -37
  44. package/templates/.codex/agents/tool-bun-expert.md +0 -26
  45. package/templates/.codex/agents/tool-npm-expert.md +0 -30
  46. package/templates/.codex/agents/tool-optimizer.md +0 -34
  47. package/templates/.codex/codex-native-hash.txt +0 -1
  48. package/templates/.codex/contexts/dev.md +0 -20
  49. package/templates/.codex/contexts/ecomode.md +0 -63
  50. package/templates/.codex/contexts/index.yaml +0 -41
  51. package/templates/.codex/contexts/research.md +0 -28
  52. package/templates/.codex/contexts/review.md +0 -23
  53. package/templates/.codex/hooks/hooks.json +0 -151
  54. package/templates/.codex/install-hooks.sh +0 -100
  55. package/templates/.codex/rules/MAY-optimization.md +0 -29
  56. package/templates/.codex/rules/MUST-agent-design.md +0 -57
  57. package/templates/.codex/rules/MUST-agent-identification.md +0 -29
  58. package/templates/.codex/rules/MUST-continuous-improvement.md +0 -25
  59. package/templates/.codex/rules/MUST-intent-transparency.md +0 -42
  60. package/templates/.codex/rules/MUST-language-policy.md +0 -27
  61. package/templates/.codex/rules/MUST-orchestrator-coordination.md +0 -128
  62. package/templates/.codex/rules/MUST-parallel-execution.md +0 -97
  63. package/templates/.codex/rules/MUST-permissions.md +0 -30
  64. package/templates/.codex/rules/MUST-safety.md +0 -23
  65. package/templates/.codex/rules/MUST-sync-verification.md +0 -125
  66. package/templates/.codex/rules/MUST-tool-identification.md +0 -82
  67. package/templates/.codex/rules/SHOULD-agent-teams.md +0 -39
  68. package/templates/.codex/rules/SHOULD-ecomode.md +0 -37
  69. package/templates/.codex/rules/SHOULD-error-handling.md +0 -33
  70. package/templates/.codex/rules/SHOULD-hud-statusline.md +0 -32
  71. package/templates/.codex/rules/SHOULD-interaction.md +0 -34
  72. package/templates/.codex/rules/SHOULD-memory-integration.md +0 -39
  73. package/templates/.codex/rules/index.yaml +0 -141
  74. package/templates/.codex/skills/airflow-best-practices/SKILL.md +0 -56
  75. package/templates/.codex/skills/audit-agents/SKILL.md +0 -116
  76. package/templates/.codex/skills/aws-best-practices/SKILL.md +0 -280
  77. package/templates/.codex/skills/claude-code-bible/SKILL.md +0 -180
  78. package/templates/.codex/skills/claude-code-bible/scripts/fetch-docs.js +0 -244
  79. package/templates/.codex/skills/create-agent/SKILL.md +0 -91
  80. package/templates/.codex/skills/dbt-best-practices/SKILL.md +0 -54
  81. package/templates/.codex/skills/de-lead-routing/SKILL.md +0 -243
  82. package/templates/.codex/skills/dev-lead-routing/SKILL.md +0 -94
  83. package/templates/.codex/skills/dev-refactor/SKILL.md +0 -123
  84. package/templates/.codex/skills/dev-review/SKILL.md +0 -81
  85. package/templates/.codex/skills/docker-best-practices/SKILL.md +0 -275
  86. package/templates/.codex/skills/fastapi-best-practices/SKILL.md +0 -270
  87. package/templates/.codex/skills/fix-refs/SKILL.md +0 -107
  88. package/templates/.codex/skills/go-backend-best-practices/SKILL.md +0 -338
  89. package/templates/.codex/skills/go-best-practices/CLAUDE.md +0 -9
  90. package/templates/.codex/skills/go-best-practices/SKILL.md +0 -203
  91. package/templates/.codex/skills/help/SKILL.md +0 -125
  92. package/templates/.codex/skills/intent-detection/SKILL.md +0 -215
  93. package/templates/.codex/skills/intent-detection/patterns/agent-triggers.yaml +0 -349
  94. package/templates/.codex/skills/kafka-best-practices/SKILL.md +0 -52
  95. package/templates/.codex/skills/kotlin-best-practices/SKILL.md +0 -256
  96. package/templates/.codex/skills/lists/SKILL.md +0 -78
  97. package/templates/.codex/skills/memory-management/SKILL.md +0 -195
  98. package/templates/.codex/skills/memory-recall/SKILL.md +0 -152
  99. package/templates/.codex/skills/memory-save/SKILL.md +0 -126
  100. package/templates/.codex/skills/monitoring-setup/SKILL.md +0 -115
  101. package/templates/.codex/skills/npm-audit/SKILL.md +0 -72
  102. package/templates/.codex/skills/npm-publish/SKILL.md +0 -63
  103. package/templates/.codex/skills/npm-version/SKILL.md +0 -75
  104. package/templates/.codex/skills/optimize-analyze/SKILL.md +0 -55
  105. package/templates/.codex/skills/optimize-bundle/SKILL.md +0 -67
  106. package/templates/.codex/skills/optimize-report/SKILL.md +0 -74
  107. package/templates/.codex/skills/pipeline-architecture-patterns/SKILL.md +0 -83
  108. package/templates/.codex/skills/postgres-best-practices/SKILL.md +0 -66
  109. package/templates/.codex/skills/python-best-practices/SKILL.md +0 -222
  110. package/templates/.codex/skills/qa-lead-routing/SKILL.md +0 -290
  111. package/templates/.codex/skills/react-best-practices/SKILL.md +0 -101
  112. package/templates/.codex/skills/redis-best-practices/SKILL.md +0 -83
  113. package/templates/.codex/skills/result-aggregation/SKILL.md +0 -164
  114. package/templates/.codex/skills/rust-best-practices/SKILL.md +0 -267
  115. package/templates/.codex/skills/sauron-watch/SKILL.md +0 -144
  116. package/templates/.codex/skills/secretary-routing/SKILL.md +0 -203
  117. package/templates/.codex/skills/snowflake-best-practices/SKILL.md +0 -65
  118. package/templates/.codex/skills/spark-best-practices/SKILL.md +0 -52
  119. package/templates/.codex/skills/springboot-best-practices/SKILL.md +0 -218
  120. package/templates/.codex/skills/status/SKILL.md +0 -153
  121. package/templates/.codex/skills/supabase-postgres-best-practices/SKILL.md +0 -99
  122. package/templates/.codex/skills/typescript-best-practices/SKILL.md +0 -321
  123. package/templates/.codex/skills/update-docs/SKILL.md +0 -140
  124. package/templates/.codex/skills/update-external/SKILL.md +0 -149
  125. package/templates/.codex/skills/vercel-deploy/SKILL.md +0 -73
  126. package/templates/.codex/skills/web-design-guidelines/SKILL.md +0 -118
  127. package/templates/.codex/skills/writing-clearly-and-concisely/SKILL.md +0 -64
  128. package/templates/.codex/uninstall-hooks.sh +0 -52
  129. package/templates/AGENTS.md.en +0 -39
  130. package/templates/AGENTS.md.ko +0 -39
  131. package/templates/manifest.codex.json +0 -43
package/dist/cli/index.js CHANGED
@@ -9153,7 +9153,7 @@ function checkOutdated(tools) {
9153
9153
  } catch {}
9154
9154
  }
9155
9155
  async function runPreflightCheck(options = {}) {
9156
- const { skip = false, tools: toolNames = ["claude-code", "codex"], timeout = 5000 } = options;
9156
+ const { skip = false, tools: toolNames = ["claude-code"], timeout = 5000 } = options;
9157
9157
  if (skip) {
9158
9158
  return {
9159
9159
  tools: [],
@@ -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 = () => {
@@ -11680,10 +11687,21 @@ 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)",
11686
- providerOption: "Provider to initialize (auto, claude, codex)",
11687
11705
  start: "Initializing oh-my-customcode...",
11688
11706
  exists: "Existing {{rootDir}} directory found.",
11689
11707
  backing_up: "Creating backup...",
@@ -11733,7 +11751,6 @@ var en_default = {
11733
11751
  guidesOption: "Update only guides",
11734
11752
  hooksOption: "Update only hooks",
11735
11753
  contextsOption: "Update only contexts",
11736
- providerOption: "Provider to update (auto, claude, codex)",
11737
11754
  dryRunHeader: "Dry run - no changes will be made:",
11738
11755
  componentUpdated: "✓ {{component}} updated",
11739
11756
  componentSkipped: "- {{component}} skipped (no changes)",
@@ -11746,7 +11763,6 @@ var en_default = {
11746
11763
  list: {
11747
11764
  description: "List installed components",
11748
11765
  typeArgument: "Type to list: agents, skills, guides, rules, or all",
11749
- providerOption: "Provider to list (auto, claude, codex)",
11750
11766
  scanning: "Scanning installed components...",
11751
11767
  empty: "No {{type}} found.",
11752
11768
  header: "{{type}} ({{count}} installed)",
@@ -11771,7 +11787,6 @@ var en_default = {
11771
11787
  doctor: {
11772
11788
  description: "Check and fix configuration issues",
11773
11789
  fixOption: "Automatically fix issues that can be fixed",
11774
- providerOption: "Provider to diagnose (auto, claude, codex)",
11775
11790
  checking: "Running diagnostic checks...",
11776
11791
  applyingFixes: "Applying fixes...",
11777
11792
  fixing: "Fixing: {{name}}...",
@@ -11964,10 +11979,21 @@ var ko_default = {
11964
11979
  homebrewNotFound: "Homebrew를 찾을 수 없어 버전 확인을 건너뜁니다",
11965
11980
  timeout: "버전 확인 시간 초과, 계속 진행합니다..."
11966
11981
  },
11982
+ selfUpdate: {
11983
+ checking: "oh-my-customcode 업데이트 확인 중...",
11984
+ available: "📦 새 버전 사용 가능: v{{current}} → v{{latest}}",
11985
+ prompt: "먼저 oh-my-customcode를 업데이트할까요? (Y/n): ",
11986
+ updatingGlobal: "⬆️ oh-my-customcode를 전역으로 v{{version}}로 업데이트 중...",
11987
+ updatingNpx: "⬆️ npx로 최신 버전(v{{version}})을 실행합니다...",
11988
+ updated: "✅ v{{version}}로 업데이트되었습니다",
11989
+ declined: "현재 버전으로 계속 진행합니다.",
11990
+ failed: "자체 업데이트 실패: {{error}}",
11991
+ relaunchFailed: "npx 최신 버전 실행 실패 (status: {{status}}).",
11992
+ continueAfterFailure: "현재 버전으로 init을 계속 진행합니다."
11993
+ },
11967
11994
  init: {
11968
11995
  description: "현재 디렉토리에 oh-my-customcode 초기화",
11969
11996
  langOption: "템플릿 언어 (en 또는 ko)",
11970
- providerOption: "초기화할 제공자 (auto, claude, codex)",
11971
11997
  start: "oh-my-customcode 초기화 중...",
11972
11998
  exists: "기존 {{rootDir}} 디렉토리가 발견되었습니다.",
11973
11999
  backing_up: "백업을 생성합니다...",
@@ -12017,7 +12043,6 @@ var ko_default = {
12017
12043
  guidesOption: "가이드만 업데이트",
12018
12044
  hooksOption: "훅만 업데이트",
12019
12045
  contextsOption: "컨텍스트만 업데이트",
12020
- providerOption: "업데이트할 제공자 (auto, claude, codex)",
12021
12046
  dryRunHeader: "드라이 런 - 변경사항 없음:",
12022
12047
  componentUpdated: "✓ {{component}} 업데이트됨",
12023
12048
  componentSkipped: "- {{component}} 건너뜀 (변경사항 없음)",
@@ -12030,7 +12055,6 @@ var ko_default = {
12030
12055
  list: {
12031
12056
  description: "설치된 컴포넌트 목록 표시",
12032
12057
  typeArgument: "표시할 타입: agents, skills, guides, rules 또는 all",
12033
- providerOption: "표시할 제공자 (auto, claude, codex)",
12034
12058
  scanning: "설치된 컴포넌트 검색 중...",
12035
12059
  empty: "{{type}}이(가) 없습니다.",
12036
12060
  header: "{{type}} ({{count}}개 설치됨)",
@@ -12055,7 +12079,6 @@ var ko_default = {
12055
12079
  doctor: {
12056
12080
  description: "설정 문제 확인 및 수정",
12057
12081
  fixOption: "자동으로 수정 가능한 문제 수정",
12058
- providerOption: "진단할 제공자 (auto, claude, codex)",
12059
12082
  checking: "진단 검사 실행 중...",
12060
12083
  applyingFixes: "수정 사항 적용 중...",
12061
12084
  fixing: "수정 중: {{name}}...",
@@ -12247,6 +12270,242 @@ var i18n = {
12247
12270
  }
12248
12271
  };
12249
12272
 
12273
+ // src/core/self-update.ts
12274
+ var DEFAULT_PACKAGE_NAME = "oh-my-customcode";
12275
+ var DEFAULT_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
12276
+ var DEFAULT_CACHE_PATH = join(homedir(), ".oh-my-customcode", "self-update-cache.json");
12277
+ function normalizeVersion(version) {
12278
+ return version.trim().replace(/^v/i, "").split("-")[0] || "";
12279
+ }
12280
+ function compareSemver(a, b) {
12281
+ const left = normalizeVersion(a).split(".").map((n) => Number.parseInt(n, 10) || 0);
12282
+ const right = normalizeVersion(b).split(".").map((n) => Number.parseInt(n, 10) || 0);
12283
+ const maxLen = Math.max(left.length, right.length, 3);
12284
+ for (let i = 0;i < maxLen; i += 1) {
12285
+ const l = left[i] ?? 0;
12286
+ const r = right[i] ?? 0;
12287
+ if (l < r)
12288
+ return -1;
12289
+ if (l > r)
12290
+ return 1;
12291
+ }
12292
+ return 0;
12293
+ }
12294
+ function isInteractiveSession(stdin = process.stdin, stdout = process.stdout) {
12295
+ return Boolean(stdin.isTTY && stdout.isTTY);
12296
+ }
12297
+ function isNpxInvocation(argv = process.argv, env = process.env) {
12298
+ const argv1 = argv[1] || "";
12299
+ const npmExecPath = env.npm_execpath || "";
12300
+ const npmCommand = env.npm_command || "";
12301
+ return argv1.includes("/_npx/") || argv1.includes("\\_npx\\") || npmExecPath.includes("npx") || npmCommand === "exec" || env.npm_lifecycle_event === "npx";
12302
+ }
12303
+ function readCache(cachePath) {
12304
+ if (!existsSync(cachePath)) {
12305
+ return null;
12306
+ }
12307
+ try {
12308
+ const parsed = JSON.parse(readFileSync(cachePath, "utf-8"));
12309
+ if (!parsed.checkedAt || !parsed.latestVersion) {
12310
+ return null;
12311
+ }
12312
+ return {
12313
+ checkedAt: parsed.checkedAt,
12314
+ latestVersion: parsed.latestVersion
12315
+ };
12316
+ } catch {
12317
+ return null;
12318
+ }
12319
+ }
12320
+ function writeCache(cachePath, latestVersion, now) {
12321
+ const dir2 = dirname(cachePath);
12322
+ if (!existsSync(dir2)) {
12323
+ mkdirSync(dir2, { recursive: true });
12324
+ }
12325
+ const payload = {
12326
+ checkedAt: new Date(now).toISOString(),
12327
+ latestVersion
12328
+ };
12329
+ writeFileSync(cachePath, `${JSON.stringify(payload, null, 2)}
12330
+ `, "utf-8");
12331
+ }
12332
+ function isCacheFresh(cache, now, cacheTtlMs) {
12333
+ const checkedAt = new Date(cache.checkedAt).getTime();
12334
+ if (Number.isNaN(checkedAt)) {
12335
+ return false;
12336
+ }
12337
+ return now - checkedAt < cacheTtlMs;
12338
+ }
12339
+ function fetchLatestVersionFromNpm(packageName = DEFAULT_PACKAGE_NAME) {
12340
+ try {
12341
+ const output = execSync2(`npm view ${packageName} version --json`, {
12342
+ encoding: "utf-8",
12343
+ stdio: "pipe",
12344
+ timeout: 3000
12345
+ }).trim();
12346
+ if (!output) {
12347
+ return null;
12348
+ }
12349
+ let version;
12350
+ if (output.startsWith('"')) {
12351
+ version = JSON.parse(output);
12352
+ } else {
12353
+ version = output;
12354
+ }
12355
+ const normalized = normalizeVersion(version);
12356
+ return normalized || null;
12357
+ } catch {
12358
+ return null;
12359
+ }
12360
+ }
12361
+ function printContinuationSpacing() {
12362
+ console.log("");
12363
+ }
12364
+ function printContinueCurrentVersion() {
12365
+ console.warn(i18n.t("cli.selfUpdate.continueAfterFailure"));
12366
+ printContinuationSpacing();
12367
+ }
12368
+ function runNpxRelaunch(packageName, latestVersion, argv, env) {
12369
+ console.log(i18n.t("cli.selfUpdate.updatingNpx", { version: latestVersion }));
12370
+ const forwardedArgs = argv.slice(2);
12371
+ const child = spawnSync("npx", ["-y", `${packageName}@${latestVersion}`, ...forwardedArgs], {
12372
+ stdio: "inherit",
12373
+ env: {
12374
+ ...env,
12375
+ OMCUSTOM_SKIP_SELF_UPDATE: "true"
12376
+ }
12377
+ });
12378
+ if ((child.status ?? 1) === 0) {
12379
+ process.exit(0);
12380
+ }
12381
+ const status = child.status ?? -1;
12382
+ console.warn(i18n.t("cli.selfUpdate.relaunchFailed", { status }));
12383
+ printContinueCurrentVersion();
12384
+ }
12385
+ function runGlobalUpdate(packageName, latestVersion) {
12386
+ try {
12387
+ console.log(i18n.t("cli.selfUpdate.updatingGlobal", { version: latestVersion }));
12388
+ execSync2(`npm install -g ${packageName}@${latestVersion}`, {
12389
+ stdio: "inherit",
12390
+ timeout: 60000
12391
+ });
12392
+ console.log(i18n.t("cli.selfUpdate.updated", { version: latestVersion }));
12393
+ printContinuationSpacing();
12394
+ } catch (error) {
12395
+ const errorMessage = error instanceof Error ? error.message : String(error);
12396
+ console.warn(i18n.t("cli.selfUpdate.failed", { error: errorMessage }));
12397
+ printContinueCurrentVersion();
12398
+ }
12399
+ }
12400
+ function checkSelfUpdate(options) {
12401
+ const packageName = options.packageName || DEFAULT_PACKAGE_NAME;
12402
+ const cachePath = options.cachePath || DEFAULT_CACHE_PATH;
12403
+ const cacheTtlMs = options.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;
12404
+ const fetchLatestVersion = options.fetchLatestVersion || fetchLatestVersionFromNpm;
12405
+ const now = options.now ?? Date.now();
12406
+ const currentVersion = normalizeVersion(options.currentVersion);
12407
+ if (!currentVersion) {
12408
+ return {
12409
+ checked: false,
12410
+ updateAvailable: false,
12411
+ latestVersion: null,
12412
+ usedCache: false,
12413
+ reason: "invalid-current-version"
12414
+ };
12415
+ }
12416
+ let latestVersion = null;
12417
+ let usedCache = false;
12418
+ const cache = readCache(cachePath);
12419
+ if (cache && isCacheFresh(cache, now, cacheTtlMs)) {
12420
+ latestVersion = normalizeVersion(cache.latestVersion);
12421
+ usedCache = true;
12422
+ }
12423
+ if (!latestVersion) {
12424
+ latestVersion = fetchLatestVersion(packageName);
12425
+ if (latestVersion) {
12426
+ writeCache(cachePath, latestVersion, now);
12427
+ }
12428
+ }
12429
+ if (!latestVersion) {
12430
+ return {
12431
+ checked: false,
12432
+ updateAvailable: false,
12433
+ latestVersion: null,
12434
+ usedCache,
12435
+ reason: "lookup-failed"
12436
+ };
12437
+ }
12438
+ return {
12439
+ checked: true,
12440
+ updateAvailable: compareSemver(currentVersion, latestVersion) < 0,
12441
+ latestVersion,
12442
+ usedCache
12443
+ };
12444
+ }
12445
+ async function promptForSelfUpdate() {
12446
+ const rl = createInterface({
12447
+ input: process.stdin,
12448
+ output: process.stdout
12449
+ });
12450
+ try {
12451
+ const answer = await rl.question(i18n.t("cli.selfUpdate.prompt"));
12452
+ const normalized = answer.trim().toLowerCase();
12453
+ return normalized === "" || normalized === "y" || normalized === "yes";
12454
+ } finally {
12455
+ rl.close();
12456
+ }
12457
+ }
12458
+ function shouldSkipSelfUpdate(options) {
12459
+ const env = options.env || process.env;
12460
+ const argv = options.argv || process.argv;
12461
+ if (options.skip) {
12462
+ return true;
12463
+ }
12464
+ if (argv.includes("--skip-version-check")) {
12465
+ return true;
12466
+ }
12467
+ if (env.OMCUSTOM_SKIP_SELF_UPDATE === "true") {
12468
+ return true;
12469
+ }
12470
+ if (env.CI === "true" || env.GITHUB_ACTIONS === "true") {
12471
+ return true;
12472
+ }
12473
+ if (!isInteractiveSession()) {
12474
+ return true;
12475
+ }
12476
+ return false;
12477
+ }
12478
+ async function maybeHandleSelfUpdateForInit(options) {
12479
+ if (shouldSkipSelfUpdate(options)) {
12480
+ return;
12481
+ }
12482
+ const packageName = options.packageName || DEFAULT_PACKAGE_NAME;
12483
+ const currentVersion = normalizeVersion(options.currentVersion);
12484
+ const argv = options.argv || process.argv;
12485
+ const env = options.env || process.env;
12486
+ if (!currentVersion) {
12487
+ return;
12488
+ }
12489
+ console.log(i18n.t("cli.selfUpdate.checking"));
12490
+ const result = checkSelfUpdate(options);
12491
+ if (!result.checked || !result.updateAvailable || !result.latestVersion) {
12492
+ return;
12493
+ }
12494
+ const latestVersion = result.latestVersion;
12495
+ console.log(i18n.t("cli.selfUpdate.available", { current: currentVersion, latest: latestVersion }));
12496
+ const wantsUpdate = await promptForSelfUpdate();
12497
+ if (!wantsUpdate) {
12498
+ console.log(i18n.t("cli.selfUpdate.declined"));
12499
+ printContinuationSpacing();
12500
+ return;
12501
+ }
12502
+ if (isNpxInvocation(argv, env)) {
12503
+ runNpxRelaunch(packageName, latestVersion, argv, env);
12504
+ return;
12505
+ }
12506
+ runGlobalUpdate(packageName, latestVersion);
12507
+ }
12508
+
12250
12509
  // src/cli/doctor.ts
12251
12510
  import { constants, promises as fs } from "node:fs";
12252
12511
  import path from "node:path";
@@ -12298,10 +12557,10 @@ var $visit = visit.visit;
12298
12557
  var $visitAsync = visit.visitAsync;
12299
12558
 
12300
12559
  // src/core/config.ts
12301
- import { join as join2 } from "node:path";
12560
+ import { join as join3 } from "node:path";
12302
12561
 
12303
12562
  // src/utils/fs.ts
12304
- import { dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
12563
+ import { dirname as dirname2, isAbsolute, join as join2, normalize, relative, resolve, sep } from "node:path";
12305
12564
  import { fileURLToPath } from "node:url";
12306
12565
  function validatePreserveFilePath(filePath, projectRoot) {
12307
12566
  if (!filePath || filePath.trim() === "") {
@@ -12454,17 +12713,17 @@ async function readTextFile(path) {
12454
12713
  }
12455
12714
  async function writeTextFile(path, content) {
12456
12715
  const fs = await import("node:fs/promises");
12457
- await ensureDirectory(dirname(path));
12716
+ await ensureDirectory(dirname2(path));
12458
12717
  await fs.writeFile(path, content, "utf-8");
12459
12718
  }
12460
12719
  function getPackageRoot() {
12461
12720
  const currentFile = fileURLToPath(import.meta.url);
12462
- const currentDir = dirname(currentFile);
12721
+ const currentDir = dirname2(currentFile);
12463
12722
  return resolve(currentDir, "..", "..");
12464
12723
  }
12465
12724
  function resolveTemplatePath(relativePath) {
12466
12725
  const packageRoot = getPackageRoot();
12467
- return join(packageRoot, "templates", relativePath);
12726
+ return join2(packageRoot, "templates", relativePath);
12468
12727
  }
12469
12728
  async function listFiles(dir2, options = {}) {
12470
12729
  const fs = await import("node:fs/promises");
@@ -12689,7 +12948,6 @@ function getDefaultConfig() {
12689
12948
  configVersion: CURRENT_CONFIG_VERSION,
12690
12949
  version: "0.0.0",
12691
12950
  language: "en",
12692
- provider: "auto",
12693
12951
  installedAt: "",
12694
12952
  lastUpdated: "",
12695
12953
  installedComponents: [],
@@ -12716,7 +12974,7 @@ function getDefaultPreferences() {
12716
12974
  };
12717
12975
  }
12718
12976
  function getConfigPath(targetDir) {
12719
- return join2(targetDir, CONFIG_FILE);
12977
+ return join3(targetDir, CONFIG_FILE);
12720
12978
  }
12721
12979
  async function loadConfig(targetDir) {
12722
12980
  const configPath = getConfigPath(targetDir);
@@ -12812,203 +13070,36 @@ function migrateConfig(config) {
12812
13070
  }
12813
13071
 
12814
13072
  // src/core/layout.ts
12815
- var PROVIDER_LAYOUTS = {
12816
- claude: {
12817
- provider: "claude",
12818
- rootDir: ".claude",
12819
- entryFile: "CLAUDE.md",
12820
- entryTemplatePrefix: "CLAUDE.md",
12821
- manifestFile: "manifest.json",
12822
- backupDirPrefix: ".claude-backup-",
12823
- directoryStructure: [
12824
- ".claude",
12825
- ".claude/rules",
12826
- ".claude/hooks",
12827
- ".claude/contexts",
12828
- ".claude/agents",
12829
- ".claude/skills",
12830
- "guides"
12831
- ]
12832
- },
12833
- codex: {
12834
- provider: "codex",
12835
- rootDir: ".codex",
12836
- entryFile: "AGENTS.md",
12837
- entryTemplatePrefix: "AGENTS.md",
12838
- manifestFile: "manifest.codex.json",
12839
- backupDirPrefix: ".codex-backup-",
12840
- directoryStructure: [
12841
- ".codex",
12842
- ".codex/rules",
12843
- ".codex/hooks",
12844
- ".codex/contexts",
12845
- ".codex/agents",
12846
- ".codex/skills",
12847
- "guides"
12848
- ]
12849
- }
13073
+ var CLAUDE_LAYOUT = {
13074
+ rootDir: ".claude",
13075
+ entryFile: "CLAUDE.md",
13076
+ entryTemplatePrefix: "CLAUDE.md",
13077
+ manifestFile: "manifest.json",
13078
+ backupDirPrefix: ".claude-backup-",
13079
+ directoryStructure: [
13080
+ ".claude",
13081
+ ".claude/rules",
13082
+ ".claude/hooks",
13083
+ ".claude/contexts",
13084
+ ".claude/agents",
13085
+ ".claude/skills",
13086
+ "guides"
13087
+ ]
12850
13088
  };
12851
- function getProviderLayout(provider) {
12852
- return PROVIDER_LAYOUTS[provider];
13089
+ function getProviderLayout() {
13090
+ return CLAUDE_LAYOUT;
12853
13091
  }
12854
- function getEntryTemplateName(provider, language) {
12855
- const layout = getProviderLayout(provider);
12856
- return `${layout.entryTemplatePrefix}.${language}`;
13092
+ function getEntryTemplateName(language) {
13093
+ return `CLAUDE.md.${language}`;
12857
13094
  }
12858
- function getComponentPath(provider, component) {
12859
- const layout = getProviderLayout(provider);
13095
+ function getComponentPath(component) {
12860
13096
  if (component === "entry-md") {
12861
- return layout.entryFile;
13097
+ return "CLAUDE.md";
12862
13098
  }
12863
13099
  if (component === "guides") {
12864
13100
  return "guides";
12865
13101
  }
12866
- return `${layout.rootDir}/${component}`;
12867
- }
12868
- function getDefaultProvider() {
12869
- return "claude";
12870
- }
12871
-
12872
- // src/core/provider.ts
12873
- import { join as join3 } from "node:path";
12874
- var ENV_SIGNALS = {
12875
- claude: [
12876
- "ANTHROPIC_API_KEY",
12877
- "CLAUDE_CODE",
12878
- "CLAUDE_CODE_EFFORT_LEVEL",
12879
- "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS",
12880
- "CLAUDE_CODE_ENABLE_TELEMETRY"
12881
- ],
12882
- codex: ["OPENAI_API_KEY", "OPENAI_ORG_ID", "OPENAI_PROJECT", "CODEX_HOME", "CODEX_PROJECT"]
12883
- };
12884
- var PROVIDER_ENV_OVERRIDES = ["OMCUSTOM_PROVIDER", "LLM_SERVICE"];
12885
- function normalizeProvider(value) {
12886
- if (!value)
12887
- return null;
12888
- const normalized = value.toLowerCase().trim();
12889
- if (normalized === "claude" || normalized === "codex" || normalized === "auto") {
12890
- return normalized;
12891
- }
12892
- return null;
12893
- }
12894
- function detectFromEnv(env) {
12895
- for (const key of PROVIDER_ENV_OVERRIDES) {
12896
- const override = normalizeProvider(env[key]);
12897
- if (override && override !== "auto") {
12898
- return {
12899
- provider: override,
12900
- source: "override",
12901
- confidence: "high",
12902
- reason: `env:${key}`
12903
- };
12904
- }
12905
- }
12906
- const claudeSignals = ENV_SIGNALS.claude.filter((key) => Boolean(env[key]));
12907
- const codexSignals = ENV_SIGNALS.codex.filter((key) => Boolean(env[key]));
12908
- const hasClaude = claudeSignals.length > 0;
12909
- const hasCodex = codexSignals.length > 0;
12910
- if (hasClaude && !hasCodex) {
12911
- return {
12912
- provider: "claude",
12913
- source: "env",
12914
- confidence: "medium",
12915
- reason: `env:${claudeSignals[0]}`
12916
- };
12917
- }
12918
- if (hasCodex && !hasClaude) {
12919
- return {
12920
- provider: "codex",
12921
- source: "env",
12922
- confidence: "medium",
12923
- reason: `env:${codexSignals[0]}`
12924
- };
12925
- }
12926
- return null;
12927
- }
12928
- async function detectFromProject(targetDir) {
12929
- const claudeMarkers = [join3(targetDir, "CLAUDE.md"), join3(targetDir, ".claude")];
12930
- const codexMarkers = [join3(targetDir, "AGENTS.md"), join3(targetDir, ".codex")];
12931
- const claudeFound = await Promise.all(claudeMarkers.map((path) => fileExists(path)));
12932
- const codexFound = await Promise.all(codexMarkers.map((path) => fileExists(path)));
12933
- const hasClaude = claudeFound.some(Boolean);
12934
- const hasCodex = codexFound.some(Boolean);
12935
- if (hasClaude && !hasCodex) {
12936
- return {
12937
- provider: "claude",
12938
- source: "project",
12939
- confidence: "medium",
12940
- reason: "project:claude"
12941
- };
12942
- }
12943
- if (hasCodex && !hasClaude) {
12944
- return {
12945
- provider: "codex",
12946
- source: "project",
12947
- confidence: "medium",
12948
- reason: "project:codex"
12949
- };
12950
- }
12951
- return null;
12952
- }
12953
- async function detectFromConfig(targetDir) {
12954
- const configPath = join3(targetDir, ".omcustomrc.json");
12955
- if (!await fileExists(configPath)) {
12956
- return null;
12957
- }
12958
- try {
12959
- const config = await readJsonFile(configPath);
12960
- const provider = normalizeProvider(config.provider);
12961
- if (provider && provider !== "auto") {
12962
- return {
12963
- provider,
12964
- source: "config",
12965
- confidence: "high",
12966
- reason: "config:provider"
12967
- };
12968
- }
12969
- } catch {}
12970
- return null;
12971
- }
12972
- async function detectProvider(options = {}) {
12973
- const env = options.env ?? process.env;
12974
- const override = options.override;
12975
- const normalizedOverride = normalizeProvider(override);
12976
- if (normalizedOverride && normalizedOverride !== "auto") {
12977
- return {
12978
- provider: normalizedOverride,
12979
- source: "override",
12980
- confidence: "high",
12981
- reason: "override:option"
12982
- };
12983
- }
12984
- if (options.targetDir) {
12985
- const fromConfig = await detectFromConfig(options.targetDir);
12986
- if (fromConfig) {
12987
- return fromConfig;
12988
- }
12989
- }
12990
- if (options.targetDir && options.preferProject) {
12991
- const fromProject = await detectFromProject(options.targetDir);
12992
- if (fromProject) {
12993
- return fromProject;
12994
- }
12995
- }
12996
- const fromEnv = detectFromEnv(env);
12997
- if (fromEnv) {
12998
- return fromEnv;
12999
- }
13000
- if (options.targetDir && !options.preferProject) {
13001
- const fromProject = await detectFromProject(options.targetDir);
13002
- if (fromProject) {
13003
- return fromProject;
13004
- }
13005
- }
13006
- return {
13007
- provider: getDefaultProvider(),
13008
- source: "default",
13009
- confidence: "low",
13010
- reason: "default"
13011
- };
13102
+ return `.claude/${component}`;
13012
13103
  }
13013
13104
 
13014
13105
  // src/cli/doctor.ts
@@ -13452,12 +13543,7 @@ async function doctorCommand(options = {}) {
13452
13543
  const targetDir = process.cwd();
13453
13544
  console.log(i18n.t("cli.doctor.checking"));
13454
13545
  console.log("");
13455
- const detection = await detectProvider({
13456
- targetDir,
13457
- override: options.provider,
13458
- preferProject: true
13459
- });
13460
- const layout = getProviderLayout(detection.provider);
13546
+ const layout = getProviderLayout();
13461
13547
  let checks = await Promise.all([
13462
13548
  checkEntryDoc(targetDir, layout.entryFile),
13463
13549
  checkRules(targetDir, layout.rootDir),
@@ -13795,21 +13881,21 @@ async function ensureTargetDirectory(targetDir) {
13795
13881
  await ensureDirectory(targetDir);
13796
13882
  }
13797
13883
  }
13798
- async function handleBackup(targetDir, provider, shouldBackup, result) {
13884
+ async function handleBackup(targetDir, shouldBackup, result) {
13799
13885
  if (!shouldBackup)
13800
13886
  return;
13801
- const backupPaths = await backupExistingInstallation(targetDir, provider);
13887
+ const backupPaths = await backupExistingInstallation(targetDir);
13802
13888
  result.backedUpPaths.push(...backupPaths);
13803
13889
  if (backupPaths.length > 0) {
13804
13890
  info("install.backup", { path: backupPaths[0] });
13805
13891
  }
13806
13892
  }
13807
- async function checkAndWarnExisting(targetDir, provider, force, backup, result) {
13893
+ async function checkAndWarnExisting(targetDir, force, backup, result) {
13808
13894
  if (force || backup)
13809
13895
  return;
13810
- const existingPaths = await checkExistingPaths(targetDir, provider);
13896
+ const existingPaths = await checkExistingPaths(targetDir);
13811
13897
  if (existingPaths.length > 0) {
13812
- const layout = getProviderLayout(provider);
13898
+ const layout = getProviderLayout();
13813
13899
  warn("install.exists", { rootDir: layout.rootDir });
13814
13900
  result.warnings.push(`Existing files found: ${existingPaths.join(", ")}. Use --force to overwrite or --backup to backup first.`);
13815
13901
  }
@@ -13820,15 +13906,15 @@ async function verifyTemplateDirectory() {
13820
13906
  throw new Error(`Template directory not found: ${templateDir}`);
13821
13907
  }
13822
13908
  }
13823
- async function installAllComponents(targetDir, provider, options, result) {
13909
+ async function installAllComponents(targetDir, options, result) {
13824
13910
  const components = options.components || getAllComponents();
13825
13911
  for (const component of components) {
13826
- await installSingleComponent(targetDir, provider, component, options, result);
13912
+ await installSingleComponent(targetDir, component, options, result);
13827
13913
  }
13828
13914
  }
13829
- async function installSingleComponent(targetDir, provider, component, options, result) {
13915
+ async function installSingleComponent(targetDir, component, options, result) {
13830
13916
  try {
13831
- const installed = await installComponent(targetDir, provider, component, options);
13917
+ const installed = await installComponent(targetDir, component, options);
13832
13918
  if (installed) {
13833
13919
  result.installedComponents.push(component);
13834
13920
  } else {
@@ -13839,36 +13925,34 @@ async function installSingleComponent(targetDir, provider, component, options, r
13839
13925
  result.warnings.push(`Failed to install ${component}: ${message}`);
13840
13926
  }
13841
13927
  }
13842
- async function installEntryDocWithTracking(targetDir, provider, options, result) {
13928
+ async function installEntryDocWithTracking(targetDir, options, result) {
13843
13929
  const language = options.language ?? DEFAULT_LANGUAGE2;
13844
13930
  const overwrite = !!(options.force || options.backup);
13845
- const installed = await installEntryDoc(targetDir, provider, language, overwrite);
13931
+ const installed = await installEntryDoc(targetDir, language, overwrite);
13846
13932
  if (installed) {
13847
13933
  result.installedComponents.push("entry-md");
13848
13934
  } else {
13849
13935
  result.skippedComponents.push("entry-md");
13850
13936
  }
13851
13937
  }
13852
- async function updateInstallConfig(targetDir, provider, options, installedComponents) {
13938
+ async function updateInstallConfig(targetDir, options, installedComponents) {
13853
13939
  const config = await loadConfig(targetDir);
13854
13940
  config.language = options.language ?? DEFAULT_LANGUAGE2;
13855
- config.provider = provider;
13856
13941
  config.installedAt = new Date().toISOString();
13857
13942
  config.installedComponents = installedComponents;
13858
13943
  await saveConfig(targetDir, config);
13859
13944
  }
13860
13945
  async function install(options) {
13861
13946
  const result = createInstallResult(options.targetDir);
13862
- const provider = options.provider ?? "claude";
13863
13947
  try {
13864
13948
  info("install.start", { targetDir: options.targetDir });
13865
13949
  await ensureTargetDirectory(options.targetDir);
13866
- await handleBackup(options.targetDir, provider, !!options.backup, result);
13867
- await checkAndWarnExisting(options.targetDir, provider, !!options.force, !!options.backup, result);
13950
+ await handleBackup(options.targetDir, !!options.backup, result);
13951
+ await checkAndWarnExisting(options.targetDir, !!options.force, !!options.backup, result);
13868
13952
  await verifyTemplateDirectory();
13869
- await installAllComponents(options.targetDir, provider, options, result);
13870
- await installEntryDocWithTracking(options.targetDir, provider, options, result);
13871
- await updateInstallConfig(options.targetDir, provider, options, result.installedComponents);
13953
+ await installAllComponents(options.targetDir, options, result);
13954
+ await installEntryDocWithTracking(options.targetDir, options, result);
13955
+ await updateInstallConfig(options.targetDir, options, result.installedComponents);
13872
13956
  result.success = true;
13873
13957
  success("install.success");
13874
13958
  } catch (err) {
@@ -13881,11 +13965,11 @@ async function install(options) {
13881
13965
  function getAllComponents() {
13882
13966
  return ["rules", "agents", "skills", "guides", "hooks", "contexts"];
13883
13967
  }
13884
- async function installComponent(targetDir, provider, component, options) {
13968
+ async function installComponent(targetDir, component, options) {
13885
13969
  if (component === "entry-md") {
13886
13970
  return false;
13887
13971
  }
13888
- const templatePath = getComponentPath(provider, component);
13972
+ const templatePath = getComponentPath(component);
13889
13973
  if (!templatePath) {
13890
13974
  return false;
13891
13975
  }
@@ -13913,9 +13997,9 @@ function renderGitWorkflowSection(targetDir, language) {
13913
13997
  const result = detectGitWorkflow(targetDir) ?? getDefaultWorkflow();
13914
13998
  return language === "ko" ? renderGitWorkflowKO(result) : renderGitWorkflowEN(result);
13915
13999
  }
13916
- async function installEntryDoc(targetDir, provider, language, overwrite = false) {
13917
- const layout = getProviderLayout(provider);
13918
- const templateFile = getEntryTemplateName(provider, language);
14000
+ async function installEntryDoc(targetDir, language, overwrite = false) {
14001
+ const layout = getProviderLayout();
14002
+ const templateFile = getEntryTemplateName(language);
13919
14003
  const srcPath = resolveTemplatePath(templateFile);
13920
14004
  const destPath = join4(targetDir, layout.entryFile);
13921
14005
  if (!await fileExists(srcPath)) {
@@ -13942,8 +14026,8 @@ async function backupExisting(sourcePath, backupDir) {
13942
14026
  await rename(sourcePath, backupPath);
13943
14027
  return backupPath;
13944
14028
  }
13945
- async function checkExistingPaths(targetDir, provider) {
13946
- const layout = getProviderLayout(provider);
14029
+ async function checkExistingPaths(targetDir) {
14030
+ const layout = getProviderLayout();
13947
14031
  const pathsToCheck = [layout.entryFile, layout.rootDir, "guides"];
13948
14032
  const existingPaths = [];
13949
14033
  for (const relativePath of pathsToCheck) {
@@ -13954,9 +14038,9 @@ async function checkExistingPaths(targetDir, provider) {
13954
14038
  }
13955
14039
  return existingPaths;
13956
14040
  }
13957
- async function backupExistingInstallation(targetDir, provider) {
13958
- const layout = getProviderLayout(provider);
13959
- const existingPaths = await checkExistingPaths(targetDir, provider);
14041
+ async function backupExistingInstallation(targetDir) {
14042
+ const layout = getProviderLayout();
14043
+ const existingPaths = await checkExistingPaths(targetDir);
13960
14044
  if (existingPaths.length === 0) {
13961
14045
  return [];
13962
14046
  }
@@ -13979,11 +14063,11 @@ async function backupExistingInstallation(targetDir, provider) {
13979
14063
  }
13980
14064
 
13981
14065
  // src/core/mcp-config.ts
13982
- import { execSync as execSync2 } from "node:child_process";
14066
+ import { execSync as execSync3 } from "node:child_process";
13983
14067
  import { writeFile } from "node:fs/promises";
13984
14068
  import { join as join5 } from "node:path";
13985
- async function generateMCPConfig(targetDir, provider) {
13986
- const layout = getProviderLayout(provider);
14069
+ async function generateMCPConfig(targetDir) {
14070
+ const layout = getProviderLayout();
13987
14071
  const mcpConfigPath = join5(targetDir, ".mcp.json");
13988
14072
  const ontologyDir = join5(layout.rootDir, "ontology");
13989
14073
  const ontologyExists = await fileExists(join5(targetDir, ontologyDir));
@@ -14025,7 +14109,7 @@ async function generateMCPConfig(targetDir, provider) {
14025
14109
  }
14026
14110
  async function checkPythonAvailable() {
14027
14111
  try {
14028
- execSync2("python --version", { stdio: "pipe" });
14112
+ execSync3("python --version", { stdio: "pipe" });
14029
14113
  return true;
14030
14114
  } catch {
14031
14115
  return false;
@@ -14033,25 +14117,25 @@ async function checkPythonAvailable() {
14033
14117
  }
14034
14118
 
14035
14119
  // src/cli/init.ts
14036
- async function checkExistingInstallation(targetDir, provider) {
14037
- const layout = getProviderLayout(provider);
14120
+ async function checkExistingInstallation(targetDir) {
14121
+ const layout = getProviderLayout();
14038
14122
  const rootDir = join6(targetDir, layout.rootDir);
14039
14123
  return fileExists(rootDir);
14040
14124
  }
14041
14125
  var PROVIDER_SUBDIR_COMPONENTS = new Set(["rules", "hooks", "contexts", "agents", "skills"]);
14042
- function componentToPath(targetDir, provider, component) {
14126
+ function componentToPath(targetDir, component) {
14043
14127
  if (component === "entry-md") {
14044
- const layout = getProviderLayout(provider);
14128
+ const layout = getProviderLayout();
14045
14129
  return join6(targetDir, layout.entryFile);
14046
14130
  }
14047
14131
  if (PROVIDER_SUBDIR_COMPONENTS.has(component)) {
14048
- const layout = getProviderLayout(provider);
14132
+ const layout = getProviderLayout();
14049
14133
  return join6(targetDir, layout.rootDir, component);
14050
14134
  }
14051
14135
  return join6(targetDir, component);
14052
14136
  }
14053
- function buildInstalledPaths(targetDir, provider, components) {
14054
- return components.map((component) => componentToPath(targetDir, provider, component));
14137
+ function buildInstalledPaths(targetDir, components) {
14138
+ return components.map((component) => componentToPath(targetDir, component));
14055
14139
  }
14056
14140
  function logItems(items, formatter) {
14057
14141
  for (const item of items) {
@@ -14084,10 +14168,8 @@ async function initCommand(options) {
14084
14168
  const targetDir = process.cwd();
14085
14169
  console.log(i18n.t("cli.init.start"));
14086
14170
  try {
14087
- const detection = await detectProvider({ targetDir, override: options.provider });
14088
- const provider = detection.provider;
14089
- const layout = getProviderLayout(provider);
14090
- const exists2 = await checkExistingInstallation(targetDir, provider);
14171
+ const layout = getProviderLayout();
14172
+ const exists2 = await checkExistingInstallation(targetDir);
14091
14173
  if (exists2) {
14092
14174
  console.log(i18n.t("cli.init.exists", { rootDir: layout.rootDir }));
14093
14175
  console.log(i18n.t("cli.init.backing_up"));
@@ -14096,20 +14178,19 @@ async function initCommand(options) {
14096
14178
  const installResult = await install({
14097
14179
  targetDir,
14098
14180
  language: options.lang,
14099
- provider,
14100
14181
  force: options.force ?? false,
14101
14182
  backup: exists2
14102
14183
  });
14103
14184
  if (!installResult.success) {
14104
14185
  return createFailureResult(installResult.error || "Unknown error");
14105
14186
  }
14106
- const installedPaths = buildInstalledPaths(targetDir, provider, installResult.installedComponents);
14187
+ const installedPaths = buildInstalledPaths(targetDir, installResult.installedComponents);
14107
14188
  logInstallResultInfo(installResult);
14108
14189
  logSuccessDetails(installedPaths, installResult.skippedComponents);
14109
14190
  const pythonAvailable = await checkPythonAvailable();
14110
14191
  if (pythonAvailable) {
14111
14192
  try {
14112
- await generateMCPConfig(targetDir, provider);
14193
+ await generateMCPConfig(targetDir);
14113
14194
  } catch {
14114
14195
  console.warn("Warning: Failed to generate MCP config. You can configure it manually.");
14115
14196
  }
@@ -14130,7 +14211,7 @@ async function initCommand(options) {
14130
14211
  }
14131
14212
 
14132
14213
  // src/cli/list.ts
14133
- import { basename as basename2, dirname as dirname2, join as join7, relative as relative2 } from "node:path";
14214
+ import { basename as basename2, dirname as dirname3, join as join7, relative as relative2 } from "node:path";
14134
14215
  var ALLOWED_TOP_LEVEL_KEYS = new Set(["name", "type", "description", "version", "category"]);
14135
14216
  function parseKeyValue(line) {
14136
14217
  const colonIndex = line.indexOf(":");
@@ -14330,7 +14411,7 @@ async function getSkills(targetDir, rootDir = ".claude", config) {
14330
14411
  const customSkillPaths = new Set(customComponents.filter((c) => c.type === "skill").map((c) => c.path));
14331
14412
  const skillMdFiles = await listFiles(skillsDir, { recursive: true, pattern: "SKILL.md" });
14332
14413
  const skills = await Promise.all(skillMdFiles.map(async (skillMdPath) => {
14333
- const skillDir = dirname2(skillMdPath);
14414
+ const skillDir = dirname3(skillMdPath);
14334
14415
  const indexYamlPath = join7(skillDir, "index.yaml");
14335
14416
  const { description, version } = await tryReadIndexYamlMetadata(indexYamlPath);
14336
14417
  const relativePath = relative2(targetDir, skillDir);
@@ -14530,12 +14611,7 @@ async function listCommand(type = "all", options = {}) {
14530
14611
  const format = options.format || "table";
14531
14612
  console.log(i18n.t("cli.list.scanning"));
14532
14613
  try {
14533
- const detection = await detectProvider({
14534
- targetDir,
14535
- override: options.provider,
14536
- preferProject: true
14537
- });
14538
- const layout = getProviderLayout(detection.provider);
14614
+ const layout = getProviderLayout();
14539
14615
  const config = await loadConfig(targetDir);
14540
14616
  const components = type === "all" ? await handleListAll(targetDir, layout.rootDir, format, config) : await COMPONENT_GETTERS[type](targetDir, layout.rootDir, config);
14541
14617
  if (type === "all" && format === "json") {
@@ -14684,14 +14760,14 @@ function createUpdateResult() {
14684
14760
  warnings: []
14685
14761
  };
14686
14762
  }
14687
- async function handleBackupIfRequested(targetDir, provider, backup, result) {
14763
+ async function handleBackupIfRequested(targetDir, backup, result) {
14688
14764
  if (!backup)
14689
14765
  return;
14690
- const backupPath = await backupInstallation(targetDir, provider);
14766
+ const backupPath = await backupInstallation(targetDir);
14691
14767
  result.backedUpPaths.push(backupPath);
14692
14768
  info("update.backup_created", { path: backupPath });
14693
14769
  }
14694
- async function processComponentUpdate(targetDir, provider, component, updateCheck, customizations, options, result, config) {
14770
+ async function processComponentUpdate(targetDir, component, updateCheck, customizations, options, result, config) {
14695
14771
  const componentUpdate = updateCheck.updatableComponents.find((c) => c.name === component);
14696
14772
  if (!componentUpdate && !options.force) {
14697
14773
  result.skippedComponents.push(component);
@@ -14703,7 +14779,7 @@ async function processComponentUpdate(targetDir, provider, component, updateChec
14703
14779
  return;
14704
14780
  }
14705
14781
  try {
14706
- const preserved = await updateComponent(targetDir, provider, component, customizations, options, config);
14782
+ const preserved = await updateComponent(targetDir, component, customizations, options, config);
14707
14783
  result.updatedComponents.push(component);
14708
14784
  result.preservedFiles.push(...preserved);
14709
14785
  } catch (err) {
@@ -14712,13 +14788,13 @@ async function processComponentUpdate(targetDir, provider, component, updateChec
14712
14788
  result.skippedComponents.push(component);
14713
14789
  }
14714
14790
  }
14715
- async function updateAllComponents(targetDir, provider, components, updateCheck, customizations, options, result, config) {
14791
+ async function updateAllComponents(targetDir, components, updateCheck, customizations, options, result, config) {
14716
14792
  for (const component of components) {
14717
- await processComponentUpdate(targetDir, provider, component, updateCheck, customizations, options, result, config);
14793
+ await processComponentUpdate(targetDir, component, updateCheck, customizations, options, result, config);
14718
14794
  }
14719
14795
  }
14720
- function getEntryTemplateName2(provider, language) {
14721
- const layout = getProviderLayout(provider);
14796
+ function getEntryTemplateName2(language) {
14797
+ const layout = getProviderLayout();
14722
14798
  const baseName = layout.entryFile.replace(".md", "");
14723
14799
  return language === "ko" ? `${baseName}.md.ko` : `${baseName}.md.en`;
14724
14800
  }
@@ -14802,10 +14878,10 @@ function resolveCustomizations(customizations, configPreserveFiles, targetDir) {
14802
14878
  }
14803
14879
  return null;
14804
14880
  }
14805
- async function updateEntryDoc(targetDir, provider, config, options) {
14806
- const layout = getProviderLayout(provider);
14881
+ async function updateEntryDoc(targetDir, config, options) {
14882
+ const layout = getProviderLayout();
14807
14883
  const entryPath = join8(targetDir, layout.entryFile);
14808
- const templateName = getEntryTemplateName2(provider, config.language);
14884
+ const templateName = getEntryTemplateName2(config.language);
14809
14885
  const templatePath = resolveTemplatePath(templateName);
14810
14886
  if (!await fileExists(templatePath)) {
14811
14887
  warn("update.entry_template_not_found", { template: templateName });
@@ -14842,9 +14918,8 @@ async function update(options) {
14842
14918
  try {
14843
14919
  info("update.start", { targetDir: options.targetDir });
14844
14920
  const config = await loadConfig(options.targetDir);
14845
- const provider = options.provider ?? (config.provider === "codex" ? "codex" : "claude");
14846
14921
  result.previousVersion = config.version;
14847
- const updateCheck = await checkForUpdates(options.targetDir, provider);
14922
+ const updateCheck = await checkForUpdates(options.targetDir);
14848
14923
  result.newVersion = updateCheck.latestVersion;
14849
14924
  if (!updateCheck.hasUpdates && !options.force) {
14850
14925
  info("update.no_updates");
@@ -14852,14 +14927,14 @@ async function update(options) {
14852
14927
  result.skippedComponents = options.components || getAllUpdateComponents();
14853
14928
  return result;
14854
14929
  }
14855
- await handleBackupIfRequested(options.targetDir, provider, !!options.backup, result);
14930
+ await handleBackupIfRequested(options.targetDir, !!options.backup, result);
14856
14931
  const manifestCustomizations = await resolveManifestCustomizations(options, options.targetDir);
14857
14932
  const configPreserveFiles = resolveConfigPreserveFiles(options, config);
14858
14933
  const customizations = resolveCustomizations(manifestCustomizations, configPreserveFiles, options.targetDir);
14859
14934
  const components = options.components || getAllUpdateComponents();
14860
- await updateAllComponents(options.targetDir, provider, components, updateCheck, customizations, options, result, config);
14935
+ await updateAllComponents(options.targetDir, components, updateCheck, customizations, options, result, config);
14861
14936
  if (!options.components || options.components.length === 0) {
14862
- await updateEntryDoc(options.targetDir, provider, config, options);
14937
+ await updateEntryDoc(options.targetDir, config, options);
14863
14938
  }
14864
14939
  config.version = result.newVersion;
14865
14940
  config.lastUpdated = new Date().toISOString();
@@ -14880,13 +14955,13 @@ async function update(options) {
14880
14955
  }
14881
14956
  return result;
14882
14957
  }
14883
- async function checkForUpdates(targetDir, provider = "claude") {
14958
+ async function checkForUpdates(targetDir) {
14884
14959
  const config = await loadConfig(targetDir);
14885
14960
  const currentVersion = config.version;
14886
- const latestVersion = await getLatestVersion(provider);
14961
+ const latestVersion = await getLatestVersion();
14887
14962
  const updatableComponents = [];
14888
14963
  for (const component of getAllUpdateComponents()) {
14889
- const hasUpdate = await componentHasUpdate(targetDir, provider, component, config);
14964
+ const hasUpdate = await componentHasUpdate(targetDir, component, config);
14890
14965
  if (hasUpdate) {
14891
14966
  updatableComponents.push({
14892
14967
  name: component,
@@ -14906,8 +14981,8 @@ async function checkForUpdates(targetDir, provider = "claude") {
14906
14981
  function getAllUpdateComponents() {
14907
14982
  return ["rules", "agents", "skills", "guides", "hooks", "contexts"];
14908
14983
  }
14909
- async function getLatestVersion(provider) {
14910
- const layout = getProviderLayout(provider);
14984
+ async function getLatestVersion() {
14985
+ const layout = getProviderLayout();
14911
14986
  const manifestPath = resolveTemplatePath(layout.manifestFile);
14912
14987
  if (await fileExists(manifestPath)) {
14913
14988
  const manifest = await readJsonFile(manifestPath);
@@ -14915,17 +14990,17 @@ async function getLatestVersion(provider) {
14915
14990
  }
14916
14991
  return "0.0.0";
14917
14992
  }
14918
- async function componentHasUpdate(_targetDir, provider, component, config) {
14993
+ async function componentHasUpdate(_targetDir, component, config) {
14919
14994
  const installedVersion = config.componentVersions?.[component];
14920
14995
  if (!installedVersion) {
14921
14996
  return true;
14922
14997
  }
14923
- const latestVersion = await getLatestVersion(provider);
14998
+ const latestVersion = await getLatestVersion();
14924
14999
  return installedVersion !== latestVersion;
14925
15000
  }
14926
- async function updateComponent(targetDir, provider, component, customizations, options, config) {
15001
+ async function updateComponent(targetDir, component, customizations, options, config) {
14927
15002
  const preservedFiles = [];
14928
- const componentPath = getComponentPath2(provider, component);
15003
+ const componentPath = getComponentPath2(component);
14929
15004
  const srcPath = resolveTemplatePath(componentPath);
14930
15005
  const destPath = join8(targetDir, componentPath);
14931
15006
  const customComponents = config.customComponents || [];
@@ -14952,19 +15027,19 @@ async function updateComponent(targetDir, provider, component, customizations, o
14952
15027
  });
14953
15028
  return preservedFiles;
14954
15029
  }
14955
- function getComponentPath2(provider, component) {
14956
- const layout = getProviderLayout(provider);
15030
+ function getComponentPath2(component) {
15031
+ const layout = getProviderLayout();
14957
15032
  if (component === "guides") {
14958
15033
  return "guides";
14959
15034
  }
14960
15035
  return `${layout.rootDir}/${component}`;
14961
15036
  }
14962
- async function backupInstallation(targetDir, provider) {
15037
+ async function backupInstallation(targetDir) {
14963
15038
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
14964
15039
  const backupDir = join8(targetDir, `.omcustom-backup-${timestamp}`);
14965
15040
  const fs2 = await import("node:fs/promises");
14966
15041
  await ensureDirectory(backupDir);
14967
- const layout = getProviderLayout(provider);
15042
+ const layout = getProviderLayout();
14968
15043
  const dirsToBackup = [layout.rootDir, "guides"];
14969
15044
  for (const dir2 of dirsToBackup) {
14970
15045
  const srcPath = join8(targetDir, dir2);
@@ -14991,18 +15066,12 @@ async function loadCustomizationManifest(targetDir) {
14991
15066
  async function updateCommand(options = {}) {
14992
15067
  try {
14993
15068
  const targetDir = process.cwd();
14994
- const detection = await detectProvider({
14995
- targetDir,
14996
- override: options.provider
14997
- });
14998
- const provider = detection.provider;
14999
15069
  const components = buildComponentsList(options);
15000
15070
  if (options.dryRun) {
15001
15071
  console.log(i18n.t("cli.update.dryRunHeader"));
15002
15072
  }
15003
15073
  const updateOptions = {
15004
15074
  targetDir,
15005
- provider,
15006
15075
  components,
15007
15076
  force: options.force,
15008
15077
  preserveCustomizations: true,
@@ -15077,25 +15146,30 @@ var packageJson = require2("../../package.json");
15077
15146
  function createProgram() {
15078
15147
  const program2 = new Command;
15079
15148
  program2.name("omcustom").description(i18n.t("cli.description")).version(packageJson.version, "-v, --version", i18n.t("cli.versionOption")).option("--skip-version-check", "Skip CLI version pre-flight check");
15080
- program2.command("init").description(i18n.t("cli.init.description")).option("-l, --lang <language>", i18n.t("cli.init.langOption"), "en").option("-p, --provider <provider>", i18n.t("cli.init.providerOption"), "auto").action(async (options) => {
15149
+ program2.command("init").description(i18n.t("cli.init.description")).option("-l, --lang <language>", i18n.t("cli.init.langOption"), "en").action(async (options) => {
15081
15150
  await initCommand(options);
15082
15151
  });
15083
- program2.command("update").description(i18n.t("cli.update.description")).option("--dry-run", i18n.t("cli.update.dryRunOption")).option("--force", i18n.t("cli.update.forceOption")).option("--force-overwrite-all", i18n.t("cli.update.forceOverwriteAllOption")).option("--backup", i18n.t("cli.update.backupOption")).option("--agents", i18n.t("cli.update.agentsOption")).option("--skills", i18n.t("cli.update.skillsOption")).option("--rules", i18n.t("cli.update.rulesOption")).option("--guides", i18n.t("cli.update.guidesOption")).option("--hooks", i18n.t("cli.update.hooksOption")).option("--contexts", i18n.t("cli.update.contextsOption")).option("-p, --provider <provider>", i18n.t("cli.update.providerOption"), "auto").action(async (options) => {
15152
+ program2.command("update").description(i18n.t("cli.update.description")).option("--dry-run", i18n.t("cli.update.dryRunOption")).option("--force", i18n.t("cli.update.forceOption")).option("--force-overwrite-all", i18n.t("cli.update.forceOverwriteAllOption")).option("--backup", i18n.t("cli.update.backupOption")).option("--agents", i18n.t("cli.update.agentsOption")).option("--skills", i18n.t("cli.update.skillsOption")).option("--rules", i18n.t("cli.update.rulesOption")).option("--guides", i18n.t("cli.update.guidesOption")).option("--hooks", i18n.t("cli.update.hooksOption")).option("--contexts", i18n.t("cli.update.contextsOption")).action(async (options) => {
15084
15153
  await updateCommand(options);
15085
15154
  });
15086
- program2.command("list").description(i18n.t("cli.list.description")).argument("[type]", i18n.t("cli.list.typeArgument"), "all").option("-f, --format <format>", "Output format: table, json, or simple", "table").option("--verbose", "Show detailed information").option("-p, --provider <provider>", i18n.t("cli.list.providerOption"), "auto").action(async (type, options) => {
15155
+ program2.command("list").description(i18n.t("cli.list.description")).argument("[type]", i18n.t("cli.list.typeArgument"), "all").option("-f, --format <format>", "Output format: table, json, or simple", "table").option("--verbose", "Show detailed information").action(async (type, options) => {
15087
15156
  await listCommand(type, {
15088
15157
  format: options.format,
15089
- verbose: options.verbose,
15090
- provider: options.provider
15158
+ verbose: options.verbose
15091
15159
  });
15092
15160
  });
15093
- 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) => {
15161
+ program2.command("doctor").description(i18n.t("cli.doctor.description")).option("--fix", i18n.t("cli.doctor.fixOption")).action(async (options) => {
15094
15162
  await doctorCommand(options);
15095
15163
  });
15096
- program2.hook("preAction", async (thisCommand) => {
15164
+ program2.hook("preAction", async (thisCommand, actionCommand) => {
15097
15165
  const opts = thisCommand.optsWithGlobals();
15098
15166
  const skipCheck = opts.skipVersionCheck || false;
15167
+ if (actionCommand.name() === "init") {
15168
+ await maybeHandleSelfUpdateForInit({
15169
+ currentVersion: packageJson.version,
15170
+ skip: skipCheck
15171
+ });
15172
+ }
15099
15173
  const result = await runPreflightCheck({ skip: skipCheck });
15100
15174
  if (result.hasUpdates) {
15101
15175
  const warnings = formatPreflightWarnings(result);