oh-my-design-cli 0.1.0 → 0.1.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.
- package/README.ko.md +3 -2
- package/README.md +3 -2
- package/dist/bin/oh-my-design.js +5 -5
- package/dist/bin/oh-my-design.js.map +1 -1
- package/dist/{init-STACB7E5.js → init-UMM4XIV5.js} +42 -2
- package/dist/init-UMM4XIV5.js.map +1 -0
- package/dist/{sync-P7X4S2DK.js → sync-FDYRKNFE.js} +16 -3
- package/dist/sync-FDYRKNFE.js.map +1 -0
- package/package.json +3 -3
- package/dist/init-STACB7E5.js.map +0 -1
- package/dist/sync-P7X4S2DK.js.map +0 -1
- package/references/Claude-Design-Sys-Prompt.txt +0 -421
- package/references/airbnb/README.md +0 -23
- package/references/airbnb/preview-dark.html +0 -234
- package/references/airbnb/preview.html +0 -233
- package/references/airtable/README.md +0 -23
- package/references/airtable/preview-dark.html +0 -165
- package/references/airtable/preview.html +0 -164
- package/references/apple/README.md +0 -24
- package/references/apple/preview-dark.html +0 -420
- package/references/apple/preview.html +0 -414
- package/references/baemin/README.md +0 -19
- package/references/bmw/README.md +0 -23
- package/references/bmw/preview-dark.html +0 -211
- package/references/bmw/preview.html +0 -210
- package/references/cal/README.md +0 -23
- package/references/cal/preview-dark.html +0 -449
- package/references/cal/preview.html +0 -575
- package/references/claude/README.md +0 -24
- package/references/claude/preview-dark.html +0 -803
- package/references/claude/preview.html +0 -826
- package/references/clay/README.md +0 -23
- package/references/clay/preview-dark.html +0 -316
- package/references/clay/preview.html +0 -315
- package/references/clickhouse/README.md +0 -24
- package/references/clickhouse/preview-dark.html +0 -834
- package/references/clickhouse/preview.html +0 -786
- package/references/cohere/README.md +0 -24
- package/references/cohere/preview-dark.html +0 -803
- package/references/cohere/preview.html +0 -807
- package/references/coinbase/README.md +0 -23
- package/references/coinbase/preview-dark.html +0 -164
- package/references/coinbase/preview.html +0 -163
- package/references/composio/README.md +0 -24
- package/references/composio/preview-dark.html +0 -958
- package/references/composio/preview.html +0 -933
- package/references/cursor/README.md +0 -24
- package/references/cursor/preview-dark.html +0 -393
- package/references/cursor/preview.html +0 -383
- package/references/dcard/README.md +0 -12
- package/references/dcard/_research/forum-1440px.png +0 -0
- package/references/dcard/_research.md +0 -77
- package/references/elevenlabs/README.md +0 -23
- package/references/elevenlabs/preview-dark.html +0 -252
- package/references/elevenlabs/preview.html +0 -251
- package/references/expo/README.md +0 -24
- package/references/expo/preview-dark.html +0 -533
- package/references/expo/preview.html +0 -533
- package/references/ferrari/README.md +0 -23
- package/references/ferrari/preview-dark.html +0 -1162
- package/references/ferrari/preview.html +0 -1122
- package/references/figma/README.md +0 -24
- package/references/figma/preview-dark.html +0 -822
- package/references/figma/preview.html +0 -832
- package/references/framer/README.md +0 -23
- package/references/framer/preview-dark.html +0 -902
- package/references/framer/preview.html +0 -883
- package/references/freee/README.md +0 -12
- package/references/freee/_research/vibes-storybook-1440px.png +0 -0
- package/references/freee/_research.md +0 -77
- package/references/hashicorp/README.md +0 -24
- package/references/hashicorp/preview-dark.html +0 -1202
- package/references/hashicorp/preview.html +0 -1193
- package/references/ibm/README.md +0 -24
- package/references/ibm/preview-dark.html +0 -443
- package/references/ibm/preview.html +0 -428
- package/references/intercom/README.md +0 -23
- package/references/intercom/preview-dark.html +0 -185
- package/references/intercom/preview.html +0 -184
- package/references/kakao/README.md +0 -18
- package/references/karrot/README.md +0 -18
- package/references/kraken/README.md +0 -23
- package/references/kraken/preview-dark.html +0 -169
- package/references/kraken/preview.html +0 -168
- package/references/lamborghini/README.md +0 -23
- package/references/lamborghini/preview-dark.html +0 -303
- package/references/lamborghini/preview.html +0 -381
- package/references/line/README.md +0 -12
- package/references/line/_research/home-1440px.png +0 -0
- package/references/line/_research.md +0 -65
- package/references/linear.app/README.md +0 -24
- package/references/linear.app/preview-dark.html +0 -383
- package/references/linear.app/preview.html +0 -373
- package/references/lovable/README.md +0 -24
- package/references/lovable/preview-dark.html +0 -349
- package/references/lovable/preview.html +0 -348
- package/references/mercari/README.md +0 -12
- package/references/mercari/_research/home-1440px.png +0 -0
- package/references/mercari/_research.md +0 -77
- package/references/minimax/README.md +0 -24
- package/references/minimax/preview-dark.html +0 -1262
- package/references/minimax/preview.html +0 -1248
- package/references/mintlify/README.md +0 -24
- package/references/mintlify/preview-dark.html +0 -409
- package/references/mintlify/preview.html +0 -398
- package/references/miro/README.md +0 -23
- package/references/miro/preview-dark.html +0 -174
- package/references/miro/preview.html +0 -173
- package/references/mistral.ai/README.md +0 -24
- package/references/mistral.ai/preview-dark.html +0 -806
- package/references/mistral.ai/preview.html +0 -805
- package/references/mongodb/README.md +0 -23
- package/references/mongodb/preview-dark.html +0 -260
- package/references/mongodb/preview.html +0 -259
- package/references/notion/README.md +0 -24
- package/references/notion/preview-dark.html +0 -372
- package/references/notion/preview.html +0 -364
- package/references/nvidia/README.md +0 -24
- package/references/nvidia/preview-dark.html +0 -374
- package/references/nvidia/preview.html +0 -366
- package/references/ollama/README.md +0 -24
- package/references/ollama/preview-dark.html +0 -678
- package/references/ollama/preview.html +0 -678
- package/references/opencode.ai/README.md +0 -24
- package/references/opencode.ai/preview-dark.html +0 -366
- package/references/opencode.ai/preview.html +0 -357
- package/references/pinkoi/README.md +0 -12
- package/references/pinkoi/_research/browse-1440px.png +0 -0
- package/references/pinkoi/_research.md +0 -115
- package/references/pinterest/README.md +0 -23
- package/references/pinterest/preview-dark.html +0 -233
- package/references/pinterest/preview.html +0 -232
- package/references/posthog/README.md +0 -23
- package/references/posthog/preview-dark.html +0 -699
- package/references/posthog/preview.html +0 -749
- package/references/raycast/README.md +0 -23
- package/references/raycast/preview-dark.html +0 -606
- package/references/raycast/preview.html +0 -688
- package/references/renault/README.md +0 -23
- package/references/renault/preview-dark.html +0 -406
- package/references/renault/preview.html +0 -606
- package/references/replicate/README.md +0 -24
- package/references/replicate/preview-dark.html +0 -828
- package/references/replicate/preview.html +0 -831
- package/references/resend/README.md +0 -23
- package/references/resend/preview-dark.html +0 -355
- package/references/resend/preview.html +0 -354
- package/references/revolut/README.md +0 -23
- package/references/revolut/preview-dark.html +0 -234
- package/references/revolut/preview.html +0 -233
- package/references/runwayml/README.md +0 -24
- package/references/runwayml/preview-dark.html +0 -664
- package/references/runwayml/preview.html +0 -665
- package/references/sanity/README.md +0 -24
- package/references/sanity/preview-dark.html +0 -990
- package/references/sanity/preview.html +0 -1135
- package/references/sentry/README.md +0 -24
- package/references/sentry/preview-dark.html +0 -626
- package/references/sentry/preview.html +0 -951
- package/references/spacex/README.md +0 -23
- package/references/spacex/preview-dark.html +0 -221
- package/references/spacex/preview.html +0 -220
- package/references/spotify/README.md +0 -23
- package/references/spotify/preview-dark.html +0 -231
- package/references/spotify/preview.html +0 -230
- package/references/stripe/README.md +0 -24
- package/references/stripe/preview-dark.html +0 -428
- package/references/stripe/preview.html +0 -419
- package/references/supabase/README.md +0 -24
- package/references/supabase/preview-dark.html +0 -977
- package/references/supabase/preview.html +0 -955
- package/references/superhuman/README.md +0 -23
- package/references/superhuman/preview-dark.html +0 -973
- package/references/superhuman/preview.html +0 -951
- package/references/tesla/README.md +0 -23
- package/references/tesla/preview-dark.html +0 -947
- package/references/tesla/preview.html +0 -925
- package/references/together.ai/README.md +0 -24
- package/references/together.ai/preview-dark.html +0 -892
- package/references/together.ai/preview.html +0 -897
- package/references/toss/README.md +0 -19
- package/references/uber/README.md +0 -24
- package/references/uber/preview-dark.html +0 -1120
- package/references/uber/preview.html +0 -1119
- package/references/vercel/README.md +0 -24
- package/references/vercel/preview-dark.html +0 -368
- package/references/vercel/preview.html +0 -367
- package/references/voltagent/README.md +0 -24
- package/references/voltagent/preview-dark.html +0 -487
- package/references/voltagent/preview.html +0 -766
- package/references/warp/README.md +0 -23
- package/references/warp/preview-dark.html +0 -500
- package/references/warp/preview.html +0 -533
- package/references/webflow/README.md +0 -23
- package/references/webflow/preview-dark.html +0 -147
- package/references/webflow/preview.html +0 -146
- package/references/wise/README.md +0 -23
- package/references/wise/preview-dark.html +0 -230
- package/references/wise/preview.html +0 -229
- package/references/x.ai/README.md +0 -24
- package/references/x.ai/preview-dark.html +0 -356
- package/references/x.ai/preview.html +0 -407
- package/references/zapier/README.md +0 -24
- package/references/zapier/preview-dark.html +0 -380
- package/references/zapier/preview.html +0 -372
package/README.ko.md
CHANGED
|
@@ -13,11 +13,12 @@
|
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
<p align="center">
|
|
16
|
+
<a href="https://www.npmjs.com/package/oh-my-design-cli"><img src="https://img.shields.io/npm/v/oh-my-design-cli?style=flat-square&color=cb3837" alt="npm version" /></a>
|
|
17
|
+
<a href="https://www.npmjs.com/package/oh-my-design-cli"><img src="https://img.shields.io/npm/dm/oh-my-design-cli?style=flat-square&color=cb3837" alt="npm downloads" /></a>
|
|
16
18
|
<a href="LICENSE"><img src="https://img.shields.io/github/license/kwakseongjae/oh-my-design?style=flat-square" alt="License" /></a>
|
|
17
19
|
<a href="https://github.com/kwakseongjae/oh-my-design/stargazers"><img src="https://img.shields.io/github/stars/kwakseongjae/oh-my-design?style=social" alt="GitHub Stars" /></a>
|
|
18
|
-
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square" alt="PRs Welcome" />
|
|
19
|
-
<img src="https://img.shields.io/badge/AI%20calls-zero-blue?style=flat-square" alt="Zero AI" />
|
|
20
20
|
<img src="https://img.shields.io/badge/references-67-7c5cfc?style=flat-square" alt="67 References" />
|
|
21
|
+
<img src="https://img.shields.io/badge/AI%20calls-zero-blue?style=flat-square" alt="Zero AI" />
|
|
21
22
|
</p>
|
|
22
23
|
|
|
23
24
|
<p align="center">
|
package/README.md
CHANGED
|
@@ -13,11 +13,12 @@
|
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
<p align="center">
|
|
16
|
+
<a href="https://www.npmjs.com/package/oh-my-design-cli"><img src="https://img.shields.io/npm/v/oh-my-design-cli?style=flat-square&color=cb3837" alt="npm version" /></a>
|
|
17
|
+
<a href="https://www.npmjs.com/package/oh-my-design-cli"><img src="https://img.shields.io/npm/dm/oh-my-design-cli?style=flat-square&color=cb3837" alt="npm downloads" /></a>
|
|
16
18
|
<a href="LICENSE"><img src="https://img.shields.io/github/license/kwakseongjae/oh-my-design?style=flat-square" alt="License" /></a>
|
|
17
19
|
<a href="https://github.com/kwakseongjae/oh-my-design/stargazers"><img src="https://img.shields.io/github/stars/kwakseongjae/oh-my-design?style=social" alt="GitHub Stars" /></a>
|
|
18
|
-
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square" alt="PRs Welcome" />
|
|
19
|
-
<img src="https://img.shields.io/badge/AI%20calls-zero-blue?style=flat-square" alt="Zero AI" />
|
|
20
20
|
<img src="https://img.shields.io/badge/references-67-7c5cfc?style=flat-square" alt="67 References" />
|
|
21
|
+
<img src="https://img.shields.io/badge/AI%20calls-zero-blue?style=flat-square" alt="Zero AI" />
|
|
21
22
|
</p>
|
|
22
23
|
|
|
23
24
|
<p align="center">
|
package/dist/bin/oh-my-design.js
CHANGED
|
@@ -730,8 +730,8 @@ function readPackageVersion() {
|
|
|
730
730
|
return "0.0.0";
|
|
731
731
|
}
|
|
732
732
|
var program = new Command();
|
|
733
|
-
program.name("oh-my-design").description("Interactive CLI to generate DESIGN.md files for AI coding agents").version(readPackageVersion());
|
|
734
|
-
program.command("generate"
|
|
733
|
+
program.name("oh-my-design").description("Interactive CLI to generate DESIGN.md files for AI coding agents").version(readPackageVersion()).showSuggestionAfterError(true).showHelpAfterError(true);
|
|
734
|
+
program.command("generate").description("Generate DESIGN.md and interactive preview").option("--config <hash>", "Apply a config hash from the web builder").action(async (opts) => {
|
|
735
735
|
if (opts.config) {
|
|
736
736
|
const { writeFileSync: writeFileSync2 } = await import("fs");
|
|
737
737
|
const { resolve: resolve2 } = await import("path");
|
|
@@ -809,7 +809,7 @@ referenceCmd.command("show <id>").description("Print the full reference DESIGN.m
|
|
|
809
809
|
var initCmd = program.command("init").description("Bootstrap DESIGN.md from a reference + project description");
|
|
810
810
|
initCmd.command("recommend <description...>").description("Recommend references matching a project description").option("--top <n>", "Number of recommendations", "5").option("--json", "Emit machine-readable JSON").action(
|
|
811
811
|
async (descParts, opts) => {
|
|
812
|
-
const { runInitRecommend } = await import("../init-
|
|
812
|
+
const { runInitRecommend } = await import("../init-UMM4XIV5.js");
|
|
813
813
|
const code = runInitRecommend({
|
|
814
814
|
description: descParts.join(" "),
|
|
815
815
|
topK: opts.top ? Number(opts.top) : 5,
|
|
@@ -819,7 +819,7 @@ initCmd.command("recommend <description...>").description("Recommend references
|
|
|
819
819
|
}
|
|
820
820
|
);
|
|
821
821
|
initCmd.command("prepare").description("Stage init context: rename existing DESIGN.md, compute delta_set, write .omd/init-context.json").requiredOption("--ref <id>", "Reference id (e.g. vercel, linear.app)").requiredOption("--description <text>", "Project description").option("--dir <path>", "Project root (defaults to cwd)").option("--reason <text>", "Reason for deprecation header", "user-initiated omd init").option("--json", "Emit machine-readable JSON").action(async (opts) => {
|
|
822
|
-
const { runInitPrepare } = await import("../init-
|
|
822
|
+
const { runInitPrepare } = await import("../init-UMM4XIV5.js");
|
|
823
823
|
const code = runInitPrepare(opts);
|
|
824
824
|
if (code !== 0) process.exit(code);
|
|
825
825
|
});
|
|
@@ -836,7 +836,7 @@ program.command("remember <note...>").description("Append a design preference/co
|
|
|
836
836
|
}
|
|
837
837
|
);
|
|
838
838
|
program.command("sync").description("Sync DESIGN.md shim files (CLAUDE.md, AGENTS.md, .cursor/rules/omd-design.mdc)").option("--dir <path>", "Project root (defaults to cwd)").option("--force", "Overwrite drift without prompting").option("--check", "Exit non-zero if any shim has drift; do not write").action(async (opts) => {
|
|
839
|
-
const { runSync } = await import("../sync-
|
|
839
|
+
const { runSync } = await import("../sync-FDYRKNFE.js");
|
|
840
840
|
const code = await runSync(opts);
|
|
841
841
|
if (code !== 0) process.exit(code);
|
|
842
842
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../bin/oh-my-design.ts","../../src/cli/index.ts","../../src/cli/prompts.ts","../../src/core/preview-generator.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { run } from '../src/cli/index.js';\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('Interactive CLI to generate DESIGN.md files for AI coding agents')\n .version(readPackageVersion());\n\nprogram\n .command('generate', { isDefault: true })\n .description('Generate DESIGN.md and interactive preview')\n .option('--config <hash>', 'Apply a config hash from the web builder')\n .action(async (opts: { config?: string }) => {\n if (opts.config) {\n // Decode config hash and generate directly without prompts\n const { writeFileSync } = await import('fs');\n const { resolve } = await import('path');\n\n // Decode the hash — format: refId|primary|font|weight|radius|dark|components|stylePrefs\n // parts[7] (stylePrefs) was added in v2. Old hashes lack it and still decode.\n let b64 = opts.config.replace(/-/g, '+').replace(/_/g, '/');\n while (b64.length % 4) b64 += '=';\n const decoded = Buffer.from(b64, 'base64').toString('utf-8');\n const parts = decoded.split('|');\n\n const refId = parts[0] || 'vercel';\n const overrides = {\n primaryColor: parts[1] || undefined,\n fontFamily: parts[2] || undefined,\n headingWeight: parts[3] || undefined,\n borderRadius: parts[4] || undefined,\n darkMode: parts[5] === '1',\n };\n const components = parts[6] ? parts[6].split(',').filter(Boolean) : [];\n // stylePreferences are decoded but not yet applied here — the CLI's\n // customizer (src/core/customizer.ts) does not mirror the web's\n // stylePreferences inline-rewrite logic yet. Parsed here so old and\n // new hashes coexist without error; CLI integration is a follow-up.\n const stylePrefs: Record<string, string> = {};\n if (parts[7]) {\n for (const pair of parts[7].split(';')) {\n const [k, v] = pair.split('=');\n if (k && v) stylePrefs[k] = v;\n }\n }\n\n // Load reference and apply\n const { loadReference } = await import('../src/core/reference-parser.js');\n const { applyOverrides } = await import('../src/core/customizer.js');\n\n const ref = loadReference(refId);\n const mode = (overrides.primaryColor || overrides.fontFamily) ? 'customized' as const : 'as-is' as const;\n const { designMd, shadcnCss, previewData } = applyOverrides(ref, {\n primaryColor: overrides.primaryColor,\n fontFamily: overrides.fontFamily,\n headingWeight: overrides.headingWeight,\n borderRadius: overrides.borderRadius,\n darkMode: overrides.darkMode,\n }, mode, components);\n\n previewData.shadcnCss = shadcnCss;\n previewData.designMd = designMd;\n\n const outputDir = process.cwd();\n const mdPath = resolve(outputDir, 'DESIGN.md');\n writeFileSync(mdPath, designMd, 'utf-8');\n\n console.log(`\\x1b[32m✓\\x1b[0m DESIGN.md generated at ${mdPath}`);\n console.log(` Based on: ${ref.name}`);\n if (overrides.primaryColor) console.log(` Primary: ${overrides.primaryColor}`);\n if (overrides.fontFamily) console.log(` Font: ${overrides.fontFamily}`);\n if (overrides.headingWeight) console.log(` Weight: ${overrides.headingWeight}`);\n if (overrides.borderRadius) console.log(` Radius: ${overrides.borderRadius}`);\n if (overrides.darkMode) console.log(` Dark mode: included`);\n } else {\n await run();\n }\n });\n\nprogram\n .command('install-skills')\n .description('Install omd:* skill files into agent directories (.claude/, .codex/, .opencode/)')\n .option('--dir <path>', 'Project root (defaults to cwd)')\n .option('--agent <name...>', 'Restrict to specific agents (claude-code | codex | opencode)')\n .option('--force', 'Overwrite existing files even without the omd marker')\n .action(\n async (opts: { dir?: string; agent?: string[]; force?: boolean }) => {\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 });\n if (code !== 0) process.exit(code);\n }\n );\n\nconst referenceCmd = program\n .command('reference')\n .description('Inspect bundled design references');\n\nreferenceCmd\n .command('list')\n .description('List all bundled reference ids')\n .action(async () => {\n const { runReferenceList } = await import('../src/cli/reference.js');\n process.exit(runReferenceList());\n });\n\nreferenceCmd\n .command('show <id>')\n .description('Print the full reference DESIGN.md to stdout')\n .action(async (id: string) => {\n const { runReferenceShow } = await import('../src/cli/reference.js');\n process.exit(runReferenceShow(id));\n });\n\nconst initCmd = program\n .command('init')\n .description('Bootstrap DESIGN.md from a reference + project description');\n\ninitCmd\n .command('recommend <description...>')\n .description('Recommend references matching a project description')\n .option('--top <n>', 'Number of recommendations', '5')\n .option('--json', 'Emit machine-readable JSON')\n .action(\n async (descParts: string[], opts: { top?: string; json?: boolean }) => {\n const { runInitRecommend } = await import('../src/cli/init.js');\n const code = runInitRecommend({\n description: descParts.join(' '),\n topK: opts.top ? Number(opts.top) : 5,\n json: opts.json,\n });\n if (code !== 0) process.exit(code);\n }\n );\n\ninitCmd\n .command('prepare')\n .description('Stage init context: rename existing DESIGN.md, compute delta_set, write .omd/init-context.json')\n .requiredOption('--ref <id>', 'Reference id (e.g. vercel, linear.app)')\n .requiredOption('--description <text>', 'Project description')\n .option('--dir <path>', 'Project root (defaults to cwd)')\n .option('--reason <text>', 'Reason for deprecation header', 'user-initiated omd init')\n .option('--json', 'Emit machine-readable JSON')\n .action(async (opts: { ref: string; description: string; dir?: string; reason?: string; json?: boolean }) => {\n const { runInitPrepare } = await import('../src/cli/init.js');\n const code = runInitPrepare(opts);\n if (code !== 0) process.exit(code);\n });\n\nprogram\n .command('learn')\n .description('List preferences and flip status (applied/rejected)')\n .option('--dir <path>', 'Project root (defaults to cwd)')\n .option('--all', 'Include all statuses (default: pending only)')\n .option('--status <s>', 'Filter by status: pending|applied|rejected|superseded')\n .option('--scope <s>', 'Filter by scope')\n .option('--mark-applied <id>', 'Mark entry as applied')\n .option('--mark-rejected <id>', 'Mark entry as rejected (requires --reason)')\n .option('--reason <text>', 'Reason for rejection')\n .option('--hash <value>', 'DESIGN.md hash to stamp on applied entry (defaults to current file)')\n .action(async (opts: Record<string, string | boolean>) => {\n const { runLearn } = await import('../src/cli/learn.js');\n const code = await runLearn(opts as never);\n if (code !== 0) process.exit(code);\n });\n\nprogram\n .command('remember <note...>')\n .description('Append a design preference/correction to .omd/preferences.md')\n .option('--dir <path>', 'Project root (defaults to cwd)')\n .option('--scope <scope>', 'Explicit scope (e.g. color, components.button)')\n .option('--agent <name>', 'Source agent (e.g. claude-code, codex)')\n .option('--context <text>', 'Source file/line context')\n .action(\n async (\n noteParts: string[],\n opts: {\n dir?: string;\n scope?: string;\n agent?: string;\n context?: string;\n }\n ) => {\n const { runRemember } = await import('../src/cli/remember.js');\n const code = await runRemember(noteParts.join(' '), opts as never);\n if (code !== 0) process.exit(code);\n }\n );\n\nprogram\n .command('sync')\n .description('Sync DESIGN.md shim files (CLAUDE.md, AGENTS.md, .cursor/rules/omd-design.mdc)')\n .option('--dir <path>', 'Project root (defaults to cwd)')\n .option('--force', 'Overwrite drift without prompting')\n .option('--check', 'Exit non-zero if any shim has drift; do not write')\n .action(async (opts: { dir?: string; force?: boolean; check?: boolean }) => {\n const { runSync } = await import('../src/cli/sync.js');\n const code = await runSync(opts);\n if (code !== 0) process.exit(code);\n });\n\nprogram\n .command('preview')\n .description('Open the preview HTML in the default browser')\n .action(async () => {\n const { existsSync } = await import('fs');\n const { resolve } = await import('path');\n const previewPath = resolve(process.cwd(), 'DESIGN.preview.html');\n\n if (!existsSync(previewPath)) {\n console.error('No DESIGN.preview.html found. Run `oh-my-design generate` first.');\n process.exit(1);\n }\n\n const { exec } = await import('child_process');\n const platform = process.platform;\n const cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'start' : 'xdg-open';\n exec(`${cmd} \"${previewPath}\"`);\n console.log(`Opening ${previewPath}...`);\n });\n\nprogram.parse();\n","import * as p from '@clack/prompts';\nimport { writeFileSync } from 'fs';\nimport { resolve } from 'path';\nimport { runPrompts } from './prompts.js';\nimport { applyOverrides } from '../core/customizer.js';\nimport { generatePreviewHtml } from '../core/preview-generator.js';\n\nexport async function run() {\n const { reference, overrides, outputMode } = await runPrompts();\n\n const s = p.spinner();\n s.start(`Building design system based on ${reference.name}...`);\n\n // Apply overrides to reference DESIGN.md\n const { designMd, shadcnCss, previewData } = applyOverrides(reference, overrides, outputMode);\n\n // Fill in the preview data with generated content\n previewData.shadcnCss = shadcnCss;\n previewData.designMd = designMd;\n\n // Generate preview HTML\n const html = generatePreviewHtml(previewData);\n\n // Write files\n const outputDir = process.cwd();\n const mdPath = resolve(outputDir, 'DESIGN.md');\n const htmlPath = resolve(outputDir, 'DESIGN.preview.html');\n\n writeFileSync(mdPath, designMd, 'utf-8');\n writeFileSync(htmlPath, html, 'utf-8');\n\n s.stop('Done!');\n\n p.log.success(`DESIGN.md → ${mdPath}`);\n p.log.success(`Preview HTML → ${htmlPath}`);\n p.outro('Open DESIGN.preview.html in your browser to explore your design system.');\n}\n","import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { listReferences, loadReference } from '../core/reference-parser.js';\nimport type { ReferenceEntry } from '../core/reference-parser.js';\n\n// ── Types ────────────────────────────────────────────────────────\n\nexport interface CustomOverrides {\n primaryColor?: string; // override primary color hex\n headingWeight?: string; // override heading weight\n borderRadius?: string; // override base radius\n fontFamily?: string; // override primary font\n darkMode: boolean;\n additionalNotes?: string;\n}\n\nexport interface PromptResult {\n reference: ReferenceEntry;\n overrides: CustomOverrides;\n outputMode: 'as-is' | 'customized';\n}\n\n// ── Main ─────────────────────────────────────────────────────────\n\nexport async function runPrompts(): Promise<PromptResult> {\n p.intro(`${pc.bold('oh-my-design')} — Generate your DESIGN.md from real design systems`);\n\n // Step 1: List all references grouped by category\n const refs = listReferences();\n const categories = [...new Set(refs.map((r) => r.category))];\n\n // Step 1a: Pick category\n const category = await p.select({\n message: 'Pick a category:',\n options: categories.map((cat) => {\n const count = refs.filter((r) => r.category === cat).length;\n return { value: cat, label: `${cat}`, hint: `${count} references` };\n }),\n });\n if (p.isCancel(category)) { p.cancel('Cancelled.'); process.exit(0); }\n\n // Step 1b: Pick reference within category\n const categoryRefs = refs.filter((r) => r.category === category);\n const refId = await p.select({\n message: `Select a design system reference:`,\n options: categoryRefs.map((r) => ({\n value: r.id,\n label: `${r.name}`,\n hint: `${r.primaryColor}`,\n })),\n });\n if (p.isCancel(refId)) { p.cancel('Cancelled.'); process.exit(0); }\n\n const reference = loadReference(refId as string);\n\n p.log.info(`${pc.bold(reference.name)} loaded`);\n p.log.info(` Primary: ${pc.bold(reference.colors.primary)} ${reference.colors.primaryName}`);\n p.log.info(` Font: ${reference.typography.primary}`);\n p.log.info(` Radius: ${reference.radius}`);\n if (reference.mood) {\n p.log.info(` Mood: ${reference.mood.slice(0, 120)}...`);\n }\n\n // Step 2: Use as-is or customize?\n const mode = await p.select({\n message: 'How do you want to use this design system?',\n options: [\n { value: 'as-is', label: 'Use as-is', hint: 'Copy the reference DESIGN.md directly' },\n { value: 'customized', label: 'Customize', hint: 'Modify colors, fonts, radius, etc.' },\n ],\n });\n if (p.isCancel(mode)) { p.cancel('Cancelled.'); process.exit(0); }\n\n if (mode === 'as-is') {\n const darkMode = await p.confirm({\n message: 'Include dark mode notes?',\n initialValue: false,\n });\n if (p.isCancel(darkMode)) { p.cancel('Cancelled.'); process.exit(0); }\n\n return {\n reference,\n overrides: { darkMode },\n outputMode: 'as-is',\n };\n }\n\n // Step 3: Customization prompts\n const overrides = await p.group(\n {\n primaryColor: () =>\n p.text({\n message: `Primary color (current: ${reference.colors.primary}):`,\n placeholder: 'Press enter to keep, or type a hex like #6366f1',\n validate: (val) => {\n if (val && !/^#[0-9a-fA-F]{6}$/.test(val)) return 'Invalid hex color';\n },\n }),\n\n fontFamily: () =>\n p.select({\n message: `Primary font (current: ${reference.typography.primary}):`,\n options: [\n { value: '', label: `Keep \"${reference.typography.primary}\"`, hint: 'No change' },\n { value: 'Inter', label: 'Inter', hint: 'Clean, geometric sans-serif' },\n { value: 'system-ui', label: 'System UI', hint: 'Native OS fonts' },\n { value: 'JetBrains Mono', label: 'JetBrains Mono', hint: 'Monospace, technical' },\n { value: 'Geist', label: 'Geist', hint: 'Vercel\\'s modern sans' },\n ],\n }),\n\n headingWeight: () =>\n p.select({\n message: `Heading weight (current: ${reference.typography.headingWeight}):`,\n options: [\n { value: '', label: `Keep ${reference.typography.headingWeight}`, hint: 'No change' },\n { value: '300', label: '300 — Light', hint: 'Whisper authority (Stripe style)' },\n { value: '400', label: '400 — Regular' },\n { value: '500', label: '500 — Medium', hint: 'Balanced emphasis' },\n { value: '600', label: '600 — Semibold', hint: 'Strong headings' },\n { value: '700', label: '700 — Bold', hint: 'Maximum impact' },\n ],\n }),\n\n borderRadius: () =>\n p.select({\n message: `Border radius (current: ${reference.radius}):`,\n options: [\n { value: '', label: `Keep \"${reference.radius}\"`, hint: 'No change' },\n { value: '2px', label: 'Sharp (2px)', hint: 'Technical, precise' },\n { value: '4px', label: 'Tight (4px)', hint: 'Conservative' },\n { value: '6px', label: 'Moderate (6px)', hint: 'Balanced' },\n { value: '8px', label: 'Comfortable (8px)', hint: 'Friendly' },\n { value: '12px', label: 'Rounded (12px)', hint: 'Soft, approachable' },\n { value: '9999px', label: 'Pill', hint: 'Fully rounded' },\n ],\n }),\n\n darkMode: () =>\n p.confirm({\n message: 'Generate dark mode variant?',\n initialValue: false,\n }),\n\n additionalNotes: () =>\n p.text({\n message: 'Any additional customization notes? (optional)',\n placeholder: 'e.g. \"Use more warm tones\" or press enter to skip',\n }),\n },\n {\n onCancel: () => { p.cancel('Cancelled.'); process.exit(0); },\n },\n );\n\n return {\n reference,\n overrides: {\n primaryColor: overrides.primaryColor || undefined,\n fontFamily: overrides.fontFamily || undefined,\n headingWeight: overrides.headingWeight || undefined,\n borderRadius: overrides.borderRadius || undefined,\n darkMode: overrides.darkMode,\n additionalNotes: overrides.additionalNotes || undefined,\n },\n outputMode: 'customized',\n };\n}\n","import type { PreviewData } from './customizer.js';\nimport {\n generateColorScale,\n contrastForeground,\n hslString,\n hexToHsl,\n hslToHex,\n lighten,\n darken,\n generateChartColors,\n} from '../utils/color.js';\n\nexport function generatePreviewHtml(data: PreviewData): string {\n const {\n name, basedOn, primary, background, foreground, font, headingWeight,\n radius, colors, darkMode, shadcnCss,\n } = data;\n\n const isLightBg = isLight(background);\n const scale = generateColorScale(primary);\n const radiusPx = radius === '9999px' ? '24px' : radius;\n const borderColor = colors.border;\n const accent = colors.accent;\n const muted = colors.muted;\n const chart = colors.chart;\n\n // Generate dark mode vars for CSS\n const darkBg = hslToHex(hexToHsl(primary)[0], 15, 7);\n const darkFg = '#fafafa';\n const darkBorder = hslToHex(hexToHsl(primary)[0], 10, 18);\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>${esc(name)} — Design System Preview</title>\n<style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n\n :root {\n --bg: ${background};\n --fg: ${foreground};\n --primary: ${primary};\n --primary-fg: ${contrastForeground(primary)};\n --accent: ${accent};\n --muted: ${muted};\n --muted-fg: ${lighten(foreground, 40)};\n --border: ${borderColor};\n --destructive: #ef4444;\n --card: ${isLightBg ? '#ffffff' : lighten(background, 3)};\n --radius: ${radiusPx};\n }\n\n .dark {\n --bg: ${darkBg};\n --fg: ${darkFg};\n --card: ${lighten(darkBg, 3)};\n --muted: ${hslToHex(hexToHsl(primary)[0], 10, 15)};\n --muted-fg: ${darken(darkFg, 35)};\n --border: ${darkBorder};\n }\n\n body {\n font-family: \"${font}\", \"Inter\", system-ui, sans-serif;\n background: var(--bg);\n color: var(--fg);\n line-height: 1.5;\n transition: background 0.25s, color 0.25s;\n }\n\n .shell { max-width: 1100px; margin: 0 auto; padding: 40px 24px 80px; }\n\n /* ── Header ─────── */\n .header {\n display: flex; justify-content: space-between; align-items: center;\n padding-bottom: 24px; margin-bottom: 40px;\n border-bottom: 1px solid var(--border);\n }\n .header h1 {\n font-size: 2rem; font-weight: ${headingWeight};\n letter-spacing: -0.02em;\n }\n .header .sub {\n font-size: 0.875rem; color: var(--muted-fg); margin-top: 4px;\n }\n .controls { display: flex; gap: 8px; }\n .ctrl-btn {\n padding: 8px 16px; border-radius: var(--radius);\n font-size: 0.8125rem; font-family: inherit; cursor: pointer;\n transition: all 0.15s; border: 1px solid var(--border);\n background: var(--card); color: var(--fg);\n }\n .ctrl-btn:hover { opacity: 0.85; }\n .ctrl-btn.primary { background: var(--primary); color: var(--primary-fg); border-color: transparent; }\n\n /* ── Sections ───── */\n .section { margin-bottom: 48px; }\n .section-title {\n font-size: 1.375rem; font-weight: ${headingWeight};\n letter-spacing: -0.01em; margin-bottom: 16px;\n }\n .section-sub { font-size: 0.8125rem; color: var(--muted-fg); margin-bottom: 16px; }\n\n /* ── Color Scale ── */\n .scale-row {\n display: flex; border-radius: var(--radius); overflow: hidden;\n border: 1px solid var(--border); margin-bottom: 24px;\n }\n .scale-stop {\n flex: 1; padding: 28px 4px 8px; text-align: center;\n font-size: 10px; font-family: monospace; cursor: pointer;\n transition: transform 0.1s; position: relative;\n }\n .scale-stop:hover { z-index: 1; transform: scaleY(1.12); }\n .scale-stop .lbl { display: block; opacity: 0.7; margin-bottom: 2px; }\n .scale-stop .hex {\n background: rgba(0,0,0,0.2); color: #fff;\n padding: 1px 4px; border-radius: 3px; font-size: 9px;\n }\n\n /* ── Color Chips ── */\n .chip-grid {\n display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px;\n }\n .chip {\n border-radius: var(--radius); overflow: hidden;\n border: 1px solid var(--border); cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n }\n .chip:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.1); }\n .chip .sw { height: 64px; display: flex; align-items: end; padding: 6px; }\n .chip .sw span {\n font-size: 10px; font-family: monospace;\n background: rgba(0,0,0,0.25); color: #fff;\n padding: 1px 5px; border-radius: 3px;\n }\n .chip .inf { padding: 8px; background: var(--card); }\n .chip .inf .n { font-size: 0.75rem; font-weight: 500; }\n .chip .inf .v { font-size: 10px; color: var(--muted-fg); font-family: monospace; }\n\n /* ── Typography ── */\n .type-rows { display: flex; flex-direction: column; gap: 8px; }\n .type-row {\n display: flex; align-items: baseline; gap: 16px;\n padding: 12px 16px; border-radius: var(--radius);\n background: var(--card); border: 1px solid var(--border);\n }\n .type-row .lbl {\n min-width: 48px; font-size: 0.75rem; color: var(--muted-fg);\n font-family: monospace; flex-shrink: 0;\n }\n .type-row .sample { flex: 1; }\n\n /* ── Components ── */\n .comp-card {\n padding: 24px; border-radius: var(--radius);\n background: var(--card); border: 1px solid var(--border);\n margin-bottom: 16px;\n }\n .comp-card h3 { font-size: 1rem; font-weight: 600; margin-bottom: 16px; }\n .comp-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-bottom: 12px; }\n\n .btn {\n display: inline-flex; align-items: center; justify-content: center;\n font-family: inherit; font-weight: 500; cursor: pointer;\n transition: all 0.15s; border: none; font-size: 0.8125rem;\n padding: 8px 16px; height: 36px; border-radius: var(--radius);\n }\n .btn-primary { background: var(--primary); color: var(--primary-fg); }\n .btn-secondary { background: var(--muted); color: var(--fg); }\n .btn-outline { background: transparent; color: var(--fg); border: 1px solid var(--border); }\n .btn-ghost { background: transparent; color: var(--fg); }\n .btn-destructive { background: var(--destructive); color: #fff; }\n .btn:hover { opacity: 0.9; }\n\n .badge {\n display: inline-flex; font-size: 0.6875rem; font-weight: 500;\n padding: 2px 10px; border-radius: 9999px;\n }\n .badge-primary { background: var(--primary); color: var(--primary-fg); }\n .badge-secondary { background: var(--muted); color: var(--fg); }\n .badge-outline { background: transparent; color: var(--fg); border: 1px solid var(--border); }\n\n .input-demo {\n width: 100%; max-width: 320px; font-family: inherit;\n background: var(--bg); color: var(--fg);\n border: 1px solid var(--border); border-radius: var(--radius);\n padding: 8px 12px; font-size: 0.8125rem; outline: none;\n transition: border-color 0.15s;\n }\n .input-demo:focus {\n border-color: var(--primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 20%, transparent);\n }\n\n .demo-table {\n width: 100%; border-collapse: collapse; font-size: 0.8125rem;\n }\n .demo-table th, .demo-table td {\n padding: 10px 12px; text-align: left;\n border-bottom: 1px solid var(--border);\n }\n .demo-table th {\n font-weight: 500; color: var(--muted-fg);\n font-size: 0.75rem; text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n .demo-table tr:hover td { background: var(--muted); }\n\n .demo-card {\n padding: 20px; border-radius: var(--radius);\n background: var(--card); border: 1px solid var(--border);\n max-width: 340px; box-shadow: 0 1px 3px rgba(0,0,0,0.06);\n }\n .demo-card h4 { font-weight: 600; margin-bottom: 6px; }\n .demo-card p { font-size: 0.8125rem; color: var(--muted-fg); margin-bottom: 14px; }\n\n .demo-dialog {\n padding: 24px; border-radius: var(--radius);\n background: var(--card); box-shadow: 0 20px 40px rgba(0,0,0,0.15);\n max-width: 400px; border: 1px solid var(--border);\n }\n .demo-dialog h4 { font-weight: 600; margin-bottom: 8px; }\n .demo-dialog p { font-size: 0.8125rem; color: var(--muted-fg); margin-bottom: 16px; }\n .demo-dialog .acts { display: flex; justify-content: flex-end; gap: 8px; }\n\n .tabs {\n display: flex; background: var(--muted); border-radius: var(--radius); padding: 4px; gap: 2px;\n }\n .tab {\n padding: 6px 14px; border-radius: calc(var(--radius) - 2px);\n font-size: 0.8125rem; font-family: inherit; font-weight: 500;\n border: none; cursor: pointer; background: transparent;\n color: var(--muted-fg); transition: all 0.15s;\n }\n .tab.active {\n background: var(--bg); color: var(--fg);\n box-shadow: 0 1px 2px rgba(0,0,0,0.05);\n }\n .tab:hover:not(.active) { color: var(--fg); }\n\n /* ── CSS Block ──── */\n .css-block {\n position: relative; background: var(--card);\n border: 1px solid var(--border); border-radius: var(--radius);\n overflow: hidden;\n }\n .css-block pre {\n padding: 20px; overflow-x: auto; font-family: monospace;\n font-size: 11px; line-height: 1.6; color: var(--fg);\n }\n .css-block .copy-css { position: absolute; top: 8px; right: 8px; }\n\n /* ── Spacing ────── */\n .spacing-vis {\n display: flex; align-items: end; gap: 8px; padding: 24px;\n background: var(--card); border: 1px solid var(--border);\n border-radius: var(--radius);\n }\n .sp-bar { display: flex; flex-direction: column; align-items: center; gap: 4px; }\n .sp-bar .bar { background: var(--primary); border-radius: 2px; width: 28px; }\n .sp-bar .val { font-size: 10px; font-family: monospace; color: var(--muted-fg); }\n\n /* ── Radius ─────── */\n .radius-grid { display: flex; gap: 16px; flex-wrap: wrap; }\n .radius-demo {\n width: 72px; height: 72px; background: var(--primary);\n display: flex; align-items: center; justify-content: center;\n color: var(--primary-fg); font-size: 0.6875rem; font-family: monospace;\n }\n\n /* ── Toast ──────── */\n .toast-popup {\n position: fixed; bottom: 24px; right: 24px;\n padding: 10px 20px; background: var(--fg); color: var(--bg);\n border-radius: var(--radius); font-size: 0.8125rem;\n box-shadow: 0 8px 20px rgba(0,0,0,0.15);\n transform: translateY(100px); opacity: 0;\n transition: all 0.3s; z-index: 100;\n }\n .toast-popup.show { transform: translateY(0); opacity: 1; }\n\n @media (max-width: 768px) {\n .shell { padding: 16px 12px 48px; }\n .header { flex-direction: column; gap: 12px; align-items: flex-start; }\n .chip-grid { grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); }\n }\n</style>\n</head>\n<body>\n<div class=\"shell\">\n\n <div class=\"header\">\n <div>\n <h1>${esc(name)}</h1>\n <div class=\"sub\">Based on ${esc(basedOn)} · Generated by oh-my-design</div>\n </div>\n <div class=\"controls\">\n ${darkMode ? '<button class=\"ctrl-btn\" onclick=\"toggleTheme()\" id=\"theme-btn\">🌙 Dark</button>' : ''}\n <button class=\"ctrl-btn primary\" onclick=\"copyCss()\">Copy CSS</button>\n </div>\n </div>\n\n <!-- Primary Scale -->\n <div class=\"section\">\n <h2 class=\"section-title\">Primary Color Scale</h2>\n <div class=\"section-sub\">Click to copy hex value</div>\n <div class=\"scale-row\">\n${Object.entries(scale).map(([stop, hex]) =>\n ` <div class=\"scale-stop\" style=\"background:${hex};color:${isLight(hex) ? '#000' : '#fff'}\" onclick=\"copy('${hex}')\">\n <span class=\"lbl\">${stop}</span><span class=\"hex\">${hex}</span>\n </div>`).join('\\n')}\n </div>\n </div>\n\n <!-- Semantic Colors -->\n <div class=\"section\">\n <h2 class=\"section-title\">Semantic Colors</h2>\n <div class=\"chip-grid\">\n${[\n { n: 'Primary', bg: primary, v: '--primary' },\n { n: 'Accent', bg: accent, v: '--accent' },\n { n: 'Muted', bg: muted, v: '--muted' },\n { n: 'Destructive', bg: '#ef4444', v: '--destructive' },\n { n: 'Background', bg: background, v: '--background' },\n { n: 'Foreground', bg: foreground, v: '--foreground' },\n { n: 'Border', bg: borderColor, v: '--border' },\n { n: 'Card', bg: isLightBg ? '#ffffff' : lighten(background, 3), v: '--card' },\n].map((c) => ` <div class=\"chip\" onclick=\"copy('${c.bg}')\">\n <div class=\"sw\" style=\"background:${c.bg}\"><span>${c.bg}</span></div>\n <div class=\"inf\"><div class=\"n\">${c.n}</div><div class=\"v\">${c.v}</div></div>\n </div>`).join('\\n')}\n </div>\n </div>\n\n <!-- Chart Colors -->\n <div class=\"section\">\n <h2 class=\"section-title\">Chart Colors</h2>\n <div style=\"display:flex;gap:8px;\">\n${chart.map((c, i) => ` <div style=\"width:48px;height:48px;border-radius:var(--radius);background:${c};cursor:pointer;\" onclick=\"copy('${c}')\" title=\"Chart ${i + 1}: ${c}\"></div>`).join('\\n')}\n </div>\n </div>\n\n <!-- Typography -->\n <div class=\"section\">\n <h2 class=\"section-title\">Typography</h2>\n <div class=\"type-rows\">\n <div class=\"type-row\">\n <span class=\"lbl\">H1</span>\n <span class=\"sample\" style=\"font-size:2.25rem;font-weight:${headingWeight};letter-spacing:-0.02em;line-height:1.2\">Page Title Heading</span>\n </div>\n <div class=\"type-row\">\n <span class=\"lbl\">H2</span>\n <span class=\"sample\" style=\"font-size:1.875rem;font-weight:${headingWeight};letter-spacing:-0.01em;line-height:1.25\">Section Heading</span>\n </div>\n <div class=\"type-row\">\n <span class=\"lbl\">H3</span>\n <span class=\"sample\" style=\"font-size:1.5rem;font-weight:${headingWeight};line-height:1.3\">Subsection</span>\n </div>\n <div class=\"type-row\">\n <span class=\"lbl\">body</span>\n <span class=\"sample\" style=\"font-size:1rem;\">The quick brown fox jumps over the lazy dog. 다람쥐 헌 쳇바퀴에 타고파.</span>\n </div>\n <div class=\"type-row\">\n <span class=\"lbl\">sm</span>\n <span class=\"sample\" style=\"font-size:0.875rem;color:var(--muted-fg)\">Secondary text, labels, and metadata</span>\n </div>\n <div class=\"type-row\">\n <span class=\"lbl\">mono</span>\n <span class=\"sample\" style=\"font-family:monospace;font-size:0.875rem\">const theme = generateDesignSystem();</span>\n </div>\n </div>\n </div>\n\n <!-- Radius -->\n <div class=\"section\">\n <h2 class=\"section-title\">Border Radius</h2>\n <div class=\"radius-grid\">\n <div style=\"text-align:center\"><div class=\"radius-demo\" style=\"border-radius:0\">0</div><div style=\"font-size:10px;margin-top:4px;color:var(--muted-fg)\">none</div></div>\n <div style=\"text-align:center\"><div class=\"radius-demo\" style=\"border-radius:${radiusPx}\">${radiusPx}</div><div style=\"font-size:10px;margin-top:4px;color:var(--muted-fg)\">base</div></div>\n <div style=\"text-align:center\"><div class=\"radius-demo\" style=\"border-radius:${parseInt(radiusPx) * 2}px\">${parseInt(radiusPx) * 2}px</div><div style=\"font-size:10px;margin-top:4px;color:var(--muted-fg)\">lg</div></div>\n <div style=\"text-align:center\"><div class=\"radius-demo\" style=\"border-radius:9999px\">pill</div><div style=\"font-size:10px;margin-top:4px;color:var(--muted-fg)\">full</div></div>\n </div>\n </div>\n\n <!-- Components -->\n <div class=\"section\">\n <h2 class=\"section-title\">Components</h2>\n\n <!-- Buttons -->\n <div class=\"comp-card\">\n <h3>Buttons</h3>\n <div class=\"comp-row\">\n <button class=\"btn btn-primary\">Primary</button>\n <button class=\"btn btn-secondary\">Secondary</button>\n <button class=\"btn btn-outline\">Outline</button>\n <button class=\"btn btn-ghost\">Ghost</button>\n <button class=\"btn btn-destructive\">Delete</button>\n </div>\n </div>\n\n <!-- Badges -->\n <div class=\"comp-card\">\n <h3>Badges</h3>\n <div class=\"comp-row\">\n <span class=\"badge badge-primary\">Active</span>\n <span class=\"badge badge-secondary\">Draft</span>\n <span class=\"badge badge-outline\">Archived</span>\n </div>\n </div>\n\n <!-- Input -->\n <div class=\"comp-card\">\n <h3>Input</h3>\n <div style=\"display:flex;flex-direction:column;gap:12px;max-width:400px;\">\n <div>\n <label style=\"font-size:0.8125rem;font-weight:500;display:block;margin-bottom:4px;\">Email</label>\n <input class=\"input-demo\" type=\"email\" placeholder=\"you@example.com\">\n </div>\n <div>\n <label style=\"font-size:0.8125rem;font-weight:500;display:block;margin-bottom:4px;\">Password</label>\n <input class=\"input-demo\" type=\"password\" placeholder=\"••••••••\">\n </div>\n </div>\n </div>\n\n <!-- Card -->\n <div class=\"comp-card\">\n <h3>Card</h3>\n <div class=\"comp-row\" style=\"align-items:stretch;\">\n <div class=\"demo-card\">\n <h4>Project Overview</h4>\n <p>A summary card showing key metrics and status for your project.</p>\n <button class=\"btn btn-primary\" style=\"height:32px;font-size:0.75rem;\">View Details</button>\n </div>\n </div>\n </div>\n\n <!-- Table -->\n <div class=\"comp-card\">\n <h3>Table</h3>\n <div style=\"overflow-x:auto;\">\n <table class=\"demo-table\">\n <thead><tr><th>Name</th><th>Status</th><th>Role</th><th>Email</th></tr></thead>\n <tbody>\n <tr><td>Kim Minjae</td><td><span class=\"badge badge-primary\" style=\"font-size:10px;\">Active</span></td><td>Developer</td><td>minjae@example.com</td></tr>\n <tr><td>Lee Soyeon</td><td><span class=\"badge badge-secondary\" style=\"font-size:10px;\">Pending</span></td><td>Designer</td><td>soyeon@example.com</td></tr>\n <tr><td>Park Jiwoo</td><td><span class=\"badge badge-outline\" style=\"font-size:10px;\">Inactive</span></td><td>PM</td><td>jiwoo@example.com</td></tr>\n </tbody>\n </table>\n </div>\n </div>\n\n <!-- Dialog -->\n <div class=\"comp-card\">\n <h3>Dialog</h3>\n <div class=\"demo-dialog\">\n <h4>Delete item?</h4>\n <p>This action cannot be undone.</p>\n <div class=\"acts\">\n <button class=\"btn btn-outline\" style=\"height:32px;\">Cancel</button>\n <button class=\"btn btn-destructive\" style=\"height:32px;\">Delete</button>\n </div>\n </div>\n </div>\n\n <!-- Tabs -->\n <div class=\"comp-card\">\n <h3>Tabs</h3>\n <div class=\"tabs\">\n <button class=\"tab active\">Overview</button>\n <button class=\"tab\">Analytics</button>\n <button class=\"tab\">Settings</button>\n </div>\n </div>\n </div>\n\n <!-- shadcn CSS -->\n <div class=\"section\">\n <h2 class=\"section-title\">shadcn/ui CSS Variables</h2>\n <div class=\"section-sub\">Ready to paste into globals.css</div>\n <div class=\"css-block\">\n <button class=\"ctrl-btn copy-css\" onclick=\"copyCss()\" style=\"position:absolute;top:8px;right:8px;\">Copy</button>\n <pre id=\"css-output\">${escHtml(shadcnCss)}</pre>\n </div>\n </div>\n\n</div>\n\n<div class=\"toast-popup\" id=\"toast\">Copied!</div>\n\n<script>\nlet isDark = false;\nfunction toggleTheme() {\n isDark = !isDark;\n document.body.classList.toggle('dark', isDark);\n const btn = document.getElementById('theme-btn');\n if (btn) btn.textContent = isDark ? '☀️ Light' : '🌙 Dark';\n}\nfunction showToast(msg) {\n const el = document.getElementById('toast');\n el.textContent = msg;\n el.classList.add('show');\n setTimeout(() => el.classList.remove('show'), 1800);\n}\nfunction copy(val) {\n navigator.clipboard.writeText(val).then(() => showToast('Copied: ' + val));\n}\nfunction copyCss() {\n const css = document.getElementById('css-output').textContent;\n navigator.clipboard.writeText(css).then(() => showToast('CSS variables copied!'));\n}\ndocument.querySelectorAll('.tab').forEach(t => {\n t.addEventListener('click', () => {\n t.parentElement.querySelectorAll('.tab').forEach(x => x.classList.remove('active'));\n t.classList.add('active');\n });\n});\n</script>\n</body>\n</html>`;\n}\n\nfunction isLight(hex: string): boolean {\n const h = hex.replace('#', '');\n const r = parseInt(h.slice(0, 2), 16);\n const g = parseInt(h.slice(2, 4), 16);\n const b = parseInt(h.slice(4, 6), 16);\n return (r * 299 + g * 587 + b * 114) / 1000 > 140;\n}\n\nfunction esc(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n}\n\nfunction escHtml(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n}\n"],"mappings":"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","names":["p","writeFileSync","resolve","loadReference","applyOverrides","existsSync"]}
|
|
1
|
+
{"version":3,"sources":["../../bin/oh-my-design.ts","../../src/cli/index.ts","../../src/cli/prompts.ts","../../src/core/preview-generator.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { run } from '../src/cli/index.js';\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('Interactive CLI to generate DESIGN.md files for AI coding agents')\n .version(readPackageVersion())\n .showSuggestionAfterError(true)\n .showHelpAfterError(true);\n\nprogram\n .command('generate')\n .description('Generate DESIGN.md and interactive preview')\n .option('--config <hash>', 'Apply a config hash from the web builder')\n .action(async (opts: { config?: string }) => {\n if (opts.config) {\n // Decode config hash and generate directly without prompts\n const { writeFileSync } = await import('fs');\n const { resolve } = await import('path');\n\n // Decode the hash — format: refId|primary|font|weight|radius|dark|components|stylePrefs\n // parts[7] (stylePrefs) was added in v2. Old hashes lack it and still decode.\n let b64 = opts.config.replace(/-/g, '+').replace(/_/g, '/');\n while (b64.length % 4) b64 += '=';\n const decoded = Buffer.from(b64, 'base64').toString('utf-8');\n const parts = decoded.split('|');\n\n const refId = parts[0] || 'vercel';\n const overrides = {\n primaryColor: parts[1] || undefined,\n fontFamily: parts[2] || undefined,\n headingWeight: parts[3] || undefined,\n borderRadius: parts[4] || undefined,\n darkMode: parts[5] === '1',\n };\n const components = parts[6] ? parts[6].split(',').filter(Boolean) : [];\n // stylePreferences are decoded but not yet applied here — the CLI's\n // customizer (src/core/customizer.ts) does not mirror the web's\n // stylePreferences inline-rewrite logic yet. Parsed here so old and\n // new hashes coexist without error; CLI integration is a follow-up.\n const stylePrefs: Record<string, string> = {};\n if (parts[7]) {\n for (const pair of parts[7].split(';')) {\n const [k, v] = pair.split('=');\n if (k && v) stylePrefs[k] = v;\n }\n }\n\n // Load reference and apply\n const { loadReference } = await import('../src/core/reference-parser.js');\n const { applyOverrides } = await import('../src/core/customizer.js');\n\n const ref = loadReference(refId);\n const mode = (overrides.primaryColor || overrides.fontFamily) ? 'customized' as const : 'as-is' as const;\n const { designMd, shadcnCss, previewData } = applyOverrides(ref, {\n primaryColor: overrides.primaryColor,\n fontFamily: overrides.fontFamily,\n headingWeight: overrides.headingWeight,\n borderRadius: overrides.borderRadius,\n darkMode: overrides.darkMode,\n }, mode, components);\n\n previewData.shadcnCss = shadcnCss;\n previewData.designMd = designMd;\n\n const outputDir = process.cwd();\n const mdPath = resolve(outputDir, 'DESIGN.md');\n writeFileSync(mdPath, designMd, 'utf-8');\n\n console.log(`\\x1b[32m✓\\x1b[0m DESIGN.md generated at ${mdPath}`);\n console.log(` Based on: ${ref.name}`);\n if (overrides.primaryColor) console.log(` Primary: ${overrides.primaryColor}`);\n if (overrides.fontFamily) console.log(` Font: ${overrides.fontFamily}`);\n if (overrides.headingWeight) console.log(` Weight: ${overrides.headingWeight}`);\n if (overrides.borderRadius) console.log(` Radius: ${overrides.borderRadius}`);\n if (overrides.darkMode) console.log(` Dark mode: included`);\n } else {\n await run();\n }\n });\n\nprogram\n .command('install-skills')\n .description('Install omd:* skill files into agent directories (.claude/, .codex/, .opencode/)')\n .option('--dir <path>', 'Project root (defaults to cwd)')\n .option('--agent <name...>', 'Restrict to specific agents (claude-code | codex | opencode)')\n .option('--force', 'Overwrite existing files even without the omd marker')\n .action(\n async (opts: { dir?: string; agent?: string[]; force?: boolean }) => {\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 });\n if (code !== 0) process.exit(code);\n }\n );\n\nconst referenceCmd = program\n .command('reference')\n .description('Inspect bundled design references');\n\nreferenceCmd\n .command('list')\n .description('List all bundled reference ids')\n .action(async () => {\n const { runReferenceList } = await import('../src/cli/reference.js');\n process.exit(runReferenceList());\n });\n\nreferenceCmd\n .command('show <id>')\n .description('Print the full reference DESIGN.md to stdout')\n .action(async (id: string) => {\n const { runReferenceShow } = await import('../src/cli/reference.js');\n process.exit(runReferenceShow(id));\n });\n\nconst initCmd = program\n .command('init')\n .description('Bootstrap DESIGN.md from a reference + project description');\n\ninitCmd\n .command('recommend <description...>')\n .description('Recommend references matching a project description')\n .option('--top <n>', 'Number of recommendations', '5')\n .option('--json', 'Emit machine-readable JSON')\n .action(\n async (descParts: string[], opts: { top?: string; json?: boolean }) => {\n const { runInitRecommend } = await import('../src/cli/init.js');\n const code = runInitRecommend({\n description: descParts.join(' '),\n topK: opts.top ? Number(opts.top) : 5,\n json: opts.json,\n });\n if (code !== 0) process.exit(code);\n }\n );\n\ninitCmd\n .command('prepare')\n .description('Stage init context: rename existing DESIGN.md, compute delta_set, write .omd/init-context.json')\n .requiredOption('--ref <id>', 'Reference id (e.g. vercel, linear.app)')\n .requiredOption('--description <text>', 'Project description')\n .option('--dir <path>', 'Project root (defaults to cwd)')\n .option('--reason <text>', 'Reason for deprecation header', 'user-initiated omd init')\n .option('--json', 'Emit machine-readable JSON')\n .action(async (opts: { ref: string; description: string; dir?: string; reason?: string; json?: boolean }) => {\n const { runInitPrepare } = await import('../src/cli/init.js');\n const code = runInitPrepare(opts);\n if (code !== 0) process.exit(code);\n });\n\nprogram\n .command('learn')\n .description('List preferences and flip status (applied/rejected)')\n .option('--dir <path>', 'Project root (defaults to cwd)')\n .option('--all', 'Include all statuses (default: pending only)')\n .option('--status <s>', 'Filter by status: pending|applied|rejected|superseded')\n .option('--scope <s>', 'Filter by scope')\n .option('--mark-applied <id>', 'Mark entry as applied')\n .option('--mark-rejected <id>', 'Mark entry as rejected (requires --reason)')\n .option('--reason <text>', 'Reason for rejection')\n .option('--hash <value>', 'DESIGN.md hash to stamp on applied entry (defaults to current file)')\n .action(async (opts: Record<string, string | boolean>) => {\n const { runLearn } = await import('../src/cli/learn.js');\n const code = await runLearn(opts as never);\n if (code !== 0) process.exit(code);\n });\n\nprogram\n .command('remember <note...>')\n .description('Append a design preference/correction to .omd/preferences.md')\n .option('--dir <path>', 'Project root (defaults to cwd)')\n .option('--scope <scope>', 'Explicit scope (e.g. color, components.button)')\n .option('--agent <name>', 'Source agent (e.g. claude-code, codex)')\n .option('--context <text>', 'Source file/line context')\n .action(\n async (\n noteParts: string[],\n opts: {\n dir?: string;\n scope?: string;\n agent?: string;\n context?: string;\n }\n ) => {\n const { runRemember } = await import('../src/cli/remember.js');\n const code = await runRemember(noteParts.join(' '), opts as never);\n if (code !== 0) process.exit(code);\n }\n );\n\nprogram\n .command('sync')\n .description('Sync DESIGN.md shim files (CLAUDE.md, AGENTS.md, .cursor/rules/omd-design.mdc)')\n .option('--dir <path>', 'Project root (defaults to cwd)')\n .option('--force', 'Overwrite drift without prompting')\n .option('--check', 'Exit non-zero if any shim has drift; do not write')\n .action(async (opts: { dir?: string; force?: boolean; check?: boolean }) => {\n const { runSync } = await import('../src/cli/sync.js');\n const code = await runSync(opts);\n if (code !== 0) process.exit(code);\n });\n\nprogram\n .command('preview')\n .description('Open the preview HTML in the default browser')\n .action(async () => {\n const { existsSync } = await import('fs');\n const { resolve } = await import('path');\n const previewPath = resolve(process.cwd(), 'DESIGN.preview.html');\n\n if (!existsSync(previewPath)) {\n console.error('No DESIGN.preview.html found. Run `oh-my-design generate` first.');\n process.exit(1);\n }\n\n const { exec } = await import('child_process');\n const platform = process.platform;\n const cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'start' : 'xdg-open';\n exec(`${cmd} \"${previewPath}\"`);\n console.log(`Opening ${previewPath}...`);\n });\n\nprogram.parse();\n","import * as p from '@clack/prompts';\nimport { writeFileSync } from 'fs';\nimport { resolve } from 'path';\nimport { runPrompts } from './prompts.js';\nimport { applyOverrides } from '../core/customizer.js';\nimport { generatePreviewHtml } from '../core/preview-generator.js';\n\nexport async function run() {\n const { reference, overrides, outputMode } = await runPrompts();\n\n const s = p.spinner();\n s.start(`Building design system based on ${reference.name}...`);\n\n // Apply overrides to reference DESIGN.md\n const { designMd, shadcnCss, previewData } = applyOverrides(reference, overrides, outputMode);\n\n // Fill in the preview data with generated content\n previewData.shadcnCss = shadcnCss;\n previewData.designMd = designMd;\n\n // Generate preview HTML\n const html = generatePreviewHtml(previewData);\n\n // Write files\n const outputDir = process.cwd();\n const mdPath = resolve(outputDir, 'DESIGN.md');\n const htmlPath = resolve(outputDir, 'DESIGN.preview.html');\n\n writeFileSync(mdPath, designMd, 'utf-8');\n writeFileSync(htmlPath, html, 'utf-8');\n\n s.stop('Done!');\n\n p.log.success(`DESIGN.md → ${mdPath}`);\n p.log.success(`Preview HTML → ${htmlPath}`);\n p.outro('Open DESIGN.preview.html in your browser to explore your design system.');\n}\n","import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { listReferences, loadReference } from '../core/reference-parser.js';\nimport type { ReferenceEntry } from '../core/reference-parser.js';\n\n// ── Types ────────────────────────────────────────────────────────\n\nexport interface CustomOverrides {\n primaryColor?: string; // override primary color hex\n headingWeight?: string; // override heading weight\n borderRadius?: string; // override base radius\n fontFamily?: string; // override primary font\n darkMode: boolean;\n additionalNotes?: string;\n}\n\nexport interface PromptResult {\n reference: ReferenceEntry;\n overrides: CustomOverrides;\n outputMode: 'as-is' | 'customized';\n}\n\n// ── Main ─────────────────────────────────────────────────────────\n\nexport async function runPrompts(): Promise<PromptResult> {\n p.intro(`${pc.bold('oh-my-design')} — Generate your DESIGN.md from real design systems`);\n\n // Step 1: List all references grouped by category\n const refs = listReferences();\n const categories = [...new Set(refs.map((r) => r.category))];\n\n // Step 1a: Pick category\n const category = await p.select({\n message: 'Pick a category:',\n options: categories.map((cat) => {\n const count = refs.filter((r) => r.category === cat).length;\n return { value: cat, label: `${cat}`, hint: `${count} references` };\n }),\n });\n if (p.isCancel(category)) { p.cancel('Cancelled.'); process.exit(0); }\n\n // Step 1b: Pick reference within category\n const categoryRefs = refs.filter((r) => r.category === category);\n const refId = await p.select({\n message: `Select a design system reference:`,\n options: categoryRefs.map((r) => ({\n value: r.id,\n label: `${r.name}`,\n hint: `${r.primaryColor}`,\n })),\n });\n if (p.isCancel(refId)) { p.cancel('Cancelled.'); process.exit(0); }\n\n const reference = loadReference(refId as string);\n\n p.log.info(`${pc.bold(reference.name)} loaded`);\n p.log.info(` Primary: ${pc.bold(reference.colors.primary)} ${reference.colors.primaryName}`);\n p.log.info(` Font: ${reference.typography.primary}`);\n p.log.info(` Radius: ${reference.radius}`);\n if (reference.mood) {\n p.log.info(` Mood: ${reference.mood.slice(0, 120)}...`);\n }\n\n // Step 2: Use as-is or customize?\n const mode = await p.select({\n message: 'How do you want to use this design system?',\n options: [\n { value: 'as-is', label: 'Use as-is', hint: 'Copy the reference DESIGN.md directly' },\n { value: 'customized', label: 'Customize', hint: 'Modify colors, fonts, radius, etc.' },\n ],\n });\n if (p.isCancel(mode)) { p.cancel('Cancelled.'); process.exit(0); }\n\n if (mode === 'as-is') {\n const darkMode = await p.confirm({\n message: 'Include dark mode notes?',\n initialValue: false,\n });\n if (p.isCancel(darkMode)) { p.cancel('Cancelled.'); process.exit(0); }\n\n return {\n reference,\n overrides: { darkMode },\n outputMode: 'as-is',\n };\n }\n\n // Step 3: Customization prompts\n const overrides = await p.group(\n {\n primaryColor: () =>\n p.text({\n message: `Primary color (current: ${reference.colors.primary}):`,\n placeholder: 'Press enter to keep, or type a hex like #6366f1',\n validate: (val) => {\n if (val && !/^#[0-9a-fA-F]{6}$/.test(val)) return 'Invalid hex color';\n },\n }),\n\n fontFamily: () =>\n p.select({\n message: `Primary font (current: ${reference.typography.primary}):`,\n options: [\n { value: '', label: `Keep \"${reference.typography.primary}\"`, hint: 'No change' },\n { value: 'Inter', label: 'Inter', hint: 'Clean, geometric sans-serif' },\n { value: 'system-ui', label: 'System UI', hint: 'Native OS fonts' },\n { value: 'JetBrains Mono', label: 'JetBrains Mono', hint: 'Monospace, technical' },\n { value: 'Geist', label: 'Geist', hint: 'Vercel\\'s modern sans' },\n ],\n }),\n\n headingWeight: () =>\n p.select({\n message: `Heading weight (current: ${reference.typography.headingWeight}):`,\n options: [\n { value: '', label: `Keep ${reference.typography.headingWeight}`, hint: 'No change' },\n { value: '300', label: '300 — Light', hint: 'Whisper authority (Stripe style)' },\n { value: '400', label: '400 — Regular' },\n { value: '500', label: '500 — Medium', hint: 'Balanced emphasis' },\n { value: '600', label: '600 — Semibold', hint: 'Strong headings' },\n { value: '700', label: '700 — Bold', hint: 'Maximum impact' },\n ],\n }),\n\n borderRadius: () =>\n p.select({\n message: `Border radius (current: ${reference.radius}):`,\n options: [\n { value: '', label: `Keep \"${reference.radius}\"`, hint: 'No change' },\n { value: '2px', label: 'Sharp (2px)', hint: 'Technical, precise' },\n { value: '4px', label: 'Tight (4px)', hint: 'Conservative' },\n { value: '6px', label: 'Moderate (6px)', hint: 'Balanced' },\n { value: '8px', label: 'Comfortable (8px)', hint: 'Friendly' },\n { value: '12px', label: 'Rounded (12px)', hint: 'Soft, approachable' },\n { value: '9999px', label: 'Pill', hint: 'Fully rounded' },\n ],\n }),\n\n darkMode: () =>\n p.confirm({\n message: 'Generate dark mode variant?',\n initialValue: false,\n }),\n\n additionalNotes: () =>\n p.text({\n message: 'Any additional customization notes? (optional)',\n placeholder: 'e.g. \"Use more warm tones\" or press enter to skip',\n }),\n },\n {\n onCancel: () => { p.cancel('Cancelled.'); process.exit(0); },\n },\n );\n\n return {\n reference,\n overrides: {\n primaryColor: overrides.primaryColor || undefined,\n fontFamily: overrides.fontFamily || undefined,\n headingWeight: overrides.headingWeight || undefined,\n borderRadius: overrides.borderRadius || undefined,\n darkMode: overrides.darkMode,\n additionalNotes: overrides.additionalNotes || undefined,\n },\n outputMode: 'customized',\n };\n}\n","import type { PreviewData } from './customizer.js';\nimport {\n generateColorScale,\n contrastForeground,\n hslString,\n hexToHsl,\n hslToHex,\n lighten,\n darken,\n generateChartColors,\n} from '../utils/color.js';\n\nexport function generatePreviewHtml(data: PreviewData): string {\n const {\n name, basedOn, primary, background, foreground, font, headingWeight,\n radius, colors, darkMode, shadcnCss,\n } = data;\n\n const isLightBg = isLight(background);\n const scale = generateColorScale(primary);\n const radiusPx = radius === '9999px' ? '24px' : radius;\n const borderColor = colors.border;\n const accent = colors.accent;\n const muted = colors.muted;\n const chart = colors.chart;\n\n // Generate dark mode vars for CSS\n const darkBg = hslToHex(hexToHsl(primary)[0], 15, 7);\n const darkFg = '#fafafa';\n const darkBorder = hslToHex(hexToHsl(primary)[0], 10, 18);\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>${esc(name)} — Design System Preview</title>\n<style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n\n :root {\n --bg: ${background};\n --fg: ${foreground};\n --primary: ${primary};\n --primary-fg: ${contrastForeground(primary)};\n --accent: ${accent};\n --muted: ${muted};\n --muted-fg: ${lighten(foreground, 40)};\n --border: ${borderColor};\n --destructive: #ef4444;\n --card: ${isLightBg ? '#ffffff' : lighten(background, 3)};\n --radius: ${radiusPx};\n }\n\n .dark {\n --bg: ${darkBg};\n --fg: ${darkFg};\n --card: ${lighten(darkBg, 3)};\n --muted: ${hslToHex(hexToHsl(primary)[0], 10, 15)};\n --muted-fg: ${darken(darkFg, 35)};\n --border: ${darkBorder};\n }\n\n body {\n font-family: \"${font}\", \"Inter\", system-ui, sans-serif;\n background: var(--bg);\n color: var(--fg);\n line-height: 1.5;\n transition: background 0.25s, color 0.25s;\n }\n\n .shell { max-width: 1100px; margin: 0 auto; padding: 40px 24px 80px; }\n\n /* ── Header ─────── */\n .header {\n display: flex; justify-content: space-between; align-items: center;\n padding-bottom: 24px; margin-bottom: 40px;\n border-bottom: 1px solid var(--border);\n }\n .header h1 {\n font-size: 2rem; font-weight: ${headingWeight};\n letter-spacing: -0.02em;\n }\n .header .sub {\n font-size: 0.875rem; color: var(--muted-fg); margin-top: 4px;\n }\n .controls { display: flex; gap: 8px; }\n .ctrl-btn {\n padding: 8px 16px; border-radius: var(--radius);\n font-size: 0.8125rem; font-family: inherit; cursor: pointer;\n transition: all 0.15s; border: 1px solid var(--border);\n background: var(--card); color: var(--fg);\n }\n .ctrl-btn:hover { opacity: 0.85; }\n .ctrl-btn.primary { background: var(--primary); color: var(--primary-fg); border-color: transparent; }\n\n /* ── Sections ───── */\n .section { margin-bottom: 48px; }\n .section-title {\n font-size: 1.375rem; font-weight: ${headingWeight};\n letter-spacing: -0.01em; margin-bottom: 16px;\n }\n .section-sub { font-size: 0.8125rem; color: var(--muted-fg); margin-bottom: 16px; }\n\n /* ── Color Scale ── */\n .scale-row {\n display: flex; border-radius: var(--radius); overflow: hidden;\n border: 1px solid var(--border); margin-bottom: 24px;\n }\n .scale-stop {\n flex: 1; padding: 28px 4px 8px; text-align: center;\n font-size: 10px; font-family: monospace; cursor: pointer;\n transition: transform 0.1s; position: relative;\n }\n .scale-stop:hover { z-index: 1; transform: scaleY(1.12); }\n .scale-stop .lbl { display: block; opacity: 0.7; margin-bottom: 2px; }\n .scale-stop .hex {\n background: rgba(0,0,0,0.2); color: #fff;\n padding: 1px 4px; border-radius: 3px; font-size: 9px;\n }\n\n /* ── Color Chips ── */\n .chip-grid {\n display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px;\n }\n .chip {\n border-radius: var(--radius); overflow: hidden;\n border: 1px solid var(--border); cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n }\n .chip:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.1); }\n .chip .sw { height: 64px; display: flex; align-items: end; padding: 6px; }\n .chip .sw span {\n font-size: 10px; font-family: monospace;\n background: rgba(0,0,0,0.25); color: #fff;\n padding: 1px 5px; border-radius: 3px;\n }\n .chip .inf { padding: 8px; background: var(--card); }\n .chip .inf .n { font-size: 0.75rem; font-weight: 500; }\n .chip .inf .v { font-size: 10px; color: var(--muted-fg); font-family: monospace; }\n\n /* ── Typography ── */\n .type-rows { display: flex; flex-direction: column; gap: 8px; }\n .type-row {\n display: flex; align-items: baseline; gap: 16px;\n padding: 12px 16px; border-radius: var(--radius);\n background: var(--card); border: 1px solid var(--border);\n }\n .type-row .lbl {\n min-width: 48px; font-size: 0.75rem; color: var(--muted-fg);\n font-family: monospace; flex-shrink: 0;\n }\n .type-row .sample { flex: 1; }\n\n /* ── Components ── */\n .comp-card {\n padding: 24px; border-radius: var(--radius);\n background: var(--card); border: 1px solid var(--border);\n margin-bottom: 16px;\n }\n .comp-card h3 { font-size: 1rem; font-weight: 600; margin-bottom: 16px; }\n .comp-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-bottom: 12px; }\n\n .btn {\n display: inline-flex; align-items: center; justify-content: center;\n font-family: inherit; font-weight: 500; cursor: pointer;\n transition: all 0.15s; border: none; font-size: 0.8125rem;\n padding: 8px 16px; height: 36px; border-radius: var(--radius);\n }\n .btn-primary { background: var(--primary); color: var(--primary-fg); }\n .btn-secondary { background: var(--muted); color: var(--fg); }\n .btn-outline { background: transparent; color: var(--fg); border: 1px solid var(--border); }\n .btn-ghost { background: transparent; color: var(--fg); }\n .btn-destructive { background: var(--destructive); color: #fff; }\n .btn:hover { opacity: 0.9; }\n\n .badge {\n display: inline-flex; font-size: 0.6875rem; font-weight: 500;\n padding: 2px 10px; border-radius: 9999px;\n }\n .badge-primary { background: var(--primary); color: var(--primary-fg); }\n .badge-secondary { background: var(--muted); color: var(--fg); }\n .badge-outline { background: transparent; color: var(--fg); border: 1px solid var(--border); }\n\n .input-demo {\n width: 100%; max-width: 320px; font-family: inherit;\n background: var(--bg); color: var(--fg);\n border: 1px solid var(--border); border-radius: var(--radius);\n padding: 8px 12px; font-size: 0.8125rem; outline: none;\n transition: border-color 0.15s;\n }\n .input-demo:focus {\n border-color: var(--primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 20%, transparent);\n }\n\n .demo-table {\n width: 100%; border-collapse: collapse; font-size: 0.8125rem;\n }\n .demo-table th, .demo-table td {\n padding: 10px 12px; text-align: left;\n border-bottom: 1px solid var(--border);\n }\n .demo-table th {\n font-weight: 500; color: var(--muted-fg);\n font-size: 0.75rem; text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n .demo-table tr:hover td { background: var(--muted); }\n\n .demo-card {\n padding: 20px; border-radius: var(--radius);\n background: var(--card); border: 1px solid var(--border);\n max-width: 340px; box-shadow: 0 1px 3px rgba(0,0,0,0.06);\n }\n .demo-card h4 { font-weight: 600; margin-bottom: 6px; }\n .demo-card p { font-size: 0.8125rem; color: var(--muted-fg); margin-bottom: 14px; }\n\n .demo-dialog {\n padding: 24px; border-radius: var(--radius);\n background: var(--card); box-shadow: 0 20px 40px rgba(0,0,0,0.15);\n max-width: 400px; border: 1px solid var(--border);\n }\n .demo-dialog h4 { font-weight: 600; margin-bottom: 8px; }\n .demo-dialog p { font-size: 0.8125rem; color: var(--muted-fg); margin-bottom: 16px; }\n .demo-dialog .acts { display: flex; justify-content: flex-end; gap: 8px; }\n\n .tabs {\n display: flex; background: var(--muted); border-radius: var(--radius); padding: 4px; gap: 2px;\n }\n .tab {\n padding: 6px 14px; border-radius: calc(var(--radius) - 2px);\n font-size: 0.8125rem; font-family: inherit; font-weight: 500;\n border: none; cursor: pointer; background: transparent;\n color: var(--muted-fg); transition: all 0.15s;\n }\n .tab.active {\n background: var(--bg); color: var(--fg);\n box-shadow: 0 1px 2px rgba(0,0,0,0.05);\n }\n .tab:hover:not(.active) { color: var(--fg); }\n\n /* ── CSS Block ──── */\n .css-block {\n position: relative; background: var(--card);\n border: 1px solid var(--border); border-radius: var(--radius);\n overflow: hidden;\n }\n .css-block pre {\n padding: 20px; overflow-x: auto; font-family: monospace;\n font-size: 11px; line-height: 1.6; color: var(--fg);\n }\n .css-block .copy-css { position: absolute; top: 8px; right: 8px; }\n\n /* ── Spacing ────── */\n .spacing-vis {\n display: flex; align-items: end; gap: 8px; padding: 24px;\n background: var(--card); border: 1px solid var(--border);\n border-radius: var(--radius);\n }\n .sp-bar { display: flex; flex-direction: column; align-items: center; gap: 4px; }\n .sp-bar .bar { background: var(--primary); border-radius: 2px; width: 28px; }\n .sp-bar .val { font-size: 10px; font-family: monospace; color: var(--muted-fg); }\n\n /* ── Radius ─────── */\n .radius-grid { display: flex; gap: 16px; flex-wrap: wrap; }\n .radius-demo {\n width: 72px; height: 72px; background: var(--primary);\n display: flex; align-items: center; justify-content: center;\n color: var(--primary-fg); font-size: 0.6875rem; font-family: monospace;\n }\n\n /* ── Toast ──────── */\n .toast-popup {\n position: fixed; bottom: 24px; right: 24px;\n padding: 10px 20px; background: var(--fg); color: var(--bg);\n border-radius: var(--radius); font-size: 0.8125rem;\n box-shadow: 0 8px 20px rgba(0,0,0,0.15);\n transform: translateY(100px); opacity: 0;\n transition: all 0.3s; z-index: 100;\n }\n .toast-popup.show { transform: translateY(0); opacity: 1; }\n\n @media (max-width: 768px) {\n .shell { padding: 16px 12px 48px; }\n .header { flex-direction: column; gap: 12px; align-items: flex-start; }\n .chip-grid { grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); }\n }\n</style>\n</head>\n<body>\n<div class=\"shell\">\n\n <div class=\"header\">\n <div>\n <h1>${esc(name)}</h1>\n <div class=\"sub\">Based on ${esc(basedOn)} · Generated by oh-my-design</div>\n </div>\n <div class=\"controls\">\n ${darkMode ? '<button class=\"ctrl-btn\" onclick=\"toggleTheme()\" id=\"theme-btn\">🌙 Dark</button>' : ''}\n <button class=\"ctrl-btn primary\" onclick=\"copyCss()\">Copy CSS</button>\n </div>\n </div>\n\n <!-- Primary Scale -->\n <div class=\"section\">\n <h2 class=\"section-title\">Primary Color Scale</h2>\n <div class=\"section-sub\">Click to copy hex value</div>\n <div class=\"scale-row\">\n${Object.entries(scale).map(([stop, hex]) =>\n ` <div class=\"scale-stop\" style=\"background:${hex};color:${isLight(hex) ? '#000' : '#fff'}\" onclick=\"copy('${hex}')\">\n <span class=\"lbl\">${stop}</span><span class=\"hex\">${hex}</span>\n </div>`).join('\\n')}\n </div>\n </div>\n\n <!-- Semantic Colors -->\n <div class=\"section\">\n <h2 class=\"section-title\">Semantic Colors</h2>\n <div class=\"chip-grid\">\n${[\n { n: 'Primary', bg: primary, v: '--primary' },\n { n: 'Accent', bg: accent, v: '--accent' },\n { n: 'Muted', bg: muted, v: '--muted' },\n { n: 'Destructive', bg: '#ef4444', v: '--destructive' },\n { n: 'Background', bg: background, v: '--background' },\n { n: 'Foreground', bg: foreground, v: '--foreground' },\n { n: 'Border', bg: borderColor, v: '--border' },\n { n: 'Card', bg: isLightBg ? '#ffffff' : lighten(background, 3), v: '--card' },\n].map((c) => ` <div class=\"chip\" onclick=\"copy('${c.bg}')\">\n <div class=\"sw\" style=\"background:${c.bg}\"><span>${c.bg}</span></div>\n <div class=\"inf\"><div class=\"n\">${c.n}</div><div class=\"v\">${c.v}</div></div>\n </div>`).join('\\n')}\n </div>\n </div>\n\n <!-- Chart Colors -->\n <div class=\"section\">\n <h2 class=\"section-title\">Chart Colors</h2>\n <div style=\"display:flex;gap:8px;\">\n${chart.map((c, i) => ` <div style=\"width:48px;height:48px;border-radius:var(--radius);background:${c};cursor:pointer;\" onclick=\"copy('${c}')\" title=\"Chart ${i + 1}: ${c}\"></div>`).join('\\n')}\n </div>\n </div>\n\n <!-- Typography -->\n <div class=\"section\">\n <h2 class=\"section-title\">Typography</h2>\n <div class=\"type-rows\">\n <div class=\"type-row\">\n <span class=\"lbl\">H1</span>\n <span class=\"sample\" style=\"font-size:2.25rem;font-weight:${headingWeight};letter-spacing:-0.02em;line-height:1.2\">Page Title Heading</span>\n </div>\n <div class=\"type-row\">\n <span class=\"lbl\">H2</span>\n <span class=\"sample\" style=\"font-size:1.875rem;font-weight:${headingWeight};letter-spacing:-0.01em;line-height:1.25\">Section Heading</span>\n </div>\n <div class=\"type-row\">\n <span class=\"lbl\">H3</span>\n <span class=\"sample\" style=\"font-size:1.5rem;font-weight:${headingWeight};line-height:1.3\">Subsection</span>\n </div>\n <div class=\"type-row\">\n <span class=\"lbl\">body</span>\n <span class=\"sample\" style=\"font-size:1rem;\">The quick brown fox jumps over the lazy dog. 다람쥐 헌 쳇바퀴에 타고파.</span>\n </div>\n <div class=\"type-row\">\n <span class=\"lbl\">sm</span>\n <span class=\"sample\" style=\"font-size:0.875rem;color:var(--muted-fg)\">Secondary text, labels, and metadata</span>\n </div>\n <div class=\"type-row\">\n <span class=\"lbl\">mono</span>\n <span class=\"sample\" style=\"font-family:monospace;font-size:0.875rem\">const theme = generateDesignSystem();</span>\n </div>\n </div>\n </div>\n\n <!-- Radius -->\n <div class=\"section\">\n <h2 class=\"section-title\">Border Radius</h2>\n <div class=\"radius-grid\">\n <div style=\"text-align:center\"><div class=\"radius-demo\" style=\"border-radius:0\">0</div><div style=\"font-size:10px;margin-top:4px;color:var(--muted-fg)\">none</div></div>\n <div style=\"text-align:center\"><div class=\"radius-demo\" style=\"border-radius:${radiusPx}\">${radiusPx}</div><div style=\"font-size:10px;margin-top:4px;color:var(--muted-fg)\">base</div></div>\n <div style=\"text-align:center\"><div class=\"radius-demo\" style=\"border-radius:${parseInt(radiusPx) * 2}px\">${parseInt(radiusPx) * 2}px</div><div style=\"font-size:10px;margin-top:4px;color:var(--muted-fg)\">lg</div></div>\n <div style=\"text-align:center\"><div class=\"radius-demo\" style=\"border-radius:9999px\">pill</div><div style=\"font-size:10px;margin-top:4px;color:var(--muted-fg)\">full</div></div>\n </div>\n </div>\n\n <!-- Components -->\n <div class=\"section\">\n <h2 class=\"section-title\">Components</h2>\n\n <!-- Buttons -->\n <div class=\"comp-card\">\n <h3>Buttons</h3>\n <div class=\"comp-row\">\n <button class=\"btn btn-primary\">Primary</button>\n <button class=\"btn btn-secondary\">Secondary</button>\n <button class=\"btn btn-outline\">Outline</button>\n <button class=\"btn btn-ghost\">Ghost</button>\n <button class=\"btn btn-destructive\">Delete</button>\n </div>\n </div>\n\n <!-- Badges -->\n <div class=\"comp-card\">\n <h3>Badges</h3>\n <div class=\"comp-row\">\n <span class=\"badge badge-primary\">Active</span>\n <span class=\"badge badge-secondary\">Draft</span>\n <span class=\"badge badge-outline\">Archived</span>\n </div>\n </div>\n\n <!-- Input -->\n <div class=\"comp-card\">\n <h3>Input</h3>\n <div style=\"display:flex;flex-direction:column;gap:12px;max-width:400px;\">\n <div>\n <label style=\"font-size:0.8125rem;font-weight:500;display:block;margin-bottom:4px;\">Email</label>\n <input class=\"input-demo\" type=\"email\" placeholder=\"you@example.com\">\n </div>\n <div>\n <label style=\"font-size:0.8125rem;font-weight:500;display:block;margin-bottom:4px;\">Password</label>\n <input class=\"input-demo\" type=\"password\" placeholder=\"••••••••\">\n </div>\n </div>\n </div>\n\n <!-- Card -->\n <div class=\"comp-card\">\n <h3>Card</h3>\n <div class=\"comp-row\" style=\"align-items:stretch;\">\n <div class=\"demo-card\">\n <h4>Project Overview</h4>\n <p>A summary card showing key metrics and status for your project.</p>\n <button class=\"btn btn-primary\" style=\"height:32px;font-size:0.75rem;\">View Details</button>\n </div>\n </div>\n </div>\n\n <!-- Table -->\n <div class=\"comp-card\">\n <h3>Table</h3>\n <div style=\"overflow-x:auto;\">\n <table class=\"demo-table\">\n <thead><tr><th>Name</th><th>Status</th><th>Role</th><th>Email</th></tr></thead>\n <tbody>\n <tr><td>Kim Minjae</td><td><span class=\"badge badge-primary\" style=\"font-size:10px;\">Active</span></td><td>Developer</td><td>minjae@example.com</td></tr>\n <tr><td>Lee Soyeon</td><td><span class=\"badge badge-secondary\" style=\"font-size:10px;\">Pending</span></td><td>Designer</td><td>soyeon@example.com</td></tr>\n <tr><td>Park Jiwoo</td><td><span class=\"badge badge-outline\" style=\"font-size:10px;\">Inactive</span></td><td>PM</td><td>jiwoo@example.com</td></tr>\n </tbody>\n </table>\n </div>\n </div>\n\n <!-- Dialog -->\n <div class=\"comp-card\">\n <h3>Dialog</h3>\n <div class=\"demo-dialog\">\n <h4>Delete item?</h4>\n <p>This action cannot be undone.</p>\n <div class=\"acts\">\n <button class=\"btn btn-outline\" style=\"height:32px;\">Cancel</button>\n <button class=\"btn btn-destructive\" style=\"height:32px;\">Delete</button>\n </div>\n </div>\n </div>\n\n <!-- Tabs -->\n <div class=\"comp-card\">\n <h3>Tabs</h3>\n <div class=\"tabs\">\n <button class=\"tab active\">Overview</button>\n <button class=\"tab\">Analytics</button>\n <button class=\"tab\">Settings</button>\n </div>\n </div>\n </div>\n\n <!-- shadcn CSS -->\n <div class=\"section\">\n <h2 class=\"section-title\">shadcn/ui CSS Variables</h2>\n <div class=\"section-sub\">Ready to paste into globals.css</div>\n <div class=\"css-block\">\n <button class=\"ctrl-btn copy-css\" onclick=\"copyCss()\" style=\"position:absolute;top:8px;right:8px;\">Copy</button>\n <pre id=\"css-output\">${escHtml(shadcnCss)}</pre>\n </div>\n </div>\n\n</div>\n\n<div class=\"toast-popup\" id=\"toast\">Copied!</div>\n\n<script>\nlet isDark = false;\nfunction toggleTheme() {\n isDark = !isDark;\n document.body.classList.toggle('dark', isDark);\n const btn = document.getElementById('theme-btn');\n if (btn) btn.textContent = isDark ? '☀️ Light' : '🌙 Dark';\n}\nfunction showToast(msg) {\n const el = document.getElementById('toast');\n el.textContent = msg;\n el.classList.add('show');\n setTimeout(() => el.classList.remove('show'), 1800);\n}\nfunction copy(val) {\n navigator.clipboard.writeText(val).then(() => showToast('Copied: ' + val));\n}\nfunction copyCss() {\n const css = document.getElementById('css-output').textContent;\n navigator.clipboard.writeText(css).then(() => showToast('CSS variables copied!'));\n}\ndocument.querySelectorAll('.tab').forEach(t => {\n t.addEventListener('click', () => {\n t.parentElement.querySelectorAll('.tab').forEach(x => x.classList.remove('active'));\n t.classList.add('active');\n });\n});\n</script>\n</body>\n</html>`;\n}\n\nfunction isLight(hex: string): boolean {\n const h = hex.replace('#', '');\n const r = parseInt(h.slice(0, 2), 16);\n const g = parseInt(h.slice(2, 4), 16);\n const b = parseInt(h.slice(4, 6), 16);\n return (r * 299 + g * 587 + b * 114) / 1000 > 140;\n}\n\nfunction esc(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n}\n\nfunction escHtml(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n}\n"],"mappings":"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","names":["p","writeFileSync","resolve","loadReference","applyOverrides","existsSync"]}
|
|
@@ -509,6 +509,21 @@ function deprecateDesignMd(opts) {
|
|
|
509
509
|
|
|
510
510
|
// src/cli/init.ts
|
|
511
511
|
function runInitRecommend(opts) {
|
|
512
|
+
const trimmed = opts.description.trim();
|
|
513
|
+
if (!trimmed) {
|
|
514
|
+
if (opts.json) {
|
|
515
|
+
process.stdout.write(
|
|
516
|
+
JSON.stringify({ error: "description is empty" }, null, 2) + "\n"
|
|
517
|
+
);
|
|
518
|
+
} else {
|
|
519
|
+
console.error(
|
|
520
|
+
pc.red(
|
|
521
|
+
'omd init recommend: description is required. Try a few keywords like "warm fintech dashboard" or "minimal dev tool".'
|
|
522
|
+
)
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
return 1;
|
|
526
|
+
}
|
|
512
527
|
const hits = recommend(opts.description, { topK: opts.topK ?? 5 });
|
|
513
528
|
const delta = buildDeltaSet(opts.description);
|
|
514
529
|
if (opts.json) {
|
|
@@ -533,6 +548,10 @@ function runInitRecommend(opts) {
|
|
|
533
548
|
p.log.message(
|
|
534
549
|
pc.bold("Matched keywords: ") + delta.matchedKeywords.map((k) => pc.cyan(k.keyword) + pc.dim(` (${k.modifier.toFixed(2)})`)).join(", ")
|
|
535
550
|
);
|
|
551
|
+
} else {
|
|
552
|
+
p.log.warn(
|
|
553
|
+
"No vocabulary keywords matched. Recommendations will rank by tag overlap only \u2014 try adding tone words (warm / minimal / playful / premium / dense / casual / formal / etc.) for stronger matches. See https://github.com/kwakseongjae/oh-my-design#vocabulary for the full list."
|
|
554
|
+
);
|
|
536
555
|
}
|
|
537
556
|
if (delta.warnings.length > 0) {
|
|
538
557
|
for (const w of delta.warnings) p.log.warn(w);
|
|
@@ -553,9 +572,22 @@ function runInitRecommend(opts) {
|
|
|
553
572
|
function runInitPrepare(opts) {
|
|
554
573
|
const projectRoot = opts.dir ?? process.cwd();
|
|
555
574
|
const relRoot = relative(process.cwd(), projectRoot) || ".";
|
|
575
|
+
if (!opts.description?.trim()) {
|
|
576
|
+
console.error(
|
|
577
|
+
pc.red(
|
|
578
|
+
"omd init prepare: --description is required and cannot be empty."
|
|
579
|
+
)
|
|
580
|
+
);
|
|
581
|
+
return 1;
|
|
582
|
+
}
|
|
556
583
|
const refPath = findReferencePath(opts.ref);
|
|
557
584
|
if (!refPath) {
|
|
558
|
-
console.error(
|
|
585
|
+
console.error(
|
|
586
|
+
pc.red(`omd init prepare: reference not found: ${opts.ref}`)
|
|
587
|
+
);
|
|
588
|
+
console.error(
|
|
589
|
+
pc.dim(" Run `omd reference list` to see all available references.")
|
|
590
|
+
);
|
|
559
591
|
return 1;
|
|
560
592
|
}
|
|
561
593
|
const referenceMd = readFileSync4(refPath, "utf8");
|
|
@@ -605,6 +637,11 @@ function runInitPrepare(opts) {
|
|
|
605
637
|
p.log.success(
|
|
606
638
|
`Context staged \u2192 ${relative(projectRoot, contextPath)}`
|
|
607
639
|
);
|
|
640
|
+
if (!skillsInstalled(projectRoot)) {
|
|
641
|
+
p.log.warn(
|
|
642
|
+
"No omd:* skills installed in this project \u2014 your agent won't know how to consume this context. Run `npx oh-my-design-cli install-skills` first."
|
|
643
|
+
);
|
|
644
|
+
}
|
|
608
645
|
p.outro(
|
|
609
646
|
pc.dim(
|
|
610
647
|
"Next: have your agent (Claude Code / Codex / OpenCode) run the `omd:init` skill to generate DESIGN.md from this context."
|
|
@@ -612,6 +649,9 @@ function runInitPrepare(opts) {
|
|
|
612
649
|
);
|
|
613
650
|
return 0;
|
|
614
651
|
}
|
|
652
|
+
function skillsInstalled(projectRoot) {
|
|
653
|
+
return existsSync2(join4(projectRoot, ".claude", "skills", "omd-init", "SKILL.md")) || existsSync2(join4(projectRoot, ".codex", "skills", "omd-init", "SKILL.md")) || existsSync2(join4(projectRoot, ".opencode", "agents", "omd-init.md"));
|
|
654
|
+
}
|
|
615
655
|
function findReferencePath(refId) {
|
|
616
656
|
const root = findRepoRoot();
|
|
617
657
|
if (!root) return null;
|
|
@@ -632,4 +672,4 @@ export {
|
|
|
632
672
|
runInitPrepare,
|
|
633
673
|
runInitRecommend
|
|
634
674
|
};
|
|
635
|
-
//# sourceMappingURL=init-
|
|
675
|
+
//# sourceMappingURL=init-UMM4XIV5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/init.ts","../src/core/vocabulary.ts","../src/core/recommend.ts","../src/core/init-deprecate.ts"],"sourcesContent":["import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport {\n writeFileSync,\n readFileSync,\n mkdirSync,\n existsSync,\n} from 'node:fs';\nimport { join, relative, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { buildDeltaSet } from '../core/vocabulary.js';\nimport { recommend } from '../core/recommend.js';\nimport { deprecateDesignMd } from '../core/init-deprecate.js';\n\nexport interface InitRecommendOptions {\n description: string;\n topK?: number;\n json?: boolean;\n}\n\nexport interface InitPrepareOptions {\n dir?: string;\n ref: string;\n description: string;\n reason?: string;\n json?: boolean;\n}\n\nexport function runInitRecommend(opts: InitRecommendOptions): number {\n const trimmed = opts.description.trim();\n if (!trimmed) {\n if (opts.json) {\n process.stdout.write(\n JSON.stringify({ error: 'description is empty' }, null, 2) + '\\n'\n );\n } else {\n console.error(\n pc.red(\n 'omd init recommend: description is required. Try a few keywords like \"warm fintech dashboard\" or \"minimal dev tool\".'\n )\n );\n }\n return 1;\n }\n\n const hits = recommend(opts.description, { topK: opts.topK ?? 5 });\n const delta = buildDeltaSet(opts.description);\n\n if (opts.json) {\n process.stdout.write(\n JSON.stringify(\n {\n description: opts.description,\n recommendations: hits,\n delta_set: delta,\n },\n null,\n 2\n )\n );\n process.stdout.write('\\n');\n return 0;\n }\n\n p.intro(pc.bold('omd init — recommend'));\n p.log.message(pc.dim(`Query: \"${opts.description}\"\\n`));\n\n if (delta.matchedKeywords.length > 0) {\n p.log.message(\n pc.bold('Matched keywords: ') +\n delta.matchedKeywords\n .map((k) => pc.cyan(k.keyword) + pc.dim(` (${k.modifier.toFixed(2)})`))\n .join(', ')\n );\n } else {\n p.log.warn(\n 'No vocabulary keywords matched. Recommendations will rank by tag overlap only — try adding tone words (warm / minimal / playful / premium / dense / casual / formal / etc.) for stronger matches. See https://github.com/kwakseongjae/oh-my-design#vocabulary for the full list.'\n );\n }\n if (delta.warnings.length > 0) {\n for (const w of delta.warnings) p.log.warn(w);\n }\n\n p.log.message(pc.bold('\\nTop references:'));\n for (const [i, hit] of hits.entries()) {\n const scoreStr = pc.dim(`[${hit.score.toFixed(2)}]`);\n const matched = hit.matchedKeywords.length > 0\n ? pc.green(hit.matchedKeywords.join(', '))\n : pc.dim('(no direct tag match)');\n p.log.message(\n ` ${i + 1}. ${pc.bold(hit.id.padEnd(14))} ${scoreStr} ${pc.dim(hit.category.padEnd(14))} ${matched}`\n );\n }\n\n p.outro(\n pc.dim('Next: `omd init prepare --ref <id> --description \"...\"` to stage.')\n );\n return 0;\n}\n\nexport function runInitPrepare(opts: InitPrepareOptions): number {\n const projectRoot = opts.dir ?? process.cwd();\n const relRoot = relative(process.cwd(), projectRoot) || '.';\n\n if (!opts.description?.trim()) {\n console.error(\n pc.red(\n 'omd init prepare: --description is required and cannot be empty.'\n )\n );\n return 1;\n }\n\n const refPath = findReferencePath(opts.ref);\n if (!refPath) {\n console.error(\n pc.red(`omd init prepare: reference not found: ${opts.ref}`)\n );\n console.error(\n pc.dim(' Run `omd reference list` to see all available references.')\n );\n return 1;\n }\n\n const referenceMd = readFileSync(refPath, 'utf8');\n const delta = buildDeltaSet(opts.description);\n\n // Handle existing DESIGN.md\n const deprecate = deprecateDesignMd({\n projectRoot,\n newReference: opts.ref,\n reason: opts.reason ?? 'user-initiated omd init',\n });\n\n // Write init-context.json that the omd:init skill consumes.\n // Note: we deliberately do NOT persist reference_path (absolute paths are\n // fragile across machines / npm reinstalls). The skill reads reference_md\n // directly from this command's --json output, and can re-fetch reference\n // content via `omd reference show <id>` if needed.\n const contextPath = join(projectRoot, '.omd', 'init-context.json');\n mkdirSync(join(projectRoot, '.omd'), { recursive: true });\n const context = {\n schema: 'omd.init-context/v1',\n created_at: new Date().toISOString(),\n reference_id: opts.ref,\n description: opts.description,\n delta_set: delta,\n deprecated_from: deprecate.renamed ? deprecate.to : null,\n };\n writeFileSync(contextPath, JSON.stringify(context, null, 2) + '\\n', 'utf8');\n\n if (opts.json) {\n process.stdout.write(\n JSON.stringify(\n {\n project_root: projectRoot,\n reference_path: refPath,\n context_path: contextPath,\n deprecated_from: deprecate.renamed ? deprecate.to : null,\n reference_md: referenceMd,\n delta_set: delta,\n },\n null,\n 2\n )\n );\n process.stdout.write('\\n');\n return 0;\n }\n\n p.intro(pc.bold('omd init — prepare') + pc.dim(` (${relRoot})`));\n p.log.message(`Reference: ${pc.cyan(opts.ref)}`);\n p.log.message(`Description: ${pc.dim(opts.description)}`);\n if (deprecate.renamed) {\n p.log.warn(\n `Existing DESIGN.md renamed → ${relative(projectRoot, deprecate.to)}`\n );\n }\n p.log.success(\n `Context staged → ${relative(projectRoot, contextPath)}`\n );\n\n if (!skillsInstalled(projectRoot)) {\n p.log.warn(\n 'No omd:* skills installed in this project — your agent won\\'t know how to consume this context. Run `npx oh-my-design-cli install-skills` first.'\n );\n }\n\n p.outro(\n pc.dim(\n 'Next: have your agent (Claude Code / Codex / OpenCode) run the `omd:init` skill to generate DESIGN.md from this context.'\n )\n );\n return 0;\n}\n\nfunction skillsInstalled(projectRoot: string): boolean {\n return (\n existsSync(join(projectRoot, '.claude', 'skills', 'omd-init', 'SKILL.md')) ||\n existsSync(join(projectRoot, '.codex', 'skills', 'omd-init', 'SKILL.md')) ||\n existsSync(join(projectRoot, '.opencode', 'agents', 'omd-init.md'))\n );\n}\n\nfunction findReferencePath(refId: string): string | null {\n const root = findRepoRoot();\n if (!root) return null;\n const path = join(root, 'references', refId, 'DESIGN.md');\n return existsSync(path) ? path : null;\n}\n\nfunction findRepoRoot(): string | null {\n let cur = dirname(fileURLToPath(import.meta.url));\n for (let i = 0; i < 8; i++) {\n if (existsSync(join(cur, 'references'))) return cur;\n const parent = dirname(cur);\n if (parent === cur) break;\n cur = parent;\n }\n return null;\n}\n","import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nexport interface AxisSpec {\n type: 'int' | 'float' | 'enum';\n domain: [number, number];\n unit?: string;\n step?: number;\n}\n\nexport interface KeywordAxes {\n [axis: string]: { delta: number; range: [number, number] };\n}\n\nexport interface KeywordSpec {\n group: 'tone' | 'density' | 'formality' | 'domain';\n axes: KeywordAxes;\n conflicts_with: string[];\n voice_hints: string[];\n coupled_axes?: string[];\n sources?: string[];\n}\n\nexport interface Vocabulary {\n version: number;\n generated_at: string;\n axis_registry: Record<string, AxisSpec>;\n modifiers: Record<string, number>;\n keywords: Record<string, KeywordSpec>;\n}\n\nexport interface SynonymsFile {\n version: number;\n map: Record<string, string>;\n}\n\nlet cachedVocab: Vocabulary | null = null;\nlet cachedSynonyms: SynonymsFile | null = null;\n\nfunction dataDir(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n // When built (dist/) we are at dist/*.js → data/ is ../data\n // When running from src/ via tsx we are at src/core/ → data/ is ../../data\n const candidates = [\n join(here, '..', 'data'),\n join(here, '..', '..', 'data'),\n ];\n for (const c of candidates) {\n try {\n readFileSync(join(c, 'vocabulary.json'), 'utf8');\n return c;\n } catch {\n // continue\n }\n }\n throw new Error('data/vocabulary.json not found relative to ' + here);\n}\n\nexport function loadVocabulary(): Vocabulary {\n if (cachedVocab) return cachedVocab;\n const path = join(dataDir(), 'vocabulary.json');\n cachedVocab = JSON.parse(readFileSync(path, 'utf8')) as Vocabulary;\n return cachedVocab;\n}\n\nexport function loadSynonyms(): SynonymsFile {\n if (cachedSynonyms) return cachedSynonyms;\n const path = join(dataDir(), 'synonyms.json');\n cachedSynonyms = JSON.parse(readFileSync(path, 'utf8')) as SynonymsFile;\n return cachedSynonyms;\n}\n\nexport interface ResolvedKeyword {\n keyword: string;\n modifier: number;\n matchedAs: 'direct' | 'synonym';\n synonymSource?: string;\n}\n\nconst MODIFIER_RE = /\\b(primarily|mostly|slightly|very|not)\\s+([a-z][a-z-]*)/gi;\n\nexport function tokenize(description: string): string[] {\n return description\n .toLowerCase()\n .split(/[^a-z-]+/)\n .filter(Boolean);\n}\n\nexport function extractKeywords(description: string): ResolvedKeyword[] {\n const vocab = loadVocabulary();\n const { map: synonyms } = loadSynonyms();\n\n const lower = description.toLowerCase();\n const modifierOverrides = new Map<string, number>();\n let match: RegExpExecArray | null;\n const modRe = new RegExp(MODIFIER_RE.source, MODIFIER_RE.flags);\n while ((match = modRe.exec(lower)) !== null) {\n const modName = match[1];\n const target = match[2];\n const value = vocab.modifiers[modName];\n if (value !== undefined) modifierOverrides.set(target, value);\n }\n\n const tokens = tokenize(description);\n const seen = new Set<string>();\n const results: ResolvedKeyword[] = [];\n\n for (const token of tokens) {\n if (seen.has(token)) continue;\n seen.add(token);\n\n if (vocab.keywords[token]) {\n results.push({\n keyword: token,\n modifier: modifierOverrides.get(token) ?? 1.0,\n matchedAs: 'direct',\n });\n continue;\n }\n\n const syn = synonyms[token];\n if (syn && vocab.keywords[syn]) {\n results.push({\n keyword: syn,\n modifier: modifierOverrides.get(token) ?? 1.0,\n matchedAs: 'synonym',\n synonymSource: token,\n });\n }\n }\n\n return results;\n}\n\nexport interface ConflictResolution {\n kept: ResolvedKeyword[];\n dropped: Array<{ keyword: string; reason: string }>;\n warnings: string[];\n}\n\nexport function resolveConflicts(\n keywords: ResolvedKeyword[]\n): ConflictResolution {\n const vocab = loadVocabulary();\n const kept: ResolvedKeyword[] = [];\n const dropped: Array<{ keyword: string; reason: string }> = [];\n\n // Classify each keyword: kept if strictly higher modifier than any conflicter, else dropped.\n for (const kw of keywords) {\n const spec = vocab.keywords[kw.keyword];\n if (!spec) continue;\n\n const conflictingHere = keywords.filter(\n (other) =>\n other.keyword !== kw.keyword &&\n spec.conflicts_with.includes(other.keyword)\n );\n\n if (conflictingHere.length === 0) {\n kept.push(kw);\n continue;\n }\n\n const strictlyHigherThanAll = conflictingHere.every(\n (c) => kw.modifier > c.modifier + 1e-9\n );\n if (strictlyHigherThanAll) {\n kept.push(kw);\n continue;\n }\n\n dropped.push({\n keyword: kw.keyword,\n reason: `conflicts with ${conflictingHere.map((c) => c.keyword).join(',')}`,\n });\n }\n\n // Emit warnings ONLY for conflict groups where no member was kept\n // (genuine tie — user should disambiguate).\n const warnings: string[] = [];\n const keptSet = new Set(kept.map((k) => k.keyword));\n const warned = new Set<string>();\n for (const kw of keywords) {\n const spec = vocab.keywords[kw.keyword];\n if (!spec) continue;\n const conflictingHere = keywords.filter(\n (other) =>\n other.keyword !== kw.keyword &&\n spec.conflicts_with.includes(other.keyword)\n );\n if (conflictingHere.length === 0) continue;\n const groupKeys = [kw.keyword, ...conflictingHere.map((c) => c.keyword)];\n const groupHasWinner = groupKeys.some((k) => keptSet.has(k));\n if (groupHasWinner) continue;\n const pairKey = [...new Set(groupKeys)].sort().join(',');\n if (warned.has(pairKey)) continue;\n warned.add(pairKey);\n warnings.push(\n `${kw.keyword} ↔ ${conflictingHere.map((c) => c.keyword).join(',')}: use \"primarily <kw>\" or \"very <kw>\" to pick a winner`\n );\n }\n\n return { kept, dropped, warnings };\n}\n\nexport interface DeltaSet {\n axes: Record<string, { value: number; rangeUnion: [number, number]; sources: string[] }>;\n voiceHints: string[];\n unresolved: string[];\n warnings: string[];\n droppedKeywords: Array<{ keyword: string; reason: string }>;\n matchedKeywords: ResolvedKeyword[];\n}\n\nfunction clamp(value: number, lo: number, hi: number): number {\n return Math.max(lo, Math.min(hi, value));\n}\n\nfunction snap(value: number, spec: AxisSpec): number {\n if (spec.type === 'int') return Math.round(value);\n if (spec.type === 'enum') {\n const [lo, hi] = spec.domain;\n return Math.abs(value - lo) < Math.abs(value - hi) ? lo : hi;\n }\n return Number(value.toFixed(3));\n}\n\nexport function buildDeltaSet(description: string): DeltaSet {\n const vocab = loadVocabulary();\n const matched = extractKeywords(description);\n const { kept, dropped, warnings } = resolveConflicts(matched);\n\n const axes: DeltaSet['axes'] = {};\n const voiceHintSet = new Set<string>();\n\n for (const kw of kept) {\n const spec = vocab.keywords[kw.keyword];\n const multiplier = kw.modifier;\n\n for (const hint of spec.voice_hints) voiceHintSet.add(hint);\n\n for (const [axisName, axisDelta] of Object.entries(spec.axes)) {\n const bucket = axes[axisName] ?? {\n value: 0,\n rangeUnion: [axisDelta.range[0], axisDelta.range[1]] as [number, number],\n sources: [] as string[],\n };\n bucket.value += axisDelta.delta * multiplier;\n bucket.rangeUnion = [\n Math.min(bucket.rangeUnion[0], axisDelta.range[0]),\n Math.max(bucket.rangeUnion[1], axisDelta.range[1]),\n ];\n bucket.sources.push(kw.keyword);\n axes[axisName] = bucket;\n }\n }\n\n for (const [axisName, bucket] of Object.entries(axes)) {\n const registry = vocab.axis_registry[axisName];\n if (!registry) continue;\n let v = clamp(bucket.value, bucket.rangeUnion[0], bucket.rangeUnion[1]);\n v = clamp(v, registry.domain[0], registry.domain[1]);\n bucket.value = snap(v, registry);\n bucket.sources.sort();\n }\n\n return {\n axes,\n voiceHints: [...voiceHintSet],\n unresolved: [],\n warnings,\n droppedKeywords: dropped,\n matchedKeywords: kept,\n };\n}\n\nexport function listKeywords(): string[] {\n return Object.keys(loadVocabulary().keywords).sort();\n}\n","import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\nimport { tokenize } from './vocabulary.js';\n\nexport interface ReferenceTag {\n id: string;\n color: string;\n category: string;\n keywords: string[];\n}\n\nexport interface RecommendHit {\n id: string;\n category: string;\n color: string;\n keywords: string[];\n score: number;\n matchedKeywords: string[];\n matchedCategories: string[];\n}\n\nconst CATEGORY_HINTS: Record<string, string[]> = {\n Consumer: [\n 'marketplace',\n 'shopping',\n 'ecommerce',\n 'consumer',\n 'b2c',\n 'retail',\n 'subscription',\n 'family',\n 'families',\n 'meal',\n 'meals',\n 'meal-kit',\n 'food',\n 'travel',\n 'social',\n 'community',\n 'buyer',\n 'seller',\n 'parents',\n 'kids',\n 'lifestyle',\n 'recipe',\n 'recipes',\n ],\n Fintech: [\n 'fintech',\n 'banking',\n 'bank',\n 'payment',\n 'payments',\n 'crypto',\n 'trading',\n 'wallet',\n 'invest',\n 'investing',\n 'money',\n 'finance',\n 'financial',\n 'lending',\n 'remittance',\n 'tax',\n ],\n 'Developer Tools': [\n 'developer',\n 'devtool',\n 'devtools',\n 'dev-tool',\n 'deploy',\n 'deployment',\n 'build',\n 'ci',\n 'cd',\n 'cli',\n 'sdk',\n 'editor',\n 'ide',\n 'engineering',\n 'compiler',\n 'runtime',\n ],\n AI: [\n 'ai',\n 'ml',\n 'llm',\n 'agent',\n 'agents',\n 'model',\n 'models',\n 'inference',\n 'gpt',\n 'chatbot',\n 'rag',\n 'embedding',\n 'embeddings',\n 'mcp',\n ],\n 'Design Tools': [\n 'design',\n 'design-tool',\n 'whiteboard',\n 'prototype',\n 'prototyping',\n 'wireframe',\n 'wireframes',\n 'mockup',\n 'mockups',\n 'figma-like',\n 'illustration',\n 'canvas',\n ],\n Productivity: [\n 'saas',\n 'workspace',\n 'team',\n 'teams',\n 'project-management',\n 'enterprise',\n 'b2b',\n 'crm',\n 'docs',\n 'wiki',\n 'collaboration',\n 'kanban',\n 'scheduling',\n 'meetings',\n ],\n Backend: [\n 'backend',\n 'database',\n 'db',\n 'api',\n 'apis',\n 'observability',\n 'monitoring',\n 'logging',\n 'analytics',\n 'pipeline',\n 'data-pipeline',\n 'streaming',\n 'queue',\n 'cache',\n ],\n Automotive: [\n 'car',\n 'cars',\n 'vehicle',\n 'vehicles',\n 'auto',\n 'automotive',\n 'driving',\n 'ev',\n 'electric-vehicle',\n ],\n Marketing: [\n 'marketing',\n 'seo',\n 'campaign',\n 'campaigns',\n 'newsletter',\n 'email-marketing',\n 'attribution',\n ],\n};\n\nfunction matchedCategoriesFor(\n queryTokens: Set<string>,\n queryStems: Set<string>\n): Set<string> {\n const out = new Set<string>();\n for (const [category, hints] of Object.entries(CATEGORY_HINTS)) {\n for (const hint of hints) {\n if (queryTokens.has(hint) || queryStems.has(stem(hint))) {\n out.add(category);\n break;\n }\n }\n }\n return out;\n}\n\nlet cachedTags: ReferenceTag[] | null = null;\n\nfunction stem(s: string): string {\n // Minimal English suffix stripping for recall across -ing/-ed/-s variants.\n // Preserves stems of length ≥3 so we don't collapse short words.\n let out = s;\n for (const suffix of ['ing', 'ed', 'ly', 'es', 's']) {\n if (out.length - suffix.length >= 3 && out.endsWith(suffix)) {\n out = out.slice(0, -suffix.length);\n break;\n }\n }\n return out;\n}\n\nfunction tagsFilePath(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n const candidates = [\n join(here, '..', 'data', 'reference-tags.md'),\n join(here, '..', '..', 'data', 'reference-tags.md'),\n ];\n for (const c of candidates) {\n try {\n readFileSync(c, 'utf8');\n return c;\n } catch {\n // continue\n }\n }\n throw new Error('data/reference-tags.md not found');\n}\n\nconst ROW_RE = /^\\|\\s*([a-z0-9._-]+)\\s*\\|\\s*([^|]*?)\\s*\\|\\s*([^|]*?)\\s*\\|\\s*([^|]*?)\\s*\\|$/i;\n\nexport function loadReferenceTags(): ReferenceTag[] {\n if (cachedTags) return cachedTags;\n const raw = readFileSync(tagsFilePath(), 'utf8');\n const rows: ReferenceTag[] = [];\n for (const line of raw.split('\\n')) {\n const m = ROW_RE.exec(line);\n if (!m) continue;\n const [, id, color, category, keywordsRaw] = m;\n if (id === 'id') continue; // header\n if (id.startsWith('---')) continue;\n rows.push({\n id: id.trim(),\n color: color.trim(),\n category: category.trim(),\n keywords: keywordsRaw\n .split(',')\n .map((k) => k.trim().toLowerCase())\n .filter(Boolean),\n });\n }\n cachedTags = rows;\n return rows;\n}\n\nexport interface RecommendOptions {\n topK?: number;\n diversityByCategory?: boolean;\n}\n\nexport function recommend(\n description: string,\n opts: RecommendOptions = {}\n): RecommendHit[] {\n const topK = opts.topK ?? 5;\n const diversityByCategory = opts.diversityByCategory ?? true;\n\n const tags = loadReferenceTags();\n const rawTokens = [\n ...tokenize(description),\n ...description\n .toLowerCase()\n .split(/[^a-z0-9-]+/)\n .filter(Boolean),\n ];\n const queryTokens = new Set(rawTokens);\n const queryStems = new Set(rawTokens.map(stem));\n const matchedCategories = matchedCategoriesFor(queryTokens, queryStems);\n\n // First pass: tag matches per ref, to know whether to gate category bonus.\n const tagMatchByRef = tags.map((t) =>\n t.keywords.filter(\n (kw) => queryTokens.has(kw) || queryStems.has(stem(kw))\n )\n );\n const totalTagMatches = tagMatchByRef.reduce((a, m) => a + m.length, 0);\n\n const scored: Array<RecommendHit & { _ratio: number }> = tags.map((t, i) => {\n const matched = tagMatchByRef[i];\n const tagScore = matched.length;\n const categoryHit = matchedCategories.has(t.category);\n // Category bonus normally requires ≥1 tag match (prevents flooding).\n // But when the description produces zero tag matches anywhere, we\n // fall back to category-only scoring so users still get a useful\n // top-K instead of an alphabetical no-op.\n const categoryBonus =\n categoryHit && (tagScore > 0 || totalTagMatches === 0) ? 0.5 : 0;\n const score = tagScore + categoryBonus;\n const ratio = matched.length / Math.max(1, t.keywords.length);\n return {\n id: t.id,\n category: t.category,\n color: t.color,\n keywords: t.keywords,\n score,\n matchedKeywords: matched,\n matchedCategories: categoryHit ? [t.category] : [],\n _ratio: ratio,\n };\n });\n\n scored.sort(\n (a, b) =>\n b.score - a.score || b._ratio - a._ratio || a.id.localeCompare(b.id)\n );\n\n const stripRatio = (s: typeof scored): RecommendHit[] =>\n s.map(({ _ratio, ...rest }) => {\n void _ratio;\n return rest;\n });\n\n if (!diversityByCategory) return stripRatio(scored.slice(0, topK));\n\n // Category-bucketed diversity: one top hit per category, fill with next best.\n const picked = stripRatio(scored).slice(0, 0);\n const pickedSet = new Set<string>();\n const usedCategories = new Set<string>();\n const allHits = stripRatio(scored);\n for (const hit of allHits) {\n if (picked.length >= topK) break;\n if (usedCategories.has(hit.category)) continue;\n picked.push(hit);\n pickedSet.add(hit.id);\n usedCategories.add(hit.category);\n }\n for (const hit of allHits) {\n if (picked.length >= topK) break;\n if (pickedSet.has(hit.id)) continue;\n picked.push(hit);\n pickedSet.add(hit.id);\n }\n return picked;\n}\n","import {\n existsSync,\n readFileSync,\n writeFileSync,\n unlinkSync,\n mkdirSync,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nexport interface DeprecateOptions {\n projectRoot: string;\n previousReference?: string;\n newReference: string;\n preferencesReplayed?: number;\n preferencesOrphaned?: number;\n orphanFile?: string;\n reason: string;\n now?: Date;\n}\n\nexport interface DeprecateResult {\n renamed: boolean;\n from: string;\n to: string;\n}\n\nfunction deprecationHeader(opts: DeprecateOptions): string {\n const now = (opts.now ?? new Date()).toISOString();\n const lines = [\n '<!--',\n 'omd:deprecated',\n ` deprecated_at: ${now}`,\n ];\n if (opts.previousReference)\n lines.push(` previous_reference: ${opts.previousReference}`);\n lines.push(` new_reference: ${opts.newReference}`);\n if (opts.preferencesReplayed !== undefined)\n lines.push(` preferences_replayed: ${opts.preferencesReplayed}`);\n if (opts.preferencesOrphaned !== undefined)\n lines.push(` preferences_orphaned: ${opts.preferencesOrphaned}`);\n if (opts.orphanFile) lines.push(` orphan_file: ${opts.orphanFile}`);\n lines.push(` reason: ${opts.reason}`);\n lines.push('-->', '', '');\n return lines.join('\\n');\n}\n\nexport function deprecateDesignMd(opts: DeprecateOptions): DeprecateResult {\n const from = join(opts.projectRoot, 'DESIGN.md');\n const baseTo = join(opts.projectRoot, 'DESIGN_DEPRECATED.md');\n\n if (!existsSync(from)) {\n return { renamed: false, from, to: baseTo };\n }\n\n let target = baseTo;\n if (existsSync(baseTo)) {\n const ts = (opts.now ?? new Date()).toISOString().replace(/[:.]/g, '-');\n target = join(opts.projectRoot, `DESIGN_DEPRECATED.${ts}.md`);\n }\n\n mkdirSync(dirname(target), { recursive: true });\n const prior = readFileSync(from, 'utf8');\n writeFileSync(target, deprecationHeader(opts) + prior, 'utf8');\n unlinkSync(from);\n\n return { renamed: true, from, to: target };\n}\n"],"mappings":"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A;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,IAAI;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAA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","names":["writeFileSync","readFileSync","mkdirSync","existsSync","join","dirname","fileURLToPath","readFileSync","fileURLToPath","dirname","join","dirname","fileURLToPath","join","readFileSync","readFileSync","dirname","join","readFileSync","join","mkdirSync","writeFileSync","existsSync","dirname","fileURLToPath"]}
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
// src/cli/sync.ts
|
|
10
10
|
import * as p from "@clack/prompts";
|
|
11
11
|
import pc from "picocolors";
|
|
12
|
-
import {
|
|
12
|
+
import { existsSync as existsSync3 } from "fs";
|
|
13
|
+
import { join as join3, relative } from "path";
|
|
13
14
|
|
|
14
15
|
// src/core/shims.ts
|
|
15
16
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
|
|
@@ -286,6 +287,9 @@ function refreshDesignMdHash(projectRoot) {
|
|
|
286
287
|
}
|
|
287
288
|
|
|
288
289
|
// src/cli/sync.ts
|
|
290
|
+
var DESIGN_MD_NAME = "DESIGN.md";
|
|
291
|
+
var DEPRECATED_MD_NAME = "DESIGN_DEPRECATED.md";
|
|
292
|
+
var INIT_CONTEXT_PATH = ".omd/init-context.json";
|
|
289
293
|
var STATUS_LABEL = {
|
|
290
294
|
missing: pc.yellow("missing"),
|
|
291
295
|
clean: pc.green("clean"),
|
|
@@ -337,6 +341,10 @@ async function runSync(opts = {}) {
|
|
|
337
341
|
const rel = relative(projectRoot, result.path);
|
|
338
342
|
p.log.message(` ${STATUS_LABEL[result.status]} ${rel}`);
|
|
339
343
|
}
|
|
344
|
+
const designMdMissing = !existsSync3(join3(projectRoot, DESIGN_MD_NAME));
|
|
345
|
+
const initContextExists = existsSync3(join3(projectRoot, INIT_CONTEXT_PATH));
|
|
346
|
+
const deprecatedExists = existsSync3(join3(projectRoot, DEPRECATED_MD_NAME));
|
|
347
|
+
const midInitFlow = designMdMissing && (initContextExists || deprecatedExists);
|
|
340
348
|
if (opts.check) {
|
|
341
349
|
const unsynced = inspections.filter(
|
|
342
350
|
(i) => i.result.status !== "clean"
|
|
@@ -349,7 +357,12 @@ async function runSync(opts = {}) {
|
|
|
349
357
|
);
|
|
350
358
|
return 1;
|
|
351
359
|
}
|
|
352
|
-
|
|
360
|
+
if (designMdMissing) {
|
|
361
|
+
p.log.warn(
|
|
362
|
+
midInitFlow ? "DESIGN.md is missing but init-context is staged \u2014 your agent still needs to run the `omd:init` skill to write DESIGN.md." : 'DESIGN.md is missing \u2014 run `npx oh-my-design-cli init recommend "<description>"` to bootstrap, or have your agent run the `omd:init` skill.'
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
p.outro(pc.green("Shims clean."));
|
|
353
366
|
return 0;
|
|
354
367
|
}
|
|
355
368
|
const results = [];
|
|
@@ -401,4 +414,4 @@ async function runSync(opts = {}) {
|
|
|
401
414
|
export {
|
|
402
415
|
runSync
|
|
403
416
|
};
|
|
404
|
-
//# sourceMappingURL=sync-
|
|
417
|
+
//# sourceMappingURL=sync-FDYRKNFE.js.map
|