oh-my-customcode 0.8.0 → 0.9.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 +10 -2
- package/dist/cli/index.js +517 -274
- package/dist/index.js +303 -101
- package/package.json +1 -1
- package/templates/.codex/agents/arch-documenter.md +97 -0
- package/templates/.codex/agents/arch-speckit-agent.md +134 -0
- package/templates/.codex/agents/be-express-expert.md +80 -0
- package/templates/.codex/agents/be-fastapi-expert.md +43 -0
- package/templates/.codex/agents/be-go-backend-expert.md +43 -0
- package/templates/.codex/agents/be-nestjs-expert.md +60 -0
- package/templates/.codex/agents/be-springboot-expert.md +85 -0
- package/templates/.codex/agents/db-postgres-expert.md +106 -0
- package/templates/.codex/agents/db-redis-expert.md +101 -0
- package/templates/.codex/agents/db-supabase-expert.md +71 -0
- package/templates/.codex/agents/de-airflow-expert.md +71 -0
- package/templates/.codex/agents/de-dbt-expert.md +72 -0
- package/templates/.codex/agents/de-kafka-expert.md +81 -0
- package/templates/.codex/agents/de-pipeline-expert.md +92 -0
- package/templates/.codex/agents/de-snowflake-expert.md +89 -0
- package/templates/.codex/agents/de-spark-expert.md +80 -0
- package/templates/.codex/agents/fe-svelte-agent.md +65 -0
- package/templates/.codex/agents/fe-vercel-agent.md +69 -0
- package/templates/.codex/agents/fe-vuejs-agent.md +65 -0
- package/templates/.codex/agents/infra-aws-expert.md +47 -0
- package/templates/.codex/agents/infra-docker-expert.md +47 -0
- package/templates/.codex/agents/lang-golang-expert.md +43 -0
- package/templates/.codex/agents/lang-java21-expert.md +65 -0
- package/templates/.codex/agents/lang-kotlin-expert.md +43 -0
- package/templates/.codex/agents/lang-python-expert.md +43 -0
- package/templates/.codex/agents/lang-rust-expert.md +43 -0
- package/templates/.codex/agents/lang-typescript-expert.md +43 -0
- package/templates/.codex/agents/mgr-claude-code-bible.md +246 -0
- package/templates/.codex/agents/mgr-creator.md +120 -0
- package/templates/.codex/agents/mgr-gitnerd.md +113 -0
- package/templates/.codex/agents/mgr-sauron.md +154 -0
- package/templates/.codex/agents/mgr-supplier.md +120 -0
- package/templates/.codex/agents/mgr-sync-checker.md +99 -0
- package/templates/.codex/agents/mgr-updater.md +103 -0
- package/templates/.codex/agents/qa-engineer.md +96 -0
- package/templates/.codex/agents/qa-planner.md +74 -0
- package/templates/.codex/agents/qa-writer.md +97 -0
- package/templates/.codex/agents/sys-memory-keeper.md +117 -0
- package/templates/.codex/agents/sys-naggy.md +90 -0
- package/templates/.codex/agents/tool-bun-expert.md +71 -0
- package/templates/.codex/agents/tool-npm-expert.md +88 -0
- package/templates/.codex/agents/tool-optimizer.md +87 -0
- package/templates/.codex/codex-native-hash.txt +1 -0
- package/templates/.codex/contexts/dev.md +20 -0
- package/templates/.codex/contexts/ecomode.md +63 -0
- package/templates/.codex/contexts/index.yaml +41 -0
- package/templates/.codex/contexts/research.md +28 -0
- package/templates/.codex/contexts/review.md +23 -0
- package/templates/.codex/hooks/hooks.json +151 -0
- package/templates/.codex/install-hooks.sh +100 -0
- package/templates/.codex/rules/MAY-optimization.md +93 -0
- package/templates/.codex/rules/MUST-agent-design.md +162 -0
- package/templates/.codex/rules/MUST-agent-identification.md +108 -0
- package/templates/.codex/rules/MUST-continuous-improvement.md +132 -0
- package/templates/.codex/rules/MUST-intent-transparency.md +199 -0
- package/templates/.codex/rules/MUST-language-policy.md +62 -0
- package/templates/.codex/rules/MUST-orchestrator-coordination.md +471 -0
- package/templates/.codex/rules/MUST-parallel-execution.md +469 -0
- package/templates/.codex/rules/MUST-permissions.md +84 -0
- package/templates/.codex/rules/MUST-safety.md +69 -0
- package/templates/.codex/rules/MUST-sync-verification.md +281 -0
- package/templates/.codex/rules/MUST-tool-identification.md +195 -0
- package/templates/.codex/rules/SHOULD-agent-teams.md +183 -0
- package/templates/.codex/rules/SHOULD-ecomode.md +145 -0
- package/templates/.codex/rules/SHOULD-error-handling.md +102 -0
- package/templates/.codex/rules/SHOULD-hud-statusline.md +112 -0
- package/templates/.codex/rules/SHOULD-interaction.md +103 -0
- package/templates/.codex/rules/SHOULD-memory-integration.md +132 -0
- package/templates/.codex/rules/index.yaml +141 -0
- package/templates/.codex/skills/airflow-best-practices/SKILL.md +56 -0
- package/templates/.codex/skills/audit-agents/SKILL.md +116 -0
- package/templates/.codex/skills/aws-best-practices/SKILL.md +280 -0
- package/templates/.codex/skills/claude-code-bible/SKILL.md +180 -0
- package/templates/.codex/skills/claude-code-bible/scripts/fetch-docs.js +244 -0
- package/templates/.codex/skills/create-agent/SKILL.md +91 -0
- package/templates/.codex/skills/dbt-best-practices/SKILL.md +54 -0
- package/templates/.codex/skills/de-lead-routing/SKILL.md +230 -0
- package/templates/.codex/skills/dev-lead-routing/SKILL.md +253 -0
- package/templates/.codex/skills/dev-refactor/SKILL.md +123 -0
- package/templates/.codex/skills/dev-review/SKILL.md +81 -0
- package/templates/.codex/skills/docker-best-practices/SKILL.md +275 -0
- package/templates/.codex/skills/fastapi-best-practices/SKILL.md +270 -0
- package/templates/.codex/skills/fix-refs/SKILL.md +107 -0
- package/templates/.codex/skills/go-backend-best-practices/SKILL.md +338 -0
- package/templates/.codex/skills/go-best-practices/CLAUDE.md +9 -0
- package/templates/.codex/skills/go-best-practices/SKILL.md +203 -0
- package/templates/.codex/skills/help/SKILL.md +125 -0
- package/templates/.codex/skills/intent-detection/SKILL.md +215 -0
- package/templates/.codex/skills/intent-detection/patterns/agent-triggers.yaml +349 -0
- package/templates/.codex/skills/kafka-best-practices/SKILL.md +52 -0
- package/templates/.codex/skills/kotlin-best-practices/SKILL.md +256 -0
- package/templates/.codex/skills/lists/SKILL.md +78 -0
- package/templates/.codex/skills/memory-management/SKILL.md +195 -0
- package/templates/.codex/skills/memory-recall/SKILL.md +152 -0
- package/templates/.codex/skills/memory-save/SKILL.md +126 -0
- package/templates/.codex/skills/monitoring-setup/SKILL.md +115 -0
- package/templates/.codex/skills/npm-audit/SKILL.md +72 -0
- package/templates/.codex/skills/npm-publish/SKILL.md +63 -0
- package/templates/.codex/skills/npm-version/SKILL.md +75 -0
- package/templates/.codex/skills/optimize-analyze/SKILL.md +55 -0
- package/templates/.codex/skills/optimize-bundle/SKILL.md +67 -0
- package/templates/.codex/skills/optimize-report/SKILL.md +74 -0
- package/templates/.codex/skills/pipeline-architecture-patterns/SKILL.md +83 -0
- package/templates/.codex/skills/postgres-best-practices/SKILL.md +66 -0
- package/templates/.codex/skills/python-best-practices/SKILL.md +222 -0
- package/templates/.codex/skills/qa-lead-routing/SKILL.md +277 -0
- package/templates/.codex/skills/react-best-practices/SKILL.md +101 -0
- package/templates/.codex/skills/redis-best-practices/SKILL.md +83 -0
- package/templates/.codex/skills/result-aggregation/SKILL.md +164 -0
- package/templates/.codex/skills/rust-best-practices/SKILL.md +267 -0
- package/templates/.codex/skills/sauron-watch/SKILL.md +144 -0
- package/templates/.codex/skills/secretary-routing/SKILL.md +190 -0
- package/templates/.codex/skills/snowflake-best-practices/SKILL.md +65 -0
- package/templates/.codex/skills/spark-best-practices/SKILL.md +52 -0
- package/templates/.codex/skills/springboot-best-practices/SKILL.md +357 -0
- package/templates/.codex/skills/status/SKILL.md +153 -0
- package/templates/.codex/skills/supabase-postgres-best-practices/SKILL.md +99 -0
- package/templates/.codex/skills/typescript-best-practices/SKILL.md +321 -0
- package/templates/.codex/skills/update-docs/SKILL.md +140 -0
- package/templates/.codex/skills/update-external/SKILL.md +149 -0
- package/templates/.codex/skills/vercel-deploy/SKILL.md +73 -0
- package/templates/.codex/skills/web-design-guidelines/SKILL.md +118 -0
- package/templates/.codex/skills/writing-clearly-and-concisely/SKILL.md +64 -0
- package/templates/.codex/uninstall-hooks.sh +52 -0
- package/templates/AGENTS.md.en +39 -0
- package/templates/AGENTS.md.ko +39 -0
- package/templates/manifest.codex.json +43 -0
- package/templates/manifest.json +5 -5
package/dist/cli/index.js
CHANGED
|
@@ -11464,8 +11464,9 @@ var en_default = {
|
|
|
11464
11464
|
init: {
|
|
11465
11465
|
description: "Initialize oh-my-customcode in the current directory",
|
|
11466
11466
|
langOption: "Language for templates (en or ko)",
|
|
11467
|
+
providerOption: "Provider to initialize (auto, claude, codex)",
|
|
11467
11468
|
start: "Initializing oh-my-customcode...",
|
|
11468
|
-
exists: "Existing
|
|
11469
|
+
exists: "Existing {{rootDir}} directory found.",
|
|
11469
11470
|
backing_up: "Creating backup...",
|
|
11470
11471
|
backedUp: "Backed up existing installation to: {{path}}",
|
|
11471
11472
|
copying: "Copying templates...",
|
|
@@ -11507,6 +11508,7 @@ var en_default = {
|
|
|
11507
11508
|
list: {
|
|
11508
11509
|
description: "List installed components",
|
|
11509
11510
|
typeArgument: "Type to list: agents, skills, guides, rules, or all",
|
|
11511
|
+
providerOption: "Provider to list (auto, claude, codex)",
|
|
11510
11512
|
scanning: "Scanning installed components...",
|
|
11511
11513
|
empty: "No {{type}} found.",
|
|
11512
11514
|
header: "{{type}} ({{count}} installed)",
|
|
@@ -11531,6 +11533,7 @@ var en_default = {
|
|
|
11531
11533
|
doctor: {
|
|
11532
11534
|
description: "Check and fix configuration issues",
|
|
11533
11535
|
fixOption: "Automatically fix issues that can be fixed",
|
|
11536
|
+
providerOption: "Provider to diagnose (auto, claude, codex)",
|
|
11534
11537
|
checking: "Running diagnostic checks...",
|
|
11535
11538
|
applyingFixes: "Applying fixes...",
|
|
11536
11539
|
fixing: "Fixing: {{name}}...",
|
|
@@ -11571,6 +11574,10 @@ var en_default = {
|
|
|
11571
11574
|
pass: "CLAUDE.md exists",
|
|
11572
11575
|
fail: "CLAUDE.md not found"
|
|
11573
11576
|
},
|
|
11577
|
+
entryMd: {
|
|
11578
|
+
pass: "{{entry}} exists",
|
|
11579
|
+
fail: "{{entry}} not found"
|
|
11580
|
+
},
|
|
11574
11581
|
rules: {
|
|
11575
11582
|
pass: "Rules directory is valid",
|
|
11576
11583
|
fail: "Rules directory is missing or incomplete"
|
|
@@ -11711,8 +11718,9 @@ var ko_default = {
|
|
|
11711
11718
|
init: {
|
|
11712
11719
|
description: "현재 디렉토리에 oh-my-customcode 초기화",
|
|
11713
11720
|
langOption: "템플릿 언어 (en 또는 ko)",
|
|
11721
|
+
providerOption: "초기화할 제공자 (auto, claude, codex)",
|
|
11714
11722
|
start: "oh-my-customcode 초기화 중...",
|
|
11715
|
-
exists: "기존
|
|
11723
|
+
exists: "기존 {{rootDir}} 디렉토리가 발견되었습니다.",
|
|
11716
11724
|
backing_up: "백업을 생성합니다...",
|
|
11717
11725
|
backedUp: "기존 설치가 백업되었습니다: {{path}}",
|
|
11718
11726
|
copying: "템플릿 복사 중...",
|
|
@@ -11754,6 +11762,7 @@ var ko_default = {
|
|
|
11754
11762
|
list: {
|
|
11755
11763
|
description: "설치된 컴포넌트 목록 표시",
|
|
11756
11764
|
typeArgument: "표시할 타입: agents, skills, guides, rules 또는 all",
|
|
11765
|
+
providerOption: "표시할 제공자 (auto, claude, codex)",
|
|
11757
11766
|
scanning: "설치된 컴포넌트 검색 중...",
|
|
11758
11767
|
empty: "{{type}}이(가) 없습니다.",
|
|
11759
11768
|
header: "{{type}} ({{count}}개 설치됨)",
|
|
@@ -11778,6 +11787,7 @@ var ko_default = {
|
|
|
11778
11787
|
doctor: {
|
|
11779
11788
|
description: "설정 문제 확인 및 수정",
|
|
11780
11789
|
fixOption: "자동으로 수정 가능한 문제 수정",
|
|
11790
|
+
providerOption: "진단할 제공자 (auto, claude, codex)",
|
|
11781
11791
|
checking: "진단 검사 실행 중...",
|
|
11782
11792
|
applyingFixes: "수정 사항 적용 중...",
|
|
11783
11793
|
fixing: "수정 중: {{name}}...",
|
|
@@ -11818,6 +11828,10 @@ var ko_default = {
|
|
|
11818
11828
|
pass: "CLAUDE.md 존재함",
|
|
11819
11829
|
fail: "CLAUDE.md를 찾을 수 없음"
|
|
11820
11830
|
},
|
|
11831
|
+
entryMd: {
|
|
11832
|
+
pass: "{{entry}} 존재함",
|
|
11833
|
+
fail: "{{entry}}를 찾을 수 없음"
|
|
11834
|
+
},
|
|
11821
11835
|
rules: {
|
|
11822
11836
|
pass: "Rules 디렉토리 정상",
|
|
11823
11837
|
fail: "Rules 디렉토리가 없거나 불완전함"
|
|
@@ -12015,6 +12029,341 @@ var $stringify = publicApi.stringify;
|
|
|
12015
12029
|
var $visit = visit.visit;
|
|
12016
12030
|
var $visitAsync = visit.visitAsync;
|
|
12017
12031
|
|
|
12032
|
+
// src/core/layout.ts
|
|
12033
|
+
var PROVIDER_LAYOUTS = {
|
|
12034
|
+
claude: {
|
|
12035
|
+
provider: "claude",
|
|
12036
|
+
rootDir: ".claude",
|
|
12037
|
+
entryFile: "CLAUDE.md",
|
|
12038
|
+
entryTemplatePrefix: "CLAUDE.md",
|
|
12039
|
+
manifestFile: "manifest.json",
|
|
12040
|
+
backupDirPrefix: ".claude-backup-",
|
|
12041
|
+
directoryStructure: [
|
|
12042
|
+
".claude",
|
|
12043
|
+
".claude/rules",
|
|
12044
|
+
".claude/hooks",
|
|
12045
|
+
".claude/contexts",
|
|
12046
|
+
".claude/agents",
|
|
12047
|
+
".claude/skills",
|
|
12048
|
+
"guides"
|
|
12049
|
+
]
|
|
12050
|
+
},
|
|
12051
|
+
codex: {
|
|
12052
|
+
provider: "codex",
|
|
12053
|
+
rootDir: ".codex",
|
|
12054
|
+
entryFile: "AGENTS.md",
|
|
12055
|
+
entryTemplatePrefix: "AGENTS.md",
|
|
12056
|
+
manifestFile: "manifest.codex.json",
|
|
12057
|
+
backupDirPrefix: ".codex-backup-",
|
|
12058
|
+
directoryStructure: [
|
|
12059
|
+
".codex",
|
|
12060
|
+
".codex/rules",
|
|
12061
|
+
".codex/hooks",
|
|
12062
|
+
".codex/contexts",
|
|
12063
|
+
".codex/agents",
|
|
12064
|
+
".codex/skills",
|
|
12065
|
+
"guides"
|
|
12066
|
+
]
|
|
12067
|
+
}
|
|
12068
|
+
};
|
|
12069
|
+
function getProviderLayout(provider) {
|
|
12070
|
+
return PROVIDER_LAYOUTS[provider];
|
|
12071
|
+
}
|
|
12072
|
+
function getEntryTemplateName(provider, language) {
|
|
12073
|
+
const layout = getProviderLayout(provider);
|
|
12074
|
+
return `${layout.entryTemplatePrefix}.${language}`;
|
|
12075
|
+
}
|
|
12076
|
+
function getComponentPath(provider, component) {
|
|
12077
|
+
const layout = getProviderLayout(provider);
|
|
12078
|
+
if (component === "entry-md") {
|
|
12079
|
+
return layout.entryFile;
|
|
12080
|
+
}
|
|
12081
|
+
if (component === "guides") {
|
|
12082
|
+
return "guides";
|
|
12083
|
+
}
|
|
12084
|
+
return `${layout.rootDir}/${component}`;
|
|
12085
|
+
}
|
|
12086
|
+
function getDefaultProvider() {
|
|
12087
|
+
return "claude";
|
|
12088
|
+
}
|
|
12089
|
+
|
|
12090
|
+
// src/core/provider.ts
|
|
12091
|
+
import { join as join2 } from "node:path";
|
|
12092
|
+
|
|
12093
|
+
// src/utils/fs.ts
|
|
12094
|
+
import { dirname, join, resolve } from "node:path";
|
|
12095
|
+
import { fileURLToPath } from "node:url";
|
|
12096
|
+
async function fileExists(path) {
|
|
12097
|
+
const fs = await import("node:fs/promises");
|
|
12098
|
+
try {
|
|
12099
|
+
await fs.access(path);
|
|
12100
|
+
return true;
|
|
12101
|
+
} catch {
|
|
12102
|
+
return false;
|
|
12103
|
+
}
|
|
12104
|
+
}
|
|
12105
|
+
async function ensureDirectory(path) {
|
|
12106
|
+
const fs = await import("node:fs/promises");
|
|
12107
|
+
await fs.mkdir(path, { recursive: true });
|
|
12108
|
+
}
|
|
12109
|
+
function shouldSkipEntry(entryName, options) {
|
|
12110
|
+
if (options.exclude?.some((pattern) => matchesPattern(entryName, pattern))) {
|
|
12111
|
+
return true;
|
|
12112
|
+
}
|
|
12113
|
+
if (options.include && !options.include.some((pattern) => matchesPattern(entryName, pattern))) {
|
|
12114
|
+
return true;
|
|
12115
|
+
}
|
|
12116
|
+
return false;
|
|
12117
|
+
}
|
|
12118
|
+
async function handleSymlink(srcPath, destPath, options, fs) {
|
|
12119
|
+
const destExists = await fileExists(destPath);
|
|
12120
|
+
if (destExists && !options.overwrite) {
|
|
12121
|
+
return;
|
|
12122
|
+
}
|
|
12123
|
+
if (options.preserveSymlinks !== false) {
|
|
12124
|
+
await copyPreservedSymlink(srcPath, destPath, destExists, fs);
|
|
12125
|
+
} else {
|
|
12126
|
+
await copyFollowedSymlink(srcPath, destPath, destExists, options, fs);
|
|
12127
|
+
}
|
|
12128
|
+
}
|
|
12129
|
+
async function copyPreservedSymlink(srcPath, destPath, destExists, fs) {
|
|
12130
|
+
const linkTarget = await fs.readlink(srcPath);
|
|
12131
|
+
if (destExists) {
|
|
12132
|
+
await fs.unlink(destPath);
|
|
12133
|
+
}
|
|
12134
|
+
await fs.symlink(linkTarget, destPath);
|
|
12135
|
+
}
|
|
12136
|
+
async function copyFollowedSymlink(srcPath, destPath, destExists, options, fs) {
|
|
12137
|
+
const realPath = await fs.realpath(srcPath);
|
|
12138
|
+
const stat = await fs.stat(realPath);
|
|
12139
|
+
if (stat.isDirectory()) {
|
|
12140
|
+
await copyDirectory(realPath, destPath, options);
|
|
12141
|
+
return;
|
|
12142
|
+
}
|
|
12143
|
+
if (destExists) {
|
|
12144
|
+
await fs.unlink(destPath);
|
|
12145
|
+
}
|
|
12146
|
+
await fs.copyFile(realPath, destPath);
|
|
12147
|
+
}
|
|
12148
|
+
async function handleFile(srcPath, destPath, options, fs) {
|
|
12149
|
+
const destExists = await fileExists(destPath);
|
|
12150
|
+
if (destExists && !options.overwrite) {
|
|
12151
|
+
return;
|
|
12152
|
+
}
|
|
12153
|
+
await fs.copyFile(srcPath, destPath);
|
|
12154
|
+
if (options.preserveTimestamps) {
|
|
12155
|
+
const stats = await fs.stat(srcPath);
|
|
12156
|
+
await fs.utimes(destPath, stats.atime, stats.mtime);
|
|
12157
|
+
}
|
|
12158
|
+
}
|
|
12159
|
+
async function copyDirectory(src, dest, options = {}) {
|
|
12160
|
+
const fs = await import("node:fs/promises");
|
|
12161
|
+
const path = await import("node:path");
|
|
12162
|
+
await ensureDirectory(dest);
|
|
12163
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
12164
|
+
for (const entry of entries) {
|
|
12165
|
+
if (shouldSkipEntry(entry.name, options)) {
|
|
12166
|
+
continue;
|
|
12167
|
+
}
|
|
12168
|
+
const srcPath = path.join(src, entry.name);
|
|
12169
|
+
const destPath = path.join(dest, entry.name);
|
|
12170
|
+
if (entry.isSymbolicLink()) {
|
|
12171
|
+
await handleSymlink(srcPath, destPath, options, fs);
|
|
12172
|
+
} else if (entry.isDirectory()) {
|
|
12173
|
+
await copyDirectory(srcPath, destPath, options);
|
|
12174
|
+
} else if (entry.isFile()) {
|
|
12175
|
+
await handleFile(srcPath, destPath, options, fs);
|
|
12176
|
+
}
|
|
12177
|
+
}
|
|
12178
|
+
}
|
|
12179
|
+
async function readJsonFile(path) {
|
|
12180
|
+
const fs = await import("node:fs/promises");
|
|
12181
|
+
const content = await fs.readFile(path, "utf-8");
|
|
12182
|
+
return JSON.parse(content);
|
|
12183
|
+
}
|
|
12184
|
+
async function writeJsonFile(path, data) {
|
|
12185
|
+
const fs = await import("node:fs/promises");
|
|
12186
|
+
const content = JSON.stringify(data, null, 2);
|
|
12187
|
+
await fs.writeFile(path, content, "utf-8");
|
|
12188
|
+
}
|
|
12189
|
+
async function readTextFile(path) {
|
|
12190
|
+
const fs = await import("node:fs/promises");
|
|
12191
|
+
return fs.readFile(path, "utf-8");
|
|
12192
|
+
}
|
|
12193
|
+
function getPackageRoot() {
|
|
12194
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
12195
|
+
const currentDir = dirname(currentFile);
|
|
12196
|
+
return resolve(currentDir, "..", "..");
|
|
12197
|
+
}
|
|
12198
|
+
function resolveTemplatePath(relativePath) {
|
|
12199
|
+
const packageRoot = getPackageRoot();
|
|
12200
|
+
return join(packageRoot, "templates", relativePath);
|
|
12201
|
+
}
|
|
12202
|
+
async function listFiles(dir2, options = {}) {
|
|
12203
|
+
const fs = await import("node:fs/promises");
|
|
12204
|
+
const path = await import("node:path");
|
|
12205
|
+
const files = [];
|
|
12206
|
+
const entries = await fs.readdir(dir2, { withFileTypes: true });
|
|
12207
|
+
for (const entry of entries) {
|
|
12208
|
+
const fullPath = path.join(dir2, entry.name);
|
|
12209
|
+
if (entry.isDirectory() && options.recursive) {
|
|
12210
|
+
const subFiles = await listFiles(fullPath, options);
|
|
12211
|
+
files.push(...subFiles);
|
|
12212
|
+
} else if (entry.isFile()) {
|
|
12213
|
+
if (!options.pattern || matchesPattern(entry.name, options.pattern)) {
|
|
12214
|
+
files.push(fullPath);
|
|
12215
|
+
}
|
|
12216
|
+
}
|
|
12217
|
+
}
|
|
12218
|
+
return files;
|
|
12219
|
+
}
|
|
12220
|
+
function matchesPattern(filename, pattern) {
|
|
12221
|
+
const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
12222
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
12223
|
+
return regex.test(filename);
|
|
12224
|
+
}
|
|
12225
|
+
|
|
12226
|
+
// src/core/provider.ts
|
|
12227
|
+
var ENV_SIGNALS = {
|
|
12228
|
+
claude: [
|
|
12229
|
+
"ANTHROPIC_API_KEY",
|
|
12230
|
+
"CLAUDE_CODE",
|
|
12231
|
+
"CLAUDE_CODE_EFFORT_LEVEL",
|
|
12232
|
+
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS",
|
|
12233
|
+
"CLAUDE_CODE_ENABLE_TELEMETRY"
|
|
12234
|
+
],
|
|
12235
|
+
codex: ["OPENAI_API_KEY", "OPENAI_ORG_ID", "OPENAI_PROJECT", "CODEX_HOME", "CODEX_PROJECT"]
|
|
12236
|
+
};
|
|
12237
|
+
var PROVIDER_ENV_OVERRIDES = ["OMCUSTOM_PROVIDER", "LLM_SERVICE"];
|
|
12238
|
+
function normalizeProvider(value) {
|
|
12239
|
+
if (!value)
|
|
12240
|
+
return null;
|
|
12241
|
+
const normalized = value.toLowerCase().trim();
|
|
12242
|
+
if (normalized === "claude" || normalized === "codex" || normalized === "auto") {
|
|
12243
|
+
return normalized;
|
|
12244
|
+
}
|
|
12245
|
+
return null;
|
|
12246
|
+
}
|
|
12247
|
+
function detectFromEnv(env) {
|
|
12248
|
+
for (const key of PROVIDER_ENV_OVERRIDES) {
|
|
12249
|
+
const override = normalizeProvider(env[key]);
|
|
12250
|
+
if (override && override !== "auto") {
|
|
12251
|
+
return {
|
|
12252
|
+
provider: override,
|
|
12253
|
+
source: "override",
|
|
12254
|
+
confidence: "high",
|
|
12255
|
+
reason: `env:${key}`
|
|
12256
|
+
};
|
|
12257
|
+
}
|
|
12258
|
+
}
|
|
12259
|
+
const claudeSignals = ENV_SIGNALS.claude.filter((key) => Boolean(env[key]));
|
|
12260
|
+
const codexSignals = ENV_SIGNALS.codex.filter((key) => Boolean(env[key]));
|
|
12261
|
+
const hasClaude = claudeSignals.length > 0;
|
|
12262
|
+
const hasCodex = codexSignals.length > 0;
|
|
12263
|
+
if (hasClaude && !hasCodex) {
|
|
12264
|
+
return {
|
|
12265
|
+
provider: "claude",
|
|
12266
|
+
source: "env",
|
|
12267
|
+
confidence: "medium",
|
|
12268
|
+
reason: `env:${claudeSignals[0]}`
|
|
12269
|
+
};
|
|
12270
|
+
}
|
|
12271
|
+
if (hasCodex && !hasClaude) {
|
|
12272
|
+
return {
|
|
12273
|
+
provider: "codex",
|
|
12274
|
+
source: "env",
|
|
12275
|
+
confidence: "medium",
|
|
12276
|
+
reason: `env:${codexSignals[0]}`
|
|
12277
|
+
};
|
|
12278
|
+
}
|
|
12279
|
+
return null;
|
|
12280
|
+
}
|
|
12281
|
+
async function detectFromProject(targetDir) {
|
|
12282
|
+
const claudeMarkers = [join2(targetDir, "CLAUDE.md"), join2(targetDir, ".claude")];
|
|
12283
|
+
const codexMarkers = [join2(targetDir, "AGENTS.md"), join2(targetDir, ".codex")];
|
|
12284
|
+
const claudeFound = await Promise.all(claudeMarkers.map((path) => fileExists(path)));
|
|
12285
|
+
const codexFound = await Promise.all(codexMarkers.map((path) => fileExists(path)));
|
|
12286
|
+
const hasClaude = claudeFound.some(Boolean);
|
|
12287
|
+
const hasCodex = codexFound.some(Boolean);
|
|
12288
|
+
if (hasClaude && !hasCodex) {
|
|
12289
|
+
return {
|
|
12290
|
+
provider: "claude",
|
|
12291
|
+
source: "project",
|
|
12292
|
+
confidence: "medium",
|
|
12293
|
+
reason: "project:claude"
|
|
12294
|
+
};
|
|
12295
|
+
}
|
|
12296
|
+
if (hasCodex && !hasClaude) {
|
|
12297
|
+
return {
|
|
12298
|
+
provider: "codex",
|
|
12299
|
+
source: "project",
|
|
12300
|
+
confidence: "medium",
|
|
12301
|
+
reason: "project:codex"
|
|
12302
|
+
};
|
|
12303
|
+
}
|
|
12304
|
+
return null;
|
|
12305
|
+
}
|
|
12306
|
+
async function detectFromConfig(targetDir) {
|
|
12307
|
+
const configPath = join2(targetDir, ".omcustomrc.json");
|
|
12308
|
+
if (!await fileExists(configPath)) {
|
|
12309
|
+
return null;
|
|
12310
|
+
}
|
|
12311
|
+
try {
|
|
12312
|
+
const config = await readJsonFile(configPath);
|
|
12313
|
+
const provider = normalizeProvider(config.provider);
|
|
12314
|
+
if (provider && provider !== "auto") {
|
|
12315
|
+
return {
|
|
12316
|
+
provider,
|
|
12317
|
+
source: "config",
|
|
12318
|
+
confidence: "high",
|
|
12319
|
+
reason: "config:provider"
|
|
12320
|
+
};
|
|
12321
|
+
}
|
|
12322
|
+
} catch {}
|
|
12323
|
+
return null;
|
|
12324
|
+
}
|
|
12325
|
+
async function detectProvider(options = {}) {
|
|
12326
|
+
const env = options.env ?? process.env;
|
|
12327
|
+
const override = options.override;
|
|
12328
|
+
const normalizedOverride = normalizeProvider(override);
|
|
12329
|
+
if (normalizedOverride && normalizedOverride !== "auto") {
|
|
12330
|
+
return {
|
|
12331
|
+
provider: normalizedOverride,
|
|
12332
|
+
source: "override",
|
|
12333
|
+
confidence: "high",
|
|
12334
|
+
reason: "override:option"
|
|
12335
|
+
};
|
|
12336
|
+
}
|
|
12337
|
+
if (options.targetDir) {
|
|
12338
|
+
const fromConfig = await detectFromConfig(options.targetDir);
|
|
12339
|
+
if (fromConfig) {
|
|
12340
|
+
return fromConfig;
|
|
12341
|
+
}
|
|
12342
|
+
}
|
|
12343
|
+
if (options.targetDir && options.preferProject) {
|
|
12344
|
+
const fromProject = await detectFromProject(options.targetDir);
|
|
12345
|
+
if (fromProject) {
|
|
12346
|
+
return fromProject;
|
|
12347
|
+
}
|
|
12348
|
+
}
|
|
12349
|
+
const fromEnv = detectFromEnv(env);
|
|
12350
|
+
if (fromEnv) {
|
|
12351
|
+
return fromEnv;
|
|
12352
|
+
}
|
|
12353
|
+
if (options.targetDir && !options.preferProject) {
|
|
12354
|
+
const fromProject = await detectFromProject(options.targetDir);
|
|
12355
|
+
if (fromProject) {
|
|
12356
|
+
return fromProject;
|
|
12357
|
+
}
|
|
12358
|
+
}
|
|
12359
|
+
return {
|
|
12360
|
+
provider: getDefaultProvider(),
|
|
12361
|
+
source: "default",
|
|
12362
|
+
confidence: "low",
|
|
12363
|
+
reason: "default"
|
|
12364
|
+
};
|
|
12365
|
+
}
|
|
12366
|
+
|
|
12018
12367
|
// src/cli/doctor.ts
|
|
12019
12368
|
async function pathExists(targetPath) {
|
|
12020
12369
|
try {
|
|
@@ -12107,18 +12456,18 @@ async function countAgents(agentsDir) {
|
|
|
12107
12456
|
} catch {}
|
|
12108
12457
|
return count;
|
|
12109
12458
|
}
|
|
12110
|
-
async function
|
|
12111
|
-
const
|
|
12112
|
-
const exists2 = await pathExists(
|
|
12459
|
+
async function checkEntryDoc(targetDir, entryFile) {
|
|
12460
|
+
const entryPath = path.join(targetDir, entryFile);
|
|
12461
|
+
const exists2 = await pathExists(entryPath);
|
|
12113
12462
|
return {
|
|
12114
|
-
name:
|
|
12463
|
+
name: entryFile,
|
|
12115
12464
|
status: exists2 ? "pass" : "fail",
|
|
12116
|
-
message: exists2 ? i18n.t("cli.doctor.checks.
|
|
12465
|
+
message: exists2 ? i18n.t("cli.doctor.checks.entryMd.pass", { entry: entryFile }) : i18n.t("cli.doctor.checks.entryMd.fail", { entry: entryFile }),
|
|
12117
12466
|
fixable: false
|
|
12118
12467
|
};
|
|
12119
12468
|
}
|
|
12120
|
-
async function checkRules(targetDir) {
|
|
12121
|
-
const rulesDir = path.join(targetDir,
|
|
12469
|
+
async function checkRules(targetDir, rootDir = ".claude") {
|
|
12470
|
+
const rulesDir = path.join(targetDir, rootDir, "rules");
|
|
12122
12471
|
const exists2 = await isDirectory(rulesDir);
|
|
12123
12472
|
if (!exists2) {
|
|
12124
12473
|
return {
|
|
@@ -12144,8 +12493,8 @@ async function checkRules(targetDir) {
|
|
|
12144
12493
|
fixable: false
|
|
12145
12494
|
};
|
|
12146
12495
|
}
|
|
12147
|
-
async function checkAgents(targetDir) {
|
|
12148
|
-
const agentsDir = path.join(targetDir,
|
|
12496
|
+
async function checkAgents(targetDir, rootDir = ".claude") {
|
|
12497
|
+
const agentsDir = path.join(targetDir, rootDir, "agents");
|
|
12149
12498
|
const exists2 = await isDirectory(agentsDir);
|
|
12150
12499
|
if (!exists2) {
|
|
12151
12500
|
return {
|
|
@@ -12171,8 +12520,8 @@ async function checkAgents(targetDir) {
|
|
|
12171
12520
|
fixable: false
|
|
12172
12521
|
};
|
|
12173
12522
|
}
|
|
12174
|
-
async function checkSymlinks(targetDir) {
|
|
12175
|
-
const skillsDir = path.join(targetDir,
|
|
12523
|
+
async function checkSymlinks(targetDir, rootDir = ".claude") {
|
|
12524
|
+
const skillsDir = path.join(targetDir, rootDir, "skills");
|
|
12176
12525
|
const brokenSymlinks = [];
|
|
12177
12526
|
if (await isDirectory(skillsDir)) {
|
|
12178
12527
|
const skillSymlinks = await findRefsSymlinks(skillsDir);
|
|
@@ -12233,8 +12582,8 @@ async function checkIndexFiles(targetDir) {
|
|
|
12233
12582
|
fixable: false
|
|
12234
12583
|
};
|
|
12235
12584
|
}
|
|
12236
|
-
async function checkSkills(targetDir) {
|
|
12237
|
-
const skillsDir = path.join(targetDir,
|
|
12585
|
+
async function checkSkills(targetDir, rootDir = ".claude") {
|
|
12586
|
+
const skillsDir = path.join(targetDir, rootDir, "skills");
|
|
12238
12587
|
const exists2 = await isDirectory(skillsDir);
|
|
12239
12588
|
if (!exists2) {
|
|
12240
12589
|
return {
|
|
@@ -12287,14 +12636,14 @@ async function checkGuides(targetDir) {
|
|
|
12287
12636
|
fixable: false
|
|
12288
12637
|
};
|
|
12289
12638
|
}
|
|
12290
|
-
async function checkHooks(targetDir) {
|
|
12291
|
-
const hooksDir = path.join(targetDir,
|
|
12639
|
+
async function checkHooks(targetDir, rootDir = ".claude") {
|
|
12640
|
+
const hooksDir = path.join(targetDir, rootDir, "hooks");
|
|
12292
12641
|
const exists2 = await isDirectory(hooksDir);
|
|
12293
12642
|
if (!exists2) {
|
|
12294
12643
|
return {
|
|
12295
12644
|
name: "Hooks",
|
|
12296
12645
|
status: "fail",
|
|
12297
|
-
message:
|
|
12646
|
+
message: `${rootDir}/hooks/ directory not found`,
|
|
12298
12647
|
fixable: true
|
|
12299
12648
|
};
|
|
12300
12649
|
}
|
|
@@ -12303,7 +12652,7 @@ async function checkHooks(targetDir) {
|
|
|
12303
12652
|
return {
|
|
12304
12653
|
name: "Hooks",
|
|
12305
12654
|
status: "warn",
|
|
12306
|
-
message:
|
|
12655
|
+
message: `${rootDir}/hooks/ directory is empty`,
|
|
12307
12656
|
fixable: false
|
|
12308
12657
|
};
|
|
12309
12658
|
}
|
|
@@ -12314,14 +12663,14 @@ async function checkHooks(targetDir) {
|
|
|
12314
12663
|
fixable: false
|
|
12315
12664
|
};
|
|
12316
12665
|
}
|
|
12317
|
-
async function checkContexts(targetDir) {
|
|
12318
|
-
const contextsDir = path.join(targetDir,
|
|
12666
|
+
async function checkContexts(targetDir, rootDir = ".claude") {
|
|
12667
|
+
const contextsDir = path.join(targetDir, rootDir, "contexts");
|
|
12319
12668
|
const exists2 = await isDirectory(contextsDir);
|
|
12320
12669
|
if (!exists2) {
|
|
12321
12670
|
return {
|
|
12322
12671
|
name: "Contexts",
|
|
12323
12672
|
status: "fail",
|
|
12324
|
-
message:
|
|
12673
|
+
message: `${rootDir}/contexts/ directory not found`,
|
|
12325
12674
|
fixable: true
|
|
12326
12675
|
};
|
|
12327
12676
|
}
|
|
@@ -12330,7 +12679,7 @@ async function checkContexts(targetDir) {
|
|
|
12330
12679
|
return {
|
|
12331
12680
|
name: "Contexts",
|
|
12332
12681
|
status: "warn",
|
|
12333
|
-
message:
|
|
12682
|
+
message: `${rootDir}/contexts/ directory is empty`,
|
|
12334
12683
|
fixable: false
|
|
12335
12684
|
};
|
|
12336
12685
|
}
|
|
@@ -12359,14 +12708,14 @@ async function createMissingDirectory(dirPath) {
|
|
|
12359
12708
|
return false;
|
|
12360
12709
|
}
|
|
12361
12710
|
}
|
|
12362
|
-
async function fixSingleIssue(check, targetDir) {
|
|
12711
|
+
async function fixSingleIssue(check, targetDir, rootDir = ".claude") {
|
|
12363
12712
|
const fixMap = {
|
|
12364
|
-
Rules: () => createMissingDirectory(path.join(targetDir,
|
|
12365
|
-
Agents: () => createMissingDirectory(path.join(targetDir,
|
|
12366
|
-
Skills: () => createMissingDirectory(path.join(targetDir,
|
|
12713
|
+
Rules: () => createMissingDirectory(path.join(targetDir, rootDir, "rules")),
|
|
12714
|
+
Agents: () => createMissingDirectory(path.join(targetDir, rootDir, "agents")),
|
|
12715
|
+
Skills: () => createMissingDirectory(path.join(targetDir, rootDir, "skills")),
|
|
12367
12716
|
Guides: () => createMissingDirectory(path.join(targetDir, "guides")),
|
|
12368
|
-
Hooks: () => createMissingDirectory(path.join(targetDir,
|
|
12369
|
-
Contexts: () => createMissingDirectory(path.join(targetDir,
|
|
12717
|
+
Hooks: () => createMissingDirectory(path.join(targetDir, rootDir, "hooks")),
|
|
12718
|
+
Contexts: () => createMissingDirectory(path.join(targetDir, rootDir, "contexts")),
|
|
12370
12719
|
Symlinks: async () => {
|
|
12371
12720
|
if (!check.details || check.details.length === 0)
|
|
12372
12721
|
return false;
|
|
@@ -12378,7 +12727,7 @@ async function fixSingleIssue(check, targetDir) {
|
|
|
12378
12727
|
const fixer = fixMap[check.name];
|
|
12379
12728
|
return fixer ? fixer() : false;
|
|
12380
12729
|
}
|
|
12381
|
-
async function fixIssues(checks, targetDir) {
|
|
12730
|
+
async function fixIssues(checks, targetDir, rootDir = ".claude") {
|
|
12382
12731
|
const fixedChecks = [];
|
|
12383
12732
|
for (const check of checks) {
|
|
12384
12733
|
if (check.status !== "fail" || !check.fixable) {
|
|
@@ -12386,7 +12735,7 @@ async function fixIssues(checks, targetDir) {
|
|
|
12386
12735
|
continue;
|
|
12387
12736
|
}
|
|
12388
12737
|
console.log(i18n.t("cli.doctor.fixing", { name: check.name }));
|
|
12389
|
-
const fixed = await fixSingleIssue(check, targetDir);
|
|
12738
|
+
const fixed = await fixSingleIssue(check, targetDir, rootDir);
|
|
12390
12739
|
fixedChecks.push(fixed ? { ...check, fixed: true, message: i18n.t("cli.doctor.fixed", { name: check.name }) } : check);
|
|
12391
12740
|
}
|
|
12392
12741
|
return fixedChecks;
|
|
@@ -12413,23 +12762,29 @@ async function doctorCommand(options = {}) {
|
|
|
12413
12762
|
const targetDir = process.cwd();
|
|
12414
12763
|
console.log(i18n.t("cli.doctor.checking"));
|
|
12415
12764
|
console.log("");
|
|
12765
|
+
const detection = await detectProvider({
|
|
12766
|
+
targetDir,
|
|
12767
|
+
override: options.provider,
|
|
12768
|
+
preferProject: true
|
|
12769
|
+
});
|
|
12770
|
+
const layout = getProviderLayout(detection.provider);
|
|
12416
12771
|
let checks = await Promise.all([
|
|
12417
|
-
|
|
12418
|
-
checkRules(targetDir),
|
|
12419
|
-
checkAgents(targetDir),
|
|
12420
|
-
checkSkills(targetDir),
|
|
12421
|
-
checkSymlinks(targetDir),
|
|
12772
|
+
checkEntryDoc(targetDir, layout.entryFile),
|
|
12773
|
+
checkRules(targetDir, layout.rootDir),
|
|
12774
|
+
checkAgents(targetDir, layout.rootDir),
|
|
12775
|
+
checkSkills(targetDir, layout.rootDir),
|
|
12776
|
+
checkSymlinks(targetDir, layout.rootDir),
|
|
12422
12777
|
checkIndexFiles(targetDir),
|
|
12423
12778
|
checkGuides(targetDir),
|
|
12424
|
-
checkHooks(targetDir),
|
|
12425
|
-
checkContexts(targetDir)
|
|
12779
|
+
checkHooks(targetDir, layout.rootDir),
|
|
12780
|
+
checkContexts(targetDir, layout.rootDir)
|
|
12426
12781
|
]);
|
|
12427
12782
|
if (options.fix) {
|
|
12428
12783
|
const hasFixableIssues = checks.some((c) => c.status === "fail" && c.fixable);
|
|
12429
12784
|
if (hasFixableIssues) {
|
|
12430
12785
|
console.log(i18n.t("cli.doctor.applyingFixes"));
|
|
12431
12786
|
console.log("");
|
|
12432
|
-
checks = await fixIssues(checks, targetDir);
|
|
12787
|
+
checks = await fixIssues(checks, targetDir, layout.rootDir);
|
|
12433
12788
|
console.log("");
|
|
12434
12789
|
}
|
|
12435
12790
|
}
|
|
@@ -12471,144 +12826,11 @@ async function doctorCommand(options = {}) {
|
|
|
12471
12826
|
}
|
|
12472
12827
|
|
|
12473
12828
|
// src/cli/init.ts
|
|
12474
|
-
import { join as
|
|
12829
|
+
import { join as join5 } from "node:path";
|
|
12475
12830
|
|
|
12476
12831
|
// src/core/installer.ts
|
|
12477
12832
|
import { copyFile as fsCopyFile, rename } from "node:fs/promises";
|
|
12478
|
-
import { basename, join as
|
|
12479
|
-
|
|
12480
|
-
// src/utils/fs.ts
|
|
12481
|
-
import { dirname, join, resolve } from "node:path";
|
|
12482
|
-
import { fileURLToPath } from "node:url";
|
|
12483
|
-
async function fileExists(path2) {
|
|
12484
|
-
const fs2 = await import("node:fs/promises");
|
|
12485
|
-
try {
|
|
12486
|
-
await fs2.access(path2);
|
|
12487
|
-
return true;
|
|
12488
|
-
} catch {
|
|
12489
|
-
return false;
|
|
12490
|
-
}
|
|
12491
|
-
}
|
|
12492
|
-
async function ensureDirectory(path2) {
|
|
12493
|
-
const fs2 = await import("node:fs/promises");
|
|
12494
|
-
await fs2.mkdir(path2, { recursive: true });
|
|
12495
|
-
}
|
|
12496
|
-
function shouldSkipEntry(entryName, options) {
|
|
12497
|
-
if (options.exclude?.some((pattern) => matchesPattern(entryName, pattern))) {
|
|
12498
|
-
return true;
|
|
12499
|
-
}
|
|
12500
|
-
if (options.include && !options.include.some((pattern) => matchesPattern(entryName, pattern))) {
|
|
12501
|
-
return true;
|
|
12502
|
-
}
|
|
12503
|
-
return false;
|
|
12504
|
-
}
|
|
12505
|
-
async function handleSymlink(srcPath, destPath, options, fs2) {
|
|
12506
|
-
const destExists = await fileExists(destPath);
|
|
12507
|
-
if (destExists && !options.overwrite) {
|
|
12508
|
-
return;
|
|
12509
|
-
}
|
|
12510
|
-
if (options.preserveSymlinks !== false) {
|
|
12511
|
-
await copyPreservedSymlink(srcPath, destPath, destExists, fs2);
|
|
12512
|
-
} else {
|
|
12513
|
-
await copyFollowedSymlink(srcPath, destPath, destExists, options, fs2);
|
|
12514
|
-
}
|
|
12515
|
-
}
|
|
12516
|
-
async function copyPreservedSymlink(srcPath, destPath, destExists, fs2) {
|
|
12517
|
-
const linkTarget = await fs2.readlink(srcPath);
|
|
12518
|
-
if (destExists) {
|
|
12519
|
-
await fs2.unlink(destPath);
|
|
12520
|
-
}
|
|
12521
|
-
await fs2.symlink(linkTarget, destPath);
|
|
12522
|
-
}
|
|
12523
|
-
async function copyFollowedSymlink(srcPath, destPath, destExists, options, fs2) {
|
|
12524
|
-
const realPath = await fs2.realpath(srcPath);
|
|
12525
|
-
const stat = await fs2.stat(realPath);
|
|
12526
|
-
if (stat.isDirectory()) {
|
|
12527
|
-
await copyDirectory(realPath, destPath, options);
|
|
12528
|
-
return;
|
|
12529
|
-
}
|
|
12530
|
-
if (destExists) {
|
|
12531
|
-
await fs2.unlink(destPath);
|
|
12532
|
-
}
|
|
12533
|
-
await fs2.copyFile(realPath, destPath);
|
|
12534
|
-
}
|
|
12535
|
-
async function handleFile(srcPath, destPath, options, fs2) {
|
|
12536
|
-
const destExists = await fileExists(destPath);
|
|
12537
|
-
if (destExists && !options.overwrite) {
|
|
12538
|
-
return;
|
|
12539
|
-
}
|
|
12540
|
-
await fs2.copyFile(srcPath, destPath);
|
|
12541
|
-
if (options.preserveTimestamps) {
|
|
12542
|
-
const stats = await fs2.stat(srcPath);
|
|
12543
|
-
await fs2.utimes(destPath, stats.atime, stats.mtime);
|
|
12544
|
-
}
|
|
12545
|
-
}
|
|
12546
|
-
async function copyDirectory(src, dest, options = {}) {
|
|
12547
|
-
const fs2 = await import("node:fs/promises");
|
|
12548
|
-
const path2 = await import("node:path");
|
|
12549
|
-
await ensureDirectory(dest);
|
|
12550
|
-
const entries = await fs2.readdir(src, { withFileTypes: true });
|
|
12551
|
-
for (const entry of entries) {
|
|
12552
|
-
if (shouldSkipEntry(entry.name, options)) {
|
|
12553
|
-
continue;
|
|
12554
|
-
}
|
|
12555
|
-
const srcPath = path2.join(src, entry.name);
|
|
12556
|
-
const destPath = path2.join(dest, entry.name);
|
|
12557
|
-
if (entry.isSymbolicLink()) {
|
|
12558
|
-
await handleSymlink(srcPath, destPath, options, fs2);
|
|
12559
|
-
} else if (entry.isDirectory()) {
|
|
12560
|
-
await copyDirectory(srcPath, destPath, options);
|
|
12561
|
-
} else if (entry.isFile()) {
|
|
12562
|
-
await handleFile(srcPath, destPath, options, fs2);
|
|
12563
|
-
}
|
|
12564
|
-
}
|
|
12565
|
-
}
|
|
12566
|
-
async function readJsonFile(path2) {
|
|
12567
|
-
const fs2 = await import("node:fs/promises");
|
|
12568
|
-
const content = await fs2.readFile(path2, "utf-8");
|
|
12569
|
-
return JSON.parse(content);
|
|
12570
|
-
}
|
|
12571
|
-
async function writeJsonFile(path2, data) {
|
|
12572
|
-
const fs2 = await import("node:fs/promises");
|
|
12573
|
-
const content = JSON.stringify(data, null, 2);
|
|
12574
|
-
await fs2.writeFile(path2, content, "utf-8");
|
|
12575
|
-
}
|
|
12576
|
-
async function readTextFile(path2) {
|
|
12577
|
-
const fs2 = await import("node:fs/promises");
|
|
12578
|
-
return fs2.readFile(path2, "utf-8");
|
|
12579
|
-
}
|
|
12580
|
-
function getPackageRoot() {
|
|
12581
|
-
const currentFile = fileURLToPath(import.meta.url);
|
|
12582
|
-
const currentDir = dirname(currentFile);
|
|
12583
|
-
return resolve(currentDir, "..", "..");
|
|
12584
|
-
}
|
|
12585
|
-
function resolveTemplatePath(relativePath) {
|
|
12586
|
-
const packageRoot = getPackageRoot();
|
|
12587
|
-
return join(packageRoot, "templates", relativePath);
|
|
12588
|
-
}
|
|
12589
|
-
async function listFiles(dir2, options = {}) {
|
|
12590
|
-
const fs2 = await import("node:fs/promises");
|
|
12591
|
-
const path2 = await import("node:path");
|
|
12592
|
-
const files = [];
|
|
12593
|
-
const entries = await fs2.readdir(dir2, { withFileTypes: true });
|
|
12594
|
-
for (const entry of entries) {
|
|
12595
|
-
const fullPath = path2.join(dir2, entry.name);
|
|
12596
|
-
if (entry.isDirectory() && options.recursive) {
|
|
12597
|
-
const subFiles = await listFiles(fullPath, options);
|
|
12598
|
-
files.push(...subFiles);
|
|
12599
|
-
} else if (entry.isFile()) {
|
|
12600
|
-
if (!options.pattern || matchesPattern(entry.name, options.pattern)) {
|
|
12601
|
-
files.push(fullPath);
|
|
12602
|
-
}
|
|
12603
|
-
}
|
|
12604
|
-
}
|
|
12605
|
-
return files;
|
|
12606
|
-
}
|
|
12607
|
-
function matchesPattern(filename, pattern) {
|
|
12608
|
-
const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
12609
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
12610
|
-
return regex.test(filename);
|
|
12611
|
-
}
|
|
12833
|
+
import { basename, join as join4 } from "node:path";
|
|
12612
12834
|
|
|
12613
12835
|
// src/utils/logger.ts
|
|
12614
12836
|
var currentOptions = {
|
|
@@ -12659,7 +12881,7 @@ var MESSAGES = {
|
|
|
12659
12881
|
"install.start": "Initializing oh-my-customcode...",
|
|
12660
12882
|
"install.success": "Successfully initialized!",
|
|
12661
12883
|
"install.failed": "Installation failed: {{error}}",
|
|
12662
|
-
"install.exists": "Existing
|
|
12884
|
+
"install.exists": "Existing {{rootDir}} directory found",
|
|
12663
12885
|
"install.backup": "Backed up existing files to: {{path}}",
|
|
12664
12886
|
"install.directories_created": "Directory structure created",
|
|
12665
12887
|
"install.component_skipped": "Skipped {{component}} (already exists)",
|
|
@@ -12667,6 +12889,9 @@ var MESSAGES = {
|
|
|
12667
12889
|
"install.template_not_found": "Template not found for {{component}}: {{path}}",
|
|
12668
12890
|
"install.claude_md_installed": "CLAUDE.md installed ({{language}})",
|
|
12669
12891
|
"install.claude_md_not_found": "CLAUDE.md template not found for {{language}}",
|
|
12892
|
+
"install.entry_md_installed": "{{entry}} installed ({{language}})",
|
|
12893
|
+
"install.entry_md_not_found": "{{entry}} template not found for {{language}}",
|
|
12894
|
+
"install.entry_md_skipped": "{{entry}} skipped ({{reason}})",
|
|
12670
12895
|
"update.start": "Checking for updates...",
|
|
12671
12896
|
"update.success": "Updated from {{from}} to {{to}}",
|
|
12672
12897
|
"update.failed": "Update failed: {{error}}",
|
|
@@ -12687,7 +12912,7 @@ var MESSAGES = {
|
|
|
12687
12912
|
"install.start": "oh-my-customcode 초기화 중...",
|
|
12688
12913
|
"install.success": "초기화 완료!",
|
|
12689
12914
|
"install.failed": "설치 실패: {{error}}",
|
|
12690
|
-
"install.exists": "기존
|
|
12915
|
+
"install.exists": "기존 {{rootDir}} 디렉토리 발견",
|
|
12691
12916
|
"install.backup": "기존 파일 백업 완료: {{path}}",
|
|
12692
12917
|
"install.directories_created": "디렉토리 구조 생성 완료",
|
|
12693
12918
|
"install.component_skipped": "{{component}} 건너뜀 (이미 존재)",
|
|
@@ -12695,6 +12920,9 @@ var MESSAGES = {
|
|
|
12695
12920
|
"install.template_not_found": "{{component}} 템플릿 없음: {{path}}",
|
|
12696
12921
|
"install.claude_md_installed": "CLAUDE.md 설치 완료 ({{language}})",
|
|
12697
12922
|
"install.claude_md_not_found": "{{language}}용 CLAUDE.md 템플릿 없음",
|
|
12923
|
+
"install.entry_md_installed": "{{entry}} 설치 완료 ({{language}})",
|
|
12924
|
+
"install.entry_md_not_found": "{{language}}용 {{entry}} 템플릿 없음",
|
|
12925
|
+
"install.entry_md_skipped": "{{entry}} 건너뜀 ({{reason}})",
|
|
12698
12926
|
"update.start": "업데이트 확인 중...",
|
|
12699
12927
|
"update.success": "{{from}}에서 {{to}}로 업데이트 완료",
|
|
12700
12928
|
"update.failed": "업데이트 실패: {{error}}",
|
|
@@ -12794,7 +13022,7 @@ function success(messageKey, params) {
|
|
|
12794
13022
|
}
|
|
12795
13023
|
|
|
12796
13024
|
// src/core/config.ts
|
|
12797
|
-
import { join as
|
|
13025
|
+
import { join as join3 } from "node:path";
|
|
12798
13026
|
var CONFIG_FILE = ".omcustomrc.json";
|
|
12799
13027
|
var CURRENT_CONFIG_VERSION = 1;
|
|
12800
13028
|
function getDefaultConfig() {
|
|
@@ -12827,7 +13055,7 @@ function getDefaultPreferences() {
|
|
|
12827
13055
|
};
|
|
12828
13056
|
}
|
|
12829
13057
|
function getConfigPath(targetDir) {
|
|
12830
|
-
return
|
|
13058
|
+
return join3(targetDir, CONFIG_FILE);
|
|
12831
13059
|
}
|
|
12832
13060
|
async function loadConfig(targetDir) {
|
|
12833
13061
|
const configPath = getConfigPath(targetDir);
|
|
@@ -12888,18 +13116,10 @@ function migrateConfig(config) {
|
|
|
12888
13116
|
}
|
|
12889
13117
|
|
|
12890
13118
|
// src/core/installer.ts
|
|
12891
|
-
var
|
|
12892
|
-
"claude-md": "",
|
|
12893
|
-
rules: ".claude/rules",
|
|
12894
|
-
agents: ".claude/agents",
|
|
12895
|
-
skills: ".claude/skills",
|
|
12896
|
-
guides: "guides",
|
|
12897
|
-
hooks: ".claude/hooks",
|
|
12898
|
-
contexts: ".claude/contexts"
|
|
12899
|
-
};
|
|
13119
|
+
var DEFAULT_LANGUAGE2 = "en";
|
|
12900
13120
|
function getTemplateDir() {
|
|
12901
13121
|
const packageRoot = getPackageRoot();
|
|
12902
|
-
return
|
|
13122
|
+
return join4(packageRoot, "templates");
|
|
12903
13123
|
}
|
|
12904
13124
|
function createInstallResult(targetDir) {
|
|
12905
13125
|
return {
|
|
@@ -12917,21 +13137,22 @@ async function ensureTargetDirectory(targetDir) {
|
|
|
12917
13137
|
await ensureDirectory(targetDir);
|
|
12918
13138
|
}
|
|
12919
13139
|
}
|
|
12920
|
-
async function handleBackup(targetDir, shouldBackup, result) {
|
|
13140
|
+
async function handleBackup(targetDir, provider, shouldBackup, result) {
|
|
12921
13141
|
if (!shouldBackup)
|
|
12922
13142
|
return;
|
|
12923
|
-
const backupPaths = await backupExistingInstallation(targetDir);
|
|
13143
|
+
const backupPaths = await backupExistingInstallation(targetDir, provider);
|
|
12924
13144
|
result.backedUpPaths.push(...backupPaths);
|
|
12925
13145
|
if (backupPaths.length > 0) {
|
|
12926
13146
|
info("install.backup", { path: backupPaths[0] });
|
|
12927
13147
|
}
|
|
12928
13148
|
}
|
|
12929
|
-
async function checkAndWarnExisting(targetDir, force, backup, result) {
|
|
13149
|
+
async function checkAndWarnExisting(targetDir, provider, force, backup, result) {
|
|
12930
13150
|
if (force || backup)
|
|
12931
13151
|
return;
|
|
12932
|
-
const existingPaths = await checkExistingPaths(targetDir);
|
|
13152
|
+
const existingPaths = await checkExistingPaths(targetDir, provider);
|
|
12933
13153
|
if (existingPaths.length > 0) {
|
|
12934
|
-
|
|
13154
|
+
const layout = getProviderLayout(provider);
|
|
13155
|
+
warn("install.exists", { rootDir: layout.rootDir });
|
|
12935
13156
|
result.warnings.push(`Existing files found: ${existingPaths.join(", ")}. Use --force to overwrite or --backup to backup first.`);
|
|
12936
13157
|
}
|
|
12937
13158
|
}
|
|
@@ -12941,15 +13162,15 @@ async function verifyTemplateDirectory() {
|
|
|
12941
13162
|
throw new Error(`Template directory not found: ${templateDir}`);
|
|
12942
13163
|
}
|
|
12943
13164
|
}
|
|
12944
|
-
async function installAllComponents(targetDir, options, result) {
|
|
13165
|
+
async function installAllComponents(targetDir, provider, options, result) {
|
|
12945
13166
|
const components = options.components || getAllComponents();
|
|
12946
13167
|
for (const component of components) {
|
|
12947
|
-
await installSingleComponent(targetDir, component, options, result);
|
|
13168
|
+
await installSingleComponent(targetDir, provider, component, options, result);
|
|
12948
13169
|
}
|
|
12949
13170
|
}
|
|
12950
|
-
async function installSingleComponent(targetDir, component, options, result) {
|
|
13171
|
+
async function installSingleComponent(targetDir, provider, component, options, result) {
|
|
12951
13172
|
try {
|
|
12952
|
-
const installed = await installComponent(targetDir, component, options);
|
|
13173
|
+
const installed = await installComponent(targetDir, provider, component, options);
|
|
12953
13174
|
if (installed) {
|
|
12954
13175
|
result.installedComponents.push(component);
|
|
12955
13176
|
} else {
|
|
@@ -12960,34 +13181,36 @@ async function installSingleComponent(targetDir, component, options, result) {
|
|
|
12960
13181
|
result.warnings.push(`Failed to install ${component}: ${message}`);
|
|
12961
13182
|
}
|
|
12962
13183
|
}
|
|
12963
|
-
async function
|
|
12964
|
-
const language = options.language
|
|
13184
|
+
async function installEntryDocWithTracking(targetDir, provider, options, result) {
|
|
13185
|
+
const language = options.language ?? DEFAULT_LANGUAGE2;
|
|
12965
13186
|
const overwrite = !!(options.force || options.backup);
|
|
12966
|
-
const installed = await
|
|
13187
|
+
const installed = await installEntryDoc(targetDir, provider, language, overwrite);
|
|
12967
13188
|
if (installed) {
|
|
12968
|
-
result.installedComponents.push("
|
|
13189
|
+
result.installedComponents.push("entry-md");
|
|
12969
13190
|
} else {
|
|
12970
|
-
result.skippedComponents.push("
|
|
13191
|
+
result.skippedComponents.push("entry-md");
|
|
12971
13192
|
}
|
|
12972
13193
|
}
|
|
12973
|
-
async function updateInstallConfig(targetDir, options, installedComponents) {
|
|
13194
|
+
async function updateInstallConfig(targetDir, provider, options, installedComponents) {
|
|
12974
13195
|
const config = await loadConfig(targetDir);
|
|
12975
|
-
config.language = options.language
|
|
13196
|
+
config.language = options.language ?? DEFAULT_LANGUAGE2;
|
|
13197
|
+
config.provider = provider;
|
|
12976
13198
|
config.installedAt = new Date().toISOString();
|
|
12977
13199
|
config.installedComponents = installedComponents;
|
|
12978
13200
|
await saveConfig(targetDir, config);
|
|
12979
13201
|
}
|
|
12980
13202
|
async function install(options) {
|
|
12981
13203
|
const result = createInstallResult(options.targetDir);
|
|
13204
|
+
const provider = options.provider ?? "claude";
|
|
12982
13205
|
try {
|
|
12983
13206
|
info("install.start", { targetDir: options.targetDir });
|
|
12984
13207
|
await ensureTargetDirectory(options.targetDir);
|
|
12985
|
-
await handleBackup(options.targetDir, !!options.backup, result);
|
|
12986
|
-
await checkAndWarnExisting(options.targetDir, !!options.force, !!options.backup, result);
|
|
13208
|
+
await handleBackup(options.targetDir, provider, !!options.backup, result);
|
|
13209
|
+
await checkAndWarnExisting(options.targetDir, provider, !!options.force, !!options.backup, result);
|
|
12987
13210
|
await verifyTemplateDirectory();
|
|
12988
|
-
await installAllComponents(options.targetDir, options, result);
|
|
12989
|
-
await
|
|
12990
|
-
await updateInstallConfig(options.targetDir, options, result.installedComponents);
|
|
13211
|
+
await installAllComponents(options.targetDir, provider, options, result);
|
|
13212
|
+
await installEntryDocWithTracking(options.targetDir, provider, options, result);
|
|
13213
|
+
await updateInstallConfig(options.targetDir, provider, options, result.installedComponents);
|
|
12991
13214
|
result.success = true;
|
|
12992
13215
|
success("install.success");
|
|
12993
13216
|
} catch (err) {
|
|
@@ -13000,12 +13223,15 @@ async function install(options) {
|
|
|
13000
13223
|
function getAllComponents() {
|
|
13001
13224
|
return ["rules", "agents", "skills", "guides", "hooks", "contexts"];
|
|
13002
13225
|
}
|
|
13003
|
-
async function installComponent(targetDir, component, options) {
|
|
13004
|
-
|
|
13226
|
+
async function installComponent(targetDir, provider, component, options) {
|
|
13227
|
+
if (component === "entry-md") {
|
|
13228
|
+
return false;
|
|
13229
|
+
}
|
|
13230
|
+
const templatePath = getComponentPath(provider, component);
|
|
13005
13231
|
if (!templatePath) {
|
|
13006
13232
|
return false;
|
|
13007
13233
|
}
|
|
13008
|
-
const destPath =
|
|
13234
|
+
const destPath = join4(targetDir, templatePath);
|
|
13009
13235
|
const destExists = await fileExists(destPath);
|
|
13010
13236
|
if (destExists && !options.force && !options.backup) {
|
|
13011
13237
|
debug("install.component_skipped", { component });
|
|
@@ -13024,51 +13250,54 @@ async function installComponent(targetDir, component, options) {
|
|
|
13024
13250
|
debug("install.component_installed", { component });
|
|
13025
13251
|
return true;
|
|
13026
13252
|
}
|
|
13027
|
-
async function
|
|
13028
|
-
const
|
|
13253
|
+
async function installEntryDoc(targetDir, provider, language, overwrite = false) {
|
|
13254
|
+
const layout = getProviderLayout(provider);
|
|
13255
|
+
const templateFile = getEntryTemplateName(provider, language);
|
|
13029
13256
|
const srcPath = resolveTemplatePath(templateFile);
|
|
13030
|
-
const destPath =
|
|
13257
|
+
const destPath = join4(targetDir, layout.entryFile);
|
|
13031
13258
|
if (!await fileExists(srcPath)) {
|
|
13032
|
-
warn("install.
|
|
13259
|
+
warn("install.entry_md_not_found", { language, path: srcPath, entry: layout.entryFile });
|
|
13033
13260
|
return false;
|
|
13034
13261
|
}
|
|
13035
13262
|
const destExists = await fileExists(destPath);
|
|
13036
13263
|
if (destExists && !overwrite) {
|
|
13037
|
-
debug("install.
|
|
13264
|
+
debug("install.entry_md_skipped", { reason: "exists", language, entry: layout.entryFile });
|
|
13038
13265
|
return false;
|
|
13039
13266
|
}
|
|
13040
13267
|
await fsCopyFile(srcPath, destPath);
|
|
13041
|
-
debug("install.
|
|
13268
|
+
debug("install.entry_md_installed", { language, entry: layout.entryFile });
|
|
13042
13269
|
return true;
|
|
13043
13270
|
}
|
|
13044
13271
|
async function backupExisting(sourcePath, backupDir) {
|
|
13045
13272
|
const name = basename(sourcePath);
|
|
13046
|
-
const backupPath =
|
|
13273
|
+
const backupPath = join4(backupDir, name);
|
|
13047
13274
|
await rename(sourcePath, backupPath);
|
|
13048
13275
|
return backupPath;
|
|
13049
13276
|
}
|
|
13050
|
-
async function checkExistingPaths(targetDir) {
|
|
13051
|
-
const
|
|
13277
|
+
async function checkExistingPaths(targetDir, provider) {
|
|
13278
|
+
const layout = getProviderLayout(provider);
|
|
13279
|
+
const pathsToCheck = [layout.entryFile, layout.rootDir, "guides"];
|
|
13052
13280
|
const existingPaths = [];
|
|
13053
13281
|
for (const relativePath of pathsToCheck) {
|
|
13054
|
-
const fullPath =
|
|
13282
|
+
const fullPath = join4(targetDir, relativePath);
|
|
13055
13283
|
if (await fileExists(fullPath)) {
|
|
13056
13284
|
existingPaths.push(relativePath);
|
|
13057
13285
|
}
|
|
13058
13286
|
}
|
|
13059
13287
|
return existingPaths;
|
|
13060
13288
|
}
|
|
13061
|
-
async function backupExistingInstallation(targetDir) {
|
|
13062
|
-
const
|
|
13289
|
+
async function backupExistingInstallation(targetDir, provider) {
|
|
13290
|
+
const layout = getProviderLayout(provider);
|
|
13291
|
+
const existingPaths = await checkExistingPaths(targetDir, provider);
|
|
13063
13292
|
if (existingPaths.length === 0) {
|
|
13064
13293
|
return [];
|
|
13065
13294
|
}
|
|
13066
13295
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
13067
|
-
const backupDir =
|
|
13296
|
+
const backupDir = join4(targetDir, `${layout.backupDirPrefix}${timestamp}`);
|
|
13068
13297
|
await ensureDirectory(backupDir);
|
|
13069
13298
|
const backedUpPaths = [];
|
|
13070
13299
|
for (const relativePath of existingPaths) {
|
|
13071
|
-
const fullPath =
|
|
13300
|
+
const fullPath = join4(targetDir, relativePath);
|
|
13072
13301
|
try {
|
|
13073
13302
|
const backupPath = await backupExisting(fullPath, backupDir);
|
|
13074
13303
|
backedUpPaths.push(backupPath);
|
|
@@ -13082,22 +13311,25 @@ async function backupExistingInstallation(targetDir) {
|
|
|
13082
13311
|
}
|
|
13083
13312
|
|
|
13084
13313
|
// src/cli/init.ts
|
|
13085
|
-
async function checkExistingInstallation(targetDir) {
|
|
13086
|
-
const
|
|
13087
|
-
|
|
13314
|
+
async function checkExistingInstallation(targetDir, provider) {
|
|
13315
|
+
const layout = getProviderLayout(provider);
|
|
13316
|
+
const rootDir = join5(targetDir, layout.rootDir);
|
|
13317
|
+
return fileExists(rootDir);
|
|
13088
13318
|
}
|
|
13089
|
-
var
|
|
13090
|
-
function componentToPath(targetDir, component) {
|
|
13091
|
-
if (component === "
|
|
13092
|
-
|
|
13319
|
+
var PROVIDER_SUBDIR_COMPONENTS = new Set(["rules", "hooks", "contexts", "agents", "skills"]);
|
|
13320
|
+
function componentToPath(targetDir, provider, component) {
|
|
13321
|
+
if (component === "entry-md") {
|
|
13322
|
+
const layout = getProviderLayout(provider);
|
|
13323
|
+
return join5(targetDir, layout.entryFile);
|
|
13093
13324
|
}
|
|
13094
|
-
if (
|
|
13095
|
-
|
|
13325
|
+
if (PROVIDER_SUBDIR_COMPONENTS.has(component)) {
|
|
13326
|
+
const layout = getProviderLayout(provider);
|
|
13327
|
+
return join5(targetDir, layout.rootDir, component);
|
|
13096
13328
|
}
|
|
13097
|
-
return
|
|
13329
|
+
return join5(targetDir, component);
|
|
13098
13330
|
}
|
|
13099
|
-
function buildInstalledPaths(targetDir, components) {
|
|
13100
|
-
return components.map((component) => componentToPath(targetDir, component));
|
|
13331
|
+
function buildInstalledPaths(targetDir, provider, components) {
|
|
13332
|
+
return components.map((component) => componentToPath(targetDir, provider, component));
|
|
13101
13333
|
}
|
|
13102
13334
|
function logItems(items, formatter) {
|
|
13103
13335
|
for (const item of items) {
|
|
@@ -13122,10 +13354,6 @@ function createFailureResult(errorMessage) {
|
|
|
13122
13354
|
errors: [errorMessage]
|
|
13123
13355
|
};
|
|
13124
13356
|
}
|
|
13125
|
-
function notifyExistingInstallation() {
|
|
13126
|
-
console.log(i18n.t("cli.init.exists"));
|
|
13127
|
-
console.log(i18n.t("cli.init.backing_up"));
|
|
13128
|
-
}
|
|
13129
13357
|
function logInstallResultInfo(result) {
|
|
13130
13358
|
logItems(result.backedUpPaths, (path2) => console.log(i18n.t("cli.init.backedUp", { path: path2 })));
|
|
13131
13359
|
logItems(result.warnings, (warning) => console.warn(`Warning: ${warning}`));
|
|
@@ -13134,21 +13362,26 @@ async function initCommand(options) {
|
|
|
13134
13362
|
const targetDir = process.cwd();
|
|
13135
13363
|
console.log(i18n.t("cli.init.start"));
|
|
13136
13364
|
try {
|
|
13137
|
-
const
|
|
13365
|
+
const detection = await detectProvider({ targetDir, override: options.provider });
|
|
13366
|
+
const provider = detection.provider;
|
|
13367
|
+
const layout = getProviderLayout(provider);
|
|
13368
|
+
const exists2 = await checkExistingInstallation(targetDir, provider);
|
|
13138
13369
|
if (exists2) {
|
|
13139
|
-
|
|
13370
|
+
console.log(i18n.t("cli.init.exists", { rootDir: layout.rootDir }));
|
|
13371
|
+
console.log(i18n.t("cli.init.backing_up"));
|
|
13140
13372
|
}
|
|
13141
13373
|
console.log(i18n.t("cli.init.copying"));
|
|
13142
13374
|
const installResult = await install({
|
|
13143
13375
|
targetDir,
|
|
13144
13376
|
language: options.lang,
|
|
13377
|
+
provider,
|
|
13145
13378
|
force: options.force ?? false,
|
|
13146
13379
|
backup: exists2
|
|
13147
13380
|
});
|
|
13148
13381
|
if (!installResult.success) {
|
|
13149
13382
|
return createFailureResult(installResult.error || "Unknown error");
|
|
13150
13383
|
}
|
|
13151
|
-
const installedPaths = buildInstalledPaths(targetDir, installResult.installedComponents);
|
|
13384
|
+
const installedPaths = buildInstalledPaths(targetDir, provider, installResult.installedComponents);
|
|
13152
13385
|
logInstallResultInfo(installResult);
|
|
13153
13386
|
logSuccessDetails(installedPaths, installResult.skippedComponents);
|
|
13154
13387
|
return {
|
|
@@ -13164,7 +13397,7 @@ async function initCommand(options) {
|
|
|
13164
13397
|
}
|
|
13165
13398
|
|
|
13166
13399
|
// src/cli/list.ts
|
|
13167
|
-
import { basename as basename2, dirname as dirname2, join as
|
|
13400
|
+
import { basename as basename2, dirname as dirname2, join as join6, relative } from "node:path";
|
|
13168
13401
|
var ALLOWED_TOP_LEVEL_KEYS = new Set(["name", "type", "description", "version", "category"]);
|
|
13169
13402
|
function parseKeyValue(line) {
|
|
13170
13403
|
const colonIndex = line.indexOf(":");
|
|
@@ -13227,13 +13460,13 @@ function extractAgentTypeFromFilename(filename) {
|
|
|
13227
13460
|
const prefix = name.split("-")[0];
|
|
13228
13461
|
return prefixMap[prefix] || "unknown";
|
|
13229
13462
|
}
|
|
13230
|
-
function extractSkillCategoryFromPath(skillPath, baseDir) {
|
|
13231
|
-
const relativePath = relative(
|
|
13463
|
+
function extractSkillCategoryFromPath(skillPath, baseDir, rootDir) {
|
|
13464
|
+
const relativePath = relative(join6(baseDir, rootDir, "skills"), skillPath);
|
|
13232
13465
|
const parts = relativePath.split("/").filter(Boolean);
|
|
13233
13466
|
return parts[0] || "unknown";
|
|
13234
13467
|
}
|
|
13235
13468
|
function extractGuideCategoryFromPath(guidePath, baseDir) {
|
|
13236
|
-
const relativePath = relative(
|
|
13469
|
+
const relativePath = relative(join6(baseDir, "guides"), guidePath);
|
|
13237
13470
|
const parts = relativePath.split("/").filter(Boolean);
|
|
13238
13471
|
return parts[0] || "unknown";
|
|
13239
13472
|
}
|
|
@@ -13326,8 +13559,8 @@ async function tryExtractMarkdownDescription(mdPath, options = {}) {
|
|
|
13326
13559
|
return;
|
|
13327
13560
|
}
|
|
13328
13561
|
}
|
|
13329
|
-
async function getAgents(targetDir) {
|
|
13330
|
-
const agentsDir =
|
|
13562
|
+
async function getAgents(targetDir, rootDir = ".claude") {
|
|
13563
|
+
const agentsDir = join6(targetDir, rootDir, "agents");
|
|
13331
13564
|
if (!await fileExists(agentsDir))
|
|
13332
13565
|
return [];
|
|
13333
13566
|
try {
|
|
@@ -13349,20 +13582,20 @@ async function getAgents(targetDir) {
|
|
|
13349
13582
|
return [];
|
|
13350
13583
|
}
|
|
13351
13584
|
}
|
|
13352
|
-
async function getSkills(targetDir) {
|
|
13353
|
-
const skillsDir =
|
|
13585
|
+
async function getSkills(targetDir, rootDir = ".claude") {
|
|
13586
|
+
const skillsDir = join6(targetDir, rootDir, "skills");
|
|
13354
13587
|
if (!await fileExists(skillsDir))
|
|
13355
13588
|
return [];
|
|
13356
13589
|
try {
|
|
13357
13590
|
const skillMdFiles = await listFiles(skillsDir, { recursive: true, pattern: "SKILL.md" });
|
|
13358
13591
|
const skills = await Promise.all(skillMdFiles.map(async (skillMdPath) => {
|
|
13359
13592
|
const skillDir = dirname2(skillMdPath);
|
|
13360
|
-
const indexYamlPath =
|
|
13593
|
+
const indexYamlPath = join6(skillDir, "index.yaml");
|
|
13361
13594
|
const { description, version } = await tryReadIndexYamlMetadata(indexYamlPath);
|
|
13362
13595
|
return {
|
|
13363
13596
|
name: basename2(skillDir),
|
|
13364
13597
|
type: "skill",
|
|
13365
|
-
category: extractSkillCategoryFromPath(skillDir, targetDir),
|
|
13598
|
+
category: extractSkillCategoryFromPath(skillDir, targetDir, rootDir),
|
|
13366
13599
|
path: relative(targetDir, skillDir),
|
|
13367
13600
|
description,
|
|
13368
13601
|
version
|
|
@@ -13374,7 +13607,7 @@ async function getSkills(targetDir) {
|
|
|
13374
13607
|
}
|
|
13375
13608
|
}
|
|
13376
13609
|
async function getGuides(targetDir) {
|
|
13377
|
-
const guidesDir =
|
|
13610
|
+
const guidesDir = join6(targetDir, "guides");
|
|
13378
13611
|
if (!await fileExists(guidesDir))
|
|
13379
13612
|
return [];
|
|
13380
13613
|
try {
|
|
@@ -13395,8 +13628,8 @@ async function getGuides(targetDir) {
|
|
|
13395
13628
|
}
|
|
13396
13629
|
}
|
|
13397
13630
|
var RULE_PRIORITY_ORDER = { MUST: 0, SHOULD: 1, MAY: 2 };
|
|
13398
|
-
async function getRules(targetDir) {
|
|
13399
|
-
const rulesDir =
|
|
13631
|
+
async function getRules(targetDir, rootDir = ".claude") {
|
|
13632
|
+
const rulesDir = join6(targetDir, rootDir, "rules");
|
|
13400
13633
|
if (!await fileExists(rulesDir))
|
|
13401
13634
|
return [];
|
|
13402
13635
|
try {
|
|
@@ -13460,8 +13693,8 @@ ${type} (${components.length}):`);
|
|
|
13460
13693
|
function formatAsJson(components) {
|
|
13461
13694
|
console.log(JSON.stringify(components, null, 2));
|
|
13462
13695
|
}
|
|
13463
|
-
async function getHooks(targetDir) {
|
|
13464
|
-
const hooksDir =
|
|
13696
|
+
async function getHooks(targetDir, rootDir = ".claude") {
|
|
13697
|
+
const hooksDir = join6(targetDir, rootDir, "hooks");
|
|
13465
13698
|
if (!await fileExists(hooksDir))
|
|
13466
13699
|
return [];
|
|
13467
13700
|
try {
|
|
@@ -13478,8 +13711,8 @@ async function getHooks(targetDir) {
|
|
|
13478
13711
|
return [];
|
|
13479
13712
|
}
|
|
13480
13713
|
}
|
|
13481
|
-
async function getContexts(targetDir) {
|
|
13482
|
-
const contextsDir =
|
|
13714
|
+
async function getContexts(targetDir, rootDir = ".claude") {
|
|
13715
|
+
const contextsDir = join6(targetDir, rootDir, "contexts");
|
|
13483
13716
|
if (!await fileExists(contextsDir))
|
|
13484
13717
|
return [];
|
|
13485
13718
|
try {
|
|
@@ -13504,7 +13737,7 @@ async function getContexts(targetDir) {
|
|
|
13504
13737
|
var COMPONENT_GETTERS = {
|
|
13505
13738
|
agents: getAgents,
|
|
13506
13739
|
skills: getSkills,
|
|
13507
|
-
guides: getGuides,
|
|
13740
|
+
guides: async (dir2) => getGuides(dir2),
|
|
13508
13741
|
rules: getRules,
|
|
13509
13742
|
hooks: getHooks,
|
|
13510
13743
|
contexts: getContexts
|
|
@@ -13518,14 +13751,14 @@ function displayComponents(components, type, format) {
|
|
|
13518
13751
|
formatAsTable(components, type);
|
|
13519
13752
|
}
|
|
13520
13753
|
}
|
|
13521
|
-
async function handleListAll(targetDir, format) {
|
|
13754
|
+
async function handleListAll(targetDir, rootDir, format) {
|
|
13522
13755
|
const [agents, skills, guides, rules, hooks, contexts] = await Promise.all([
|
|
13523
|
-
getAgents(targetDir),
|
|
13524
|
-
getSkills(targetDir),
|
|
13756
|
+
getAgents(targetDir, rootDir),
|
|
13757
|
+
getSkills(targetDir, rootDir),
|
|
13525
13758
|
getGuides(targetDir),
|
|
13526
|
-
getRules(targetDir),
|
|
13527
|
-
getHooks(targetDir),
|
|
13528
|
-
getContexts(targetDir)
|
|
13759
|
+
getRules(targetDir, rootDir),
|
|
13760
|
+
getHooks(targetDir, rootDir),
|
|
13761
|
+
getContexts(targetDir, rootDir)
|
|
13529
13762
|
]);
|
|
13530
13763
|
if (format !== "json") {
|
|
13531
13764
|
displayComponents(agents, "agents", format);
|
|
@@ -13542,7 +13775,13 @@ async function listCommand(type = "all", options = {}) {
|
|
|
13542
13775
|
const format = options.format || "table";
|
|
13543
13776
|
console.log(i18n.t("cli.list.scanning"));
|
|
13544
13777
|
try {
|
|
13545
|
-
const
|
|
13778
|
+
const detection = await detectProvider({
|
|
13779
|
+
targetDir,
|
|
13780
|
+
override: options.provider,
|
|
13781
|
+
preferProject: true
|
|
13782
|
+
});
|
|
13783
|
+
const layout = getProviderLayout(detection.provider);
|
|
13784
|
+
const components = type === "all" ? await handleListAll(targetDir, layout.rootDir, format) : await COMPONENT_GETTERS[type](targetDir, layout.rootDir);
|
|
13546
13785
|
if (type === "all" && format === "json") {
|
|
13547
13786
|
formatAsJson(components);
|
|
13548
13787
|
} else if (type !== "all") {
|
|
@@ -13632,16 +13871,20 @@ var packageJson = require2("../../package.json");
|
|
|
13632
13871
|
function createProgram() {
|
|
13633
13872
|
const program2 = new Command;
|
|
13634
13873
|
program2.name("omcustom").description(i18n.t("cli.description")).version(packageJson.version, "-v, --version", i18n.t("cli.versionOption"));
|
|
13635
|
-
program2.command("init").description(i18n.t("cli.init.description")).option("-l, --lang <language>", i18n.t("cli.init.langOption"), "en").action(async (options) => {
|
|
13874
|
+
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) => {
|
|
13636
13875
|
await initCommand(options);
|
|
13637
13876
|
});
|
|
13638
13877
|
program2.command("update").description(i18n.t("cli.update.description")).action(async () => {
|
|
13639
13878
|
await updateCommand();
|
|
13640
13879
|
});
|
|
13641
|
-
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) => {
|
|
13642
|
-
await listCommand(type, {
|
|
13880
|
+
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) => {
|
|
13881
|
+
await listCommand(type, {
|
|
13882
|
+
format: options.format,
|
|
13883
|
+
verbose: options.verbose,
|
|
13884
|
+
provider: options.provider
|
|
13885
|
+
});
|
|
13643
13886
|
});
|
|
13644
|
-
program2.command("doctor").description(i18n.t("cli.doctor.description")).option("--fix", i18n.t("cli.doctor.fixOption")).action(async (options) => {
|
|
13887
|
+
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) => {
|
|
13645
13888
|
await doctorCommand(options);
|
|
13646
13889
|
});
|
|
13647
13890
|
return program2;
|