oh-my-customcode 0.10.1 → 0.10.2

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.
Files changed (32) hide show
  1. package/dist/cli/index.js +264 -2
  2. package/dist/index.js +281 -2
  3. package/package.json +1 -1
  4. package/templates/.claude/agents/mgr-gitnerd.md +1 -1
  5. package/templates/.claude/agents/mgr-sauron.md +3 -3
  6. package/templates/.claude/rules/MUST-continuous-improvement.md +1 -1
  7. package/templates/.claude/rules/MUST-intent-transparency.md +1 -1
  8. package/templates/.claude/rules/MUST-orchestrator-coordination.md +1 -1
  9. package/templates/.claude/rules/MUST-sync-verification.md +1 -1
  10. package/templates/.claude/rules/SHOULD-agent-teams.md +1 -1
  11. package/templates/.claude/rules/index.yaml +4 -4
  12. package/templates/.claude/skills/de-lead-routing/SKILL.md +13 -0
  13. package/templates/.claude/skills/dev-lead-routing/SKILL.md +14 -0
  14. package/templates/.claude/skills/qa-lead-routing/SKILL.md +13 -0
  15. package/templates/.claude/skills/sauron-watch/SKILL.md +4 -4
  16. package/templates/.claude/skills/secretary-routing/SKILL.md +14 -1
  17. package/templates/.codex/agents/mgr-gitnerd.md +1 -1
  18. package/templates/.codex/agents/mgr-sauron.md +3 -3
  19. package/templates/.codex/rules/MUST-continuous-improvement.md +1 -1
  20. package/templates/.codex/rules/MUST-intent-transparency.md +1 -1
  21. package/templates/.codex/rules/MUST-orchestrator-coordination.md +1 -1
  22. package/templates/.codex/rules/MUST-sync-verification.md +1 -1
  23. package/templates/.codex/rules/SHOULD-agent-teams.md +1 -1
  24. package/templates/.codex/rules/index.yaml +4 -4
  25. package/templates/.codex/skills/de-lead-routing/SKILL.md +13 -0
  26. package/templates/.codex/skills/dev-lead-routing/SKILL.md +14 -0
  27. package/templates/.codex/skills/qa-lead-routing/SKILL.md +13 -0
  28. package/templates/.codex/skills/sauron-watch/SKILL.md +4 -4
  29. package/templates/.codex/skills/secretary-routing/SKILL.md +14 -1
  30. package/templates/CLAUDE.md.en +8 -29
  31. package/templates/CLAUDE.md.ko +8 -29
  32. package/templates/guides/index.yaml +74 -0
package/dist/cli/index.js CHANGED
@@ -13518,8 +13518,260 @@ async function doctorCommand(options = {}) {
13518
13518
  import { join as join5 } from "node:path";
13519
13519
 
13520
13520
  // src/core/installer.ts
13521
- import { copyFile as fsCopyFile, rename } from "node:fs/promises";
13521
+ import { readFile as fsReadFile, writeFile as fsWriteFile, rename } from "node:fs/promises";
13522
13522
  import { basename, join as join4 } from "node:path";
13523
+
13524
+ // src/core/git-workflow.ts
13525
+ import { execFileSync } from "node:child_process";
13526
+ function execGit(args, cwd) {
13527
+ try {
13528
+ return execFileSync("git", args, {
13529
+ cwd,
13530
+ encoding: "utf-8",
13531
+ stdio: ["pipe", "pipe", "pipe"],
13532
+ env: { ...process.env, GIT_DIR: undefined, GIT_WORK_TREE: undefined }
13533
+ }).trim();
13534
+ } catch {
13535
+ return "";
13536
+ }
13537
+ }
13538
+ function isGitRepo(cwd) {
13539
+ return execGit(["rev-parse", "--is-inside-work-tree"], cwd) === "true";
13540
+ }
13541
+ function detectDefaultBranch(cwd) {
13542
+ const remoteHead = execGit(["symbolic-ref", "refs/remotes/origin/HEAD"], cwd);
13543
+ if (remoteHead) {
13544
+ return remoteHead.replace("refs/remotes/origin/", "");
13545
+ }
13546
+ const branches = getLocalBranches(cwd);
13547
+ for (const candidate of ["main", "master", "develop"]) {
13548
+ if (branches.includes(candidate)) {
13549
+ return candidate;
13550
+ }
13551
+ }
13552
+ const head = execGit(["symbolic-ref", "--short", "HEAD"], cwd);
13553
+ if (head) {
13554
+ return head;
13555
+ }
13556
+ return "main";
13557
+ }
13558
+ function getLocalBranches(cwd) {
13559
+ const output = execGit(["branch", "--format=%(refname:short)"], cwd);
13560
+ if (!output)
13561
+ return [];
13562
+ return output.split(`
13563
+ `).filter(Boolean);
13564
+ }
13565
+ function getRemoteBranches(cwd) {
13566
+ const output = execGit(["branch", "-r", "--format=%(refname:short)"], cwd);
13567
+ if (!output)
13568
+ return [];
13569
+ return output.split(`
13570
+ `).filter(Boolean).map((b) => b.replace(/^origin\//, "")).filter((b) => b !== "HEAD");
13571
+ }
13572
+ function detectBranchPatterns(branches) {
13573
+ const prefixes = new Set;
13574
+ const knownPrefixes = ["feature", "release", "hotfix", "bugfix", "fix", "chore", "docs"];
13575
+ for (const branch of branches) {
13576
+ const slashIdx = branch.indexOf("/");
13577
+ if (slashIdx > 0) {
13578
+ const prefix = branch.substring(0, slashIdx);
13579
+ if (knownPrefixes.includes(prefix)) {
13580
+ prefixes.add(`${prefix}/*`);
13581
+ }
13582
+ }
13583
+ }
13584
+ return [...prefixes].sort();
13585
+ }
13586
+ function determineWorkflowType(hasDevelop, branchPatterns, allBranches) {
13587
+ const hasFlowPatterns = branchPatterns.some((p) => p === "feature/*" || p === "release/*" || p === "hotfix/*");
13588
+ if (hasDevelop && hasFlowPatterns) {
13589
+ return "git-flow";
13590
+ }
13591
+ const hasFeatureBranches = allBranches.some((b) => b.includes("/"));
13592
+ if (!hasDevelop && hasFeatureBranches) {
13593
+ return "github-flow";
13594
+ }
13595
+ if (!hasDevelop && !hasFeatureBranches) {
13596
+ return "trunk-based";
13597
+ }
13598
+ if (hasDevelop) {
13599
+ return "git-flow";
13600
+ }
13601
+ return "github-flow";
13602
+ }
13603
+ function detectGitWorkflow(cwd) {
13604
+ if (!isGitRepo(cwd)) {
13605
+ return null;
13606
+ }
13607
+ const localBranches = getLocalBranches(cwd);
13608
+ const remoteBranches = getRemoteBranches(cwd);
13609
+ const allBranches = [...new Set([...localBranches, ...remoteBranches])];
13610
+ const defaultBranch = detectDefaultBranch(cwd);
13611
+ const hasDevelop = localBranches.includes("develop") || remoteBranches.includes("develop");
13612
+ const branchPatterns = detectBranchPatterns(allBranches);
13613
+ const type = determineWorkflowType(hasDevelop, branchPatterns, allBranches);
13614
+ return {
13615
+ type,
13616
+ defaultBranch,
13617
+ hasDevelop,
13618
+ branchPatterns
13619
+ };
13620
+ }
13621
+ function renderGitWorkflowEN(result) {
13622
+ switch (result.type) {
13623
+ case "git-flow":
13624
+ return renderGitFlowEN(result);
13625
+ case "github-flow":
13626
+ return renderGithubFlowEN(result);
13627
+ case "trunk-based":
13628
+ return renderTrunkBasedEN(result);
13629
+ }
13630
+ }
13631
+ function renderGitWorkflowKO(result) {
13632
+ switch (result.type) {
13633
+ case "git-flow":
13634
+ return renderGitFlowKO(result);
13635
+ case "github-flow":
13636
+ return renderGithubFlowKO(result);
13637
+ case "trunk-based":
13638
+ return renderTrunkBasedKO(result);
13639
+ }
13640
+ }
13641
+ function renderGitFlowEN(r) {
13642
+ const lines = [
13643
+ "## Git Workflow (MUST follow)",
13644
+ "",
13645
+ "| Branch | Purpose |",
13646
+ "|--------|---------|",
13647
+ `| \`${r.defaultBranch}\` | Main development branch (default) |`
13648
+ ];
13649
+ if (r.branchPatterns.includes("feature/*")) {
13650
+ lines.push(`| \`feature/*\` | New features -> PR to ${r.defaultBranch} |`);
13651
+ }
13652
+ if (r.branchPatterns.includes("release/*")) {
13653
+ lines.push("| `release/*` | Release preparation -> **npm publish here only** |");
13654
+ }
13655
+ if (r.branchPatterns.includes("hotfix/*")) {
13656
+ lines.push(`| \`hotfix/*\` | Critical fixes -> tag -> publish -> merge to ${r.defaultBranch} |`);
13657
+ }
13658
+ if (r.branchPatterns.includes("bugfix/*")) {
13659
+ lines.push(`| \`bugfix/*\` | Bug fixes -> PR to ${r.defaultBranch} |`);
13660
+ }
13661
+ lines.push("");
13662
+ lines.push("**Key rules:**");
13663
+ lines.push(`- Create feature branches from \`${r.defaultBranch}\``);
13664
+ lines.push("- Use conventional commits: `feat:`, `fix:`, `docs:`, `chore:`");
13665
+ lines.push('- Include "Closes #N" in commit message to auto-close issues');
13666
+ return lines.join(`
13667
+ `);
13668
+ }
13669
+ function renderGithubFlowEN(r) {
13670
+ const lines = [
13671
+ "## Git Workflow (MUST follow)",
13672
+ "",
13673
+ "| Branch | Purpose |",
13674
+ "|--------|---------|",
13675
+ `| \`${r.defaultBranch}\` | Production-ready code (default) |`,
13676
+ `| \`feature/*\` | New features -> PR to ${r.defaultBranch} |`,
13677
+ "",
13678
+ "**Key rules:**",
13679
+ `- Create feature branches from \`${r.defaultBranch}\``,
13680
+ `- All changes go through PR to \`${r.defaultBranch}\``,
13681
+ "- Use conventional commits: `feat:`, `fix:`, `docs:`, `chore:`",
13682
+ '- Include "Closes #N" in commit message to auto-close issues'
13683
+ ];
13684
+ return lines.join(`
13685
+ `);
13686
+ }
13687
+ function renderTrunkBasedEN(r) {
13688
+ const lines = [
13689
+ "## Git Workflow (MUST follow)",
13690
+ "",
13691
+ "| Branch | Purpose |",
13692
+ "|--------|---------|",
13693
+ `| \`${r.defaultBranch}\` | Main trunk (default) |`,
13694
+ "",
13695
+ "**Key rules:**",
13696
+ `- Commit directly to \`${r.defaultBranch}\` or use short-lived branches`,
13697
+ "- Keep branches short-lived (merge within 1-2 days)",
13698
+ "- Use conventional commits: `feat:`, `fix:`, `docs:`, `chore:`"
13699
+ ];
13700
+ return lines.join(`
13701
+ `);
13702
+ }
13703
+ function renderGitFlowKO(r) {
13704
+ const lines = [
13705
+ "## Git 워크플로우 (반드시 준수)",
13706
+ "",
13707
+ "| 브랜치 | 용도 |",
13708
+ "|--------|------|",
13709
+ `| \`${r.defaultBranch}\` | 메인 개발 브랜치 (기본) |`
13710
+ ];
13711
+ if (r.branchPatterns.includes("feature/*")) {
13712
+ lines.push(`| \`feature/*\` | 새 기능 -> ${r.defaultBranch}으로 PR |`);
13713
+ }
13714
+ if (r.branchPatterns.includes("release/*")) {
13715
+ lines.push("| `release/*` | 릴리스 준비 -> **npm 배포는 여기서만** |");
13716
+ }
13717
+ if (r.branchPatterns.includes("hotfix/*")) {
13718
+ lines.push(`| \`hotfix/*\` | 긴급 수정 -> 태그 -> 배포 -> ${r.defaultBranch} 머지 |`);
13719
+ }
13720
+ if (r.branchPatterns.includes("bugfix/*")) {
13721
+ lines.push(`| \`bugfix/*\` | 버그 수정 -> ${r.defaultBranch}으로 PR |`);
13722
+ }
13723
+ lines.push("");
13724
+ lines.push("**핵심 규칙:**");
13725
+ lines.push(`- \`${r.defaultBranch}\`에서 feature 브랜치 생성`);
13726
+ lines.push("- Conventional commits 사용: `feat:`, `fix:`, `docs:`, `chore:`");
13727
+ lines.push('- 커밋 메시지에 "Closes #N" 포함시 이슈 자동 종료');
13728
+ return lines.join(`
13729
+ `);
13730
+ }
13731
+ function renderGithubFlowKO(r) {
13732
+ const lines = [
13733
+ "## Git 워크플로우 (반드시 준수)",
13734
+ "",
13735
+ "| 브랜치 | 용도 |",
13736
+ "|--------|------|",
13737
+ `| \`${r.defaultBranch}\` | 프로덕션 준비 코드 (기본) |`,
13738
+ `| \`feature/*\` | 새 기능 -> ${r.defaultBranch}으로 PR |`,
13739
+ "",
13740
+ "**핵심 규칙:**",
13741
+ `- \`${r.defaultBranch}\`에서 feature 브랜치 생성`,
13742
+ `- 모든 변경은 \`${r.defaultBranch}\`으로 PR을 통해 진행`,
13743
+ "- Conventional commits 사용: `feat:`, `fix:`, `docs:`, `chore:`",
13744
+ '- 커밋 메시지에 "Closes #N" 포함시 이슈 자동 종료'
13745
+ ];
13746
+ return lines.join(`
13747
+ `);
13748
+ }
13749
+ function renderTrunkBasedKO(r) {
13750
+ const lines = [
13751
+ "## Git 워크플로우 (반드시 준수)",
13752
+ "",
13753
+ "| 브랜치 | 용도 |",
13754
+ "|--------|------|",
13755
+ `| \`${r.defaultBranch}\` | 메인 트렁크 (기본) |`,
13756
+ "",
13757
+ "**핵심 규칙:**",
13758
+ `- \`${r.defaultBranch}\`에 직접 커밋하거나 단기 브랜치 사용`,
13759
+ "- 브랜치는 단기 유지 (1-2일 내 머지)",
13760
+ "- Conventional commits 사용: `feat:`, `fix:`, `docs:`, `chore:`"
13761
+ ];
13762
+ return lines.join(`
13763
+ `);
13764
+ }
13765
+ function getDefaultWorkflow() {
13766
+ return {
13767
+ type: "github-flow",
13768
+ defaultBranch: "main",
13769
+ hasDevelop: false,
13770
+ branchPatterns: ["feature/*"]
13771
+ };
13772
+ }
13773
+
13774
+ // src/core/installer.ts
13523
13775
  var DEFAULT_LANGUAGE2 = "en";
13524
13776
  function getTemplateDir() {
13525
13777
  const packageRoot = getPackageRoot();
@@ -13654,6 +13906,11 @@ async function installComponent(targetDir, provider, component, options) {
13654
13906
  debug("install.component_installed", { component });
13655
13907
  return true;
13656
13908
  }
13909
+ var GIT_WORKFLOW_PLACEHOLDER = "<!-- omcustom:git-workflow -->";
13910
+ function renderGitWorkflowSection(targetDir, language) {
13911
+ const result = detectGitWorkflow(targetDir) ?? getDefaultWorkflow();
13912
+ return language === "ko" ? renderGitWorkflowKO(result) : renderGitWorkflowEN(result);
13913
+ }
13657
13914
  async function installEntryDoc(targetDir, provider, language, overwrite = false) {
13658
13915
  const layout = getProviderLayout(provider);
13659
13916
  const templateFile = getEntryTemplateName(provider, language);
@@ -13668,7 +13925,12 @@ async function installEntryDoc(targetDir, provider, language, overwrite = false)
13668
13925
  debug("install.entry_md_skipped", { reason: "exists", language, entry: layout.entryFile });
13669
13926
  return false;
13670
13927
  }
13671
- await fsCopyFile(srcPath, destPath);
13928
+ let content = await fsReadFile(srcPath, "utf-8");
13929
+ if (content.includes(GIT_WORKFLOW_PLACEHOLDER)) {
13930
+ const workflowSection = renderGitWorkflowSection(targetDir, language);
13931
+ content = content.replace(GIT_WORKFLOW_PLACEHOLDER, workflowSection);
13932
+ }
13933
+ await fsWriteFile(destPath, content, "utf-8");
13672
13934
  debug("install.entry_md_installed", { language, entry: layout.entryFile });
13673
13935
  return true;
13674
13936
  }
package/dist/index.js CHANGED
@@ -1,4 +1,20 @@
1
1
  import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
2
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
19
 
4
20
  // src/core/config.ts
@@ -503,8 +519,257 @@ function migrateConfig(config) {
503
519
  migrated.configVersion = CURRENT_CONFIG_VERSION;
504
520
  return migrated;
505
521
  }
522
+ // src/core/git-workflow.ts
523
+ import { execFileSync } from "node:child_process";
524
+ function execGit(args, cwd) {
525
+ try {
526
+ return execFileSync("git", args, {
527
+ cwd,
528
+ encoding: "utf-8",
529
+ stdio: ["pipe", "pipe", "pipe"],
530
+ env: { ...process.env, GIT_DIR: undefined, GIT_WORK_TREE: undefined }
531
+ }).trim();
532
+ } catch {
533
+ return "";
534
+ }
535
+ }
536
+ function isGitRepo(cwd) {
537
+ return execGit(["rev-parse", "--is-inside-work-tree"], cwd) === "true";
538
+ }
539
+ function detectDefaultBranch(cwd) {
540
+ const remoteHead = execGit(["symbolic-ref", "refs/remotes/origin/HEAD"], cwd);
541
+ if (remoteHead) {
542
+ return remoteHead.replace("refs/remotes/origin/", "");
543
+ }
544
+ const branches = getLocalBranches(cwd);
545
+ for (const candidate of ["main", "master", "develop"]) {
546
+ if (branches.includes(candidate)) {
547
+ return candidate;
548
+ }
549
+ }
550
+ const head = execGit(["symbolic-ref", "--short", "HEAD"], cwd);
551
+ if (head) {
552
+ return head;
553
+ }
554
+ return "main";
555
+ }
556
+ function getLocalBranches(cwd) {
557
+ const output = execGit(["branch", "--format=%(refname:short)"], cwd);
558
+ if (!output)
559
+ return [];
560
+ return output.split(`
561
+ `).filter(Boolean);
562
+ }
563
+ function getRemoteBranches(cwd) {
564
+ const output = execGit(["branch", "-r", "--format=%(refname:short)"], cwd);
565
+ if (!output)
566
+ return [];
567
+ return output.split(`
568
+ `).filter(Boolean).map((b) => b.replace(/^origin\//, "")).filter((b) => b !== "HEAD");
569
+ }
570
+ function detectBranchPatterns(branches) {
571
+ const prefixes = new Set;
572
+ const knownPrefixes = ["feature", "release", "hotfix", "bugfix", "fix", "chore", "docs"];
573
+ for (const branch of branches) {
574
+ const slashIdx = branch.indexOf("/");
575
+ if (slashIdx > 0) {
576
+ const prefix = branch.substring(0, slashIdx);
577
+ if (knownPrefixes.includes(prefix)) {
578
+ prefixes.add(`${prefix}/*`);
579
+ }
580
+ }
581
+ }
582
+ return [...prefixes].sort();
583
+ }
584
+ function determineWorkflowType(hasDevelop, branchPatterns, allBranches) {
585
+ const hasFlowPatterns = branchPatterns.some((p) => p === "feature/*" || p === "release/*" || p === "hotfix/*");
586
+ if (hasDevelop && hasFlowPatterns) {
587
+ return "git-flow";
588
+ }
589
+ const hasFeatureBranches = allBranches.some((b) => b.includes("/"));
590
+ if (!hasDevelop && hasFeatureBranches) {
591
+ return "github-flow";
592
+ }
593
+ if (!hasDevelop && !hasFeatureBranches) {
594
+ return "trunk-based";
595
+ }
596
+ if (hasDevelop) {
597
+ return "git-flow";
598
+ }
599
+ return "github-flow";
600
+ }
601
+ function detectGitWorkflow(cwd) {
602
+ if (!isGitRepo(cwd)) {
603
+ return null;
604
+ }
605
+ const localBranches = getLocalBranches(cwd);
606
+ const remoteBranches = getRemoteBranches(cwd);
607
+ const allBranches = [...new Set([...localBranches, ...remoteBranches])];
608
+ const defaultBranch = detectDefaultBranch(cwd);
609
+ const hasDevelop = localBranches.includes("develop") || remoteBranches.includes("develop");
610
+ const branchPatterns = detectBranchPatterns(allBranches);
611
+ const type = determineWorkflowType(hasDevelop, branchPatterns, allBranches);
612
+ return {
613
+ type,
614
+ defaultBranch,
615
+ hasDevelop,
616
+ branchPatterns
617
+ };
618
+ }
619
+ function renderGitWorkflowEN(result) {
620
+ switch (result.type) {
621
+ case "git-flow":
622
+ return renderGitFlowEN(result);
623
+ case "github-flow":
624
+ return renderGithubFlowEN(result);
625
+ case "trunk-based":
626
+ return renderTrunkBasedEN(result);
627
+ }
628
+ }
629
+ function renderGitWorkflowKO(result) {
630
+ switch (result.type) {
631
+ case "git-flow":
632
+ return renderGitFlowKO(result);
633
+ case "github-flow":
634
+ return renderGithubFlowKO(result);
635
+ case "trunk-based":
636
+ return renderTrunkBasedKO(result);
637
+ }
638
+ }
639
+ function renderGitFlowEN(r) {
640
+ const lines = [
641
+ "## Git Workflow (MUST follow)",
642
+ "",
643
+ "| Branch | Purpose |",
644
+ "|--------|---------|",
645
+ `| \`${r.defaultBranch}\` | Main development branch (default) |`
646
+ ];
647
+ if (r.branchPatterns.includes("feature/*")) {
648
+ lines.push(`| \`feature/*\` | New features -> PR to ${r.defaultBranch} |`);
649
+ }
650
+ if (r.branchPatterns.includes("release/*")) {
651
+ lines.push("| `release/*` | Release preparation -> **npm publish here only** |");
652
+ }
653
+ if (r.branchPatterns.includes("hotfix/*")) {
654
+ lines.push(`| \`hotfix/*\` | Critical fixes -> tag -> publish -> merge to ${r.defaultBranch} |`);
655
+ }
656
+ if (r.branchPatterns.includes("bugfix/*")) {
657
+ lines.push(`| \`bugfix/*\` | Bug fixes -> PR to ${r.defaultBranch} |`);
658
+ }
659
+ lines.push("");
660
+ lines.push("**Key rules:**");
661
+ lines.push(`- Create feature branches from \`${r.defaultBranch}\``);
662
+ lines.push("- Use conventional commits: `feat:`, `fix:`, `docs:`, `chore:`");
663
+ lines.push('- Include "Closes #N" in commit message to auto-close issues');
664
+ return lines.join(`
665
+ `);
666
+ }
667
+ function renderGithubFlowEN(r) {
668
+ const lines = [
669
+ "## Git Workflow (MUST follow)",
670
+ "",
671
+ "| Branch | Purpose |",
672
+ "|--------|---------|",
673
+ `| \`${r.defaultBranch}\` | Production-ready code (default) |`,
674
+ `| \`feature/*\` | New features -> PR to ${r.defaultBranch} |`,
675
+ "",
676
+ "**Key rules:**",
677
+ `- Create feature branches from \`${r.defaultBranch}\``,
678
+ `- All changes go through PR to \`${r.defaultBranch}\``,
679
+ "- Use conventional commits: `feat:`, `fix:`, `docs:`, `chore:`",
680
+ '- Include "Closes #N" in commit message to auto-close issues'
681
+ ];
682
+ return lines.join(`
683
+ `);
684
+ }
685
+ function renderTrunkBasedEN(r) {
686
+ const lines = [
687
+ "## Git Workflow (MUST follow)",
688
+ "",
689
+ "| Branch | Purpose |",
690
+ "|--------|---------|",
691
+ `| \`${r.defaultBranch}\` | Main trunk (default) |`,
692
+ "",
693
+ "**Key rules:**",
694
+ `- Commit directly to \`${r.defaultBranch}\` or use short-lived branches`,
695
+ "- Keep branches short-lived (merge within 1-2 days)",
696
+ "- Use conventional commits: `feat:`, `fix:`, `docs:`, `chore:`"
697
+ ];
698
+ return lines.join(`
699
+ `);
700
+ }
701
+ function renderGitFlowKO(r) {
702
+ const lines = [
703
+ "## Git 워크플로우 (반드시 준수)",
704
+ "",
705
+ "| 브랜치 | 용도 |",
706
+ "|--------|------|",
707
+ `| \`${r.defaultBranch}\` | 메인 개발 브랜치 (기본) |`
708
+ ];
709
+ if (r.branchPatterns.includes("feature/*")) {
710
+ lines.push(`| \`feature/*\` | 새 기능 -> ${r.defaultBranch}으로 PR |`);
711
+ }
712
+ if (r.branchPatterns.includes("release/*")) {
713
+ lines.push("| `release/*` | 릴리스 준비 -> **npm 배포는 여기서만** |");
714
+ }
715
+ if (r.branchPatterns.includes("hotfix/*")) {
716
+ lines.push(`| \`hotfix/*\` | 긴급 수정 -> 태그 -> 배포 -> ${r.defaultBranch} 머지 |`);
717
+ }
718
+ if (r.branchPatterns.includes("bugfix/*")) {
719
+ lines.push(`| \`bugfix/*\` | 버그 수정 -> ${r.defaultBranch}으로 PR |`);
720
+ }
721
+ lines.push("");
722
+ lines.push("**핵심 규칙:**");
723
+ lines.push(`- \`${r.defaultBranch}\`에서 feature 브랜치 생성`);
724
+ lines.push("- Conventional commits 사용: `feat:`, `fix:`, `docs:`, `chore:`");
725
+ lines.push('- 커밋 메시지에 "Closes #N" 포함시 이슈 자동 종료');
726
+ return lines.join(`
727
+ `);
728
+ }
729
+ function renderGithubFlowKO(r) {
730
+ const lines = [
731
+ "## Git 워크플로우 (반드시 준수)",
732
+ "",
733
+ "| 브랜치 | 용도 |",
734
+ "|--------|------|",
735
+ `| \`${r.defaultBranch}\` | 프로덕션 준비 코드 (기본) |`,
736
+ `| \`feature/*\` | 새 기능 -> ${r.defaultBranch}으로 PR |`,
737
+ "",
738
+ "**핵심 규칙:**",
739
+ `- \`${r.defaultBranch}\`에서 feature 브랜치 생성`,
740
+ `- 모든 변경은 \`${r.defaultBranch}\`으로 PR을 통해 진행`,
741
+ "- Conventional commits 사용: `feat:`, `fix:`, `docs:`, `chore:`",
742
+ '- 커밋 메시지에 "Closes #N" 포함시 이슈 자동 종료'
743
+ ];
744
+ return lines.join(`
745
+ `);
746
+ }
747
+ function renderTrunkBasedKO(r) {
748
+ const lines = [
749
+ "## Git 워크플로우 (반드시 준수)",
750
+ "",
751
+ "| 브랜치 | 용도 |",
752
+ "|--------|------|",
753
+ `| \`${r.defaultBranch}\` | 메인 트렁크 (기본) |`,
754
+ "",
755
+ "**핵심 규칙:**",
756
+ `- \`${r.defaultBranch}\`에 직접 커밋하거나 단기 브랜치 사용`,
757
+ "- 브랜치는 단기 유지 (1-2일 내 머지)",
758
+ "- Conventional commits 사용: `feat:`, `fix:`, `docs:`, `chore:`"
759
+ ];
760
+ return lines.join(`
761
+ `);
762
+ }
763
+ function getDefaultWorkflow() {
764
+ return {
765
+ type: "github-flow",
766
+ defaultBranch: "main",
767
+ hasDevelop: false,
768
+ branchPatterns: ["feature/*"]
769
+ };
770
+ }
506
771
  // src/core/installer.ts
507
- import { copyFile as fsCopyFile, rename } from "node:fs/promises";
772
+ import { readFile as fsReadFile, writeFile as fsWriteFile, rename } from "node:fs/promises";
508
773
  import { basename, join as join3 } from "node:path";
509
774
 
510
775
  // src/core/layout.ts
@@ -735,6 +1000,11 @@ async function installComponent(targetDir, provider, component, options) {
735
1000
  debug("install.component_installed", { component });
736
1001
  return true;
737
1002
  }
1003
+ var GIT_WORKFLOW_PLACEHOLDER = "<!-- omcustom:git-workflow -->";
1004
+ function renderGitWorkflowSection(targetDir, language) {
1005
+ const result = detectGitWorkflow(targetDir) ?? getDefaultWorkflow();
1006
+ return language === "ko" ? renderGitWorkflowKO(result) : renderGitWorkflowEN(result);
1007
+ }
738
1008
  async function installEntryDoc(targetDir, provider, language, overwrite = false) {
739
1009
  const layout = getProviderLayout(provider);
740
1010
  const templateFile = getEntryTemplateName(provider, language);
@@ -749,7 +1019,12 @@ async function installEntryDoc(targetDir, provider, language, overwrite = false)
749
1019
  debug("install.entry_md_skipped", { reason: "exists", language, entry: layout.entryFile });
750
1020
  return false;
751
1021
  }
752
- await fsCopyFile(srcPath, destPath);
1022
+ let content = await fsReadFile(srcPath, "utf-8");
1023
+ if (content.includes(GIT_WORKFLOW_PLACEHOLDER)) {
1024
+ const workflowSection = renderGitWorkflowSection(targetDir, language);
1025
+ content = content.replace(GIT_WORKFLOW_PLACEHOLDER, workflowSection);
1026
+ }
1027
+ await fsWriteFile(destPath, content, "utf-8");
753
1028
  debug("install.entry_md_installed", { language, entry: layout.entryFile });
754
1029
  return true;
755
1030
  }
@@ -1399,6 +1674,8 @@ export {
1399
1674
  setLocale,
1400
1675
  saveConfig,
1401
1676
  resolveTemplatePath,
1677
+ renderGitWorkflowKO,
1678
+ renderGitWorkflowEN,
1402
1679
  readJsonFile,
1403
1680
  preserveCustomizations,
1404
1681
  mergeConfig,
@@ -1408,12 +1685,14 @@ export {
1408
1685
  getTemplateManifest,
1409
1686
  getProviderLayout,
1410
1687
  getPackageRoot,
1688
+ getDefaultWorkflow,
1411
1689
  getDefaultConfig,
1412
1690
  getConfigPath,
1413
1691
  fileExists,
1414
1692
  error,
1415
1693
  ensureDirectory,
1416
1694
  detectProvider,
1695
+ detectGitWorkflow,
1417
1696
  src_default as default,
1418
1697
  debug,
1419
1698
  createLogger,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-customcode",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "description": "Batteries-included agent harness for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
@@ -40,6 +40,6 @@ Types: feat, fix, docs, style, refactor, test, chore
40
40
  - NEVER skip pre-commit hooks without reason
41
41
  - ALWAYS create new commits (avoid --amend unless requested)
42
42
 
43
- ## Push Rules (R017)
43
+ ## Push Rules (R016)
44
44
 
45
45
  All pushes require prior mgr-sauron:watch verification. If sauron was not run, REFUSE the push.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: mgr-sauron
3
- description: Use when you need automated verification of R017 compliance, executing mandatory multi-round verification (5 manager rounds + 3 deep review rounds) before commits
3
+ description: Use when you need automated verification of R016 compliance, executing mandatory multi-round verification (5 manager rounds + 3 deep review rounds) before commits
4
4
  model: sonnet
5
5
  memory: project
6
6
  effort: high
@@ -15,7 +15,7 @@ tools:
15
15
  - Bash
16
16
  ---
17
17
 
18
- You are an automated verification specialist that executes the mandatory R017 verification process, acting as the "all-seeing eye" that ensures system integrity through comprehensive multi-round verification.
18
+ You are an automated verification specialist that executes the mandatory R016 verification process, acting as the "all-seeing eye" that ensures system integrity through comprehensive multi-round verification.
19
19
 
20
20
  ## Core Capabilities
21
21
 
@@ -34,7 +34,7 @@ You are an automated verification specialist that executes the mandatory R017 ve
34
34
 
35
35
  | Command | Description |
36
36
  |---------|-------------|
37
- | `mgr-sauron:watch` | Full R017 verification (5+3 rounds) |
37
+ | `mgr-sauron:watch` | Full R016 verification (5+3 rounds) |
38
38
  | `mgr-sauron:quick` | Quick verification (single pass) |
39
39
  | `mgr-sauron:report` | Generate verification status report |
40
40
 
@@ -1,6 +1,6 @@
1
1
  # [MUST] Continuous Improvement Rules
2
2
 
3
- > **Priority**: MUST | **ID**: R016 | **Trigger**: User points out rule violation
3
+ > **Priority**: MUST | **ID**: R015 | **Trigger**: User points out rule violation
4
4
 
5
5
  ## Core Rule
6
6
 
@@ -1,6 +1,6 @@
1
1
  # [MUST] Intent Transparency Rules
2
2
 
3
- > **Priority**: MUST | **ID**: R015
3
+ > **Priority**: MUST | **ID**: R014
4
4
 
5
5
  ## Core Rule
6
6
 
@@ -117,7 +117,7 @@ The skill's WORKFLOW is followed, but git EXECUTION is delegated to mgr-gitnerd
117
117
 
118
118
  ## Agent Teams (when enabled)
119
119
 
120
- When `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`: use Agent Teams for 3+ agent coordinated tasks. See R018 for decision matrix. Task tool remains fallback for simple/independent tasks.
120
+ When `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`: use Agent Teams for 3+ agent coordinated tasks. See R017 for decision matrix. Task tool remains fallback for simple/independent tasks.
121
121
 
122
122
  ## Announcement Format
123
123