oh-my-design-cli 1.6.1 → 1.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +14 -0
- package/README.md +16 -0
- package/data/reference-fingerprints.json +979 -402
- package/dist/bin/oh-my-design.js +5 -3
- package/dist/bin/oh-my-design.js.map +1 -1
- package/dist/{install-skills-UKEVE3KT.js → install-skills-52LCRBZZ.js} +125 -40
- package/dist/install-skills-52LCRBZZ.js.map +1 -0
- package/package.json +2 -1
- package/skills/claude-design/SKILL.md +385 -0
- package/skills/claude-design/references/claude-design-flow.md +425 -0
- package/skills/claude-design/references/codebase-analysis.md +373 -0
- package/skills/claude-design/scripts/analyze_codebase.py +1369 -0
- package/skills/claude-design/scripts/clickable_link.sh +48 -0
- package/skills/claude-design/scripts/collect_source.py +178 -0
- package/skills/claude-design/scripts/drive_claude_design.cjs +378 -0
- package/skills/claude-design/scripts/gather_references.py +437 -0
- package/web/references/bunjang/DESIGN.md +1 -1
- package/web/references/classting/DESIGN.md +251 -0
- package/web/references/coinone/DESIGN.md +218 -0
- package/web/references/devsisters/DESIGN.md +253 -0
- package/web/references/drnow/DESIGN.md +331 -0
- package/web/references/flo/DESIGN.md +306 -0
- package/web/references/fugle/DESIGN.md +250 -0
- package/web/references/gogolook/DESIGN.md +5 -0
- package/web/references/grip/DESIGN.md +250 -0
- package/web/references/hogangnono/DESIGN.md +308 -0
- package/web/references/hyundaicard/DESIGN.md +5 -0
- package/web/references/jkopay/DESIGN.md +249 -0
- package/web/references/jobkorea/DESIGN.md +310 -0
- package/web/references/krafton/DESIGN.md +230 -0
- package/web/references/laftel/DESIGN.md +253 -0
- package/web/references/lezhin/DESIGN.md +301 -0
- package/web/references/momoshop/DESIGN.md +279 -0
- package/web/references/mustit/DESIGN.md +282 -0
- package/web/references/payco/DESIGN.md +227 -0
- package/web/references/piccollage/DESIGN.md +277 -0
- package/web/references/riiid/DESIGN.md +228 -0
- package/web/references/trenbe/DESIGN.md +252 -0
- package/web/references/voicetube/DESIGN.md +227 -0
- package/dist/install-skills-UKEVE3KT.js.map +0 -1
package/dist/bin/oh-my-design.js
CHANGED
|
@@ -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)").option("--global", "Install to the user-level dir (~/.claude/skills, available in every project) instead of this project. Writes skills + sub-agents; never touches global hooks/settings.").action(
|
|
28
28
|
async (opts) => {
|
|
29
|
-
const { runInstallSkills } = await import("../install-skills-
|
|
29
|
+
const { runInstallSkills } = await import("../install-skills-52LCRBZZ.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,9 @@ 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,
|
|
42
|
+
global: opts.global
|
|
41
43
|
});
|
|
42
44
|
if (code !== 0) process.exit(code);
|
|
43
45
|
}
|
|
@@ -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,
|
|
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 .option('--global', 'Install to the user-level dir (~/.claude/skills, available in every project) instead of this project. Writes skills + sub-agents; never touches global hooks/settings.')\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 global?: 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 global: opts.global,\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,OAAO,YAAY,wKAAwK,EAC3L;AAAA,EACC,OAAO,SASD;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,MACjB,QAAQ,KAAK;AAAA,IACf,CAAC;AACD,QAAI,SAAS,EAAG,SAAQ,KAAK,IAAI;AAAA,EACnC;AACF;AAEF,QAAQ,MAAM;","names":[]}
|
|
@@ -8,9 +8,11 @@ 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";
|
|
15
|
+
import { homedir } from "os";
|
|
14
16
|
import { fileURLToPath } from "url";
|
|
15
17
|
|
|
16
18
|
// src/core/agent-detect.ts
|
|
@@ -155,16 +157,45 @@ function planForTarget(projectRoot, target) {
|
|
|
155
157
|
}
|
|
156
158
|
}
|
|
157
159
|
var MANAGED_HEADER = "<!-- omd:installed-skill \u2014 managed by `omd install-skills`. Do not edit; rerun the command to refresh. -->";
|
|
160
|
+
var IGNORED_SKILL_ENTRIES = /* @__PURE__ */ new Set([".runtime", "__pycache__", ".DS_Store"]);
|
|
161
|
+
function parseSkillChannels(skillMd) {
|
|
162
|
+
const fm = /^---\n([\s\S]*?)\n---/.exec(skillMd);
|
|
163
|
+
if (!fm) return null;
|
|
164
|
+
const m = /^x-omd-channels:\s*(.+)$/m.exec(fm[1]);
|
|
165
|
+
if (!m) return null;
|
|
166
|
+
const valid = ["claude-code", "codex", "opencode"];
|
|
167
|
+
const list = m[1].split(/[,\s]+/).map((s) => s.trim()).filter((s) => valid.includes(s));
|
|
168
|
+
return list.length > 0 ? list : null;
|
|
169
|
+
}
|
|
158
170
|
function installOne(packageRoot, plan, skill, force) {
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
"utf8"
|
|
162
|
-
);
|
|
171
|
+
const skillDir = join2(packageRoot, "skills", skill);
|
|
172
|
+
const src = readFileSync(join2(skillDir, "SKILL.md"), "utf8");
|
|
163
173
|
const managed = MANAGED_HEADER + "\n\n" + src;
|
|
174
|
+
const channels = parseSkillChannels(src);
|
|
175
|
+
if (channels && !channels.includes(plan.target)) {
|
|
176
|
+
return {
|
|
177
|
+
target: plan.target,
|
|
178
|
+
skill,
|
|
179
|
+
destPath: join2(plan.destDir, skill + ".md"),
|
|
180
|
+
status: "skipped-incompat"
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
const extras = readdirSync(skillDir).filter(
|
|
184
|
+
(n) => n !== "SKILL.md" && !IGNORED_SKILL_ENTRIES.has(n)
|
|
185
|
+
);
|
|
186
|
+
const isMultiFile = extras.length > 0;
|
|
187
|
+
if (plan.layout !== "folder" && isMultiFile) {
|
|
188
|
+
return {
|
|
189
|
+
target: plan.target,
|
|
190
|
+
skill,
|
|
191
|
+
destPath: join2(plan.destDir, skill + ".md"),
|
|
192
|
+
status: "skipped-incompat"
|
|
193
|
+
};
|
|
194
|
+
}
|
|
164
195
|
const destPath = plan.layout === "folder" ? join2(plan.destDir, skill, "SKILL.md") : join2(plan.destDir, skill + ".md");
|
|
165
196
|
const exists = existsSync2(destPath);
|
|
166
197
|
const existing = exists ? readFileSync(destPath, "utf8") : "";
|
|
167
|
-
if (exists && existing === managed) {
|
|
198
|
+
if (exists && existing === managed && !isMultiFile) {
|
|
168
199
|
return { target: plan.target, skill, destPath, status: "unchanged" };
|
|
169
200
|
}
|
|
170
201
|
if (exists && !existing.startsWith(MANAGED_HEADER) && !force) {
|
|
@@ -172,6 +203,15 @@ function installOne(packageRoot, plan, skill, force) {
|
|
|
172
203
|
}
|
|
173
204
|
mkdirSync(dirname(destPath), { recursive: true });
|
|
174
205
|
writeFileSync(destPath, managed, "utf8");
|
|
206
|
+
if (plan.layout === "folder" && isMultiFile) {
|
|
207
|
+
const destSkillDir = join2(plan.destDir, skill);
|
|
208
|
+
for (const entry of extras) {
|
|
209
|
+
cpSync(join2(skillDir, entry), join2(destSkillDir, entry), {
|
|
210
|
+
recursive: true,
|
|
211
|
+
filter: (s) => !/(\/__pycache__|\/\.runtime|\.pyc$|\.DS_Store$)/.test(s)
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
175
215
|
return {
|
|
176
216
|
target: plan.target,
|
|
177
217
|
skill,
|
|
@@ -290,7 +330,8 @@ var STATUS_LABEL = {
|
|
|
290
330
|
created: pc.green("created"),
|
|
291
331
|
updated: pc.cyan("updated"),
|
|
292
332
|
unchanged: pc.dim("unchanged"),
|
|
293
|
-
"skipped-drift": pc.yellow("skipped")
|
|
333
|
+
"skipped-drift": pc.yellow("skipped"),
|
|
334
|
+
"skipped-incompat": pc.yellow("skipped (claude-code only)")
|
|
294
335
|
};
|
|
295
336
|
function autoDetectTargets(projectRoot) {
|
|
296
337
|
const presence = detectInstalledAgents(projectRoot);
|
|
@@ -317,11 +358,13 @@ async function runInstallSkills(opts = {}) {
|
|
|
317
358
|
}
|
|
318
359
|
const allAgents = listCanonicalAgents(packageRoot);
|
|
319
360
|
const force = opts.force ?? false;
|
|
361
|
+
const minimal = opts.skillsOnly === true;
|
|
362
|
+
let scope = opts.global ? "global" : "project";
|
|
320
363
|
p.intro(
|
|
321
364
|
pc.bold("omd install-skills") + pc.dim(` (${relative(process.cwd(), projectRoot) || "."})`)
|
|
322
365
|
);
|
|
323
366
|
const isTTY = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
324
|
-
const nonInteractive = opts.all || !isTTY || opts.skillsFilter || opts.agentsFilter;
|
|
367
|
+
const nonInteractive = opts.all || !isTTY || opts.skillsFilter || opts.agentsFilter || minimal;
|
|
325
368
|
const detected = autoDetectTargets(projectRoot);
|
|
326
369
|
const presence = detectInstalledAgents(projectRoot);
|
|
327
370
|
const actuallyDetected = [
|
|
@@ -337,6 +380,21 @@ async function runInstallSkills(opts = {}) {
|
|
|
337
380
|
canonicalAgents = opts.agentsFilter ? allAgents.filter((a) => opts.agentsFilter.includes(a.replace(/\.md$/, ""))) : allAgents;
|
|
338
381
|
targets = opts.agents ? opts.agents : opts.all ? ["claude-code", "codex", "opencode"] : detected;
|
|
339
382
|
} else {
|
|
383
|
+
if (!opts.global) {
|
|
384
|
+
const scopeResult = await p.select({
|
|
385
|
+
message: "Install scope \xB7 \uC5B4\uB514\uC5D0 \uC124\uCE58\uD560\uAE4C\uC694?",
|
|
386
|
+
options: [
|
|
387
|
+
{ value: "project", label: "Project", hint: `${relative(process.cwd(), projectRoot) || "."}/.claude/skills \xB7 \uC774 \uD504\uB85C\uC81D\uD2B8\uB9CC` },
|
|
388
|
+
{ value: "global", label: "Global", hint: "~/.claude/skills \xB7 \uBAA8\uB4E0 \uD504\uB85C\uC81D\uD2B8 (skills + sub-agents, hooks/settings \uC81C\uC678)" }
|
|
389
|
+
],
|
|
390
|
+
initialValue: "project"
|
|
391
|
+
});
|
|
392
|
+
if (p.isCancel(scopeResult)) {
|
|
393
|
+
p.cancel("Install cancelled.");
|
|
394
|
+
return 130;
|
|
395
|
+
}
|
|
396
|
+
scope = scopeResult;
|
|
397
|
+
}
|
|
340
398
|
const skillResult = await p.multiselect({
|
|
341
399
|
message: "Skills \xB7 space = \uD1A0\uAE00 \xB7 a = \uC804\uCCB4 \xB7 enter = \uD655\uC778 (default ALL)",
|
|
342
400
|
options: allSkills.map((s) => ({ value: s, label: s, hint: "omd skill" })),
|
|
@@ -399,7 +457,11 @@ async function runInstallSkills(opts = {}) {
|
|
|
399
457
|
targets = targetResult;
|
|
400
458
|
}
|
|
401
459
|
}
|
|
402
|
-
const
|
|
460
|
+
const installRoot = scope === "global" ? homedir() : projectRoot;
|
|
461
|
+
const plans = targets.map((t) => planForTarget(installRoot, t));
|
|
462
|
+
p.log.message(
|
|
463
|
+
pc.bold("Scope: ") + pc.cyan(scope) + pc.dim(scope === "global" ? " (~/.claude)" : ` (${relative(process.cwd(), projectRoot) || "."})`)
|
|
464
|
+
);
|
|
403
465
|
p.log.message(
|
|
404
466
|
pc.bold(`Skills (${skills.length}): `) + skills.map((s) => pc.cyan(s)).join(", ")
|
|
405
467
|
);
|
|
@@ -411,6 +473,7 @@ async function runInstallSkills(opts = {}) {
|
|
|
411
473
|
p.log.message(
|
|
412
474
|
pc.bold("Targets: ") + targets.map((t) => pc.cyan(t)).join(", ")
|
|
413
475
|
);
|
|
476
|
+
if (minimal) canonicalAgents = [];
|
|
414
477
|
const results = [];
|
|
415
478
|
for (const plan of plans) {
|
|
416
479
|
for (const skill of skills) {
|
|
@@ -420,46 +483,48 @@ async function runInstallSkills(opts = {}) {
|
|
|
420
483
|
for (const target of targets) {
|
|
421
484
|
if (target === "claude-code") {
|
|
422
485
|
for (const filename of canonicalAgents) {
|
|
423
|
-
results.push(installAgentFile(packageRoot,
|
|
486
|
+
results.push(installAgentFile(packageRoot, installRoot, "claude", filename, force));
|
|
424
487
|
}
|
|
425
488
|
} else if (target === "codex") {
|
|
426
489
|
for (const filename of canonicalAgents) {
|
|
427
|
-
results.push(installAgentFile(packageRoot,
|
|
490
|
+
results.push(installAgentFile(packageRoot, installRoot, "codex", filename, force));
|
|
428
491
|
}
|
|
429
492
|
}
|
|
430
493
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
494
|
+
if (!minimal) {
|
|
495
|
+
const dataFiles = [
|
|
496
|
+
"reference-fingerprints.json",
|
|
497
|
+
"reference-tags.md",
|
|
498
|
+
"vocabulary.json",
|
|
499
|
+
"synonyms.json",
|
|
500
|
+
"opt-out-corpus.json"
|
|
501
|
+
];
|
|
502
|
+
for (const target of targets) {
|
|
503
|
+
if (target === "claude-code") {
|
|
504
|
+
for (const dataFile of dataFiles) {
|
|
505
|
+
results.push(installDataFile(packageRoot, installRoot, ".claude", dataFile, force));
|
|
506
|
+
}
|
|
507
|
+
} else if (target === "codex") {
|
|
508
|
+
for (const dataFile of dataFiles) {
|
|
509
|
+
results.push(installDataFile(packageRoot, installRoot, ".codex", dataFile, force));
|
|
510
|
+
}
|
|
446
511
|
}
|
|
447
512
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
513
|
+
if (scope === "project" && targets.includes("claude-code")) {
|
|
514
|
+
for (const hookFile of [
|
|
515
|
+
"skill-activation.cjs",
|
|
516
|
+
"session-state-loader.cjs",
|
|
517
|
+
"post-edit-watch.cjs",
|
|
518
|
+
"session-end-foldin.cjs"
|
|
519
|
+
]) {
|
|
520
|
+
results.push(installHookFile(packageRoot, installRoot, hookFile, force));
|
|
521
|
+
}
|
|
522
|
+
results.push(installSettingsJson(packageRoot, installRoot, force));
|
|
457
523
|
}
|
|
458
|
-
results.push(installSettingsJson(packageRoot, projectRoot, force));
|
|
459
524
|
}
|
|
460
525
|
p.log.message(pc.bold("\nResults:"));
|
|
461
526
|
for (const r of results) {
|
|
462
|
-
const rel = relative(
|
|
527
|
+
const rel = relative(installRoot, r.destPath);
|
|
463
528
|
p.log.message(
|
|
464
529
|
` ${STATUS_LABEL[r.status]} ${pc.dim(r.target.padEnd(12))} ${rel}`
|
|
465
530
|
);
|
|
@@ -476,6 +541,26 @@ async function runInstallSkills(opts = {}) {
|
|
|
476
541
|
);
|
|
477
542
|
return 0;
|
|
478
543
|
}
|
|
544
|
+
if (minimal) {
|
|
545
|
+
for (const r of results.filter((x) => x.status === "skipped-incompat")) {
|
|
546
|
+
p.log.warn(
|
|
547
|
+
`${pc.bold(r.skill)} ${pc.dim("skipped for ")}${pc.cyan(r.target)}${pc.dim(" \u2014 declares x-omd-channels (channel not supported).")}`
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
const installed = results.filter(
|
|
551
|
+
(r) => r.status === "created" || r.status === "updated"
|
|
552
|
+
);
|
|
553
|
+
if (installed.length === 0) {
|
|
554
|
+
p.outro(pc.yellow("Nothing installed \u2014 no compatible skill/channel match."));
|
|
555
|
+
return 0;
|
|
556
|
+
}
|
|
557
|
+
p.outro(
|
|
558
|
+
pc.green(
|
|
559
|
+
`Done. Installed ${skills.map((s) => pc.bold(s)).join(", ")} ${scope === "global" ? "globally (~/.claude/skills)" : `for ${targets.join(", ")}`}.`
|
|
560
|
+
) + pc.dim(" \u2192 restart your agent, then use the skill (e.g. ") + pc.cyan("/claude-design") + pc.dim(").")
|
|
561
|
+
);
|
|
562
|
+
return 0;
|
|
563
|
+
}
|
|
479
564
|
const nextSteps = [
|
|
480
565
|
`${pc.bold("Restart your agent, then type your first prompt:")}`,
|
|
481
566
|
"",
|
|
@@ -491,10 +576,10 @@ async function runInstallSkills(opts = {}) {
|
|
|
491
576
|
`${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.")}`
|
|
492
577
|
].join("\n");
|
|
493
578
|
p.note(nextSteps, "Next");
|
|
494
|
-
const hookCount = targets.includes("claude-code") ? 4 : 0;
|
|
579
|
+
const hookCount = scope === "project" && targets.includes("claude-code") ? 4 : 0;
|
|
495
580
|
p.outro(
|
|
496
581
|
pc.green(
|
|
497
|
-
`Done. ${skills.length} skills \xB7 ${canonicalAgents.length} sub-agents \xB7 ${hookCount} hooks installed (${writtenCount} files).`
|
|
582
|
+
`Done. ${skills.length} skills \xB7 ${canonicalAgents.length} sub-agents \xB7 ${hookCount} hooks installed (${writtenCount} files)${scope === "global" ? " globally (~/.claude)" : ""}.`
|
|
498
583
|
)
|
|
499
584
|
);
|
|
500
585
|
return 0;
|
|
@@ -502,4 +587,4 @@ async function runInstallSkills(opts = {}) {
|
|
|
502
587
|
export {
|
|
503
588
|
runInstallSkills
|
|
504
589
|
};
|
|
505
|
-
//# sourceMappingURL=install-skills-
|
|
590
|
+
//# sourceMappingURL=install-skills-52LCRBZZ.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 { homedir } from 'node:os';\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 /** Install to the user-level dir (~/.claude/skills) instead of this project.\n * Writes skills + sub-agents (+ data); never touches global hooks/settings.\n * When unset and interactive, the TUI asks project-vs-global. */\n global?: 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 // Install scope: 'project' (<cwd>/.claude/…) or 'global' (~/.claude/…). --global\n // forces it; otherwise the interactive TUI asks. Global writes skills + sub-agents\n // (+ data) to the user-level dir but never touches global hooks/settings.json.\n let scope: 'project' | 'global' = opts.global ? 'global' : 'project';\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 — scope → skill → subagent → channel order ===\n // 0. Scope (project vs global) — skipped when --global already forced it.\n if (!opts.global) {\n const scopeResult = await p.select({\n message: 'Install scope · 어디에 설치할까요?',\n options: [\n { value: 'project', label: 'Project', hint: `${relative(process.cwd(), projectRoot) || '.'}/.claude/skills · 이 프로젝트만` },\n { value: 'global', label: 'Global', hint: '~/.claude/skills · 모든 프로젝트 (skills + sub-agents, hooks/settings 제외)' },\n ],\n initialValue: 'project',\n });\n if (p.isCancel(scopeResult)) {\n p.cancel('Install cancelled.');\n return 130;\n }\n scope = scopeResult as 'project' | 'global';\n }\n\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 // Global scope roots everything at the home dir, so plan dirs resolve to\n // ~/.claude/skills, ~/.claude/agents, etc. Project scope uses cwd (or --dir).\n const installRoot = scope === 'global' ? homedir() : projectRoot;\n const plans = targets.map((t) => planForTarget(installRoot, t));\n\n p.log.message(\n pc.bold('Scope: ') +\n pc.cyan(scope) +\n pc.dim(scope === 'global' ? ' (~/.claude)' : ` (${relative(process.cwd(), projectRoot) || '.'})`)\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, installRoot, 'claude', filename, force));\n }\n } else if (target === 'codex') {\n for (const filename of canonicalAgents) {\n results.push(installAgentFile(packageRoot, installRoot, '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) so skills + hooks can run entirely\n // 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, installRoot, '.claude', dataFile, force));\n }\n } else if (target === 'codex') {\n for (const dataFile of dataFiles) {\n results.push(installDataFile(packageRoot, installRoot, '.codex', dataFile, force));\n }\n }\n }\n\n // Hooks + settings.json are PROJECT-SCOPED only — a global install must not\n // mutate the user's global Claude config / make hooks fire in every project.\n if (scope === 'project' && 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, installRoot, hookFile, force));\n }\n // settings.json (with merge, never clobber user)\n results.push(installSettingsJson(packageRoot, installRoot, 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(installRoot, 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(', ')} ${scope === 'global' ? 'globally (~/.claude/skills)' : `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 = scope === 'project' && 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)${scope === 'global' ? ' globally (~/.claude)' : ''}.`,\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.
|
|
3
|
+
"version": "1.6.3",
|
|
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,6 +24,7 @@
|
|
|
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
29
|
"data/opt-out-corpus.json",
|
|
29
30
|
"data/synonyms.json",
|