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