oh-my-design-cli 1.6.0 → 1.6.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 (81) hide show
  1. package/AGENTS.md +1 -1
  2. package/README.ko.md +12 -0
  3. package/README.md +49 -0
  4. package/data/reference-fingerprints.json +957 -2
  5. package/dist/bin/oh-my-design.js +4 -3
  6. package/dist/bin/oh-my-design.js.map +1 -1
  7. package/dist/{install-skills-IETT2TBJ.js → install-skills-6QFSN5BN.js} +108 -42
  8. package/dist/install-skills-6QFSN5BN.js.map +1 -0
  9. package/package.json +9 -3
  10. package/scripts/postinstall.cjs +6 -6
  11. package/skills/claude-design/SKILL.md +385 -0
  12. package/skills/claude-design/references/claude-design-flow.md +425 -0
  13. package/skills/claude-design/references/codebase-analysis.md +373 -0
  14. package/skills/claude-design/scripts/analyze_codebase.py +1369 -0
  15. package/skills/claude-design/scripts/clickable_link.sh +48 -0
  16. package/skills/claude-design/scripts/collect_source.py +178 -0
  17. package/skills/claude-design/scripts/drive_claude_design.cjs +378 -0
  18. package/skills/claude-design/scripts/gather_references.py +437 -0
  19. package/web/references/91app/DESIGN.md +151 -0
  20. package/web/references/airtable/DESIGN.md +16 -2
  21. package/web/references/bithumb/DESIGN.md +170 -0
  22. package/web/references/bunjang/DESIGN.md +20 -1
  23. package/web/references/cakeresume/DESIGN.md +162 -0
  24. package/web/references/catchtable/DESIGN.md +19 -0
  25. package/web/references/classting/DESIGN.md +251 -0
  26. package/web/references/classum/DESIGN.md +19 -0
  27. package/web/references/coinone/DESIGN.md +218 -0
  28. package/web/references/dabang/DESIGN.md +19 -0
  29. package/web/references/devsisters/DESIGN.md +253 -0
  30. package/web/references/dji/DESIGN.md +0 -1
  31. package/web/references/drnow/DESIGN.md +331 -0
  32. package/web/references/fastcampus/DESIGN.md +19 -0
  33. package/web/references/flex/DESIGN.md +19 -0
  34. package/web/references/flo/DESIGN.md +306 -0
  35. package/web/references/fugle/DESIGN.md +250 -0
  36. package/web/references/gmarket/DESIGN.md +19 -0
  37. package/web/references/gogolook/DESIGN.md +131 -0
  38. package/web/references/grip/DESIGN.md +250 -0
  39. package/web/references/hahow/DESIGN.md +158 -0
  40. package/web/references/hogangnono/DESIGN.md +308 -0
  41. package/web/references/hyundaicard/DESIGN.md +177 -0
  42. package/web/references/inflearn/DESIGN.md +19 -0
  43. package/web/references/jkopay/DESIGN.md +249 -0
  44. package/web/references/jobkorea/DESIGN.md +310 -0
  45. package/web/references/kbank/DESIGN.md +18 -0
  46. package/web/references/kdan/DESIGN.md +160 -0
  47. package/web/references/kkbox/DESIGN.md +114 -0
  48. package/web/references/krafton/DESIGN.md +230 -0
  49. package/web/references/kream/DESIGN.md +18 -0
  50. package/web/references/laftel/DESIGN.md +253 -0
  51. package/web/references/lezhin/DESIGN.md +301 -0
  52. package/web/references/lunit/DESIGN.md +19 -0
  53. package/web/references/melon/DESIGN.md +153 -0
  54. package/web/references/momoshop/DESIGN.md +279 -0
  55. package/web/references/mustit/DESIGN.md +282 -0
  56. package/web/references/nhncloud/DESIGN.md +174 -0
  57. package/web/references/oliveyoung/DESIGN.md +19 -0
  58. package/web/references/payco/DESIGN.md +227 -0
  59. package/web/references/piccollage/DESIGN.md +277 -0
  60. package/web/references/rayark/DESIGN.md +132 -0
  61. package/web/references/riiid/DESIGN.md +228 -0
  62. package/web/references/sendbird/DESIGN.md +285 -0
  63. package/web/references/socar/DESIGN.md +18 -0
  64. package/web/references/toss-securities/DESIGN.md +19 -0
  65. package/web/references/trenbe/DESIGN.md +252 -0
  66. package/web/references/tving/DESIGN.md +18 -0
  67. package/web/references/upbit/DESIGN.md +19 -0
  68. package/web/references/upstage/DESIGN.md +18 -0
  69. package/web/references/velog/DESIGN.md +168 -0
  70. package/web/references/voicetube/DESIGN.md +227 -0
  71. package/web/references/wadiz/DESIGN.md +19 -0
  72. package/web/references/webflow/DESIGN.md +16 -2
  73. package/web/references/yeogiotte/DESIGN.md +19 -0
  74. package/data/architecture-proposals/2026-05-13-thin-install-fresh-fetch.md +0 -189
  75. package/data/issues/2026-05-13-multi-surface-schema-rfc.md +0 -67
  76. package/data/reference-audits/2026-05-13-kr10.md +0 -132
  77. package/data/reference-audits/2026-05-14-kr10.md +0 -72
  78. package/data/reference-audits/2026-05-15-kr10.md +0 -124
  79. package/data/research/2026-05-18-agent-landscape.md +0 -69
  80. package/data/research/2026-05-18-kr-style-presets.md +0 -572
  81. package/dist/install-skills-IETT2TBJ.js.map +0 -1
@@ -24,9 +24,9 @@ function readPackageVersion() {
24
24
  }
25
25
  var program = new Command();
26
26
  program.name("oh-my-design").description("Bootstrap oh-my-design skills + agents into your project. After install, talk to your agent in natural language \u2014 no other CLI commands.").version(readPackageVersion()).showSuggestionAfterError(true).showHelpAfterError(true);
27
- program.command("install-skills").description("Install omd skill files + canonical agents into agent directories (.claude/, .codex/, .opencode/). Interactive multiselect TUI by default \u2014 picks which skills + sub-agents to install.").option("--dir <path>", "Project root (defaults to cwd)").option("--agent <name...>", "Restrict to specific channels (claude-code | codex | opencode)").option("--force", "Overwrite existing files even without the omd marker").option("--all", "Skip the interactive TUI and install every shipped skill + agent (use in CI)").option("--skills <names>", "Comma-separated skill names to install (overrides TUI)", (v) => v.split(",").map((s) => s.trim()).filter(Boolean)).option("--agents-only <names>", "Comma-separated agent names to install (overrides TUI). Use --agents-only to disambiguate from --agent (channel selector).", (v) => v.split(",").map((s) => s.trim()).filter(Boolean)).action(
27
+ program.command("install-skills").description("Install omd skill files + canonical agents into agent directories (.claude/, .codex/, .opencode/). Interactive multiselect TUI by default \u2014 picks which skills + sub-agents to install.").option("--dir <path>", "Project root (defaults to cwd)").option("--agent <name...>", "Restrict to specific channels (claude-code | codex | opencode)").option("--force", "Overwrite existing files even without the omd marker").option("--all", "Skip the interactive TUI and install every shipped skill + agent (use in CI)").option("--skills <names>", "Comma-separated skill names to install (overrides TUI)", (v) => v.split(",").map((s) => s.trim()).filter(Boolean)).option("--agents-only <names>", "Comma-separated agent names to install (overrides TUI). Use --agents-only to disambiguate from --agent (channel selector).", (v) => v.split(",").map((s) => s.trim()).filter(Boolean)).option("--skills-only", "Install only the named skill files \u2014 skip sub-agents, hooks, and settings.json (minimal single-skill install, e.g. --skills claude-design --skills-only)").action(
28
28
  async (opts) => {
29
- const { runInstallSkills } = await import("../install-skills-IETT2TBJ.js");
29
+ const { runInstallSkills } = await import("../install-skills-6QFSN5BN.js");
30
30
  const validAgents = ["claude-code", "codex", "opencode"];
31
31
  const agents = opts.agent ? opts.agent.filter(
32
32
  (a) => validAgents.includes(a)
@@ -37,7 +37,8 @@ program.command("install-skills").description("Install omd skill files + canonic
37
37
  force: opts.force,
38
38
  all: opts.all,
39
39
  skillsFilter: opts.skills,
40
- agentsFilter: opts.agentsOnly
40
+ agentsFilter: opts.agentsOnly,
41
+ skillsOnly: opts.skillsOnly
41
42
  });
42
43
  if (code !== 0) process.exit(code);
43
44
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../bin/oh-my-design.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nfunction readPackageVersion(): string {\n let cur = dirname(fileURLToPath(import.meta.url));\n for (let i = 0; i < 8; i++) {\n const pkg = join(cur, 'package.json');\n if (existsSync(pkg)) {\n try {\n return JSON.parse(readFileSync(pkg, 'utf8')).version ?? '0.0.0';\n } catch {\n return '0.0.0';\n }\n }\n const parent = dirname(cur);\n if (parent === cur) break;\n cur = parent;\n }\n return '0.0.0';\n}\n\nconst program = new Command();\n\nprogram\n .name('oh-my-design')\n .description('Bootstrap oh-my-design skills + agents into your project. After install, talk to your agent in natural language — no other CLI commands.')\n .version(readPackageVersion())\n .showSuggestionAfterError(true)\n .showHelpAfterError(true);\n\nprogram\n .command('install-skills')\n .description('Install omd skill files + canonical agents into agent directories (.claude/, .codex/, .opencode/). Interactive multiselect TUI by default — picks which skills + sub-agents to install.')\n .option('--dir <path>', 'Project root (defaults to cwd)')\n .option('--agent <name...>', 'Restrict to specific channels (claude-code | codex | opencode)')\n .option('--force', 'Overwrite existing files even without the omd marker')\n .option('--all', 'Skip the interactive TUI and install every shipped skill + agent (use in CI)')\n .option('--skills <names>', 'Comma-separated skill names to install (overrides TUI)', (v) => v.split(',').map((s) => s.trim()).filter(Boolean))\n .option('--agents-only <names>', 'Comma-separated agent names to install (overrides TUI). Use --agents-only to disambiguate from --agent (channel selector).', (v) => v.split(',').map((s) => s.trim()).filter(Boolean))\n .action(\n async (opts: {\n dir?: string;\n agent?: string[];\n force?: boolean;\n all?: boolean;\n skills?: string[];\n agentsOnly?: string[];\n }) => {\n const { runInstallSkills } = await import('../src/cli/install-skills.js');\n const validAgents = ['claude-code', 'codex', 'opencode'] as const;\n type Agent = (typeof validAgents)[number];\n const agents = opts.agent\n ? (opts.agent.filter((a): a is Agent =>\n (validAgents as readonly string[]).includes(a)\n ) as Agent[])\n : undefined;\n const code = await runInstallSkills({\n dir: opts.dir,\n agents,\n force: opts.force,\n all: opts.all,\n skillsFilter: opts.skills,\n agentsFilter: opts.agentsOnly,\n });\n if (code !== 0) process.exit(code);\n }\n );\n\nprogram.parse();\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,SAAS,cAAc,kBAAkB;AACzC,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAE9B,SAAS,qBAA6B;AACpC,MAAI,MAAM,QAAQ,cAAc,YAAY,GAAG,CAAC;AAChD,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,MAAM,KAAK,KAAK,cAAc;AACpC,QAAI,WAAW,GAAG,GAAG;AACnB,UAAI;AACF,eAAO,KAAK,MAAM,aAAa,KAAK,MAAM,CAAC,EAAE,WAAW;AAAA,MAC1D,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AACA,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK;AACpB,UAAM;AAAA,EACR;AACA,SAAO;AACT;AAEA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,cAAc,EACnB,YAAY,+IAA0I,EACtJ,QAAQ,mBAAmB,CAAC,EAC5B,yBAAyB,IAAI,EAC7B,mBAAmB,IAAI;AAE1B,QACG,QAAQ,gBAAgB,EACxB,YAAY,8LAAyL,EACrM,OAAO,gBAAgB,gCAAgC,EACvD,OAAO,qBAAqB,gEAAgE,EAC5F,OAAO,WAAW,sDAAsD,EACxE,OAAO,SAAS,8EAA8E,EAC9F,OAAO,oBAAoB,0DAA0D,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,EAC7I,OAAO,yBAAyB,8HAA8H,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,EACtN;AAAA,EACC,OAAO,SAOD;AACJ,UAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,+BAA8B;AACxE,UAAM,cAAc,CAAC,eAAe,SAAS,UAAU;AAEvD,UAAM,SAAS,KAAK,QACf,KAAK,MAAM;AAAA,MAAO,CAAC,MACjB,YAAkC,SAAS,CAAC;AAAA,IAC/C,IACA;AACJ,UAAM,OAAO,MAAM,iBAAiB;AAAA,MAClC,KAAK,KAAK;AAAA,MACV;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,KAAK,KAAK;AAAA,MACV,cAAc,KAAK;AAAA,MACnB,cAAc,KAAK;AAAA,IACrB,CAAC;AACD,QAAI,SAAS,EAAG,SAAQ,KAAK,IAAI;AAAA,EACnC;AACF;AAEF,QAAQ,MAAM;","names":[]}
1
+ {"version":3,"sources":["../../bin/oh-my-design.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nfunction readPackageVersion(): string {\n let cur = dirname(fileURLToPath(import.meta.url));\n for (let i = 0; i < 8; i++) {\n const pkg = join(cur, 'package.json');\n if (existsSync(pkg)) {\n try {\n return JSON.parse(readFileSync(pkg, 'utf8')).version ?? '0.0.0';\n } catch {\n return '0.0.0';\n }\n }\n const parent = dirname(cur);\n if (parent === cur) break;\n cur = parent;\n }\n return '0.0.0';\n}\n\nconst program = new Command();\n\nprogram\n .name('oh-my-design')\n .description('Bootstrap oh-my-design skills + agents into your project. After install, talk to your agent in natural language — no other CLI commands.')\n .version(readPackageVersion())\n .showSuggestionAfterError(true)\n .showHelpAfterError(true);\n\nprogram\n .command('install-skills')\n .description('Install omd skill files + canonical agents into agent directories (.claude/, .codex/, .opencode/). Interactive multiselect TUI by default — picks which skills + sub-agents to install.')\n .option('--dir <path>', 'Project root (defaults to cwd)')\n .option('--agent <name...>', 'Restrict to specific channels (claude-code | codex | opencode)')\n .option('--force', 'Overwrite existing files even without the omd marker')\n .option('--all', 'Skip the interactive TUI and install every shipped skill + agent (use in CI)')\n .option('--skills <names>', 'Comma-separated skill names to install (overrides TUI)', (v) => v.split(',').map((s) => s.trim()).filter(Boolean))\n .option('--agents-only <names>', 'Comma-separated agent names to install (overrides TUI). Use --agents-only to disambiguate from --agent (channel selector).', (v) => v.split(',').map((s) => s.trim()).filter(Boolean))\n .option('--skills-only', 'Install only the named skill files — skip sub-agents, hooks, and settings.json (minimal single-skill install, e.g. --skills claude-design --skills-only)')\n .action(\n async (opts: {\n dir?: string;\n agent?: string[];\n force?: boolean;\n all?: boolean;\n skills?: string[];\n agentsOnly?: string[];\n skillsOnly?: boolean;\n }) => {\n const { runInstallSkills } = await import('../src/cli/install-skills.js');\n const validAgents = ['claude-code', 'codex', 'opencode'] as const;\n type Agent = (typeof validAgents)[number];\n const agents = opts.agent\n ? (opts.agent.filter((a): a is Agent =>\n (validAgents as readonly string[]).includes(a)\n ) as Agent[])\n : undefined;\n const code = await runInstallSkills({\n dir: opts.dir,\n agents,\n force: opts.force,\n all: opts.all,\n skillsFilter: opts.skills,\n agentsFilter: opts.agentsOnly,\n skillsOnly: opts.skillsOnly,\n });\n if (code !== 0) process.exit(code);\n }\n );\n\nprogram.parse();\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,SAAS,cAAc,kBAAkB;AACzC,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAE9B,SAAS,qBAA6B;AACpC,MAAI,MAAM,QAAQ,cAAc,YAAY,GAAG,CAAC;AAChD,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,MAAM,KAAK,KAAK,cAAc;AACpC,QAAI,WAAW,GAAG,GAAG;AACnB,UAAI;AACF,eAAO,KAAK,MAAM,aAAa,KAAK,MAAM,CAAC,EAAE,WAAW;AAAA,MAC1D,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AACA,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK;AACpB,UAAM;AAAA,EACR;AACA,SAAO;AACT;AAEA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,cAAc,EACnB,YAAY,+IAA0I,EACtJ,QAAQ,mBAAmB,CAAC,EAC5B,yBAAyB,IAAI,EAC7B,mBAAmB,IAAI;AAE1B,QACG,QAAQ,gBAAgB,EACxB,YAAY,8LAAyL,EACrM,OAAO,gBAAgB,gCAAgC,EACvD,OAAO,qBAAqB,gEAAgE,EAC5F,OAAO,WAAW,sDAAsD,EACxE,OAAO,SAAS,8EAA8E,EAC9F,OAAO,oBAAoB,0DAA0D,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,EAC7I,OAAO,yBAAyB,8HAA8H,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,EACtN,OAAO,iBAAiB,+JAA0J,EAClL;AAAA,EACC,OAAO,SAQD;AACJ,UAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,+BAA8B;AACxE,UAAM,cAAc,CAAC,eAAe,SAAS,UAAU;AAEvD,UAAM,SAAS,KAAK,QACf,KAAK,MAAM;AAAA,MAAO,CAAC,MACjB,YAAkC,SAAS,CAAC;AAAA,IAC/C,IACA;AACJ,UAAM,OAAO,MAAM,iBAAiB;AAAA,MAClC,KAAK,KAAK;AAAA,MACV;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,KAAK,KAAK;AAAA,MACV,cAAc,KAAK;AAAA,MACnB,cAAc,KAAK;AAAA,MACnB,YAAY,KAAK;AAAA,IACnB,CAAC;AACD,QAAI,SAAS,EAAG,SAAQ,KAAK,IAAI;AAAA,EACnC;AACF;AAEF,QAAQ,MAAM;","names":[]}
@@ -8,7 +8,8 @@ import {
8
8
  readdirSync,
9
9
  writeFileSync,
10
10
  existsSync as existsSync2,
11
- mkdirSync
11
+ mkdirSync,
12
+ cpSync
12
13
  } from "fs";
13
14
  import { join as join2, dirname, relative } from "path";
14
15
  import { fileURLToPath } from "url";
@@ -155,16 +156,45 @@ function planForTarget(projectRoot, target) {
155
156
  }
156
157
  }
157
158
  var MANAGED_HEADER = "<!-- omd:installed-skill \u2014 managed by `omd install-skills`. Do not edit; rerun the command to refresh. -->";
159
+ var IGNORED_SKILL_ENTRIES = /* @__PURE__ */ new Set([".runtime", "__pycache__", ".DS_Store"]);
160
+ function parseSkillChannels(skillMd) {
161
+ const fm = /^---\n([\s\S]*?)\n---/.exec(skillMd);
162
+ if (!fm) return null;
163
+ const m = /^x-omd-channels:\s*(.+)$/m.exec(fm[1]);
164
+ if (!m) return null;
165
+ const valid = ["claude-code", "codex", "opencode"];
166
+ const list = m[1].split(/[,\s]+/).map((s) => s.trim()).filter((s) => valid.includes(s));
167
+ return list.length > 0 ? list : null;
168
+ }
158
169
  function installOne(packageRoot, plan, skill, force) {
159
- const src = readFileSync(
160
- join2(packageRoot, "skills", skill, "SKILL.md"),
161
- "utf8"
162
- );
170
+ const skillDir = join2(packageRoot, "skills", skill);
171
+ const src = readFileSync(join2(skillDir, "SKILL.md"), "utf8");
163
172
  const managed = MANAGED_HEADER + "\n\n" + src;
173
+ const channels = parseSkillChannels(src);
174
+ if (channels && !channels.includes(plan.target)) {
175
+ return {
176
+ target: plan.target,
177
+ skill,
178
+ destPath: join2(plan.destDir, skill + ".md"),
179
+ status: "skipped-incompat"
180
+ };
181
+ }
182
+ const extras = readdirSync(skillDir).filter(
183
+ (n) => n !== "SKILL.md" && !IGNORED_SKILL_ENTRIES.has(n)
184
+ );
185
+ const isMultiFile = extras.length > 0;
186
+ if (plan.layout !== "folder" && isMultiFile) {
187
+ return {
188
+ target: plan.target,
189
+ skill,
190
+ destPath: join2(plan.destDir, skill + ".md"),
191
+ status: "skipped-incompat"
192
+ };
193
+ }
164
194
  const destPath = plan.layout === "folder" ? join2(plan.destDir, skill, "SKILL.md") : join2(plan.destDir, skill + ".md");
165
195
  const exists = existsSync2(destPath);
166
196
  const existing = exists ? readFileSync(destPath, "utf8") : "";
167
- if (exists && existing === managed) {
197
+ if (exists && existing === managed && !isMultiFile) {
168
198
  return { target: plan.target, skill, destPath, status: "unchanged" };
169
199
  }
170
200
  if (exists && !existing.startsWith(MANAGED_HEADER) && !force) {
@@ -172,6 +202,15 @@ function installOne(packageRoot, plan, skill, force) {
172
202
  }
173
203
  mkdirSync(dirname(destPath), { recursive: true });
174
204
  writeFileSync(destPath, managed, "utf8");
205
+ if (plan.layout === "folder" && isMultiFile) {
206
+ const destSkillDir = join2(plan.destDir, skill);
207
+ for (const entry of extras) {
208
+ cpSync(join2(skillDir, entry), join2(destSkillDir, entry), {
209
+ recursive: true,
210
+ filter: (s) => !/(\/__pycache__|\/\.runtime|\.pyc$|\.DS_Store$)/.test(s)
211
+ });
212
+ }
213
+ }
175
214
  return {
176
215
  target: plan.target,
177
216
  skill,
@@ -290,7 +329,8 @@ var STATUS_LABEL = {
290
329
  created: pc.green("created"),
291
330
  updated: pc.cyan("updated"),
292
331
  unchanged: pc.dim("unchanged"),
293
- "skipped-drift": pc.yellow("skipped")
332
+ "skipped-drift": pc.yellow("skipped"),
333
+ "skipped-incompat": pc.yellow("skipped (claude-code only)")
294
334
  };
295
335
  function autoDetectTargets(projectRoot) {
296
336
  const presence = detectInstalledAgents(projectRoot);
@@ -317,11 +357,12 @@ async function runInstallSkills(opts = {}) {
317
357
  }
318
358
  const allAgents = listCanonicalAgents(packageRoot);
319
359
  const force = opts.force ?? false;
360
+ const minimal = opts.skillsOnly === true;
320
361
  p.intro(
321
362
  pc.bold("omd install-skills") + pc.dim(` (${relative(process.cwd(), projectRoot) || "."})`)
322
363
  );
323
364
  const isTTY = Boolean(process.stdin.isTTY && process.stdout.isTTY);
324
- const nonInteractive = opts.all || !isTTY || opts.skillsFilter || opts.agentsFilter;
365
+ const nonInteractive = opts.all || !isTTY || opts.skillsFilter || opts.agentsFilter || minimal;
325
366
  const detected = autoDetectTargets(projectRoot);
326
367
  const presence = detectInstalledAgents(projectRoot);
327
368
  const actuallyDetected = [
@@ -411,6 +452,7 @@ async function runInstallSkills(opts = {}) {
411
452
  p.log.message(
412
453
  pc.bold("Targets: ") + targets.map((t) => pc.cyan(t)).join(", ")
413
454
  );
455
+ if (minimal) canonicalAgents = [];
414
456
  const results = [];
415
457
  for (const plan of plans) {
416
458
  for (const skill of skills) {
@@ -428,34 +470,36 @@ async function runInstallSkills(opts = {}) {
428
470
  }
429
471
  }
430
472
  }
431
- const dataFiles = [
432
- "reference-fingerprints.json",
433
- "reference-tags.md",
434
- "vocabulary.json",
435
- "synonyms.json",
436
- "opt-out-corpus.json"
437
- ];
438
- for (const target of targets) {
439
- if (target === "claude-code") {
440
- for (const dataFile of dataFiles) {
441
- results.push(installDataFile(packageRoot, projectRoot, ".claude", dataFile, force));
442
- }
443
- } else if (target === "codex") {
444
- for (const dataFile of dataFiles) {
445
- results.push(installDataFile(packageRoot, projectRoot, ".codex", dataFile, force));
473
+ if (!minimal) {
474
+ const dataFiles = [
475
+ "reference-fingerprints.json",
476
+ "reference-tags.md",
477
+ "vocabulary.json",
478
+ "synonyms.json",
479
+ "opt-out-corpus.json"
480
+ ];
481
+ for (const target of targets) {
482
+ if (target === "claude-code") {
483
+ for (const dataFile of dataFiles) {
484
+ results.push(installDataFile(packageRoot, projectRoot, ".claude", dataFile, force));
485
+ }
486
+ } else if (target === "codex") {
487
+ for (const dataFile of dataFiles) {
488
+ results.push(installDataFile(packageRoot, projectRoot, ".codex", dataFile, force));
489
+ }
446
490
  }
447
491
  }
448
- }
449
- if (targets.includes("claude-code")) {
450
- for (const hookFile of [
451
- "skill-activation.cjs",
452
- "session-state-loader.cjs",
453
- "post-edit-watch.cjs",
454
- "session-end-foldin.cjs"
455
- ]) {
456
- results.push(installHookFile(packageRoot, projectRoot, hookFile, force));
492
+ if (targets.includes("claude-code")) {
493
+ for (const hookFile of [
494
+ "skill-activation.cjs",
495
+ "session-state-loader.cjs",
496
+ "post-edit-watch.cjs",
497
+ "session-end-foldin.cjs"
498
+ ]) {
499
+ results.push(installHookFile(packageRoot, projectRoot, hookFile, force));
500
+ }
501
+ results.push(installSettingsJson(packageRoot, projectRoot, force));
457
502
  }
458
- results.push(installSettingsJson(packageRoot, projectRoot, force));
459
503
  }
460
504
  p.log.message(pc.bold("\nResults:"));
461
505
  for (const r of results) {
@@ -476,23 +520,45 @@ async function runInstallSkills(opts = {}) {
476
520
  );
477
521
  return 0;
478
522
  }
523
+ if (minimal) {
524
+ for (const r of results.filter((x) => x.status === "skipped-incompat")) {
525
+ p.log.warn(
526
+ `${pc.bold(r.skill)} ${pc.dim("skipped for ")}${pc.cyan(r.target)}${pc.dim(" \u2014 declares x-omd-channels (channel not supported).")}`
527
+ );
528
+ }
529
+ const installed = results.filter(
530
+ (r) => r.status === "created" || r.status === "updated"
531
+ );
532
+ if (installed.length === 0) {
533
+ p.outro(pc.yellow("Nothing installed \u2014 no compatible skill/channel match."));
534
+ return 0;
535
+ }
536
+ p.outro(
537
+ pc.green(
538
+ `Done. Installed ${skills.map((s) => pc.bold(s)).join(", ")} for ${targets.join(", ")}.`
539
+ ) + pc.dim(" \u2192 restart your agent, then use the skill (e.g. ") + pc.cyan("/claude-design") + pc.dim(").")
540
+ );
541
+ return 0;
542
+ }
479
543
  const nextSteps = [
480
- `${pc.bold("Open Claude Code (or Codex). Just say what you want:")}`,
544
+ `${pc.bold("Restart your agent, then type your first prompt:")}`,
481
545
  "",
482
- ` ${pc.dim('"\uD1A0\uC2A4 \uC2A4\uD0C0\uC77C \uAC00\uC871 \uC2DD\uB2E8 \uACF5\uC720 \uC571 \uBA54\uC778 \uD654\uBA74 \uB514\uC790\uC778\uD574\uC918"')}`,
483
- ` ${pc.dim('"Linear-clone B2B SaaS dashboard \uB9CC\uB4E4\uACE0 \uC2F6\uC5B4"')}`,
484
- ` ${pc.dim('"\uC774 \uCE74\uB4DC \uC880 \uB354 \uC138\uB828\uB418\uAC8C"')} ${pc.dim("# \uC791\uC5C5 \uC911 \uC790\uC5F0\uC5B4 \u2014 \uC790\uB3D9 \uB77C\uC6B0\uD305")}`,
546
+ ` ${pc.cyan("EN")} ${pc.dim("Set up our design system \u2014 Toss-style, for a family meal-tracking app.")}`,
547
+ ` ${pc.cyan("KR")} ${pc.dim("\uD1A0\uC2A4 \uC2A4\uD0C0\uC77C\uB85C \uAC00\uC871 \uC2DD\uB2E8 \uACF5\uC720 \uC571 \uB514\uC790\uC778 \uC2DC\uC2A4\uD15C \uC7A1\uC544\uC918")}`,
485
548
  "",
486
- `${pc.bold("Claude\uAC00 description \uB9E4\uCE6D\uC73C\uB85C \uC790\uB3D9 \uB77C\uC6B0\uD305")} ${pc.dim("\u2014 \uC2AC\uB798\uC2DC \uBA85\uB839 \uC548 \uCCD0\uB3C4 \uB428. Hook\uC740 DESIGN.md \uBD80\uC7AC \uC2DC omd:init \uC548\uB0B4\uB9CC.")}`,
549
+ `${pc.dim("Your agent runs omd:init and writes DESIGN.md. Then build against it:")}`,
550
+ ` ${pc.cyan("EN")} ${pc.dim("Design the home screen.")} ${pc.cyan("KR")} ${pc.dim("\uD648 \uD654\uBA74 \uB514\uC790\uC778\uD574\uC918")}`,
487
551
  "",
488
- `${pc.dim("Power user shortcut: ")}${pc.cyan("/omd-harness <task>")} ${pc.dim("\u2014 \uC989\uC2DC \uC9C4\uC785.")}`,
552
+ `${pc.dim('Full walkthrough \u2192 "Your first 60 seconds" in the README. Routing is automatic \u2014 no slash command needed.')}`,
553
+ `${pc.dim("Power user: ")}${pc.cyan("/omd-harness <task>")}${pc.dim(" \u2014 jump straight into the pipeline.")}`,
489
554
  "",
490
- `${pc.yellow("\u26A0 Already-running Claude Code session?")} ${pc.dim("Run `/agents` inside the session to reload \u2014 or quit (Cmd+Q on macOS) and relaunch. Without reload, hooks/agents do not load.")}`
555
+ `${pc.yellow("\u26A0 Already-running session?")} ${pc.dim("Run `/agents` to reload \u2014 or quit (Cmd+Q on macOS) and relaunch. Without reload, hooks/agents do not load.")}`
491
556
  ].join("\n");
492
557
  p.note(nextSteps, "Next");
558
+ const hookCount = targets.includes("claude-code") ? 4 : 0;
493
559
  p.outro(
494
560
  pc.green(
495
- `Done. 6 skills \xB7 11 sub-agents \xB7 4 hooks installed (${writtenCount} files).`
561
+ `Done. ${skills.length} skills \xB7 ${canonicalAgents.length} sub-agents \xB7 ${hookCount} hooks installed (${writtenCount} files).`
496
562
  )
497
563
  );
498
564
  return 0;
@@ -500,4 +566,4 @@ async function runInstallSkills(opts = {}) {
500
566
  export {
501
567
  runInstallSkills
502
568
  };
503
- //# sourceMappingURL=install-skills-IETT2TBJ.js.map
569
+ //# sourceMappingURL=install-skills-6QFSN5BN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/install-skills.ts","../src/core/agent-detect.ts"],"sourcesContent":["import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport {\n readFileSync,\n readdirSync,\n writeFileSync,\n existsSync,\n mkdirSync,\n cpSync,\n} from 'node:fs';\nimport { join, dirname, relative } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { detectInstalledAgents } from '../core/agent-detect.js';\n\nexport type SkillTarget = 'claude-code' | 'codex' | 'opencode';\n\nexport interface InstallSkillsOptions {\n dir?: string;\n agents?: SkillTarget[];\n force?: boolean;\n /** Non-interactive: install all skills + all agents without TUI prompt.\n * Default false → interactive multiselect when TTY available. */\n all?: boolean;\n /** Pre-select specific skill names from CLI flag (`--skills omd-init,omd-apply`).\n * Overrides interactive prompt when set. */\n skillsFilter?: string[];\n /** Pre-select specific agent names. Overrides interactive prompt when set. */\n agentsFilter?: string[];\n /** Minimal install: only the named skill files — skip sub-agents, data files,\n * hooks, and settings.json. Ideal for shipping a single standalone skill. */\n skillsOnly?: boolean;\n}\n\ninterface InstallPlan {\n target: SkillTarget;\n destDir: string;\n layout: 'folder' | 'flat';\n}\n\nfunction findPackageRoot(): string | null {\n let cur = dirname(fileURLToPath(import.meta.url));\n for (let i = 0; i < 8; i++) {\n if (existsSync(join(cur, 'skills'))) return cur;\n const parent = dirname(cur);\n if (parent === cur) break;\n cur = parent;\n }\n return null;\n}\n\nfunction listShippedSkills(packageRoot: string): string[] {\n const skillsDir = join(packageRoot, 'skills');\n if (!existsSync(skillsDir)) return [];\n return readdirSync(skillsDir)\n .filter((name) => existsSync(join(skillsDir, name, 'SKILL.md')))\n .sort();\n}\n\n/**\n * Canonical agent definitions live at `agents/<name>.md` (markdown with YAML\n * frontmatter). Channel-specific files (.claude/agents/*.md, .codex/agents/*.toml)\n * are generated artifacts — never the source of truth.\n *\n * The package ships only `agents/` and the generator emits per-channel files\n * into the user's project on `omd install-skills`.\n */\nfunction listCanonicalAgents(packageRoot: string): string[] {\n const dir = join(packageRoot, 'agents');\n if (!existsSync(dir)) return [];\n return readdirSync(dir)\n .filter((name) => name.startsWith('omd-') && name.endsWith('.md'))\n .sort();\n}\n\ninterface ParsedAgent {\n name: string;\n description: string;\n tools: string[];\n model: string;\n body: string;\n}\n\n/** Parse `agents/<name>.md` YAML frontmatter + body into structured form. */\nfunction parseCanonicalAgent(packageRoot: string, filename: string): ParsedAgent {\n const src = readFileSync(join(packageRoot, 'agents', filename), 'utf8');\n const match = /^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/.exec(src);\n if (!match) {\n throw new Error(`agents/${filename}: missing YAML frontmatter`);\n }\n const fm = match[1];\n const body = match[2];\n const grab = (key: string): string => {\n const re = new RegExp(`^${key}:\\\\s*(.+)$`, 'm');\n const m = re.exec(fm);\n return m ? m[1].trim().replace(/^[\"']|[\"']$/g, '') : '';\n };\n return {\n name: grab('name') || filename.replace(/\\.md$/, ''),\n description: grab('description'),\n tools: grab('tools')\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean),\n model: grab('model') || 'sonnet',\n body,\n };\n}\n\n/** Map Claude tool names to Codex tool names (best-effort). */\nfunction claudeToolsToCodex(tools: string[]): string[] {\n const m: Record<string, string> = {\n Read: 'read_file',\n Write: 'write_file',\n Edit: 'edit_file',\n Bash: 'shell',\n Glob: 'search',\n Grep: 'search',\n WebFetch: 'web_fetch',\n WebSearch: 'search',\n Agent: 'spawn_agent',\n TaskCreate: 'task',\n TaskUpdate: 'task',\n TaskList: 'task',\n };\n const out = new Set<string>();\n for (const t of tools) out.add(m[t] ?? t.toLowerCase());\n return [...out].sort();\n}\n\n/** Map Claude model alias to Codex/OpenAI model id (best-effort). */\nfunction claudeModelToCodex(model: string): string {\n const m: Record<string, string> = {\n haiku: 'gpt-4.1-mini',\n sonnet: 'gpt-4.1',\n opus: 'gpt-4.1',\n };\n return m[model.toLowerCase()] ?? 'gpt-4.1';\n}\n\n/** Render a canonical agent as a Claude Code subagent file.\n * IMPORTANT: Claude Code's subagent parser requires YAML frontmatter (`---`)\n * as the FIRST line of the file. Any preceding content (HTML comments, blank\n * lines) breaks discovery. So we encode the managed-by-omd marker as a\n * custom frontmatter field (`omd_managed: true`) instead of an HTML comment.\n */\nfunction renderClaudeAgent(a: ParsedAgent): string {\n const fm = [\n '---',\n `name: ${a.name}`,\n `description: ${a.description}`,\n `tools: ${a.tools.join(', ')}`,\n `model: ${a.model}`,\n `omd_managed: true`,\n '---',\n '',\n ].join('\\n');\n return fm + a.body;\n}\n\n/** Render a canonical agent as a Codex TOML file (declarative pointer). */\nfunction renderCodexAgent(a: ParsedAgent): string {\n const tools = claudeToolsToCodex(a.tools);\n const model = claudeModelToCodex(a.model);\n const desc = a.description.replace(/\"/g, '\\\\\"');\n return [\n `[agent]`,\n `name = \"${a.name}\"`,\n `description = \"${desc}\"`,\n `model = \"${model}\"`,\n `max_threads = 1`,\n `allowed_tools = [${tools.map((t) => `\"${t}\"`).join(', ')}]`,\n '',\n `instructions = \"\"\"`,\n `Source of truth: agents/${a.name}.md (canonical). The full role spec is`,\n `mirrored to .claude/agents/${a.name}.md when installed for Claude Code.`,\n `Follow that spec verbatim regardless of channel.`,\n '',\n `Codex notes:`,\n `- Spawn sub-agents via spawn_agent with names matching .codex/agents/<name>.toml`,\n `- Use shell to invoke CLI helpers (omd init prepare, omd remember, git apply, npx axe-core, npx lighthouse)`,\n `- All artifacts go inside .omd/runs/run-<latest>/ (or skills/omd-lab-02-design-harness/runs/<lab-version>-...)`,\n `\"\"\"`,\n '',\n ].join('\\n');\n}\n\nfunction planForTarget(projectRoot: string, target: SkillTarget): InstallPlan {\n switch (target) {\n case 'claude-code':\n return {\n target,\n destDir: join(projectRoot, '.claude', 'skills'),\n layout: 'folder',\n };\n case 'codex':\n return {\n target,\n destDir: join(projectRoot, '.codex', 'skills'),\n layout: 'folder',\n };\n case 'opencode':\n return {\n target,\n destDir: join(projectRoot, '.opencode', 'agents'),\n layout: 'flat',\n };\n }\n}\n\nconst MANAGED_HEADER =\n '<!-- omd:installed-skill — managed by `omd install-skills`. Do not edit; rerun the command to refresh. -->';\n\ninterface InstallResult {\n target: SkillTarget;\n skill: string;\n destPath: string;\n status: 'created' | 'updated' | 'unchanged' | 'skipped-drift' | 'skipped-incompat';\n}\n\n// Skill-tree entries that must never be installed (runtime state, caches, OS cruft).\nconst IGNORED_SKILL_ENTRIES = new Set(['.runtime', '__pycache__', '.DS_Store']);\n\n/**\n * A skill may restrict itself to specific agent channels via a frontmatter line\n * `x-omd-channels: claude-code` (comma/space separated). Returns the allowed\n * channels, or null when channel-agnostic (installs anywhere). Used by skills that\n * depend on a particular agent runtime — e.g. claude-design needs Claude Code's\n * claude-in-chrome MCP + Bash/python/node and is therefore claude-code only.\n */\nfunction parseSkillChannels(skillMd: string): SkillTarget[] | null {\n const fm = /^---\\n([\\s\\S]*?)\\n---/.exec(skillMd);\n if (!fm) return null;\n const m = /^x-omd-channels:\\s*(.+)$/m.exec(fm[1]);\n if (!m) return null;\n const valid: SkillTarget[] = ['claude-code', 'codex', 'opencode'];\n const list = m[1]\n .split(/[,\\s]+/)\n .map((s) => s.trim())\n .filter((s): s is SkillTarget => (valid as string[]).includes(s));\n return list.length > 0 ? list : null;\n}\n\nfunction installOne(\n packageRoot: string,\n plan: InstallPlan,\n skill: string,\n force: boolean\n): InstallResult {\n const skillDir = join(packageRoot, 'skills', skill);\n const src = readFileSync(join(skillDir, 'SKILL.md'), 'utf8');\n const managed = MANAGED_HEADER + '\\n\\n' + src;\n\n // Respect a skill's declared channel restriction (frontmatter `x-omd-channels:`).\n const channels = parseSkillChannels(src);\n if (channels && !channels.includes(plan.target)) {\n return {\n target: plan.target,\n skill,\n destPath: join(plan.destDir, skill + '.md'),\n status: 'skipped-incompat',\n };\n }\n\n // A skill is \"multi-file\" when it ships more than SKILL.md (scripts/, references/, …).\n const extras = readdirSync(skillDir).filter(\n (n) => n !== 'SKILL.md' && !IGNORED_SKILL_ENTRIES.has(n)\n );\n const isMultiFile = extras.length > 0;\n\n // Flat channels (codex/opencode) store a skill as a single <skill>.md and cannot\n // host a multi-file skill's scripts/references — such skills are claude-code only.\n if (plan.layout !== 'folder' && isMultiFile) {\n return {\n target: plan.target,\n skill,\n destPath: join(plan.destDir, skill + '.md'),\n status: 'skipped-incompat',\n };\n }\n\n const destPath =\n plan.layout === 'folder'\n ? join(plan.destDir, skill, 'SKILL.md')\n : join(plan.destDir, skill + '.md');\n\n const exists = existsSync(destPath);\n const existing = exists ? readFileSync(destPath, 'utf8') : '';\n\n // Drift protection guards the user-editable SKILL.md. Single-file skills can\n // short-circuit on \"unchanged\"; multi-file skills always re-sync their tree.\n if (exists && existing === managed && !isMultiFile) {\n return { target: plan.target, skill, destPath, status: 'unchanged' };\n }\n if (exists && !existing.startsWith(MANAGED_HEADER) && !force) {\n return { target: plan.target, skill, destPath, status: 'skipped-drift' };\n }\n\n mkdirSync(dirname(destPath), { recursive: true });\n writeFileSync(destPath, managed, 'utf8');\n\n // Copy the rest of the skill tree (scripts/, references/, …) for folder layout.\n if (plan.layout === 'folder' && isMultiFile) {\n const destSkillDir = join(plan.destDir, skill);\n for (const entry of extras) {\n cpSync(join(skillDir, entry), join(destSkillDir, entry), {\n recursive: true,\n filter: (s) => !/(\\/__pycache__|\\/\\.runtime|\\.pyc$|\\.DS_Store$)/.test(s),\n });\n }\n }\n\n return {\n target: plan.target,\n skill,\n destPath,\n status: exists ? 'updated' : 'created',\n };\n}\n\n/** Install a hook script from package's .claude/hooks/ to project. */\nfunction installHookFile(\n packageRoot: string,\n projectRoot: string,\n filename: string,\n force: boolean\n): InstallResult {\n const target: SkillTarget = 'claude-code';\n const skillLabel = `hook:${filename}`;\n const srcPath = join(packageRoot, '.claude', 'hooks', filename);\n const destPath = join(projectRoot, '.claude', 'hooks', filename);\n\n if (!existsSync(srcPath)) {\n return { target, skill: skillLabel, destPath, status: 'skipped-drift' };\n }\n const src = readFileSync(srcPath, 'utf8');\n const exists = existsSync(destPath);\n const existing = exists ? readFileSync(destPath, 'utf8') : '';\n if (exists && existing === src) {\n return { target, skill: skillLabel, destPath, status: 'unchanged' };\n }\n if (exists && !force) {\n return { target, skill: skillLabel, destPath, status: 'skipped-drift' };\n }\n mkdirSync(dirname(destPath), { recursive: true });\n writeFileSync(destPath, src);\n return { target, skill: skillLabel, destPath, status: exists ? 'updated' : 'created' };\n}\n\n/**\n * Install / merge .claude/settings.json. We MERGE hooks (don't clobber user\n * customizations) by checking if the omd-managed `_doc` field is present.\n * Without --force, if a user-edited settings.json exists (no _doc field),\n * we skip with `skipped-drift`.\n */\nfunction installSettingsJson(\n packageRoot: string,\n projectRoot: string,\n force: boolean\n): InstallResult {\n const target: SkillTarget = 'claude-code';\n const skillLabel = 'settings:.claude/settings.json';\n const srcPath = join(packageRoot, '.claude', 'settings.json');\n const destPath = join(projectRoot, '.claude', 'settings.json');\n if (!existsSync(srcPath)) {\n return { target, skill: skillLabel, destPath, status: 'skipped-drift' };\n }\n const src = readFileSync(srcPath, 'utf8');\n const exists = existsSync(destPath);\n const existing = exists ? readFileSync(destPath, 'utf8') : '';\n if (exists && existing === src) {\n return { target, skill: skillLabel, destPath, status: 'unchanged' };\n }\n if (exists && !force) {\n // Check if it's the omd-managed version\n try {\n const parsed = JSON.parse(existing);\n if (typeof parsed._doc === 'string' && parsed._doc.includes('OmD')) {\n // managed — overwrite\n } else {\n return { target, skill: skillLabel, destPath, status: 'skipped-drift' };\n }\n } catch {\n return { target, skill: skillLabel, destPath, status: 'skipped-drift' };\n }\n }\n mkdirSync(dirname(destPath), { recursive: true });\n writeFileSync(destPath, src);\n return { target, skill: skillLabel, destPath, status: exists ? 'updated' : 'created' };\n}\n\n/**\n * Copy a read-only data asset (reference-fingerprints.json, vocabulary.json, …)\n * from the package's `data/` into the project's `.claude/data/` or `.codex/data/`.\n * The skill reads these at runtime — they replace the deprecated `omd init recommend` CLI.\n */\nfunction installDataFile(\n packageRoot: string,\n projectRoot: string,\n channelDir: string,\n dataFilename: string,\n force: boolean\n): InstallResult {\n const target: SkillTarget = channelDir === '.claude' ? 'claude-code' : 'codex';\n const skillLabel = `data:${dataFilename}`;\n\n const srcPath = join(packageRoot, 'data', dataFilename);\n const destPath = join(projectRoot, channelDir, 'data', dataFilename);\n\n if (!existsSync(srcPath)) {\n return { target, skill: skillLabel, destPath, status: 'skipped-drift' };\n }\n\n const src = readFileSync(srcPath, 'utf8');\n const exists = existsSync(destPath);\n const existing = exists ? readFileSync(destPath, 'utf8') : '';\n\n // Data files are pure copies — no managed header (would corrupt JSON).\n if (exists && existing === src) {\n return { target, skill: skillLabel, destPath, status: 'unchanged' };\n }\n if (exists && !force) {\n // Honor user customization unless --force\n return { target, skill: skillLabel, destPath, status: 'skipped-drift' };\n }\n\n mkdirSync(dirname(destPath), { recursive: true });\n writeFileSync(destPath, src, 'utf8');\n return {\n target,\n skill: skillLabel,\n destPath,\n status: exists ? 'updated' : 'created',\n };\n}\n\n/**\n * Generate a per-channel agent file from the canonical `agents/<name>.md`.\n *\n * Channel = 'claude' → emits `.claude/agents/<name>.md` (markdown w/ frontmatter)\n * Channel = 'codex' → emits `.codex/agents/<name>.toml` (TOML pointer)\n */\nfunction installAgentFile(\n packageRoot: string,\n projectRoot: string,\n channel: 'claude' | 'codex',\n filename: string,\n force: boolean\n): InstallResult {\n const target: SkillTarget = channel === 'claude' ? 'claude-code' : 'codex';\n const skillLabel = `agent:${filename}`;\n\n const parsed = parseCanonicalAgent(packageRoot, filename);\n const rendered =\n channel === 'claude' ? renderClaudeAgent(parsed) : renderCodexAgent(parsed);\n\n const destFilename =\n channel === 'claude' ? filename : filename.replace(/\\.md$/, '.toml');\n const destPath = join(\n projectRoot,\n channel === 'claude' ? '.claude' : '.codex',\n 'agents',\n destFilename\n );\n\n // For Claude Code: managed marker is encoded as `omd_managed: true` INSIDE the\n // frontmatter (rendered above) — no HTML comment can precede `---` or the\n // subagent loader rejects the file.\n // For Codex: TOML allows leading comments, so `# omd:installed-agent ...` is fine.\n const managed =\n channel === 'claude'\n ? rendered\n : '# omd:installed-agent — generated from agents/' +\n filename +\n ' by `omd install-skills`. Do not edit; rerun the command to refresh.\\n\\n' +\n rendered;\n\n const exists = existsSync(destPath);\n const existing = exists ? readFileSync(destPath, 'utf8') : '';\n\n if (exists && existing === managed) {\n return { target, skill: skillLabel, destPath, status: 'unchanged' };\n }\n\n // Drift detection sentinels:\n // Claude — look for `omd_managed: true` line inside frontmatter\n // Codex — look for `# omd:installed-agent` comment\n const isManaged =\n channel === 'claude'\n ? /\\nomd_managed:\\s*true\\b/.test(existing)\n : existing.startsWith('# omd:installed-agent');\n\n if (exists && !isManaged && !force) {\n return { target, skill: skillLabel, destPath, status: 'skipped-drift' };\n }\n\n mkdirSync(dirname(destPath), { recursive: true });\n writeFileSync(destPath, managed, 'utf8');\n return {\n target,\n skill: skillLabel,\n destPath,\n status: exists ? 'updated' : 'created',\n };\n}\n\nconst STATUS_LABEL: Record<InstallResult['status'], string> = {\n created: pc.green('created'),\n updated: pc.cyan('updated'),\n unchanged: pc.dim('unchanged'),\n 'skipped-drift': pc.yellow('skipped'),\n 'skipped-incompat': pc.yellow('skipped (claude-code only)'),\n};\n\nfunction autoDetectTargets(projectRoot: string): SkillTarget[] {\n const presence = detectInstalledAgents(projectRoot);\n const targets: SkillTarget[] = [];\n if (presence.claudeCode) targets.push('claude-code');\n if (presence.codex) targets.push('codex');\n if (presence.opencode) targets.push('opencode');\n // Cursor uses .mdc rules, not skills — installed via `omd sync`.\n if (targets.length === 0) {\n // Fallback: install for all three so user gets coverage even without\n // explicit signal. Idempotent so cost is low.\n return ['claude-code', 'codex', 'opencode'];\n }\n return targets;\n}\n\nexport async function runInstallSkills(\n opts: InstallSkillsOptions = {}\n): Promise<number> {\n const projectRoot = opts.dir ?? process.cwd();\n const packageRoot = findPackageRoot();\n if (!packageRoot) {\n console.error(pc.red('omd install-skills: package data not found'));\n return 1;\n }\n\n const allSkills = listShippedSkills(packageRoot);\n if (allSkills.length === 0) {\n console.error(pc.red('omd install-skills: no skills found in package'));\n return 1;\n }\n const allAgents = listCanonicalAgents(packageRoot);\n\n const force = opts.force ?? false;\n const minimal = opts.skillsOnly === true;\n\n p.intro(\n pc.bold('omd install-skills') +\n pc.dim(` (${relative(process.cwd(), projectRoot) || '.'})`)\n );\n\n // Resolve selection: --all flag, --skills/--agents/--agent filter, or interactive TUI.\n // TUI runs only when stdin is a TTY and the corresponding flag isn't set.\n const isTTY = Boolean(process.stdin.isTTY && process.stdout.isTTY);\n const nonInteractive =\n opts.all || !isTTY || opts.skillsFilter || opts.agentsFilter || minimal;\n\n const detected = autoDetectTargets(projectRoot);\n // Real presence (not the all-3 fallback) — used purely for hint labels.\n const presence = detectInstalledAgents(projectRoot);\n const actuallyDetected: SkillTarget[] = [\n presence.claudeCode ? 'claude-code' : null,\n presence.codex ? 'codex' : null,\n presence.opencode ? 'opencode' : null,\n ].filter((x): x is SkillTarget => x !== null);\n\n let skills: string[];\n let canonicalAgents: string[];\n let targets: SkillTarget[];\n\n if (nonInteractive) {\n // Non-interactive resolution\n skills = opts.skillsFilter\n ? allSkills.filter((s) => opts.skillsFilter!.includes(s))\n : allSkills;\n canonicalAgents = opts.agentsFilter\n ? allAgents.filter((a) => opts.agentsFilter!.includes(a.replace(/\\.md$/, '')))\n : allAgents;\n targets = opts.agents\n ? opts.agents\n : opts.all\n ? (['claude-code', 'codex', 'opencode'] as SkillTarget[])\n : detected;\n } else {\n // === Interactive TUI — skill → subagent → channel order ===\n // 1. Skills (default = ALL selected)\n const skillResult = await p.multiselect({\n message:\n 'Skills · space = 토글 · a = 전체 · enter = 확인 (default ALL)',\n options: allSkills.map((s) => ({ value: s, label: s, hint: 'omd skill' })),\n initialValues: allSkills,\n required: true,\n });\n if (p.isCancel(skillResult)) {\n p.cancel('Install cancelled.');\n return 130;\n }\n skills = skillResult as string[];\n\n // 2. Sub-agents (default = ALL selected)\n if (allAgents.length > 0) {\n const agentResult = await p.multiselect({\n message:\n 'Sub-agents · space = 토글 · a = 전체 · enter = 확인 (default ALL)',\n options: allAgents.map((a) => ({\n value: a,\n label: a.replace(/\\.md$/, ''),\n hint: 'subagent',\n })),\n initialValues: allAgents,\n required: false,\n });\n if (p.isCancel(agentResult)) {\n p.cancel('Install cancelled.');\n return 130;\n }\n canonicalAgents = agentResult as string[];\n } else {\n canonicalAgents = [];\n }\n\n // 3. Agent channels (default = NONE — user explicitly picks)\n if (opts.agents) {\n targets = opts.agents;\n } else {\n const targetResult = await p.multiselect({\n message:\n 'Agent channels · space = 토글 · enter = 확인 · 최소 1개 선택',\n options: [\n {\n value: 'claude-code',\n label: 'Claude Code',\n hint: actuallyDetected.includes('claude-code') ? '.claude/ detected' : '',\n },\n {\n value: 'codex',\n label: 'Codex',\n hint: actuallyDetected.includes('codex') ? '.codex/ detected' : '',\n },\n {\n value: 'opencode',\n label: 'OpenCode',\n hint: actuallyDetected.includes('opencode') ? '.opencode/ detected' : '',\n },\n ] as { value: SkillTarget; label: string; hint?: string }[],\n initialValues: [] as SkillTarget[],\n required: true,\n });\n if (p.isCancel(targetResult)) {\n p.cancel('Install cancelled.');\n return 130;\n }\n targets = targetResult as SkillTarget[];\n }\n }\n\n const plans = targets.map((t) => planForTarget(projectRoot, t));\n\n p.log.message(\n pc.bold(`Skills (${skills.length}): `) +\n skills.map((s) => pc.cyan(s)).join(', ')\n );\n if (canonicalAgents.length > 0) {\n p.log.message(\n pc.bold(`Agents (${canonicalAgents.length}): `) +\n canonicalAgents.map((a) => pc.cyan(a.replace(/\\.md$/, ''))).join(', ')\n );\n }\n p.log.message(\n pc.bold('Targets: ') + targets.map((t) => pc.cyan(t)).join(', ')\n );\n\n // skills-only minimal install: drop sub-agents (data/hooks/settings gated below).\n if (minimal) canonicalAgents = [];\n\n const results: InstallResult[] = [];\n for (const plan of plans) {\n for (const skill of skills) {\n results.push(installOne(packageRoot, plan, skill, force));\n }\n }\n\n // Generate per-channel sub-agent definitions from the canonical `agents/`.\n // This is the v2 portable source-of-truth pattern (oh-my-agent style).\n // `canonicalAgents` is already resolved above by the TUI / --agents filter.\n for (const target of targets) {\n if (target === 'claude-code') {\n for (const filename of canonicalAgents) {\n results.push(installAgentFile(packageRoot, projectRoot, 'claude', filename, force));\n }\n } else if (target === 'codex') {\n for (const filename of canonicalAgents) {\n results.push(installAgentFile(packageRoot, projectRoot, 'codex', filename, force));\n }\n }\n // OpenCode currently has no agent-definition channel — skills only.\n }\n\n if (!minimal) {\n // Ship the read-only data assets (reference fingerprints, controlled vocab,\n // human-readable tag matrix, opt-out corpus) into the project so skills + hooks\n // can run entirely on the host CLI's own model — no external API keys.\n const dataFiles = [\n 'reference-fingerprints.json',\n 'reference-tags.md',\n 'vocabulary.json',\n 'synonyms.json',\n 'opt-out-corpus.json',\n ];\n for (const target of targets) {\n if (target === 'claude-code') {\n for (const dataFile of dataFiles) {\n results.push(installDataFile(packageRoot, projectRoot, '.claude', dataFile, force));\n }\n } else if (target === 'codex') {\n for (const dataFile of dataFiles) {\n results.push(installDataFile(packageRoot, projectRoot, '.codex', dataFile, force));\n }\n }\n }\n\n // Install hooks (Claude Code only — Codex / OpenCode have separate hook systems)\n if (targets.includes('claude-code')) {\n for (const hookFile of [\n 'skill-activation.cjs',\n 'session-state-loader.cjs',\n 'post-edit-watch.cjs',\n 'session-end-foldin.cjs',\n ]) {\n results.push(installHookFile(packageRoot, projectRoot, hookFile, force));\n }\n // settings.json (with merge, never clobber user)\n results.push(installSettingsJson(packageRoot, projectRoot, force));\n }\n } // !minimal — skills-only skips data files, hooks, and settings.json\n\n p.log.message(pc.bold('\\nResults:'));\n for (const r of results) {\n const rel = relative(projectRoot, r.destPath);\n p.log.message(\n ` ${STATUS_LABEL[r.status]} ${pc.dim(r.target.padEnd(12))} ${rel}`\n );\n }\n\n const driftCount = results.filter((r) => r.status === 'skipped-drift').length;\n const writtenCount = results.filter(\n (r) => r.status === 'created' || r.status === 'updated'\n ).length;\n\n if (driftCount > 0) {\n p.outro(\n pc.yellow(\n `${writtenCount} written, ${driftCount} skipped (existing files lack the omd marker — rerun with --force to overwrite).`\n )\n );\n return 0;\n }\n\n // Minimal single-skill install (--skills-only): no omd onboarding, no agents/hooks.\n // Ideal for shipping a standalone skill (e.g. claude-design) to people who don't\n // want the rest of the omd toolchain.\n if (minimal) {\n for (const r of results.filter((x) => x.status === 'skipped-incompat')) {\n p.log.warn(\n `${pc.bold(r.skill)} ${pc.dim('skipped for ')}${pc.cyan(r.target)}${pc.dim(' — declares x-omd-channels (channel not supported).')}`\n );\n }\n const installed = results.filter(\n (r) => r.status === 'created' || r.status === 'updated'\n );\n if (installed.length === 0) {\n p.outro(pc.yellow('Nothing installed — no compatible skill/channel match.'));\n return 0;\n }\n p.outro(\n pc.green(\n `Done. Installed ${skills.map((s) => pc.bold(s)).join(', ')} for ${targets.join(', ')}.`\n ) +\n pc.dim(' → restart your agent, then use the skill (e.g. ') +\n pc.cyan('/claude-design') +\n pc.dim(').')\n );\n return 0;\n }\n\n // Friendly next-step nudge after successful install.\n // The first prompt is kept identical to the README's \"Your first 60 seconds\"\n // block so the README, the terminal, and the postinstall message all teach\n // the same activation moment. Bilingual (EN + KR) so an English reader is not\n // handed a Korean-only outro.\n const nextSteps = [\n `${pc.bold('Restart your agent, then type your first prompt:')}`,\n '',\n ` ${pc.cyan('EN')} ${pc.dim('Set up our design system — Toss-style, for a family meal-tracking app.')}`,\n ` ${pc.cyan('KR')} ${pc.dim('토스 스타일로 가족 식단 공유 앱 디자인 시스템 잡아줘')}`,\n '',\n `${pc.dim('Your agent runs omd:init and writes DESIGN.md. Then build against it:')}`,\n ` ${pc.cyan('EN')} ${pc.dim('Design the home screen.')} ${pc.cyan('KR')} ${pc.dim('홈 화면 디자인해줘')}`,\n '',\n `${pc.dim('Full walkthrough → \"Your first 60 seconds\" in the README. Routing is automatic — no slash command needed.')}`,\n `${pc.dim('Power user: ')}${pc.cyan('/omd-harness <task>')}${pc.dim(' — jump straight into the pipeline.')}`,\n '',\n `${pc.yellow('⚠ Already-running session?')} ${pc.dim('Run `/agents` to reload — or quit (Cmd+Q on macOS) and relaunch. Without reload, hooks/agents do not load.')}`,\n ].join('\\n');\n p.note(nextSteps, 'Next');\n\n // Counts derived from what was actually resolved/installed — never hardcoded,\n // so the outro can't drift from the real skill/agent/hook set (or the README).\n const hookCount = targets.includes('claude-code') ? 4 : 0;\n p.outro(\n pc.green(\n `Done. ${skills.length} skills · ${canonicalAgents.length} sub-agents · ${hookCount} hooks installed (${writtenCount} files).`,\n ),\n );\n return 0;\n}\n\n","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport type AgentId = 'claude-code' | 'codex' | 'opencode' | 'cursor' | 'unknown';\n\nexport function detectCallingAgent(): AgentId {\n const env = process.env;\n\n if (env.CLAUDECODE === '1' || env.CLAUDE_CODE === '1' || env.CLAUDE_CODE_TASK_ID) {\n return 'claude-code';\n }\n if (env.CODEX_SESSION_ID || env.CODEX || env.OPENAI_CODEX) {\n return 'codex';\n }\n if (env.OPENCODE || env.OPENCODE_SESSION) {\n return 'opencode';\n }\n if (env.CURSOR_SESSION_ID || env.CURSOR_AGENT) {\n return 'cursor';\n }\n\n return 'unknown';\n}\n\nexport interface AgentPresence {\n claudeCode: boolean;\n codex: boolean;\n opencode: boolean;\n cursor: boolean;\n}\n\nexport function detectInstalledAgents(projectRoot: string): AgentPresence {\n return {\n claudeCode:\n existsSync(join(projectRoot, '.claude')) ||\n existsSync(join(projectRoot, 'CLAUDE.md')),\n codex:\n existsSync(join(projectRoot, '.codex')) ||\n existsSync(join(projectRoot, 'AGENTS.md')) ||\n existsSync(join(projectRoot, 'AGENTS.override.md')),\n opencode:\n existsSync(join(projectRoot, '.opencode')) ||\n existsSync(join(projectRoot, 'opencode.json')) ||\n existsSync(join(projectRoot, 'opencode.jsonc')),\n cursor:\n existsSync(join(projectRoot, '.cursor')) ||\n existsSync(join(projectRoot, '.cursorrules')),\n };\n}\n"],"mappings":"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","names":["existsSync","join","existsSync","join"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-design-cli",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "Bootstrap oh-my-design skills + agents into your project. After install, talk to your AI coding agent in natural language — no other CLI commands.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -24,8 +24,13 @@
24
24
  "skills/omd-designer-review",
25
25
  "skills/omd-final-qa",
26
26
  "skills/omd-codex-image",
27
+ "skills/claude-design",
27
28
  "agents",
28
- "data",
29
+ "data/opt-out-corpus.json",
30
+ "data/synonyms.json",
31
+ "data/vocabulary.json",
32
+ "data/reference-fingerprints.json",
33
+ "data/reference-tags.md",
29
34
  "web/references/*/DESIGN.md",
30
35
  ".claude/hooks/*.cjs",
31
36
  ".claude/settings.json",
@@ -42,7 +47,8 @@
42
47
  "test:watch": "vitest",
43
48
  "lint": "tsc --noEmit",
44
49
  "prepare": "npm run build",
45
- "prepublishOnly": "npm run build",
50
+ "prepublishOnly": "npm run build && node scripts/gen-llms-full.cjs && bash scripts/check-release-hygiene.sh pack",
51
+ "gen:llms-full": "node scripts/gen-llms-full.cjs",
46
52
  "postinstall": "node scripts/postinstall.cjs"
47
53
  },
48
54
  "keywords": [
@@ -36,15 +36,15 @@ const lines = [
36
36
  ` ${c.cyan('cd')} ${c.dim('<your project>')}`,
37
37
  ` ${c.cyan('omd install-skills')} ${c.dim('# one time per project — installs the design harness')}`,
38
38
  '',
39
- ` ${c.bold('Then open Claude Code (or Codex). Just say what you want:')}`,
39
+ ` ${c.bold('Then restart your agent and type your first prompt:')}`,
40
40
  '',
41
- ` ${c.dim('"토스 스타일 가족 식단 공유 메인 화면 디자인해줘"')}`,
42
- ` ${c.dim('"Linear-clone B2B SaaS dashboard 만들고 싶어"')}`,
43
- ` ${c.dim('"이 카드 좀 더 세련되게"')}`,
41
+ ` ${c.cyan('EN')} ${c.dim('Set up our design system Toss-style, for a family meal-tracking app.')}`,
42
+ ` ${c.cyan('KR')} ${c.dim('토스 스타일로 가족 식단 공유 앱 디자인 시스템 잡아줘')}`,
44
43
  '',
45
- ` ${c.bold('하네스가 알아서 호출됨')} ${c.dim(' Claude Code hook이 디자인 요청 감지해서 자동 라우팅. 별도 슬래시 안 쳐도 됩니다.')}`,
44
+ ` ${c.dim('Your agent runs omd:init and writes DESIGN.md. Then: "Design the home screen."')}`,
45
+ ` ${c.dim('Full walkthrough → "Your first 60 seconds" in the README. Routing is automatic.')}`,
46
46
  '',
47
- ` ${c.dim('Power user shortcut: ')} ${c.cyan('/omd-harness <task>')} ${c.dim('— hook 우회하고 즉시 진입.')}`,
47
+ ` ${c.dim('Power user shortcut: ')} ${c.cyan('/omd-harness <task>')} ${c.dim('— jump straight into the pipeline.')}`,
48
48
  '',
49
49
  ` ${c.bold('⚠ Already running Claude Code?')} ${c.dim('Quit (Cmd+Q on macOS) and relaunch — subagents only load at session start.')}`,
50
50
  '',