oh-my-customcode 0.12.1 → 0.12.3
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 +8 -11
- package/dist/cli/index.js +137 -336
- package/dist/index.js +99 -260
- package/package.json +2 -4
- package/templates/.claude/skills/codex-exec/SKILL.md +123 -0
- package/templates/.claude/skills/codex-exec/scripts/codex-wrapper.cjs +413 -0
- package/templates/CLAUDE.md.en +1 -0
- package/templates/CLAUDE.md.ko +1 -0
- package/templates/.codex/agents/arch-documenter.md +0 -33
- package/templates/.codex/agents/arch-speckit-agent.md +0 -47
- package/templates/.codex/agents/be-express-expert.md +0 -30
- package/templates/.codex/agents/be-fastapi-expert.md +0 -43
- package/templates/.codex/agents/be-go-backend-expert.md +0 -43
- package/templates/.codex/agents/be-nestjs-expert.md +0 -28
- package/templates/.codex/agents/be-springboot-expert.md +0 -40
- package/templates/.codex/agents/db-postgres-expert.md +0 -36
- package/templates/.codex/agents/db-redis-expert.md +0 -36
- package/templates/.codex/agents/db-supabase-expert.md +0 -35
- package/templates/.codex/agents/de-airflow-expert.md +0 -34
- package/templates/.codex/agents/de-dbt-expert.md +0 -34
- package/templates/.codex/agents/de-kafka-expert.md +0 -81
- package/templates/.codex/agents/de-pipeline-expert.md +0 -32
- package/templates/.codex/agents/de-snowflake-expert.md +0 -36
- package/templates/.codex/agents/de-spark-expert.md +0 -36
- package/templates/.codex/agents/fe-svelte-agent.md +0 -29
- package/templates/.codex/agents/fe-vercel-agent.md +0 -37
- package/templates/.codex/agents/fe-vuejs-agent.md +0 -30
- package/templates/.codex/agents/infra-aws-expert.md +0 -47
- package/templates/.codex/agents/infra-docker-expert.md +0 -47
- package/templates/.codex/agents/lang-golang-expert.md +0 -43
- package/templates/.codex/agents/lang-java21-expert.md +0 -39
- package/templates/.codex/agents/lang-kotlin-expert.md +0 -43
- package/templates/.codex/agents/lang-python-expert.md +0 -43
- package/templates/.codex/agents/lang-rust-expert.md +0 -43
- package/templates/.codex/agents/lang-typescript-expert.md +0 -43
- package/templates/.codex/agents/mgr-claude-code-bible.md +0 -58
- package/templates/.codex/agents/mgr-creator.md +0 -39
- package/templates/.codex/agents/mgr-gitnerd.md +0 -45
- package/templates/.codex/agents/mgr-sauron.md +0 -161
- package/templates/.codex/agents/mgr-supplier.md +0 -35
- package/templates/.codex/agents/mgr-sync-checker.md +0 -38
- package/templates/.codex/agents/mgr-updater.md +0 -33
- package/templates/.codex/agents/qa-engineer.md +0 -32
- package/templates/.codex/agents/qa-planner.md +0 -73
- package/templates/.codex/agents/qa-writer.md +0 -27
- package/templates/.codex/agents/sys-memory-keeper.md +0 -43
- package/templates/.codex/agents/sys-naggy.md +0 -37
- package/templates/.codex/agents/tool-bun-expert.md +0 -26
- package/templates/.codex/agents/tool-npm-expert.md +0 -30
- package/templates/.codex/agents/tool-optimizer.md +0 -34
- package/templates/.codex/codex-native-hash.txt +0 -1
- package/templates/.codex/contexts/dev.md +0 -20
- package/templates/.codex/contexts/ecomode.md +0 -63
- package/templates/.codex/contexts/index.yaml +0 -41
- package/templates/.codex/contexts/research.md +0 -28
- package/templates/.codex/contexts/review.md +0 -23
- package/templates/.codex/hooks/hooks.json +0 -150
- package/templates/.codex/install-hooks.sh +0 -100
- package/templates/.codex/rules/MAY-optimization.md +0 -29
- package/templates/.codex/rules/MUST-agent-design.md +0 -57
- package/templates/.codex/rules/MUST-agent-identification.md +0 -29
- package/templates/.codex/rules/MUST-continuous-improvement.md +0 -25
- package/templates/.codex/rules/MUST-intent-transparency.md +0 -42
- package/templates/.codex/rules/MUST-language-policy.md +0 -27
- package/templates/.codex/rules/MUST-orchestrator-coordination.md +0 -128
- package/templates/.codex/rules/MUST-parallel-execution.md +0 -97
- package/templates/.codex/rules/MUST-permissions.md +0 -30
- package/templates/.codex/rules/MUST-safety.md +0 -23
- package/templates/.codex/rules/MUST-sync-verification.md +0 -125
- package/templates/.codex/rules/MUST-tool-identification.md +0 -82
- package/templates/.codex/rules/SHOULD-agent-teams.md +0 -39
- package/templates/.codex/rules/SHOULD-ecomode.md +0 -37
- package/templates/.codex/rules/SHOULD-error-handling.md +0 -33
- package/templates/.codex/rules/SHOULD-hud-statusline.md +0 -32
- package/templates/.codex/rules/SHOULD-interaction.md +0 -34
- package/templates/.codex/rules/SHOULD-memory-integration.md +0 -39
- package/templates/.codex/rules/index.yaml +0 -141
- package/templates/.codex/skills/airflow-best-practices/SKILL.md +0 -56
- package/templates/.codex/skills/audit-agents/SKILL.md +0 -116
- package/templates/.codex/skills/aws-best-practices/SKILL.md +0 -280
- package/templates/.codex/skills/claude-code-bible/SKILL.md +0 -100
- package/templates/.codex/skills/claude-code-bible/scripts/fetch-docs.js +0 -272
- package/templates/.codex/skills/create-agent/SKILL.md +0 -91
- package/templates/.codex/skills/dbt-best-practices/SKILL.md +0 -54
- package/templates/.codex/skills/de-lead-routing/SKILL.md +0 -243
- package/templates/.codex/skills/dev-lead-routing/SKILL.md +0 -94
- package/templates/.codex/skills/dev-refactor/SKILL.md +0 -123
- package/templates/.codex/skills/dev-review/SKILL.md +0 -81
- package/templates/.codex/skills/docker-best-practices/SKILL.md +0 -275
- package/templates/.codex/skills/fastapi-best-practices/SKILL.md +0 -270
- package/templates/.codex/skills/fix-refs/SKILL.md +0 -107
- package/templates/.codex/skills/go-backend-best-practices/SKILL.md +0 -338
- package/templates/.codex/skills/go-best-practices/SKILL.md +0 -203
- package/templates/.codex/skills/help/SKILL.md +0 -125
- package/templates/.codex/skills/intent-detection/SKILL.md +0 -215
- package/templates/.codex/skills/intent-detection/patterns/agent-triggers.yaml +0 -349
- package/templates/.codex/skills/kafka-best-practices/SKILL.md +0 -52
- package/templates/.codex/skills/kotlin-best-practices/SKILL.md +0 -256
- package/templates/.codex/skills/lists/SKILL.md +0 -78
- package/templates/.codex/skills/memory-management/SKILL.md +0 -195
- package/templates/.codex/skills/memory-recall/SKILL.md +0 -152
- package/templates/.codex/skills/memory-save/SKILL.md +0 -126
- package/templates/.codex/skills/monitoring-setup/SKILL.md +0 -115
- package/templates/.codex/skills/npm-audit/SKILL.md +0 -72
- package/templates/.codex/skills/npm-publish/SKILL.md +0 -63
- package/templates/.codex/skills/npm-version/SKILL.md +0 -75
- package/templates/.codex/skills/optimize-analyze/SKILL.md +0 -55
- package/templates/.codex/skills/optimize-bundle/SKILL.md +0 -67
- package/templates/.codex/skills/optimize-report/SKILL.md +0 -74
- package/templates/.codex/skills/pipeline-architecture-patterns/SKILL.md +0 -83
- package/templates/.codex/skills/postgres-best-practices/SKILL.md +0 -66
- package/templates/.codex/skills/python-best-practices/SKILL.md +0 -222
- package/templates/.codex/skills/qa-lead-routing/SKILL.md +0 -290
- package/templates/.codex/skills/react-best-practices/SKILL.md +0 -101
- package/templates/.codex/skills/redis-best-practices/SKILL.md +0 -83
- package/templates/.codex/skills/result-aggregation/SKILL.md +0 -164
- package/templates/.codex/skills/rust-best-practices/SKILL.md +0 -267
- package/templates/.codex/skills/sauron-watch/SKILL.md +0 -144
- package/templates/.codex/skills/secretary-routing/SKILL.md +0 -203
- package/templates/.codex/skills/snowflake-best-practices/SKILL.md +0 -65
- package/templates/.codex/skills/spark-best-practices/SKILL.md +0 -52
- package/templates/.codex/skills/springboot-best-practices/SKILL.md +0 -218
- package/templates/.codex/skills/status/SKILL.md +0 -153
- package/templates/.codex/skills/supabase-postgres-best-practices/SKILL.md +0 -99
- package/templates/.codex/skills/typescript-best-practices/SKILL.md +0 -321
- package/templates/.codex/skills/update-docs/SKILL.md +0 -140
- package/templates/.codex/skills/update-external/SKILL.md +0 -149
- package/templates/.codex/skills/vercel-deploy/SKILL.md +0 -73
- package/templates/.codex/skills/web-design-guidelines/SKILL.md +0 -118
- package/templates/.codex/skills/writing-clearly-and-concisely/SKILL.md +0 -64
- package/templates/.codex/uninstall-hooks.sh +0 -52
- package/templates/AGENTS.md.en +0 -39
- package/templates/AGENTS.md.ko +0 -39
- package/templates/manifest.codex.json +0 -43
package/dist/index.js
CHANGED
|
@@ -384,7 +384,6 @@ function getDefaultConfig() {
|
|
|
384
384
|
configVersion: CURRENT_CONFIG_VERSION,
|
|
385
385
|
version: "0.0.0",
|
|
386
386
|
language: "en",
|
|
387
|
-
provider: "auto",
|
|
388
387
|
installedAt: "",
|
|
389
388
|
lastUpdated: "",
|
|
390
389
|
installedComponents: [],
|
|
@@ -759,61 +758,36 @@ import { readFile as fsReadFile, writeFile as fsWriteFile, rename } from "node:f
|
|
|
759
758
|
import { basename, join as join3 } from "node:path";
|
|
760
759
|
|
|
761
760
|
// src/core/layout.ts
|
|
762
|
-
var
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
"guides"
|
|
778
|
-
]
|
|
779
|
-
},
|
|
780
|
-
codex: {
|
|
781
|
-
provider: "codex",
|
|
782
|
-
rootDir: ".codex",
|
|
783
|
-
entryFile: "AGENTS.md",
|
|
784
|
-
entryTemplatePrefix: "AGENTS.md",
|
|
785
|
-
manifestFile: "manifest.codex.json",
|
|
786
|
-
backupDirPrefix: ".codex-backup-",
|
|
787
|
-
directoryStructure: [
|
|
788
|
-
".codex",
|
|
789
|
-
".codex/rules",
|
|
790
|
-
".codex/hooks",
|
|
791
|
-
".codex/contexts",
|
|
792
|
-
".codex/agents",
|
|
793
|
-
".codex/skills",
|
|
794
|
-
"guides"
|
|
795
|
-
]
|
|
796
|
-
}
|
|
761
|
+
var CLAUDE_LAYOUT = {
|
|
762
|
+
rootDir: ".claude",
|
|
763
|
+
entryFile: "CLAUDE.md",
|
|
764
|
+
entryTemplatePrefix: "CLAUDE.md",
|
|
765
|
+
manifestFile: "manifest.json",
|
|
766
|
+
backupDirPrefix: ".claude-backup-",
|
|
767
|
+
directoryStructure: [
|
|
768
|
+
".claude",
|
|
769
|
+
".claude/rules",
|
|
770
|
+
".claude/hooks",
|
|
771
|
+
".claude/contexts",
|
|
772
|
+
".claude/agents",
|
|
773
|
+
".claude/skills",
|
|
774
|
+
"guides"
|
|
775
|
+
]
|
|
797
776
|
};
|
|
798
|
-
function getProviderLayout(
|
|
799
|
-
return
|
|
777
|
+
function getProviderLayout() {
|
|
778
|
+
return CLAUDE_LAYOUT;
|
|
800
779
|
}
|
|
801
|
-
function getEntryTemplateName(
|
|
802
|
-
|
|
803
|
-
return `${layout.entryTemplatePrefix}.${language}`;
|
|
780
|
+
function getEntryTemplateName(language) {
|
|
781
|
+
return `CLAUDE.md.${language}`;
|
|
804
782
|
}
|
|
805
|
-
function getComponentPath(
|
|
806
|
-
const layout = getProviderLayout(provider);
|
|
783
|
+
function getComponentPath(component) {
|
|
807
784
|
if (component === "entry-md") {
|
|
808
|
-
return
|
|
785
|
+
return "CLAUDE.md";
|
|
809
786
|
}
|
|
810
787
|
if (component === "guides") {
|
|
811
788
|
return "guides";
|
|
812
789
|
}
|
|
813
|
-
return
|
|
814
|
-
}
|
|
815
|
-
function getDefaultProvider() {
|
|
816
|
-
return "claude";
|
|
790
|
+
return `.claude/${component}`;
|
|
817
791
|
}
|
|
818
792
|
|
|
819
793
|
// src/core/installer.ts
|
|
@@ -838,21 +812,21 @@ async function ensureTargetDirectory(targetDir) {
|
|
|
838
812
|
await ensureDirectory(targetDir);
|
|
839
813
|
}
|
|
840
814
|
}
|
|
841
|
-
async function handleBackup(targetDir,
|
|
815
|
+
async function handleBackup(targetDir, shouldBackup, result) {
|
|
842
816
|
if (!shouldBackup)
|
|
843
817
|
return;
|
|
844
|
-
const backupPaths = await backupExistingInstallation(targetDir
|
|
818
|
+
const backupPaths = await backupExistingInstallation(targetDir);
|
|
845
819
|
result.backedUpPaths.push(...backupPaths);
|
|
846
820
|
if (backupPaths.length > 0) {
|
|
847
821
|
info("install.backup", { path: backupPaths[0] });
|
|
848
822
|
}
|
|
849
823
|
}
|
|
850
|
-
async function checkAndWarnExisting(targetDir,
|
|
824
|
+
async function checkAndWarnExisting(targetDir, force, backup, result) {
|
|
851
825
|
if (force || backup)
|
|
852
826
|
return;
|
|
853
|
-
const existingPaths = await checkExistingPaths(targetDir
|
|
827
|
+
const existingPaths = await checkExistingPaths(targetDir);
|
|
854
828
|
if (existingPaths.length > 0) {
|
|
855
|
-
const layout = getProviderLayout(
|
|
829
|
+
const layout = getProviderLayout();
|
|
856
830
|
warn("install.exists", { rootDir: layout.rootDir });
|
|
857
831
|
result.warnings.push(`Existing files found: ${existingPaths.join(", ")}. Use --force to overwrite or --backup to backup first.`);
|
|
858
832
|
}
|
|
@@ -863,15 +837,15 @@ async function verifyTemplateDirectory() {
|
|
|
863
837
|
throw new Error(`Template directory not found: ${templateDir}`);
|
|
864
838
|
}
|
|
865
839
|
}
|
|
866
|
-
async function installAllComponents(targetDir,
|
|
840
|
+
async function installAllComponents(targetDir, options, result) {
|
|
867
841
|
const components = options.components || getAllComponents();
|
|
868
842
|
for (const component of components) {
|
|
869
|
-
await installSingleComponent(targetDir,
|
|
843
|
+
await installSingleComponent(targetDir, component, options, result);
|
|
870
844
|
}
|
|
871
845
|
}
|
|
872
|
-
async function installSingleComponent(targetDir,
|
|
846
|
+
async function installSingleComponent(targetDir, component, options, result) {
|
|
873
847
|
try {
|
|
874
|
-
const installed = await installComponent(targetDir,
|
|
848
|
+
const installed = await installComponent(targetDir, component, options);
|
|
875
849
|
if (installed) {
|
|
876
850
|
result.installedComponents.push(component);
|
|
877
851
|
} else {
|
|
@@ -882,36 +856,34 @@ async function installSingleComponent(targetDir, provider, component, options, r
|
|
|
882
856
|
result.warnings.push(`Failed to install ${component}: ${message}`);
|
|
883
857
|
}
|
|
884
858
|
}
|
|
885
|
-
async function installEntryDocWithTracking(targetDir,
|
|
859
|
+
async function installEntryDocWithTracking(targetDir, options, result) {
|
|
886
860
|
const language = options.language ?? DEFAULT_LANGUAGE;
|
|
887
861
|
const overwrite = !!(options.force || options.backup);
|
|
888
|
-
const installed = await installEntryDoc(targetDir,
|
|
862
|
+
const installed = await installEntryDoc(targetDir, language, overwrite);
|
|
889
863
|
if (installed) {
|
|
890
864
|
result.installedComponents.push("entry-md");
|
|
891
865
|
} else {
|
|
892
866
|
result.skippedComponents.push("entry-md");
|
|
893
867
|
}
|
|
894
868
|
}
|
|
895
|
-
async function updateInstallConfig(targetDir,
|
|
869
|
+
async function updateInstallConfig(targetDir, options, installedComponents) {
|
|
896
870
|
const config = await loadConfig(targetDir);
|
|
897
871
|
config.language = options.language ?? DEFAULT_LANGUAGE;
|
|
898
|
-
config.provider = provider;
|
|
899
872
|
config.installedAt = new Date().toISOString();
|
|
900
873
|
config.installedComponents = installedComponents;
|
|
901
874
|
await saveConfig(targetDir, config);
|
|
902
875
|
}
|
|
903
876
|
async function install(options) {
|
|
904
877
|
const result = createInstallResult(options.targetDir);
|
|
905
|
-
const provider = options.provider ?? "claude";
|
|
906
878
|
try {
|
|
907
879
|
info("install.start", { targetDir: options.targetDir });
|
|
908
880
|
await ensureTargetDirectory(options.targetDir);
|
|
909
|
-
await handleBackup(options.targetDir,
|
|
910
|
-
await checkAndWarnExisting(options.targetDir,
|
|
881
|
+
await handleBackup(options.targetDir, !!options.backup, result);
|
|
882
|
+
await checkAndWarnExisting(options.targetDir, !!options.force, !!options.backup, result);
|
|
911
883
|
await verifyTemplateDirectory();
|
|
912
|
-
await installAllComponents(options.targetDir,
|
|
913
|
-
await installEntryDocWithTracking(options.targetDir,
|
|
914
|
-
await updateInstallConfig(options.targetDir,
|
|
884
|
+
await installAllComponents(options.targetDir, options, result);
|
|
885
|
+
await installEntryDocWithTracking(options.targetDir, options, result);
|
|
886
|
+
await updateInstallConfig(options.targetDir, options, result.installedComponents);
|
|
915
887
|
result.success = true;
|
|
916
888
|
success("install.success");
|
|
917
889
|
} catch (err) {
|
|
@@ -930,16 +902,16 @@ async function copyTemplates(targetDir, templatePath, options) {
|
|
|
930
902
|
preserveTimestamps: true
|
|
931
903
|
});
|
|
932
904
|
}
|
|
933
|
-
async function createDirectoryStructure(targetDir
|
|
934
|
-
const layout = getProviderLayout(
|
|
905
|
+
async function createDirectoryStructure(targetDir) {
|
|
906
|
+
const layout = getProviderLayout();
|
|
935
907
|
for (const dir of layout.directoryStructure) {
|
|
936
908
|
const fullPath = join3(targetDir, dir);
|
|
937
909
|
await ensureDirectory(fullPath);
|
|
938
910
|
}
|
|
939
911
|
}
|
|
940
|
-
async function getTemplateManifest(
|
|
912
|
+
async function getTemplateManifest() {
|
|
941
913
|
const packageRoot = getPackageRoot();
|
|
942
|
-
const layout = getProviderLayout(
|
|
914
|
+
const layout = getProviderLayout();
|
|
943
915
|
const manifestPath = join3(packageRoot, "templates", layout.manifestFile);
|
|
944
916
|
if (await fileExists(manifestPath)) {
|
|
945
917
|
return readJsonFile(manifestPath);
|
|
@@ -949,7 +921,7 @@ async function getTemplateManifest(provider = "claude") {
|
|
|
949
921
|
lastUpdated: new Date().toISOString(),
|
|
950
922
|
components: getAllComponents().map((name) => ({
|
|
951
923
|
name,
|
|
952
|
-
path: getComponentPath(
|
|
924
|
+
path: getComponentPath(name),
|
|
953
925
|
description: `${name} component`,
|
|
954
926
|
files: 0
|
|
955
927
|
})),
|
|
@@ -959,11 +931,11 @@ async function getTemplateManifest(provider = "claude") {
|
|
|
959
931
|
function getAllComponents() {
|
|
960
932
|
return ["rules", "agents", "skills", "guides", "hooks", "contexts"];
|
|
961
933
|
}
|
|
962
|
-
async function installComponent(targetDir,
|
|
934
|
+
async function installComponent(targetDir, component, options) {
|
|
963
935
|
if (component === "entry-md") {
|
|
964
936
|
return false;
|
|
965
937
|
}
|
|
966
|
-
const templatePath = getComponentPath(
|
|
938
|
+
const templatePath = getComponentPath(component);
|
|
967
939
|
if (!templatePath) {
|
|
968
940
|
return false;
|
|
969
941
|
}
|
|
@@ -991,9 +963,9 @@ function renderGitWorkflowSection(targetDir, language) {
|
|
|
991
963
|
const result = detectGitWorkflow(targetDir) ?? getDefaultWorkflow();
|
|
992
964
|
return language === "ko" ? renderGitWorkflowKO(result) : renderGitWorkflowEN(result);
|
|
993
965
|
}
|
|
994
|
-
async function installEntryDoc(targetDir,
|
|
995
|
-
const layout = getProviderLayout(
|
|
996
|
-
const templateFile = getEntryTemplateName(
|
|
966
|
+
async function installEntryDoc(targetDir, language, overwrite = false) {
|
|
967
|
+
const layout = getProviderLayout();
|
|
968
|
+
const templateFile = getEntryTemplateName(language);
|
|
997
969
|
const srcPath = resolveTemplatePath(templateFile);
|
|
998
970
|
const destPath = join3(targetDir, layout.entryFile);
|
|
999
971
|
if (!await fileExists(srcPath)) {
|
|
@@ -1020,8 +992,8 @@ async function backupExisting(sourcePath, backupDir) {
|
|
|
1020
992
|
await rename(sourcePath, backupPath);
|
|
1021
993
|
return backupPath;
|
|
1022
994
|
}
|
|
1023
|
-
async function checkExistingPaths(targetDir
|
|
1024
|
-
const layout = getProviderLayout(
|
|
995
|
+
async function checkExistingPaths(targetDir) {
|
|
996
|
+
const layout = getProviderLayout();
|
|
1025
997
|
const pathsToCheck = [layout.entryFile, layout.rootDir, "guides"];
|
|
1026
998
|
const existingPaths = [];
|
|
1027
999
|
for (const relativePath of pathsToCheck) {
|
|
@@ -1032,9 +1004,9 @@ async function checkExistingPaths(targetDir, provider) {
|
|
|
1032
1004
|
}
|
|
1033
1005
|
return existingPaths;
|
|
1034
1006
|
}
|
|
1035
|
-
async function backupExistingInstallation(targetDir
|
|
1036
|
-
const layout = getProviderLayout(
|
|
1037
|
-
const existingPaths = await checkExistingPaths(targetDir
|
|
1007
|
+
async function backupExistingInstallation(targetDir) {
|
|
1008
|
+
const layout = getProviderLayout();
|
|
1009
|
+
const existingPaths = await checkExistingPaths(targetDir);
|
|
1038
1010
|
if (existingPaths.length === 0) {
|
|
1039
1011
|
return [];
|
|
1040
1012
|
}
|
|
@@ -1056,148 +1028,16 @@ async function backupExistingInstallation(targetDir, provider) {
|
|
|
1056
1028
|
return backedUpPaths.length > 0 ? [backupDir] : [];
|
|
1057
1029
|
}
|
|
1058
1030
|
// src/core/provider.ts
|
|
1059
|
-
|
|
1060
|
-
var ENV_SIGNALS = {
|
|
1061
|
-
claude: [
|
|
1062
|
-
"ANTHROPIC_API_KEY",
|
|
1063
|
-
"CLAUDE_CODE",
|
|
1064
|
-
"CLAUDE_CODE_EFFORT_LEVEL",
|
|
1065
|
-
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS",
|
|
1066
|
-
"CLAUDE_CODE_ENABLE_TELEMETRY"
|
|
1067
|
-
],
|
|
1068
|
-
codex: ["OPENAI_API_KEY", "OPENAI_ORG_ID", "OPENAI_PROJECT", "CODEX_HOME", "CODEX_PROJECT"]
|
|
1069
|
-
};
|
|
1070
|
-
var PROVIDER_ENV_OVERRIDES = ["OMCUSTOM_PROVIDER", "LLM_SERVICE"];
|
|
1071
|
-
function normalizeProvider(value) {
|
|
1072
|
-
if (!value)
|
|
1073
|
-
return null;
|
|
1074
|
-
const normalized = value.toLowerCase().trim();
|
|
1075
|
-
if (normalized === "claude" || normalized === "codex" || normalized === "auto") {
|
|
1076
|
-
return normalized;
|
|
1077
|
-
}
|
|
1078
|
-
return null;
|
|
1079
|
-
}
|
|
1080
|
-
function detectFromEnv(env) {
|
|
1081
|
-
for (const key of PROVIDER_ENV_OVERRIDES) {
|
|
1082
|
-
const override = normalizeProvider(env[key]);
|
|
1083
|
-
if (override && override !== "auto") {
|
|
1084
|
-
return {
|
|
1085
|
-
provider: override,
|
|
1086
|
-
source: "override",
|
|
1087
|
-
confidence: "high",
|
|
1088
|
-
reason: `env:${key}`
|
|
1089
|
-
};
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
const claudeSignals = ENV_SIGNALS.claude.filter((key) => Boolean(env[key]));
|
|
1093
|
-
const codexSignals = ENV_SIGNALS.codex.filter((key) => Boolean(env[key]));
|
|
1094
|
-
const hasClaude = claudeSignals.length > 0;
|
|
1095
|
-
const hasCodex = codexSignals.length > 0;
|
|
1096
|
-
if (hasClaude && !hasCodex) {
|
|
1097
|
-
return {
|
|
1098
|
-
provider: "claude",
|
|
1099
|
-
source: "env",
|
|
1100
|
-
confidence: "medium",
|
|
1101
|
-
reason: `env:${claudeSignals[0]}`
|
|
1102
|
-
};
|
|
1103
|
-
}
|
|
1104
|
-
if (hasCodex && !hasClaude) {
|
|
1105
|
-
return {
|
|
1106
|
-
provider: "codex",
|
|
1107
|
-
source: "env",
|
|
1108
|
-
confidence: "medium",
|
|
1109
|
-
reason: `env:${codexSignals[0]}`
|
|
1110
|
-
};
|
|
1111
|
-
}
|
|
1112
|
-
return null;
|
|
1113
|
-
}
|
|
1114
|
-
async function detectFromProject(targetDir) {
|
|
1115
|
-
const claudeMarkers = [join4(targetDir, "CLAUDE.md"), join4(targetDir, ".claude")];
|
|
1116
|
-
const codexMarkers = [join4(targetDir, "AGENTS.md"), join4(targetDir, ".codex")];
|
|
1117
|
-
const claudeFound = await Promise.all(claudeMarkers.map((path) => fileExists(path)));
|
|
1118
|
-
const codexFound = await Promise.all(codexMarkers.map((path) => fileExists(path)));
|
|
1119
|
-
const hasClaude = claudeFound.some(Boolean);
|
|
1120
|
-
const hasCodex = codexFound.some(Boolean);
|
|
1121
|
-
if (hasClaude && !hasCodex) {
|
|
1122
|
-
return {
|
|
1123
|
-
provider: "claude",
|
|
1124
|
-
source: "project",
|
|
1125
|
-
confidence: "medium",
|
|
1126
|
-
reason: "project:claude"
|
|
1127
|
-
};
|
|
1128
|
-
}
|
|
1129
|
-
if (hasCodex && !hasClaude) {
|
|
1130
|
-
return {
|
|
1131
|
-
provider: "codex",
|
|
1132
|
-
source: "project",
|
|
1133
|
-
confidence: "medium",
|
|
1134
|
-
reason: "project:codex"
|
|
1135
|
-
};
|
|
1136
|
-
}
|
|
1137
|
-
return null;
|
|
1138
|
-
}
|
|
1139
|
-
async function detectFromConfig(targetDir) {
|
|
1140
|
-
const configPath = join4(targetDir, ".omcustomrc.json");
|
|
1141
|
-
if (!await fileExists(configPath)) {
|
|
1142
|
-
return null;
|
|
1143
|
-
}
|
|
1144
|
-
try {
|
|
1145
|
-
const config = await readJsonFile(configPath);
|
|
1146
|
-
const provider = normalizeProvider(config.provider);
|
|
1147
|
-
if (provider && provider !== "auto") {
|
|
1148
|
-
return {
|
|
1149
|
-
provider,
|
|
1150
|
-
source: "config",
|
|
1151
|
-
confidence: "high",
|
|
1152
|
-
reason: "config:provider"
|
|
1153
|
-
};
|
|
1154
|
-
}
|
|
1155
|
-
} catch {}
|
|
1156
|
-
return null;
|
|
1157
|
-
}
|
|
1158
|
-
async function detectProvider(options = {}) {
|
|
1159
|
-
const env = options.env ?? process.env;
|
|
1160
|
-
const override = options.override;
|
|
1161
|
-
const normalizedOverride = normalizeProvider(override);
|
|
1162
|
-
if (normalizedOverride && normalizedOverride !== "auto") {
|
|
1163
|
-
return {
|
|
1164
|
-
provider: normalizedOverride,
|
|
1165
|
-
source: "override",
|
|
1166
|
-
confidence: "high",
|
|
1167
|
-
reason: "override:option"
|
|
1168
|
-
};
|
|
1169
|
-
}
|
|
1170
|
-
if (options.targetDir) {
|
|
1171
|
-
const fromConfig = await detectFromConfig(options.targetDir);
|
|
1172
|
-
if (fromConfig) {
|
|
1173
|
-
return fromConfig;
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
if (options.targetDir && options.preferProject) {
|
|
1177
|
-
const fromProject = await detectFromProject(options.targetDir);
|
|
1178
|
-
if (fromProject) {
|
|
1179
|
-
return fromProject;
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
const fromEnv = detectFromEnv(env);
|
|
1183
|
-
if (fromEnv) {
|
|
1184
|
-
return fromEnv;
|
|
1185
|
-
}
|
|
1186
|
-
if (options.targetDir && !options.preferProject) {
|
|
1187
|
-
const fromProject = await detectFromProject(options.targetDir);
|
|
1188
|
-
if (fromProject) {
|
|
1189
|
-
return fromProject;
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1031
|
+
async function detectProvider(_options = {}) {
|
|
1192
1032
|
return {
|
|
1193
|
-
provider:
|
|
1033
|
+
provider: "claude",
|
|
1194
1034
|
source: "default",
|
|
1195
|
-
confidence: "
|
|
1196
|
-
reason: "
|
|
1035
|
+
confidence: "high",
|
|
1036
|
+
reason: "claude-only"
|
|
1197
1037
|
};
|
|
1198
1038
|
}
|
|
1199
1039
|
// src/core/updater.ts
|
|
1200
|
-
import { join as
|
|
1040
|
+
import { join as join4 } from "node:path";
|
|
1201
1041
|
|
|
1202
1042
|
// src/core/entry-merger.ts
|
|
1203
1043
|
var MANAGED_START = "<!-- omcustom:start -->";
|
|
@@ -1329,14 +1169,14 @@ function createUpdateResult() {
|
|
|
1329
1169
|
warnings: []
|
|
1330
1170
|
};
|
|
1331
1171
|
}
|
|
1332
|
-
async function handleBackupIfRequested(targetDir,
|
|
1172
|
+
async function handleBackupIfRequested(targetDir, backup, result) {
|
|
1333
1173
|
if (!backup)
|
|
1334
1174
|
return;
|
|
1335
|
-
const backupPath = await backupInstallation(targetDir
|
|
1175
|
+
const backupPath = await backupInstallation(targetDir);
|
|
1336
1176
|
result.backedUpPaths.push(backupPath);
|
|
1337
1177
|
info("update.backup_created", { path: backupPath });
|
|
1338
1178
|
}
|
|
1339
|
-
async function processComponentUpdate(targetDir,
|
|
1179
|
+
async function processComponentUpdate(targetDir, component, updateCheck, customizations, options, result, config) {
|
|
1340
1180
|
const componentUpdate = updateCheck.updatableComponents.find((c) => c.name === component);
|
|
1341
1181
|
if (!componentUpdate && !options.force) {
|
|
1342
1182
|
result.skippedComponents.push(component);
|
|
@@ -1348,7 +1188,7 @@ async function processComponentUpdate(targetDir, provider, component, updateChec
|
|
|
1348
1188
|
return;
|
|
1349
1189
|
}
|
|
1350
1190
|
try {
|
|
1351
|
-
const preserved = await updateComponent(targetDir,
|
|
1191
|
+
const preserved = await updateComponent(targetDir, component, customizations, options, config);
|
|
1352
1192
|
result.updatedComponents.push(component);
|
|
1353
1193
|
result.preservedFiles.push(...preserved);
|
|
1354
1194
|
} catch (err) {
|
|
@@ -1357,13 +1197,13 @@ async function processComponentUpdate(targetDir, provider, component, updateChec
|
|
|
1357
1197
|
result.skippedComponents.push(component);
|
|
1358
1198
|
}
|
|
1359
1199
|
}
|
|
1360
|
-
async function updateAllComponents(targetDir,
|
|
1200
|
+
async function updateAllComponents(targetDir, components, updateCheck, customizations, options, result, config) {
|
|
1361
1201
|
for (const component of components) {
|
|
1362
|
-
await processComponentUpdate(targetDir,
|
|
1202
|
+
await processComponentUpdate(targetDir, component, updateCheck, customizations, options, result, config);
|
|
1363
1203
|
}
|
|
1364
1204
|
}
|
|
1365
|
-
function getEntryTemplateName2(
|
|
1366
|
-
const layout = getProviderLayout(
|
|
1205
|
+
function getEntryTemplateName2(language) {
|
|
1206
|
+
const layout = getProviderLayout();
|
|
1367
1207
|
const baseName = layout.entryFile.replace(".md", "");
|
|
1368
1208
|
return language === "ko" ? `${baseName}.md.ko` : `${baseName}.md.en`;
|
|
1369
1209
|
}
|
|
@@ -1447,10 +1287,10 @@ function resolveCustomizations(customizations, configPreserveFiles, targetDir) {
|
|
|
1447
1287
|
}
|
|
1448
1288
|
return null;
|
|
1449
1289
|
}
|
|
1450
|
-
async function updateEntryDoc(targetDir,
|
|
1451
|
-
const layout = getProviderLayout(
|
|
1452
|
-
const entryPath =
|
|
1453
|
-
const templateName = getEntryTemplateName2(
|
|
1290
|
+
async function updateEntryDoc(targetDir, config, options) {
|
|
1291
|
+
const layout = getProviderLayout();
|
|
1292
|
+
const entryPath = join4(targetDir, layout.entryFile);
|
|
1293
|
+
const templateName = getEntryTemplateName2(config.language);
|
|
1454
1294
|
const templatePath = resolveTemplatePath(templateName);
|
|
1455
1295
|
if (!await fileExists(templatePath)) {
|
|
1456
1296
|
warn("update.entry_template_not_found", { template: templateName });
|
|
@@ -1487,9 +1327,8 @@ async function update(options) {
|
|
|
1487
1327
|
try {
|
|
1488
1328
|
info("update.start", { targetDir: options.targetDir });
|
|
1489
1329
|
const config = await loadConfig(options.targetDir);
|
|
1490
|
-
const provider = options.provider ?? (config.provider === "codex" ? "codex" : "claude");
|
|
1491
1330
|
result.previousVersion = config.version;
|
|
1492
|
-
const updateCheck = await checkForUpdates(options.targetDir
|
|
1331
|
+
const updateCheck = await checkForUpdates(options.targetDir);
|
|
1493
1332
|
result.newVersion = updateCheck.latestVersion;
|
|
1494
1333
|
if (!updateCheck.hasUpdates && !options.force) {
|
|
1495
1334
|
info("update.no_updates");
|
|
@@ -1497,14 +1336,14 @@ async function update(options) {
|
|
|
1497
1336
|
result.skippedComponents = options.components || getAllUpdateComponents();
|
|
1498
1337
|
return result;
|
|
1499
1338
|
}
|
|
1500
|
-
await handleBackupIfRequested(options.targetDir,
|
|
1339
|
+
await handleBackupIfRequested(options.targetDir, !!options.backup, result);
|
|
1501
1340
|
const manifestCustomizations = await resolveManifestCustomizations(options, options.targetDir);
|
|
1502
1341
|
const configPreserveFiles = resolveConfigPreserveFiles(options, config);
|
|
1503
1342
|
const customizations = resolveCustomizations(manifestCustomizations, configPreserveFiles, options.targetDir);
|
|
1504
1343
|
const components = options.components || getAllUpdateComponents();
|
|
1505
|
-
await updateAllComponents(options.targetDir,
|
|
1344
|
+
await updateAllComponents(options.targetDir, components, updateCheck, customizations, options, result, config);
|
|
1506
1345
|
if (!options.components || options.components.length === 0) {
|
|
1507
|
-
await updateEntryDoc(options.targetDir,
|
|
1346
|
+
await updateEntryDoc(options.targetDir, config, options);
|
|
1508
1347
|
}
|
|
1509
1348
|
config.version = result.newVersion;
|
|
1510
1349
|
config.lastUpdated = new Date().toISOString();
|
|
@@ -1525,13 +1364,13 @@ async function update(options) {
|
|
|
1525
1364
|
}
|
|
1526
1365
|
return result;
|
|
1527
1366
|
}
|
|
1528
|
-
async function checkForUpdates(targetDir
|
|
1367
|
+
async function checkForUpdates(targetDir) {
|
|
1529
1368
|
const config = await loadConfig(targetDir);
|
|
1530
1369
|
const currentVersion = config.version;
|
|
1531
|
-
const latestVersion = await getLatestVersion(
|
|
1370
|
+
const latestVersion = await getLatestVersion();
|
|
1532
1371
|
const updatableComponents = [];
|
|
1533
1372
|
for (const component of getAllUpdateComponents()) {
|
|
1534
|
-
const hasUpdate = await componentHasUpdate(targetDir,
|
|
1373
|
+
const hasUpdate = await componentHasUpdate(targetDir, component, config);
|
|
1535
1374
|
if (hasUpdate) {
|
|
1536
1375
|
updatableComponents.push({
|
|
1537
1376
|
name: component,
|
|
@@ -1551,8 +1390,8 @@ async function checkForUpdates(targetDir, provider = "claude") {
|
|
|
1551
1390
|
async function applyUpdates(targetDir, updates) {
|
|
1552
1391
|
const fs = await import("node:fs/promises");
|
|
1553
1392
|
for (const update2 of updates) {
|
|
1554
|
-
const fullPath =
|
|
1555
|
-
await ensureDirectory(
|
|
1393
|
+
const fullPath = join4(targetDir, update2.path);
|
|
1394
|
+
await ensureDirectory(join4(fullPath, ".."));
|
|
1556
1395
|
await fs.writeFile(fullPath, update2.content, "utf-8");
|
|
1557
1396
|
debug("update.file_applied", { path: update2.path });
|
|
1558
1397
|
}
|
|
@@ -1561,7 +1400,7 @@ async function preserveCustomizations(targetDir, customizations) {
|
|
|
1561
1400
|
const preserved = new Map;
|
|
1562
1401
|
const fs = await import("node:fs/promises");
|
|
1563
1402
|
for (const filePath of customizations) {
|
|
1564
|
-
const fullPath =
|
|
1403
|
+
const fullPath = join4(targetDir, filePath);
|
|
1565
1404
|
if (await fileExists(fullPath)) {
|
|
1566
1405
|
const content = await fs.readFile(fullPath, "utf-8");
|
|
1567
1406
|
preserved.set(filePath, content);
|
|
@@ -1572,8 +1411,8 @@ async function preserveCustomizations(targetDir, customizations) {
|
|
|
1572
1411
|
function getAllUpdateComponents() {
|
|
1573
1412
|
return ["rules", "agents", "skills", "guides", "hooks", "contexts"];
|
|
1574
1413
|
}
|
|
1575
|
-
async function getLatestVersion(
|
|
1576
|
-
const layout = getProviderLayout(
|
|
1414
|
+
async function getLatestVersion() {
|
|
1415
|
+
const layout = getProviderLayout();
|
|
1577
1416
|
const manifestPath = resolveTemplatePath(layout.manifestFile);
|
|
1578
1417
|
if (await fileExists(manifestPath)) {
|
|
1579
1418
|
const manifest = await readJsonFile(manifestPath);
|
|
@@ -1581,19 +1420,19 @@ async function getLatestVersion(provider) {
|
|
|
1581
1420
|
}
|
|
1582
1421
|
return "0.0.0";
|
|
1583
1422
|
}
|
|
1584
|
-
async function componentHasUpdate(_targetDir,
|
|
1423
|
+
async function componentHasUpdate(_targetDir, component, config) {
|
|
1585
1424
|
const installedVersion = config.componentVersions?.[component];
|
|
1586
1425
|
if (!installedVersion) {
|
|
1587
1426
|
return true;
|
|
1588
1427
|
}
|
|
1589
|
-
const latestVersion = await getLatestVersion(
|
|
1428
|
+
const latestVersion = await getLatestVersion();
|
|
1590
1429
|
return installedVersion !== latestVersion;
|
|
1591
1430
|
}
|
|
1592
|
-
async function updateComponent(targetDir,
|
|
1431
|
+
async function updateComponent(targetDir, component, customizations, options, config) {
|
|
1593
1432
|
const preservedFiles = [];
|
|
1594
|
-
const componentPath = getComponentPath2(
|
|
1433
|
+
const componentPath = getComponentPath2(component);
|
|
1595
1434
|
const srcPath = resolveTemplatePath(componentPath);
|
|
1596
|
-
const destPath =
|
|
1435
|
+
const destPath = join4(targetDir, componentPath);
|
|
1597
1436
|
const customComponents = config.customComponents || [];
|
|
1598
1437
|
const skipPaths = [];
|
|
1599
1438
|
if (customizations && !options.forceOverwriteAll) {
|
|
@@ -1607,7 +1446,7 @@ async function updateComponent(targetDir, provider, component, customizations, o
|
|
|
1607
1446
|
}
|
|
1608
1447
|
}
|
|
1609
1448
|
const path = await import("node:path");
|
|
1610
|
-
const normalizedSkipPaths = skipPaths.map((p) => path.relative(destPath,
|
|
1449
|
+
const normalizedSkipPaths = skipPaths.map((p) => path.relative(destPath, join4(targetDir, p)));
|
|
1611
1450
|
await copyDirectory(srcPath, destPath, {
|
|
1612
1451
|
overwrite: true,
|
|
1613
1452
|
skipPaths: normalizedSkipPaths.length > 0 ? normalizedSkipPaths : undefined
|
|
@@ -1618,35 +1457,35 @@ async function updateComponent(targetDir, provider, component, customizations, o
|
|
|
1618
1457
|
});
|
|
1619
1458
|
return preservedFiles;
|
|
1620
1459
|
}
|
|
1621
|
-
function getComponentPath2(
|
|
1622
|
-
const layout = getProviderLayout(
|
|
1460
|
+
function getComponentPath2(component) {
|
|
1461
|
+
const layout = getProviderLayout();
|
|
1623
1462
|
if (component === "guides") {
|
|
1624
1463
|
return "guides";
|
|
1625
1464
|
}
|
|
1626
1465
|
return `${layout.rootDir}/${component}`;
|
|
1627
1466
|
}
|
|
1628
|
-
async function backupInstallation(targetDir
|
|
1467
|
+
async function backupInstallation(targetDir) {
|
|
1629
1468
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
1630
|
-
const backupDir =
|
|
1469
|
+
const backupDir = join4(targetDir, `.omcustom-backup-${timestamp}`);
|
|
1631
1470
|
const fs = await import("node:fs/promises");
|
|
1632
1471
|
await ensureDirectory(backupDir);
|
|
1633
|
-
const layout = getProviderLayout(
|
|
1472
|
+
const layout = getProviderLayout();
|
|
1634
1473
|
const dirsToBackup = [layout.rootDir, "guides"];
|
|
1635
1474
|
for (const dir of dirsToBackup) {
|
|
1636
|
-
const srcPath =
|
|
1475
|
+
const srcPath = join4(targetDir, dir);
|
|
1637
1476
|
if (await fileExists(srcPath)) {
|
|
1638
|
-
const destPath =
|
|
1477
|
+
const destPath = join4(backupDir, dir);
|
|
1639
1478
|
await copyDirectory(srcPath, destPath, { overwrite: true });
|
|
1640
1479
|
}
|
|
1641
1480
|
}
|
|
1642
|
-
const entryPath =
|
|
1481
|
+
const entryPath = join4(targetDir, layout.entryFile);
|
|
1643
1482
|
if (await fileExists(entryPath)) {
|
|
1644
|
-
await fs.copyFile(entryPath,
|
|
1483
|
+
await fs.copyFile(entryPath, join4(backupDir, layout.entryFile));
|
|
1645
1484
|
}
|
|
1646
1485
|
return backupDir;
|
|
1647
1486
|
}
|
|
1648
1487
|
async function loadCustomizationManifest(targetDir) {
|
|
1649
|
-
const manifestPath =
|
|
1488
|
+
const manifestPath = join4(targetDir, CUSTOMIZATION_MANIFEST_FILE);
|
|
1650
1489
|
if (await fileExists(manifestPath)) {
|
|
1651
1490
|
return readJsonFile(manifestPath);
|
|
1652
1491
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-customcode",
|
|
3
|
-
"version": "0.12.
|
|
4
|
-
"description": "Batteries-included agent harness for Claude Code
|
|
3
|
+
"version": "0.12.3",
|
|
4
|
+
"description": "Batteries-included agent harness for Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"omcustom": "./dist/cli/index.js"
|
|
@@ -59,8 +59,6 @@
|
|
|
59
59
|
"keywords": [
|
|
60
60
|
"claude",
|
|
61
61
|
"claude-code",
|
|
62
|
-
"codex",
|
|
63
|
-
"codex-cli",
|
|
64
62
|
"openai",
|
|
65
63
|
"ai",
|
|
66
64
|
"agent",
|