oh-my-customcode 0.117.0 → 0.118.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/README.md +2 -2
- package/dist/cli/index.js +212 -94
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/templates/.claude/hooks/hooks.json +42 -22
- package/templates/.claude/hooks/scripts/auto-dev-token-summary.sh +67 -0
- package/templates/.claude/hooks/scripts/auto-dev-token-tracker.sh +57 -0
- package/templates/.claude/rules/MUST-agent-design.md +6 -0
- package/templates/.claude/skills/deep-plan/SKILL.md +37 -307
- package/templates/.claude/skills/professor-triage/SKILL.md +39 -329
- package/templates/CLAUDE.md +1 -1
- package/templates/guides/deep-plan/README.md +68 -0
- package/templates/guides/deep-plan/phases.md +266 -0
- package/templates/guides/professor-triage/README.md +42 -0
- package/templates/guides/professor-triage/phases.md +335 -0
- package/templates/manifest.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -2334,7 +2334,7 @@ var init_package = __esm(() => {
|
|
|
2334
2334
|
workspaces: [
|
|
2335
2335
|
"packages/*"
|
|
2336
2336
|
],
|
|
2337
|
-
version: "0.
|
|
2337
|
+
version: "0.118.1",
|
|
2338
2338
|
description: "Batteries-included agent harness for Claude Code",
|
|
2339
2339
|
type: "module",
|
|
2340
2340
|
bin: {
|
|
@@ -9607,9 +9607,9 @@ __export(exports_projects, {
|
|
|
9607
9607
|
default: () => projects_default
|
|
9608
9608
|
});
|
|
9609
9609
|
import { homedir as homedir3 } from "node:os";
|
|
9610
|
-
import { basename as basename4, join as
|
|
9610
|
+
import { basename as basename4, join as join11, sep as sep3 } from "node:path";
|
|
9611
9611
|
async function readLockFile(projectDir) {
|
|
9612
|
-
const lockFilePath =
|
|
9612
|
+
const lockFilePath = join11(projectDir, ".omcustom.lock.json");
|
|
9613
9613
|
try {
|
|
9614
9614
|
const fs2 = await import("node:fs/promises");
|
|
9615
9615
|
const content = await fs2.readFile(lockFilePath, "utf-8");
|
|
@@ -9715,7 +9715,7 @@ async function _scanDirForLockfiles(dir2, depth, seen, results, home, currentVer
|
|
|
9715
9715
|
}
|
|
9716
9716
|
if (depth < 3) {
|
|
9717
9717
|
const subdirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && !SCAN_SKIP_DIRS2.has(e.name));
|
|
9718
|
-
await Promise.all(subdirs.map((sub) => _scanDirForLockfiles(
|
|
9718
|
+
await Promise.all(subdirs.map((sub) => _scanDirForLockfiles(join11(dir2, sub.name), depth + 1, seen, results, home, currentVersion, fs2).catch(() => {})));
|
|
9719
9719
|
}
|
|
9720
9720
|
}
|
|
9721
9721
|
async function _findProjectsFromLockfiles(options, currentVersion) {
|
|
@@ -9738,7 +9738,7 @@ async function _findProjectsFromLockfiles(options, currentVersion) {
|
|
|
9738
9738
|
}
|
|
9739
9739
|
async function writeLockFile(projectDir, version, existing) {
|
|
9740
9740
|
const fs2 = await import("node:fs/promises");
|
|
9741
|
-
const lockFilePath =
|
|
9741
|
+
const lockFilePath = join11(projectDir, ".omcustom.lock.json");
|
|
9742
9742
|
const now = new Date().toISOString();
|
|
9743
9743
|
const merged = {
|
|
9744
9744
|
...existing || {},
|
|
@@ -9806,7 +9806,7 @@ async function runMigration(options) {
|
|
|
9806
9806
|
const { homedir: _homedir } = await import("node:os");
|
|
9807
9807
|
const DEFAULT_SEARCH_DIRS = ["workspace", "projects", "dev", "src", "code", "repos", "work"];
|
|
9808
9808
|
const home = _homedir();
|
|
9809
|
-
const searchDirs = [...DEFAULT_SEARCH_DIRS.map((d) =>
|
|
9809
|
+
const searchDirs = [...DEFAULT_SEARCH_DIRS.map((d) => join11(home, d)), ...options.paths ?? []];
|
|
9810
9810
|
const cwd = process.cwd();
|
|
9811
9811
|
if (!searchDirs.includes(cwd))
|
|
9812
9812
|
searchDirs.push(cwd);
|
|
@@ -27552,7 +27552,7 @@ async function doctorCommand(options = {}) {
|
|
|
27552
27552
|
|
|
27553
27553
|
// src/cli/init.ts
|
|
27554
27554
|
init_package();
|
|
27555
|
-
import { join as
|
|
27555
|
+
import { join as join13 } from "node:path";
|
|
27556
27556
|
|
|
27557
27557
|
// src/core/installer.ts
|
|
27558
27558
|
init_fs();
|
|
@@ -28392,7 +28392,6 @@ async function backupExistingInstallation(targetDir) {
|
|
|
28392
28392
|
|
|
28393
28393
|
// src/core/mcp-config.ts
|
|
28394
28394
|
init_fs();
|
|
28395
|
-
import { execSync as execSync5 } from "node:child_process";
|
|
28396
28395
|
import { writeFile as writeFile2 } from "node:fs/promises";
|
|
28397
28396
|
import { join as join9 } from "node:path";
|
|
28398
28397
|
async function generateMCPConfig(targetDir) {
|
|
@@ -28403,22 +28402,6 @@ async function generateMCPConfig(targetDir) {
|
|
|
28403
28402
|
if (!ontologyExists) {
|
|
28404
28403
|
return;
|
|
28405
28404
|
}
|
|
28406
|
-
try {
|
|
28407
|
-
execSync5("uv --version", { stdio: "pipe" });
|
|
28408
|
-
} catch {
|
|
28409
|
-
warn("uv (Python package manager) not found. Install it with: curl -LsSf https://astral.sh/uv/install.sh | sh");
|
|
28410
|
-
warn("Skipping ontology-rag MCP configuration. You can set it up manually later.");
|
|
28411
|
-
return;
|
|
28412
|
-
}
|
|
28413
|
-
try {
|
|
28414
|
-
execSync5("uv venv .venv", { cwd: targetDir, stdio: "pipe" });
|
|
28415
|
-
execSync5('uv pip install "ontology-rag @ git+https://github.com/baekenough/oh-my-customcode.git#subdirectory=packages/ontology-rag"', { cwd: targetDir, stdio: "pipe" });
|
|
28416
|
-
} catch (error2) {
|
|
28417
|
-
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
28418
|
-
warn(`Failed to setup ontology-rag: ${msg}`);
|
|
28419
|
-
warn("You can configure the MCP server manually. See: https://github.com/baekenough/oh-my-customcode/tree/develop/packages/ontology-rag");
|
|
28420
|
-
return;
|
|
28421
|
-
}
|
|
28422
28405
|
const config = {
|
|
28423
28406
|
mcpServers: {
|
|
28424
28407
|
"ontology-rag": {
|
|
@@ -28453,14 +28436,151 @@ async function generateMCPConfig(targetDir) {
|
|
|
28453
28436
|
}
|
|
28454
28437
|
info("ontology-rag MCP server configured successfully");
|
|
28455
28438
|
}
|
|
28456
|
-
|
|
28439
|
+
|
|
28440
|
+
// src/core/ontology-rag-setup.ts
|
|
28441
|
+
init_fs();
|
|
28442
|
+
import { execSync as execSync5 } from "node:child_process";
|
|
28443
|
+
import { join as join10 } from "node:path";
|
|
28444
|
+
var MIN_PYTHON_MINOR = 10;
|
|
28445
|
+
var DETECTION_TIMEOUT_MS = 3000;
|
|
28446
|
+
var INSTALL_TIMEOUT_MS = 90000;
|
|
28447
|
+
function parsePythonVersion(output) {
|
|
28448
|
+
const match = /Python\s+(\d+)\.(\d+)/i.exec(output);
|
|
28449
|
+
if (!match)
|
|
28450
|
+
return null;
|
|
28451
|
+
return [Number(match[1]), Number(match[2])];
|
|
28452
|
+
}
|
|
28453
|
+
function checkPython3() {
|
|
28454
|
+
try {
|
|
28455
|
+
const output = execSync5("python3 --version 2>&1", {
|
|
28456
|
+
stdio: "pipe",
|
|
28457
|
+
timeout: DETECTION_TIMEOUT_MS
|
|
28458
|
+
}).toString().trim();
|
|
28459
|
+
const parsed = parsePythonVersion(output);
|
|
28460
|
+
if (!parsed) {
|
|
28461
|
+
return { available: true, versionOk: false, version: output };
|
|
28462
|
+
}
|
|
28463
|
+
const [major, minor] = parsed;
|
|
28464
|
+
const versionOk = major === 3 && minor >= MIN_PYTHON_MINOR;
|
|
28465
|
+
return { available: true, versionOk, version: `${major}.${minor}` };
|
|
28466
|
+
} catch {
|
|
28467
|
+
return { available: false, versionOk: false, version: "" };
|
|
28468
|
+
}
|
|
28469
|
+
}
|
|
28470
|
+
function checkUvAvailableForSetup() {
|
|
28457
28471
|
try {
|
|
28458
|
-
execSync5("uv --version", { stdio: "pipe" });
|
|
28472
|
+
execSync5("uv --version", { stdio: "pipe", timeout: DETECTION_TIMEOUT_MS });
|
|
28459
28473
|
return true;
|
|
28460
28474
|
} catch {
|
|
28461
28475
|
return false;
|
|
28462
28476
|
}
|
|
28463
28477
|
}
|
|
28478
|
+
function createVenvWithUv(targetDir) {
|
|
28479
|
+
execSync5("uv venv --python 3.12 .venv", {
|
|
28480
|
+
cwd: targetDir,
|
|
28481
|
+
stdio: "pipe",
|
|
28482
|
+
timeout: INSTALL_TIMEOUT_MS
|
|
28483
|
+
});
|
|
28484
|
+
}
|
|
28485
|
+
function createVenvWithPython3(targetDir) {
|
|
28486
|
+
execSync5("python3 -m venv .venv", {
|
|
28487
|
+
cwd: targetDir,
|
|
28488
|
+
stdio: "pipe",
|
|
28489
|
+
timeout: INSTALL_TIMEOUT_MS
|
|
28490
|
+
});
|
|
28491
|
+
}
|
|
28492
|
+
function installOntologyRagEditable(targetDir, useUv) {
|
|
28493
|
+
const packageRoot = getPackageRoot();
|
|
28494
|
+
const ontologyPkgPath = join10(packageRoot, "packages", "ontology-rag");
|
|
28495
|
+
if (useUv) {
|
|
28496
|
+
execSync5(`uv pip install --python .venv/bin/python -e "${ontologyPkgPath}"`, {
|
|
28497
|
+
cwd: targetDir,
|
|
28498
|
+
stdio: "pipe",
|
|
28499
|
+
timeout: INSTALL_TIMEOUT_MS
|
|
28500
|
+
});
|
|
28501
|
+
} else {
|
|
28502
|
+
execSync5(`.venv/bin/pip install -e "${ontologyPkgPath}"`, {
|
|
28503
|
+
cwd: targetDir,
|
|
28504
|
+
stdio: "pipe",
|
|
28505
|
+
timeout: INSTALL_TIMEOUT_MS
|
|
28506
|
+
});
|
|
28507
|
+
}
|
|
28508
|
+
}
|
|
28509
|
+
async function setupOntologyRag(targetDir) {
|
|
28510
|
+
if (process.env.OMCUSTOM_SKIP_ONTOLOGY_RAG_SETUP === "1") {
|
|
28511
|
+
const statusLine = "ontology-rag MCP: ⚠ skipped (OMCUSTOM_SKIP_ONTOLOGY_RAG_SETUP=1)";
|
|
28512
|
+
console.warn(`Warning: ${statusLine}`);
|
|
28513
|
+
return { success: false, statusLine, reason: "skipped via env var" };
|
|
28514
|
+
}
|
|
28515
|
+
const python = checkPython3();
|
|
28516
|
+
if (!python.available) {
|
|
28517
|
+
const reason = `python3 not found. Install Python >= 3.${MIN_PYTHON_MINOR} (https://python.org) to enable ontology-rag.`;
|
|
28518
|
+
console.warn(`Warning: ${reason}`);
|
|
28519
|
+
return {
|
|
28520
|
+
success: false,
|
|
28521
|
+
statusLine: "ontology-rag MCP: skipped (python3 not found)",
|
|
28522
|
+
reason
|
|
28523
|
+
};
|
|
28524
|
+
}
|
|
28525
|
+
if (!python.versionOk) {
|
|
28526
|
+
const reason = `python3 ${python.version} is below the required 3.${MIN_PYTHON_MINOR}. ` + `Upgrade Python to enable ontology-rag.`;
|
|
28527
|
+
console.warn(`Warning: ${reason}`);
|
|
28528
|
+
return {
|
|
28529
|
+
success: false,
|
|
28530
|
+
statusLine: `ontology-rag MCP: skipped (python3 ${python.version} < 3.${MIN_PYTHON_MINOR})`,
|
|
28531
|
+
reason
|
|
28532
|
+
};
|
|
28533
|
+
}
|
|
28534
|
+
const uvAvailable = checkUvAvailableForSetup();
|
|
28535
|
+
if (!uvAvailable) {
|
|
28536
|
+
console.warn("Warning: uv not found. Falling back to `python3 -m venv` for ontology-rag setup.");
|
|
28537
|
+
console.warn("Install uv (https://docs.astral.sh/uv/) for faster Python environment setup.");
|
|
28538
|
+
}
|
|
28539
|
+
try {
|
|
28540
|
+
if (uvAvailable) {
|
|
28541
|
+
createVenvWithUv(targetDir);
|
|
28542
|
+
} else {
|
|
28543
|
+
createVenvWithPython3(targetDir);
|
|
28544
|
+
}
|
|
28545
|
+
} catch (err) {
|
|
28546
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
28547
|
+
const reason = `Failed to create .venv: ${msg}`;
|
|
28548
|
+
console.warn(`Warning: ${reason}`);
|
|
28549
|
+
return {
|
|
28550
|
+
success: false,
|
|
28551
|
+
statusLine: "ontology-rag MCP: skipped (venv creation failed)",
|
|
28552
|
+
reason
|
|
28553
|
+
};
|
|
28554
|
+
}
|
|
28555
|
+
try {
|
|
28556
|
+
installOntologyRagEditable(targetDir, uvAvailable);
|
|
28557
|
+
} catch (err) {
|
|
28558
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
28559
|
+
const reason = `Failed to install ontology-rag: ${msg}`;
|
|
28560
|
+
console.warn(`Warning: ${reason}`);
|
|
28561
|
+
return {
|
|
28562
|
+
success: false,
|
|
28563
|
+
statusLine: "ontology-rag MCP: skipped (install failed)",
|
|
28564
|
+
reason
|
|
28565
|
+
};
|
|
28566
|
+
}
|
|
28567
|
+
const venvPython = join10(targetDir, ".venv", "bin", "python");
|
|
28568
|
+
const venvReady = await fileExists(venvPython);
|
|
28569
|
+
if (!venvReady) {
|
|
28570
|
+
const reason = ".venv/bin/python missing after install — environment may be incomplete. " + "Run `uv pip install -e packages/ontology-rag` manually to complete setup.";
|
|
28571
|
+
console.warn(`Warning: ${reason}`);
|
|
28572
|
+
return {
|
|
28573
|
+
success: false,
|
|
28574
|
+
statusLine: "ontology-rag MCP: skipped (venv incomplete)",
|
|
28575
|
+
reason
|
|
28576
|
+
};
|
|
28577
|
+
}
|
|
28578
|
+
console.log("ontology-rag MCP: ready");
|
|
28579
|
+
return {
|
|
28580
|
+
success: true,
|
|
28581
|
+
statusLine: "ontology-rag MCP: ready"
|
|
28582
|
+
};
|
|
28583
|
+
}
|
|
28464
28584
|
|
|
28465
28585
|
// src/cli/init.ts
|
|
28466
28586
|
init_registry();
|
|
@@ -28470,12 +28590,12 @@ init_package();
|
|
|
28470
28590
|
init_projects();
|
|
28471
28591
|
import { existsSync as existsSync2 } from "node:fs";
|
|
28472
28592
|
import { copyFile as copyFile2, cp } from "node:fs/promises";
|
|
28473
|
-
import { join as
|
|
28593
|
+
import { join as join12 } from "node:path";
|
|
28474
28594
|
init_fs();
|
|
28475
28595
|
init_registry();
|
|
28476
28596
|
async function checkExistingInstallation(targetDir) {
|
|
28477
28597
|
const layout = getProviderLayout();
|
|
28478
|
-
const rootDir =
|
|
28598
|
+
const rootDir = join12(targetDir, layout.rootDir);
|
|
28479
28599
|
return fileExists(rootDir);
|
|
28480
28600
|
}
|
|
28481
28601
|
async function installFromSnapshot(targetDir, snapshotPath, options) {
|
|
@@ -28487,7 +28607,7 @@ async function installFromSnapshot(targetDir, snapshotPath, options) {
|
|
|
28487
28607
|
};
|
|
28488
28608
|
}
|
|
28489
28609
|
const layout = getProviderLayout();
|
|
28490
|
-
const snapshotClaude =
|
|
28610
|
+
const snapshotClaude = join12(snapshotPath, layout.rootDir);
|
|
28491
28611
|
if (!existsSync2(snapshotClaude)) {
|
|
28492
28612
|
return {
|
|
28493
28613
|
success: false,
|
|
@@ -28501,24 +28621,24 @@ async function installFromSnapshot(targetDir, snapshotPath, options) {
|
|
|
28501
28621
|
if (exists2 && !options.force) {
|
|
28502
28622
|
console.log(i18n.t("cli.init.exists", { rootDir: layout.rootDir }));
|
|
28503
28623
|
console.log(i18n.t("cli.init.backing_up"));
|
|
28504
|
-
const backupDir =
|
|
28505
|
-
await cp(
|
|
28624
|
+
const backupDir = join12(targetDir, `.claude-backup-${new Date().toISOString().replace(/[:.]/g, "-").slice(0, -1)}`);
|
|
28625
|
+
await cp(join12(targetDir, layout.rootDir), backupDir, { recursive: true });
|
|
28506
28626
|
console.log(` Backed up to: ${backupDir}`);
|
|
28507
28627
|
}
|
|
28508
|
-
await cp(snapshotClaude,
|
|
28628
|
+
await cp(snapshotClaude, join12(targetDir, layout.rootDir), {
|
|
28509
28629
|
recursive: true,
|
|
28510
28630
|
force: true
|
|
28511
28631
|
});
|
|
28512
|
-
const snapshotGuides =
|
|
28632
|
+
const snapshotGuides = join12(snapshotPath, "guides");
|
|
28513
28633
|
if (existsSync2(snapshotGuides)) {
|
|
28514
|
-
await cp(snapshotGuides,
|
|
28634
|
+
await cp(snapshotGuides, join12(targetDir, "guides"), {
|
|
28515
28635
|
recursive: true,
|
|
28516
28636
|
force: true
|
|
28517
28637
|
});
|
|
28518
28638
|
}
|
|
28519
|
-
const snapshotEntry =
|
|
28639
|
+
const snapshotEntry = join12(snapshotPath, layout.entryFile);
|
|
28520
28640
|
if (existsSync2(snapshotEntry)) {
|
|
28521
|
-
await copyFile2(snapshotEntry,
|
|
28641
|
+
await copyFile2(snapshotEntry, join12(targetDir, layout.entryFile));
|
|
28522
28642
|
}
|
|
28523
28643
|
try {
|
|
28524
28644
|
const existing = await readLockFile(targetDir);
|
|
@@ -29526,7 +29646,7 @@ async function runInitWizard(options) {
|
|
|
29526
29646
|
// src/cli/init.ts
|
|
29527
29647
|
async function checkExistingInstallation2(targetDir) {
|
|
29528
29648
|
const layout = getProviderLayout();
|
|
29529
|
-
const rootDir =
|
|
29649
|
+
const rootDir = join13(targetDir, layout.rootDir);
|
|
29530
29650
|
return fileExists(rootDir);
|
|
29531
29651
|
}
|
|
29532
29652
|
var PROVIDER_SUBDIR_COMPONENTS = new Set([
|
|
@@ -29540,13 +29660,13 @@ var PROVIDER_SUBDIR_COMPONENTS = new Set([
|
|
|
29540
29660
|
function componentToPath(targetDir, component) {
|
|
29541
29661
|
if (component === "entry-md") {
|
|
29542
29662
|
const layout = getProviderLayout();
|
|
29543
|
-
return
|
|
29663
|
+
return join13(targetDir, layout.entryFile);
|
|
29544
29664
|
}
|
|
29545
29665
|
if (PROVIDER_SUBDIR_COMPONENTS.has(component)) {
|
|
29546
29666
|
const layout = getProviderLayout();
|
|
29547
|
-
return
|
|
29667
|
+
return join13(targetDir, layout.rootDir, component);
|
|
29548
29668
|
}
|
|
29549
|
-
return
|
|
29669
|
+
return join13(targetDir, component);
|
|
29550
29670
|
}
|
|
29551
29671
|
function buildInstalledPaths(targetDir, components) {
|
|
29552
29672
|
return components.map((component) => componentToPath(targetDir, component));
|
|
@@ -29597,17 +29717,15 @@ async function resolveOptions(options) {
|
|
|
29597
29717
|
return { lang: defaults.lang, domain: defaults.domain };
|
|
29598
29718
|
}
|
|
29599
29719
|
async function setupMcpConfig(targetDir) {
|
|
29600
|
-
const
|
|
29601
|
-
|
|
29720
|
+
const setupResult = await setupOntologyRag(targetDir);
|
|
29721
|
+
console.log(` ${setupResult.statusLine}`);
|
|
29722
|
+
if (setupResult.success) {
|
|
29602
29723
|
try {
|
|
29603
29724
|
await generateMCPConfig(targetDir);
|
|
29604
29725
|
} catch (error2) {
|
|
29605
29726
|
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
29606
|
-
console.warn(`Warning: Failed to
|
|
29727
|
+
console.warn(`Warning: Failed to write .mcp.json: ${msg}`);
|
|
29607
29728
|
}
|
|
29608
|
-
} else {
|
|
29609
|
-
console.warn("Warning: uv not found. Skipping MCP server configuration.");
|
|
29610
|
-
console.warn("Install uv (https://docs.astral.sh/uv/) to enable MCP integration.");
|
|
29611
29729
|
}
|
|
29612
29730
|
}
|
|
29613
29731
|
async function initCommand(options) {
|
|
@@ -29671,7 +29789,7 @@ async function initCommand(options) {
|
|
|
29671
29789
|
}
|
|
29672
29790
|
|
|
29673
29791
|
// src/cli/list.ts
|
|
29674
|
-
import { basename as basename5, dirname as dirname3, join as
|
|
29792
|
+
import { basename as basename5, dirname as dirname3, join as join14, relative as relative3 } from "node:path";
|
|
29675
29793
|
init_fs();
|
|
29676
29794
|
var ALLOWED_TOP_LEVEL_KEYS = new Set(["name", "type", "description", "version", "category"]);
|
|
29677
29795
|
function parseKeyValue(line) {
|
|
@@ -29736,12 +29854,12 @@ function extractAgentTypeFromFilename(filename) {
|
|
|
29736
29854
|
return prefixMap[prefix] || "unknown";
|
|
29737
29855
|
}
|
|
29738
29856
|
function extractSkillCategoryFromPath(skillPath, baseDir, rootDir) {
|
|
29739
|
-
const relativePath = relative3(
|
|
29857
|
+
const relativePath = relative3(join14(baseDir, rootDir, "skills"), skillPath);
|
|
29740
29858
|
const parts = relativePath.split("/").filter(Boolean);
|
|
29741
29859
|
return parts[0] || "unknown";
|
|
29742
29860
|
}
|
|
29743
29861
|
function extractGuideCategoryFromPath(guidePath, baseDir) {
|
|
29744
|
-
const relativePath = relative3(
|
|
29862
|
+
const relativePath = relative3(join14(baseDir, "guides"), guidePath);
|
|
29745
29863
|
const parts = relativePath.split("/").filter(Boolean);
|
|
29746
29864
|
return parts[0] || "unknown";
|
|
29747
29865
|
}
|
|
@@ -29835,7 +29953,7 @@ async function tryExtractMarkdownDescription(mdPath, options = {}) {
|
|
|
29835
29953
|
}
|
|
29836
29954
|
}
|
|
29837
29955
|
async function getAgents(targetDir, rootDir = ".claude", config) {
|
|
29838
|
-
const agentsDir =
|
|
29956
|
+
const agentsDir = join14(targetDir, rootDir, "agents");
|
|
29839
29957
|
if (!await fileExists(agentsDir))
|
|
29840
29958
|
return [];
|
|
29841
29959
|
try {
|
|
@@ -29863,7 +29981,7 @@ async function getAgents(targetDir, rootDir = ".claude", config) {
|
|
|
29863
29981
|
}
|
|
29864
29982
|
}
|
|
29865
29983
|
async function getSkills(targetDir, rootDir = ".claude", config) {
|
|
29866
|
-
const skillsDir =
|
|
29984
|
+
const skillsDir = join14(targetDir, rootDir, "skills");
|
|
29867
29985
|
if (!await fileExists(skillsDir))
|
|
29868
29986
|
return [];
|
|
29869
29987
|
try {
|
|
@@ -29873,7 +29991,7 @@ async function getSkills(targetDir, rootDir = ".claude", config) {
|
|
|
29873
29991
|
const skillMdFiles = await listFiles(skillsDir, { recursive: true, pattern: "SKILL.md" });
|
|
29874
29992
|
const skills = await Promise.all(skillMdFiles.map(async (skillMdPath) => {
|
|
29875
29993
|
const skillDir = dirname3(skillMdPath);
|
|
29876
|
-
const indexYamlPath =
|
|
29994
|
+
const indexYamlPath = join14(skillDir, "index.yaml");
|
|
29877
29995
|
const { description, version } = await tryReadIndexYamlMetadata(indexYamlPath);
|
|
29878
29996
|
const relativePath = relative3(targetDir, skillDir);
|
|
29879
29997
|
return {
|
|
@@ -29892,7 +30010,7 @@ async function getSkills(targetDir, rootDir = ".claude", config) {
|
|
|
29892
30010
|
}
|
|
29893
30011
|
}
|
|
29894
30012
|
async function getGuides(targetDir, config) {
|
|
29895
|
-
const guidesDir =
|
|
30013
|
+
const guidesDir = join14(targetDir, "guides");
|
|
29896
30014
|
if (!await fileExists(guidesDir))
|
|
29897
30015
|
return [];
|
|
29898
30016
|
try {
|
|
@@ -29919,7 +30037,7 @@ async function getGuides(targetDir, config) {
|
|
|
29919
30037
|
}
|
|
29920
30038
|
var RULE_PRIORITY_ORDER = { MUST: 0, SHOULD: 1, MAY: 2 };
|
|
29921
30039
|
async function getRules(targetDir, rootDir = ".claude", config) {
|
|
29922
|
-
const rulesDir =
|
|
30040
|
+
const rulesDir = join14(targetDir, rootDir, "rules");
|
|
29923
30041
|
if (!await fileExists(rulesDir))
|
|
29924
30042
|
return [];
|
|
29925
30043
|
try {
|
|
@@ -29991,7 +30109,7 @@ function formatAsJson(components) {
|
|
|
29991
30109
|
console.log(JSON.stringify(components, null, 2));
|
|
29992
30110
|
}
|
|
29993
30111
|
async function getHooks(targetDir, rootDir = ".claude") {
|
|
29994
|
-
const hooksDir =
|
|
30112
|
+
const hooksDir = join14(targetDir, rootDir, "hooks");
|
|
29995
30113
|
if (!await fileExists(hooksDir))
|
|
29996
30114
|
return [];
|
|
29997
30115
|
try {
|
|
@@ -30009,7 +30127,7 @@ async function getHooks(targetDir, rootDir = ".claude") {
|
|
|
30009
30127
|
}
|
|
30010
30128
|
}
|
|
30011
30129
|
async function getContexts(targetDir, rootDir = ".claude") {
|
|
30012
|
-
const contextsDir =
|
|
30130
|
+
const contextsDir = join14(targetDir, rootDir, "contexts");
|
|
30013
30131
|
if (!await fileExists(contextsDir))
|
|
30014
30132
|
return [];
|
|
30015
30133
|
try {
|
|
@@ -30402,22 +30520,22 @@ async function securityCommand(_options = {}) {
|
|
|
30402
30520
|
|
|
30403
30521
|
// src/cli/serve-commands.ts
|
|
30404
30522
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
30405
|
-
import { join as
|
|
30523
|
+
import { join as join16 } from "node:path";
|
|
30406
30524
|
|
|
30407
30525
|
// src/cli/serve.ts
|
|
30408
30526
|
import { spawn } from "node:child_process";
|
|
30409
30527
|
import { existsSync as existsSync3 } from "node:fs";
|
|
30410
30528
|
import { readFile as readFile3, unlink, writeFile as writeFile3 } from "node:fs/promises";
|
|
30411
|
-
import { join as
|
|
30529
|
+
import { join as join15 } from "node:path";
|
|
30412
30530
|
var DEFAULT_PORT = 4321;
|
|
30413
|
-
var PID_FILE =
|
|
30531
|
+
var PID_FILE = join15(process.env.HOME ?? "~", ".omcustom-serve.pid");
|
|
30414
30532
|
function findServeBuildDir(projectRoot, options) {
|
|
30415
|
-
const localBuild =
|
|
30416
|
-
if (existsSync3(
|
|
30533
|
+
const localBuild = join15(projectRoot, "packages", "serve", "build");
|
|
30534
|
+
if (existsSync3(join15(localBuild, "index.js")))
|
|
30417
30535
|
return localBuild;
|
|
30418
30536
|
if (options?.skipNpmFallback !== true) {
|
|
30419
|
-
const npmBuild =
|
|
30420
|
-
if (existsSync3(
|
|
30537
|
+
const npmBuild = join15(import.meta.dirname, "..", "..", "packages", "serve", "build");
|
|
30538
|
+
if (existsSync3(join15(npmBuild, "index.js")))
|
|
30421
30539
|
return npmBuild;
|
|
30422
30540
|
}
|
|
30423
30541
|
return null;
|
|
@@ -30445,7 +30563,7 @@ async function startServeBackground(projectRoot, port = DEFAULT_PORT, buildDirOp
|
|
|
30445
30563
|
if (buildDir === null) {
|
|
30446
30564
|
return;
|
|
30447
30565
|
}
|
|
30448
|
-
const child = spawn("node", [
|
|
30566
|
+
const child = spawn("node", [join15(buildDir, "index.js")], {
|
|
30449
30567
|
env: {
|
|
30450
30568
|
...process.env,
|
|
30451
30569
|
OMCUSTOM_PORT: String(port),
|
|
@@ -30522,7 +30640,7 @@ function runForeground(projectRoot, port, buildDirOpts) {
|
|
|
30522
30640
|
process.exit(1);
|
|
30523
30641
|
}
|
|
30524
30642
|
console.log(`Web UI: http://localhost:${port}`);
|
|
30525
|
-
spawnSync2("node", [
|
|
30643
|
+
spawnSync2("node", [join16(buildDir, "index.js")], {
|
|
30526
30644
|
env: {
|
|
30527
30645
|
...process.env,
|
|
30528
30646
|
OMCUSTOM_PORT: String(port),
|
|
@@ -30541,12 +30659,12 @@ import { resolve as resolve3 } from "node:path";
|
|
|
30541
30659
|
init_fs();
|
|
30542
30660
|
import { existsSync as existsSync4 } from "node:fs";
|
|
30543
30661
|
import { cp as cp2, mkdir as mkdir2 } from "node:fs/promises";
|
|
30544
|
-
import { join as
|
|
30662
|
+
import { join as join17 } from "node:path";
|
|
30545
30663
|
async function loadVersions() {
|
|
30546
30664
|
try {
|
|
30547
30665
|
const packageRoot = getPackageRoot();
|
|
30548
|
-
const manifest = await readJsonFile(
|
|
30549
|
-
const pkg = await readJsonFile(
|
|
30666
|
+
const manifest = await readJsonFile(join17(packageRoot, "templates", "manifest.json"));
|
|
30667
|
+
const pkg = await readJsonFile(join17(packageRoot, "package.json"));
|
|
30550
30668
|
return { generatorVersion: pkg.version, templateVersion: manifest.version };
|
|
30551
30669
|
} catch {
|
|
30552
30670
|
return { generatorVersion: "0.0.0", templateVersion: "0.0.0" };
|
|
@@ -30616,7 +30734,7 @@ async function countFiles(dir2) {
|
|
|
30616
30734
|
return 0;
|
|
30617
30735
|
}
|
|
30618
30736
|
for (const entry of entries) {
|
|
30619
|
-
const full =
|
|
30737
|
+
const full = join17(current, entry);
|
|
30620
30738
|
try {
|
|
30621
30739
|
const s = await stat3(full);
|
|
30622
30740
|
if (s.isDirectory()) {
|
|
@@ -30631,19 +30749,19 @@ async function countFiles(dir2) {
|
|
|
30631
30749
|
return walk(dir2);
|
|
30632
30750
|
}
|
|
30633
30751
|
async function exportSnapshot(targetDir, outputPath) {
|
|
30634
|
-
const claudeDir =
|
|
30635
|
-
const guidesDir =
|
|
30752
|
+
const claudeDir = join17(targetDir, ".claude");
|
|
30753
|
+
const guidesDir = join17(targetDir, "guides");
|
|
30636
30754
|
if (!existsSync4(claudeDir)) {
|
|
30637
30755
|
return { success: false, exportPath: outputPath, fileCount: 0 };
|
|
30638
30756
|
}
|
|
30639
30757
|
await mkdir2(outputPath, { recursive: true });
|
|
30640
|
-
const destClaude =
|
|
30758
|
+
const destClaude = join17(outputPath, ".claude");
|
|
30641
30759
|
await cp2(claudeDir, destClaude, {
|
|
30642
30760
|
recursive: true,
|
|
30643
30761
|
filter: isExportable
|
|
30644
30762
|
});
|
|
30645
30763
|
if (existsSync4(guidesDir)) {
|
|
30646
|
-
await cp2(guidesDir,
|
|
30764
|
+
await cp2(guidesDir, join17(outputPath, "guides"), { recursive: true });
|
|
30647
30765
|
}
|
|
30648
30766
|
const lockfile = await generateCurrentLockfile(targetDir);
|
|
30649
30767
|
if (lockfile) {
|
|
@@ -30727,7 +30845,7 @@ import { constants as osConstants } from "node:os";
|
|
|
30727
30845
|
|
|
30728
30846
|
// src/core/updater.ts
|
|
30729
30847
|
init_package();
|
|
30730
|
-
import { join as
|
|
30848
|
+
import { join as join18 } from "node:path";
|
|
30731
30849
|
init_fs();
|
|
30732
30850
|
|
|
30733
30851
|
// src/core/entry-merger.ts
|
|
@@ -30982,7 +31100,7 @@ function resolveCustomizations(customizations, configPreserveFiles, targetDir) {
|
|
|
30982
31100
|
}
|
|
30983
31101
|
async function updateEntryDoc(targetDir, config, options) {
|
|
30984
31102
|
const layout = getProviderLayout();
|
|
30985
|
-
const entryPath =
|
|
31103
|
+
const entryPath = join18(targetDir, layout.entryFile);
|
|
30986
31104
|
const templateName = getEntryTemplateName2(config.language);
|
|
30987
31105
|
const templatePath = resolveTemplatePath(templateName);
|
|
30988
31106
|
if (!await fileExists(templatePath)) {
|
|
@@ -31020,7 +31138,7 @@ async function backfillStatusLineRefreshInterval(targetDir, options) {
|
|
|
31020
31138
|
return;
|
|
31021
31139
|
}
|
|
31022
31140
|
const layout = getProviderLayout();
|
|
31023
|
-
const settingsPath =
|
|
31141
|
+
const settingsPath = join18(targetDir, layout.rootDir, "settings.local.json");
|
|
31024
31142
|
if (!await fileExists(settingsPath)) {
|
|
31025
31143
|
return;
|
|
31026
31144
|
}
|
|
@@ -31106,7 +31224,7 @@ async function regenerateLockfile(targetDir, result) {
|
|
|
31106
31224
|
}
|
|
31107
31225
|
}
|
|
31108
31226
|
async function shouldSkipSelfUpdate2(targetDir, result) {
|
|
31109
|
-
const targetPkgPath =
|
|
31227
|
+
const targetPkgPath = join18(targetDir, "package.json");
|
|
31110
31228
|
if (await fileExists(targetPkgPath)) {
|
|
31111
31229
|
const targetPkg = await readJsonFile(targetPkgPath);
|
|
31112
31230
|
if (targetPkg.name === "oh-my-customcode") {
|
|
@@ -31245,11 +31363,11 @@ async function collectProtectedSkipPaths(srcPath, destPath, componentPath, force
|
|
|
31245
31363
|
const warnedPaths = [];
|
|
31246
31364
|
const updatedPaths = [];
|
|
31247
31365
|
for (const p of protectedRelative) {
|
|
31248
|
-
const targetFilePath =
|
|
31366
|
+
const targetFilePath = join18(targetDir, componentPath, p);
|
|
31249
31367
|
const lockfileKey = `${componentPath}/${p}`.replace(/\\/g, "/");
|
|
31250
31368
|
const shouldSkip = await shouldSkipProtectedFile(targetFilePath, lockfileKey, lockfile);
|
|
31251
31369
|
if (shouldSkip) {
|
|
31252
|
-
skipPaths.push(path3.relative(destPath,
|
|
31370
|
+
skipPaths.push(path3.relative(destPath, join18(destPath, p)));
|
|
31253
31371
|
warnedPaths.push(p);
|
|
31254
31372
|
} else {
|
|
31255
31373
|
updatedPaths.push(p);
|
|
@@ -31295,7 +31413,7 @@ async function updateComponent(targetDir, component, customizations, options, co
|
|
|
31295
31413
|
const preservedFiles = [];
|
|
31296
31414
|
const componentPath = getComponentPath2(component);
|
|
31297
31415
|
const srcPath = resolveTemplatePath(componentPath);
|
|
31298
|
-
const destPath =
|
|
31416
|
+
const destPath = join18(targetDir, componentPath);
|
|
31299
31417
|
const customComponents = config.customComponents || [];
|
|
31300
31418
|
const skipPaths = [];
|
|
31301
31419
|
if (customizations && !options.forceOverwriteAll) {
|
|
@@ -31337,7 +31455,7 @@ async function updateComponent(targetDir, component, customizations, options, co
|
|
|
31337
31455
|
}
|
|
31338
31456
|
skipPaths.push(...protectedSkipPaths);
|
|
31339
31457
|
const path3 = await import("node:path");
|
|
31340
|
-
const normalizedSkipPaths = skipPaths.map((p) => path3.relative(destPath,
|
|
31458
|
+
const normalizedSkipPaths = skipPaths.map((p) => path3.relative(destPath, join18(targetDir, p)));
|
|
31341
31459
|
const uniqueSkipPaths = [...new Set(normalizedSkipPaths)];
|
|
31342
31460
|
await copyDirectory(srcPath, destPath, {
|
|
31343
31461
|
overwrite: true,
|
|
@@ -31359,12 +31477,12 @@ async function syncRootLevelFiles(targetDir, options) {
|
|
|
31359
31477
|
const layout = getProviderLayout();
|
|
31360
31478
|
const synced = [];
|
|
31361
31479
|
for (const fileName of ROOT_LEVEL_FILES) {
|
|
31362
|
-
const srcPath = resolveTemplatePath(
|
|
31480
|
+
const srcPath = resolveTemplatePath(join18(layout.rootDir, fileName));
|
|
31363
31481
|
if (!await fileExists(srcPath)) {
|
|
31364
31482
|
continue;
|
|
31365
31483
|
}
|
|
31366
|
-
const destPath =
|
|
31367
|
-
await ensureDirectory(
|
|
31484
|
+
const destPath = join18(targetDir, layout.rootDir, fileName);
|
|
31485
|
+
await ensureDirectory(join18(destPath, ".."));
|
|
31368
31486
|
await fs3.copyFile(srcPath, destPath);
|
|
31369
31487
|
if (fileName.endsWith(".sh")) {
|
|
31370
31488
|
await fs3.chmod(destPath, 493);
|
|
@@ -31399,7 +31517,7 @@ async function removeDeprecatedFiles(targetDir, options) {
|
|
|
31399
31517
|
});
|
|
31400
31518
|
continue;
|
|
31401
31519
|
}
|
|
31402
|
-
const fullPath =
|
|
31520
|
+
const fullPath = join18(targetDir, entry.path);
|
|
31403
31521
|
if (await fileExists(fullPath)) {
|
|
31404
31522
|
await fs3.unlink(fullPath);
|
|
31405
31523
|
removed.push(entry.path);
|
|
@@ -31440,7 +31558,7 @@ async function syncNamespaceInFile(targetFilePath, upstreamFilePath) {
|
|
|
31440
31558
|
async function processNamespaceSyncEntry(entry, relPath, fullSrcPath, destPath, componentPath, lockfile) {
|
|
31441
31559
|
if (!entry.isFile() || !entry.name.endsWith(".md"))
|
|
31442
31560
|
return null;
|
|
31443
|
-
const targetFilePath =
|
|
31561
|
+
const targetFilePath = join18(destPath, relPath);
|
|
31444
31562
|
const lockfileKey = `${componentPath}/${relPath}`.replace(/\\/g, "/");
|
|
31445
31563
|
const shouldSkip = await shouldSkipProtectedFile(targetFilePath, lockfileKey, lockfile);
|
|
31446
31564
|
if (shouldSkip)
|
|
@@ -31455,7 +31573,7 @@ async function applyNamespaceSync(targetDir, component, lockfile) {
|
|
|
31455
31573
|
return [];
|
|
31456
31574
|
const componentPath = getComponentPath2(component);
|
|
31457
31575
|
const srcPath = resolveTemplatePath(componentPath);
|
|
31458
|
-
const destPath =
|
|
31576
|
+
const destPath = join18(targetDir, componentPath);
|
|
31459
31577
|
const fs3 = await import("node:fs/promises");
|
|
31460
31578
|
const synced = [];
|
|
31461
31579
|
const queue = [{ dir: srcPath, relDir: "" }];
|
|
@@ -31469,7 +31587,7 @@ async function applyNamespaceSync(targetDir, component, lockfile) {
|
|
|
31469
31587
|
}
|
|
31470
31588
|
for (const entry of entries) {
|
|
31471
31589
|
const relPath = relDir ? `${relDir}/${entry.name}` : entry.name;
|
|
31472
|
-
const fullSrcPath =
|
|
31590
|
+
const fullSrcPath = join18(dir2, entry.name);
|
|
31473
31591
|
if (entry.isDirectory()) {
|
|
31474
31592
|
queue.push({ dir: fullSrcPath, relDir: relPath });
|
|
31475
31593
|
continue;
|
|
@@ -31492,26 +31610,26 @@ function getComponentPath2(component) {
|
|
|
31492
31610
|
}
|
|
31493
31611
|
async function backupInstallation(targetDir) {
|
|
31494
31612
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
31495
|
-
const backupDir =
|
|
31613
|
+
const backupDir = join18(targetDir, `.omcustom-backup-${timestamp}`);
|
|
31496
31614
|
const fs3 = await import("node:fs/promises");
|
|
31497
31615
|
await ensureDirectory(backupDir);
|
|
31498
31616
|
const layout = getProviderLayout();
|
|
31499
31617
|
const dirsToBackup = [layout.rootDir, "guides"];
|
|
31500
31618
|
for (const dir2 of dirsToBackup) {
|
|
31501
|
-
const srcPath =
|
|
31619
|
+
const srcPath = join18(targetDir, dir2);
|
|
31502
31620
|
if (await fileExists(srcPath)) {
|
|
31503
|
-
const destPath =
|
|
31621
|
+
const destPath = join18(backupDir, dir2);
|
|
31504
31622
|
await copyDirectory(srcPath, destPath, { overwrite: true });
|
|
31505
31623
|
}
|
|
31506
31624
|
}
|
|
31507
|
-
const entryPath =
|
|
31625
|
+
const entryPath = join18(targetDir, layout.entryFile);
|
|
31508
31626
|
if (await fileExists(entryPath)) {
|
|
31509
|
-
await fs3.copyFile(entryPath,
|
|
31627
|
+
await fs3.copyFile(entryPath, join18(backupDir, layout.entryFile));
|
|
31510
31628
|
}
|
|
31511
31629
|
return backupDir;
|
|
31512
31630
|
}
|
|
31513
31631
|
async function loadCustomizationManifest(targetDir) {
|
|
31514
|
-
const manifestPath =
|
|
31632
|
+
const manifestPath = join18(targetDir, CUSTOMIZATION_MANIFEST_FILE);
|
|
31515
31633
|
if (await fileExists(manifestPath)) {
|
|
31516
31634
|
return readJsonFile(manifestPath);
|
|
31517
31635
|
}
|
package/dist/index.js
CHANGED