oh-my-customcode 0.10.3 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -166,6 +166,12 @@ Event-driven automation for Claude Code lifecycle events (PreToolUse, PostToolUs
166
166
 
167
167
  Shared context files for cross-agent knowledge and mode configurations.
168
168
 
169
+ ### Packages
170
+
171
+ | Package | Version | Description |
172
+ |---------|---------|-------------|
173
+ | [ontology-rag](packages/ontology-rag/) | 0.3.0 | Ontology+RAG context engine for intelligent context loading. Reduces token usage by 75-95% through hierarchical loading, graph-based routing, and adaptive compression. |
174
+
169
175
  ---
170
176
 
171
177
  ## CLI Commands
package/dist/cli/index.js CHANGED
@@ -12552,6 +12552,7 @@ var MESSAGES = {
12552
12552
  "install.entry_md_skipped": "{{entry}} skipped ({{reason}})",
12553
12553
  "update.start": "Checking for updates...",
12554
12554
  "update.success": "Updated from {{from}} to {{to}}",
12555
+ "update.components_synced": "Components synced (version {{version}}): {{components}}",
12555
12556
  "update.failed": "Update failed: {{error}}",
12556
12557
  "update.no_updates": "Already up to date",
12557
12558
  "update.backup_created": "Backup created at: {{path}}",
@@ -12583,6 +12584,7 @@ var MESSAGES = {
12583
12584
  "install.entry_md_skipped": "{{entry}} 건너뜀 ({{reason}})",
12584
12585
  "update.start": "업데이트 확인 중...",
12585
12586
  "update.success": "{{from}}에서 {{to}}로 업데이트 완료",
12587
+ "update.components_synced": "컴포넌트 동기화 완료 (버전 {{version}}): {{components}}",
12586
12588
  "update.failed": "업데이트 실패: {{error}}",
12587
12589
  "update.no_updates": "이미 최신 버전입니다",
12588
12590
  "update.backup_created": "백업 생성됨: {{path}}",
@@ -13515,7 +13517,7 @@ async function doctorCommand(options = {}) {
13515
13517
  }
13516
13518
 
13517
13519
  // src/cli/init.ts
13518
- import { join as join5 } from "node:path";
13520
+ import { join as join6 } from "node:path";
13519
13521
 
13520
13522
  // src/core/installer.ts
13521
13523
  import { readFile as fsReadFile, writeFile as fsWriteFile, rename } from "node:fs/promises";
@@ -13976,23 +13978,77 @@ async function backupExistingInstallation(targetDir, provider) {
13976
13978
  return backedUpPaths.length > 0 ? [backupDir] : [];
13977
13979
  }
13978
13980
 
13981
+ // src/core/mcp-config.ts
13982
+ import { execSync as execSync2 } from "node:child_process";
13983
+ import { writeFile } from "node:fs/promises";
13984
+ import { join as join5 } from "node:path";
13985
+ async function generateMCPConfig(targetDir, provider) {
13986
+ 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));
13990
+ if (!ontologyExists) {
13991
+ return;
13992
+ }
13993
+ const config = {
13994
+ mcpServers: {
13995
+ "ontology-rag": {
13996
+ type: "stdio",
13997
+ command: "python",
13998
+ args: ["-m", "ontology_rag.mcp_server"],
13999
+ env: {
14000
+ ONTOLOGY_DIR: ontologyDir
14001
+ }
14002
+ }
14003
+ }
14004
+ };
14005
+ const existingConfigPath = mcpConfigPath;
14006
+ if (await fileExists(existingConfigPath)) {
14007
+ try {
14008
+ const { readFile } = await import("node:fs/promises");
14009
+ const existingContent = await readFile(existingConfigPath, "utf-8");
14010
+ const existing = JSON.parse(existingContent);
14011
+ if (!existing.mcpServers?.["ontology-rag"]) {
14012
+ existing.mcpServers = existing.mcpServers || {};
14013
+ existing.mcpServers["ontology-rag"] = config.mcpServers["ontology-rag"];
14014
+ await writeFile(mcpConfigPath, `${JSON.stringify(existing, null, 2)}
14015
+ `);
14016
+ }
14017
+ } catch {
14018
+ await writeFile(mcpConfigPath, `${JSON.stringify(config, null, 2)}
14019
+ `);
14020
+ }
14021
+ } else {
14022
+ await writeFile(mcpConfigPath, `${JSON.stringify(config, null, 2)}
14023
+ `);
14024
+ }
14025
+ }
14026
+ async function checkPythonAvailable() {
14027
+ try {
14028
+ execSync2("python --version", { stdio: "pipe" });
14029
+ return true;
14030
+ } catch {
14031
+ return false;
14032
+ }
14033
+ }
14034
+
13979
14035
  // src/cli/init.ts
13980
14036
  async function checkExistingInstallation(targetDir, provider) {
13981
14037
  const layout = getProviderLayout(provider);
13982
- const rootDir = join5(targetDir, layout.rootDir);
14038
+ const rootDir = join6(targetDir, layout.rootDir);
13983
14039
  return fileExists(rootDir);
13984
14040
  }
13985
14041
  var PROVIDER_SUBDIR_COMPONENTS = new Set(["rules", "hooks", "contexts", "agents", "skills"]);
13986
14042
  function componentToPath(targetDir, provider, component) {
13987
14043
  if (component === "entry-md") {
13988
14044
  const layout = getProviderLayout(provider);
13989
- return join5(targetDir, layout.entryFile);
14045
+ return join6(targetDir, layout.entryFile);
13990
14046
  }
13991
14047
  if (PROVIDER_SUBDIR_COMPONENTS.has(component)) {
13992
14048
  const layout = getProviderLayout(provider);
13993
- return join5(targetDir, layout.rootDir, component);
14049
+ return join6(targetDir, layout.rootDir, component);
13994
14050
  }
13995
- return join5(targetDir, component);
14051
+ return join6(targetDir, component);
13996
14052
  }
13997
14053
  function buildInstalledPaths(targetDir, provider, components) {
13998
14054
  return components.map((component) => componentToPath(targetDir, provider, component));
@@ -14050,6 +14106,17 @@ async function initCommand(options) {
14050
14106
  const installedPaths = buildInstalledPaths(targetDir, provider, installResult.installedComponents);
14051
14107
  logInstallResultInfo(installResult);
14052
14108
  logSuccessDetails(installedPaths, installResult.skippedComponents);
14109
+ const pythonAvailable = await checkPythonAvailable();
14110
+ if (pythonAvailable) {
14111
+ try {
14112
+ await generateMCPConfig(targetDir, provider);
14113
+ } catch {
14114
+ console.warn("Warning: Failed to generate MCP config. You can configure it manually.");
14115
+ }
14116
+ } else {
14117
+ console.warn("Warning: Python not found. Skipping MCP server configuration.");
14118
+ console.warn("Install Python 3.10+ and ontology-rag to enable MCP integration.");
14119
+ }
14053
14120
  return {
14054
14121
  success: true,
14055
14122
  message: i18n.t("cli.init.success"),
@@ -14063,7 +14130,7 @@ async function initCommand(options) {
14063
14130
  }
14064
14131
 
14065
14132
  // src/cli/list.ts
14066
- import { basename as basename2, dirname as dirname2, join as join6, relative as relative2 } from "node:path";
14133
+ import { basename as basename2, dirname as dirname2, join as join7, relative as relative2 } from "node:path";
14067
14134
  var ALLOWED_TOP_LEVEL_KEYS = new Set(["name", "type", "description", "version", "category"]);
14068
14135
  function parseKeyValue(line) {
14069
14136
  const colonIndex = line.indexOf(":");
@@ -14127,12 +14194,12 @@ function extractAgentTypeFromFilename(filename) {
14127
14194
  return prefixMap[prefix] || "unknown";
14128
14195
  }
14129
14196
  function extractSkillCategoryFromPath(skillPath, baseDir, rootDir) {
14130
- const relativePath = relative2(join6(baseDir, rootDir, "skills"), skillPath);
14197
+ const relativePath = relative2(join7(baseDir, rootDir, "skills"), skillPath);
14131
14198
  const parts = relativePath.split("/").filter(Boolean);
14132
14199
  return parts[0] || "unknown";
14133
14200
  }
14134
14201
  function extractGuideCategoryFromPath(guidePath, baseDir) {
14135
- const relativePath = relative2(join6(baseDir, "guides"), guidePath);
14202
+ const relativePath = relative2(join7(baseDir, "guides"), guidePath);
14136
14203
  const parts = relativePath.split("/").filter(Boolean);
14137
14204
  return parts[0] || "unknown";
14138
14205
  }
@@ -14226,7 +14293,7 @@ async function tryExtractMarkdownDescription(mdPath, options = {}) {
14226
14293
  }
14227
14294
  }
14228
14295
  async function getAgents(targetDir, rootDir = ".claude", config) {
14229
- const agentsDir = join6(targetDir, rootDir, "agents");
14296
+ const agentsDir = join7(targetDir, rootDir, "agents");
14230
14297
  if (!await fileExists(agentsDir))
14231
14298
  return [];
14232
14299
  try {
@@ -14254,7 +14321,7 @@ async function getAgents(targetDir, rootDir = ".claude", config) {
14254
14321
  }
14255
14322
  }
14256
14323
  async function getSkills(targetDir, rootDir = ".claude", config) {
14257
- const skillsDir = join6(targetDir, rootDir, "skills");
14324
+ const skillsDir = join7(targetDir, rootDir, "skills");
14258
14325
  if (!await fileExists(skillsDir))
14259
14326
  return [];
14260
14327
  try {
@@ -14264,7 +14331,7 @@ async function getSkills(targetDir, rootDir = ".claude", config) {
14264
14331
  const skillMdFiles = await listFiles(skillsDir, { recursive: true, pattern: "SKILL.md" });
14265
14332
  const skills = await Promise.all(skillMdFiles.map(async (skillMdPath) => {
14266
14333
  const skillDir = dirname2(skillMdPath);
14267
- const indexYamlPath = join6(skillDir, "index.yaml");
14334
+ const indexYamlPath = join7(skillDir, "index.yaml");
14268
14335
  const { description, version } = await tryReadIndexYamlMetadata(indexYamlPath);
14269
14336
  const relativePath = relative2(targetDir, skillDir);
14270
14337
  return {
@@ -14283,7 +14350,7 @@ async function getSkills(targetDir, rootDir = ".claude", config) {
14283
14350
  }
14284
14351
  }
14285
14352
  async function getGuides(targetDir, config) {
14286
- const guidesDir = join6(targetDir, "guides");
14353
+ const guidesDir = join7(targetDir, "guides");
14287
14354
  if (!await fileExists(guidesDir))
14288
14355
  return [];
14289
14356
  try {
@@ -14310,7 +14377,7 @@ async function getGuides(targetDir, config) {
14310
14377
  }
14311
14378
  var RULE_PRIORITY_ORDER = { MUST: 0, SHOULD: 1, MAY: 2 };
14312
14379
  async function getRules(targetDir, rootDir = ".claude", config) {
14313
- const rulesDir = join6(targetDir, rootDir, "rules");
14380
+ const rulesDir = join7(targetDir, rootDir, "rules");
14314
14381
  if (!await fileExists(rulesDir))
14315
14382
  return [];
14316
14383
  try {
@@ -14382,7 +14449,7 @@ function formatAsJson(components) {
14382
14449
  console.log(JSON.stringify(components, null, 2));
14383
14450
  }
14384
14451
  async function getHooks(targetDir, rootDir = ".claude") {
14385
- const hooksDir = join6(targetDir, rootDir, "hooks");
14452
+ const hooksDir = join7(targetDir, rootDir, "hooks");
14386
14453
  if (!await fileExists(hooksDir))
14387
14454
  return [];
14388
14455
  try {
@@ -14400,7 +14467,7 @@ async function getHooks(targetDir, rootDir = ".claude") {
14400
14467
  }
14401
14468
  }
14402
14469
  async function getContexts(targetDir, rootDir = ".claude") {
14403
- const contextsDir = join6(targetDir, rootDir, "contexts");
14470
+ const contextsDir = join7(targetDir, rootDir, "contexts");
14404
14471
  if (!await fileExists(contextsDir))
14405
14472
  return [];
14406
14473
  try {
@@ -14485,7 +14552,7 @@ async function listCommand(type = "all", options = {}) {
14485
14552
  }
14486
14553
 
14487
14554
  // src/core/updater.ts
14488
- import { join as join7 } from "node:path";
14555
+ import { join as join8 } from "node:path";
14489
14556
 
14490
14557
  // src/core/entry-merger.ts
14491
14558
  var MANAGED_START = "<!-- omcustom:start -->";
@@ -14737,7 +14804,7 @@ function resolveCustomizations(customizations, configPreserveFiles, targetDir) {
14737
14804
  }
14738
14805
  async function updateEntryDoc(targetDir, provider, config, options) {
14739
14806
  const layout = getProviderLayout(provider);
14740
- const entryPath = join7(targetDir, layout.entryFile);
14807
+ const entryPath = join8(targetDir, layout.entryFile);
14741
14808
  const templateName = getEntryTemplateName2(provider, config.language);
14742
14809
  const templatePath = resolveTemplatePath(templateName);
14743
14810
  if (!await fileExists(templatePath)) {
@@ -14798,7 +14865,14 @@ async function update(options) {
14798
14865
  config.lastUpdated = new Date().toISOString();
14799
14866
  await saveConfig(options.targetDir, config);
14800
14867
  result.success = true;
14801
- success("update.success", { from: result.previousVersion, to: result.newVersion });
14868
+ if (result.previousVersion !== result.newVersion) {
14869
+ success("update.success", { from: result.previousVersion, to: result.newVersion });
14870
+ } else if (result.updatedComponents.length > 0) {
14871
+ success("update.components_synced", {
14872
+ version: result.newVersion,
14873
+ components: result.updatedComponents.join(", ")
14874
+ });
14875
+ }
14802
14876
  } catch (err) {
14803
14877
  const message = err instanceof Error ? err.message : String(err);
14804
14878
  result.error = message;
@@ -14853,7 +14927,7 @@ async function updateComponent(targetDir, provider, component, customizations, o
14853
14927
  const preservedFiles = [];
14854
14928
  const componentPath = getComponentPath2(provider, component);
14855
14929
  const srcPath = resolveTemplatePath(componentPath);
14856
- const destPath = join7(targetDir, componentPath);
14930
+ const destPath = join8(targetDir, componentPath);
14857
14931
  const customComponents = config.customComponents || [];
14858
14932
  const skipPaths = [];
14859
14933
  if (customizations && !options.forceOverwriteAll) {
@@ -14867,7 +14941,7 @@ async function updateComponent(targetDir, provider, component, customizations, o
14867
14941
  }
14868
14942
  }
14869
14943
  const path2 = await import("node:path");
14870
- const normalizedSkipPaths = skipPaths.map((p) => path2.relative(destPath, join7(targetDir, p)));
14944
+ const normalizedSkipPaths = skipPaths.map((p) => path2.relative(destPath, join8(targetDir, p)));
14871
14945
  await copyDirectory(srcPath, destPath, {
14872
14946
  overwrite: true,
14873
14947
  skipPaths: normalizedSkipPaths.length > 0 ? normalizedSkipPaths : undefined
@@ -14887,26 +14961,26 @@ function getComponentPath2(provider, component) {
14887
14961
  }
14888
14962
  async function backupInstallation(targetDir, provider) {
14889
14963
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
14890
- const backupDir = join7(targetDir, `.omcustom-backup-${timestamp}`);
14964
+ const backupDir = join8(targetDir, `.omcustom-backup-${timestamp}`);
14891
14965
  const fs2 = await import("node:fs/promises");
14892
14966
  await ensureDirectory(backupDir);
14893
14967
  const layout = getProviderLayout(provider);
14894
14968
  const dirsToBackup = [layout.rootDir, "guides"];
14895
14969
  for (const dir2 of dirsToBackup) {
14896
- const srcPath = join7(targetDir, dir2);
14970
+ const srcPath = join8(targetDir, dir2);
14897
14971
  if (await fileExists(srcPath)) {
14898
- const destPath = join7(backupDir, dir2);
14972
+ const destPath = join8(backupDir, dir2);
14899
14973
  await copyDirectory(srcPath, destPath, { overwrite: true });
14900
14974
  }
14901
14975
  }
14902
- const entryPath = join7(targetDir, layout.entryFile);
14976
+ const entryPath = join8(targetDir, layout.entryFile);
14903
14977
  if (await fileExists(entryPath)) {
14904
- await fs2.copyFile(entryPath, join7(backupDir, layout.entryFile));
14978
+ await fs2.copyFile(entryPath, join8(backupDir, layout.entryFile));
14905
14979
  }
14906
14980
  return backupDir;
14907
14981
  }
14908
14982
  async function loadCustomizationManifest(targetDir) {
14909
- const manifestPath = join7(targetDir, CUSTOMIZATION_MANIFEST_FILE);
14983
+ const manifestPath = join8(targetDir, CUSTOMIZATION_MANIFEST_FILE);
14910
14984
  if (await fileExists(manifestPath)) {
14911
14985
  return readJsonFile(manifestPath);
14912
14986
  }
package/dist/index.js CHANGED
@@ -238,6 +238,7 @@ var MESSAGES = {
238
238
  "install.entry_md_skipped": "{{entry}} skipped ({{reason}})",
239
239
  "update.start": "Checking for updates...",
240
240
  "update.success": "Updated from {{from}} to {{to}}",
241
+ "update.components_synced": "Components synced (version {{version}}): {{components}}",
241
242
  "update.failed": "Update failed: {{error}}",
242
243
  "update.no_updates": "Already up to date",
243
244
  "update.backup_created": "Backup created at: {{path}}",
@@ -269,6 +270,7 @@ var MESSAGES = {
269
270
  "install.entry_md_skipped": "{{entry}} 건너뜀 ({{reason}})",
270
271
  "update.start": "업데이트 확인 중...",
271
272
  "update.success": "{{from}}에서 {{to}}로 업데이트 완료",
273
+ "update.components_synced": "컴포넌트 동기화 완료 (버전 {{version}}): {{components}}",
272
274
  "update.failed": "업데이트 실패: {{error}}",
273
275
  "update.no_updates": "이미 최신 버전입니다",
274
276
  "update.backup_created": "백업 생성됨: {{path}}",
@@ -1508,7 +1510,14 @@ async function update(options) {
1508
1510
  config.lastUpdated = new Date().toISOString();
1509
1511
  await saveConfig(options.targetDir, config);
1510
1512
  result.success = true;
1511
- success("update.success", { from: result.previousVersion, to: result.newVersion });
1513
+ if (result.previousVersion !== result.newVersion) {
1514
+ success("update.success", { from: result.previousVersion, to: result.newVersion });
1515
+ } else if (result.updatedComponents.length > 0) {
1516
+ success("update.components_synced", {
1517
+ version: result.newVersion,
1518
+ components: result.updatedComponents.join(", ")
1519
+ });
1520
+ }
1512
1521
  } catch (err) {
1513
1522
  const message = err instanceof Error ? err.message : String(err);
1514
1523
  result.error = message;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-customcode",
3
- "version": "0.10.3",
3
+ "version": "0.11.0",
4
4
  "description": "Batteries-included agent harness for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {