lism-cli 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  ## コマンド体系
10
10
 
11
11
  ```
12
- lism create [targetDir] [--template <name>] # examples から新規プロジェクト
12
+ lism create [targetDir] [--template <name>] # templates から新規プロジェクト
13
13
  lism ui { init | add <names...> | list } # Lism UI コンポーネントの追加
14
14
  lism skill { add | check | update } # AI エージェント向け SKILL.md 配置
15
15
  ```
@@ -23,7 +23,7 @@ lism skill { add | check | update } # AI エージェント向け SKIL
23
23
  pnpm dlx lism-cli create
24
24
 
25
25
  # テンプレート名・出力先を指定
26
- pnpm dlx lism-cli create --template astro-minimal ./my-app
26
+ pnpm dlx lism-cli create --template minimal-astro ./my-app
27
27
  ```
28
28
 
29
29
  同じ動作は `pnpm create lism` / `npm create lism@latest` でも呼び出せます(`create-lism` パッケージ経由)。
@@ -13,16 +13,16 @@ var messages = {
13
13
  },
14
14
  // create
15
15
  "cli.create.description": {
16
- ja: "examples \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u304B\u3089\u65B0\u898F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u751F\u6210\u3059\u308B",
17
- en: "Create a new project from an examples template"
16
+ ja: "templates \u304B\u3089\u65B0\u898F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u751F\u6210\u3059\u308B",
17
+ en: "Create a new project from a template"
18
18
  },
19
19
  "cli.create.arg.targetDir": {
20
20
  ja: "\u51FA\u529B\u5148\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA",
21
21
  en: "Target directory"
22
22
  },
23
23
  "cli.create.opt.template": {
24
- ja: "\u4F7F\u7528\u3059\u308B\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u540D\uFF08\u4F8B: astro-minimal\uFF09",
25
- en: "Template name to use (e.g. astro-minimal)"
24
+ ja: "\u4F7F\u7528\u3059\u308B\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u540D\uFF08\u4F8B: minimal-astro\uFF09",
25
+ en: "Template name to use (e.g. minimal-astro)"
26
26
  },
27
27
  "cli.create.opt.force": {
28
28
  ja: "\u65E2\u5B58\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u5F37\u5236\u4E0A\u66F8\u304D",
@@ -121,9 +121,33 @@ var messages = {
121
121
  ja: '\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 "{name}" \u306F\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002\u5229\u7528\u53EF\u80FD: {list}',
122
122
  en: 'Template "{name}" not found. Available: {list}'
123
123
  },
124
- "create.promptSelectTemplate": {
125
- ja: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044:",
126
- en: "Select a template:"
124
+ "create.promptSelectCategory": {
125
+ ja: "\u30AB\u30C6\u30B4\u30EA\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044:",
126
+ en: "Select a category:"
127
+ },
128
+ "create.promptSelectVariant": {
129
+ ja: "\u30D0\u30EA\u30A2\u30F3\u30C8\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\uFF08{count}\u4EF6\uFF09:",
130
+ en: "Select a variant ({count} options):"
131
+ },
132
+ "create.promptSelectVariant.blog": {
133
+ ja: "\u6A5F\u80FD\u30EC\u30D9\u30EB\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\uFF08{count}\u4EF6\uFF09:",
134
+ en: "Select a feature level ({count} options):"
135
+ },
136
+ "create.promptSelectVariant.lp": {
137
+ ja: "\u696D\u7A2E\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\uFF08{count}\u4EF6\uFF09:",
138
+ en: "Select an industry ({count} options):"
139
+ },
140
+ "create.promptSelectVariant.web": {
141
+ ja: "\u696D\u7A2E\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\uFF08{count}\u4EF6\uFF09:",
142
+ en: "Select an industry ({count} options):"
143
+ },
144
+ "create.promptSelectStack": {
145
+ ja: "\u30B9\u30BF\u30C3\u30AF\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\uFF08{count}\u4EF6\uFF09:",
146
+ en: "Select a stack ({count} options):"
147
+ },
148
+ "create.usingStack": {
149
+ ja: "\u30B9\u30BF\u30C3\u30AF\u306F{stack}\u3092\u4F7F\u7528\u3057\u307E\u3059\uFF08{count}\u4EF6\uFF09\u3002",
150
+ en: "Using {stack} stack ({count} option)."
127
151
  },
128
152
  "create.promptTargetDir": {
129
153
  ja: "\u51FA\u529B\u5148\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA:",
@@ -141,6 +165,18 @@ var messages = {
141
165
  ja: '\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 "{name}" \u3092\u53D6\u5F97\u4E2D\uFF08ref: {ref}\uFF09...',
142
166
  en: 'Fetching template "{name}" (ref: {ref})...'
143
167
  },
168
+ "create.templatePackageMissing": {
169
+ ja: '\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8"{name}"\u306E\u53D6\u5F97\u7D50\u679C\u306Bpackage.json\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u53D6\u5F97\u5143\u30D1\u30B9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044: {path}',
170
+ en: 'Downloaded template "{name}" does not contain package.json. Check the source path: {path}'
171
+ },
172
+ "create.templateIndexMissing": {
173
+ ja: '\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8"{name}"\u306E\u53D6\u5F97\u7D50\u679C\u306Bindex.html\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u53D6\u5F97\u5143\u30D1\u30B9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044: {path}',
174
+ en: 'Downloaded template "{name}" does not contain index.html. Check the source path: {path}'
175
+ },
176
+ "create.variantMissing": {
177
+ ja: 'variant "{variant}" \u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002\u53D6\u5F97\u5143\u30D1\u30B9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044: {path}',
178
+ en: 'Variant "{variant}" directory not found. Check the source path: {path}'
179
+ },
144
180
  "create.created": {
145
181
  ja: "{dir} \u306B\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u751F\u6210\u3057\u307E\u3057\u305F\u3002",
146
182
  en: "Generated project at {dir}."
@@ -149,6 +185,18 @@ var messages = {
149
185
  ja: "\u6B21\u306E\u30B3\u30DE\u30F3\u30C9\u3067\u958B\u767A\u3092\u958B\u59CB\u3067\u304D\u307E\u3059:",
150
186
  en: "Next steps:"
151
187
  },
188
+ "create.nextStepsHtmlOpen": {
189
+ ja: " index.html\u3092\u30D6\u30E9\u30A6\u30B6\u3067\u958B\u3044\u3066\u304F\u3060\u3055\u3044",
190
+ en: " Open index.html in your browser"
191
+ },
192
+ "create.packageNameRewritten": {
193
+ ja: ' package.json\u306Ename\u3092"{name}"\u306B\u5909\u66F4\u3057\u307E\u3057\u305F\u3002',
194
+ en: ' Updated package.json name to "{name}".'
195
+ },
196
+ "create.packageNameFailed": {
197
+ ja: "package.json\u306Ename\u66F8\u304D\u63DB\u3048\u306B\u5931\u6557\u3057\u307E\u3057\u305F: {reason}",
198
+ en: "Failed to rewrite package.json name: {reason}"
199
+ },
152
200
  "create.workspaceReplaced": {
153
201
  ja: " package.json \u306E workspace:* \u3092 ^{version} \u306B\u7F6E\u63DB\u3057\u307E\u3057\u305F\u3002",
154
202
  en: " Replaced workspace:* in package.json with ^{version}."
@@ -342,8 +390,8 @@ var messages = {
342
390
  },
343
391
  // skill check
344
392
  "skill.check.noneInstalled": {
345
- ja: "\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u6E08\u307F\u306E\u30B9\u30AD\u30EB\u306F\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002`lism skill add` \u3067\u914D\u7F6E\u3067\u304D\u307E\u3059\u3002",
346
- en: "No installed skills found. Run `lism skill add` to deploy them."
393
+ ja: "\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u6E08\u307F\u306E\u30B9\u30AD\u30EB\u306F\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002`{invoke} skill add` \u3067\u914D\u7F6E\u3067\u304D\u307E\u3059\u3002",
394
+ en: "No installed skills found. Run `{invoke} skill add` to deploy them."
347
395
  },
348
396
  "skill.check.fetching": {
349
397
  ja: "\u30EA\u30E2\u30FC\u30C8\u30B9\u30AD\u30EB\u3092\u53D6\u5F97\u4E2D\uFF08ref: {ref}\uFF09...",
@@ -358,8 +406,8 @@ var messages = {
358
406
  en: "All skills are up to date."
359
407
  },
360
408
  "skill.check.outdated": {
361
- ja: "{count} \u4EF6\u306E\u30C4\u30FC\u30EB\u306B\u5DEE\u5206\u304C\u3042\u308A\u307E\u3059\u3002`lism skill update` \u3067\u6700\u65B0\u306B\u66F4\u65B0\u3067\u304D\u307E\u3059\u3002",
362
- en: "{count} tools have changes. Run `lism skill update` to update them."
409
+ ja: "{count} \u4EF6\u306E\u30C4\u30FC\u30EB\u306B\u5DEE\u5206\u304C\u3042\u308A\u307E\u3059\u3002`{invoke} skill update` \u3067\u6700\u65B0\u306B\u66F4\u65B0\u3067\u304D\u307E\u3059\u3002",
410
+ en: "{count} tools have changes. Run `{invoke} skill update` to update them."
363
411
  },
364
412
  "skill.check.diffModified": {
365
413
  ja: "\u5909\u66F4 {count}",
@@ -377,8 +425,8 @@ var messages = {
377
425
  // config
378
426
  // ---------------------------------------------------------------------------
379
427
  "config.legacyWarning": {
380
- ja: '[deprecated] {filename} \u306F\u5EC3\u6B62\u4E88\u5B9A\u3067\u3059\u3002"lism ui init" \u3067 lism.config.js \u3078\u79FB\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002',
381
- en: '[deprecated] {filename} is deprecated. Run "lism ui init" to migrate to lism.config.js.'
428
+ ja: '[deprecated] {filename} \u306F\u5EC3\u6B62\u4E88\u5B9A\u3067\u3059\u3002"{invoke} ui init" \u3067 lism.config.js \u3078\u79FB\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002',
429
+ en: '[deprecated] {filename} is deprecated. Run "{invoke} ui init" to migrate to lism.config.js.'
382
430
  },
383
431
  "config.notFound": {
384
432
  ja: "lism.config.js / lism.config.mjs / lism-ui.json \u306E\u3044\u305A\u308C\u3082\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002",
@@ -469,6 +517,7 @@ function interpolate(template, vars) {
469
517
 
470
518
  // src/commands/create.ts
471
519
  import fs from "fs";
520
+ import os from "os";
472
521
  import path from "path";
473
522
  import { downloadTemplate } from "giget";
474
523
  import { select, input, confirm } from "@inquirer/prompts";
@@ -490,12 +539,16 @@ var logger = {
490
539
  },
491
540
  log(msg) {
492
541
  console.log(msg);
542
+ },
543
+ heading(msg) {
544
+ console.log(pc.bold(pc.cyan(`
545
+ \u25B8 ${msg}`)));
493
546
  }
494
547
  };
495
548
 
496
549
  // src/version.ts
497
- var LISM_CSS_VERSION = "0.14.0" ? "0.14.0" : "unknown";
498
- var CLI_VERSION = "0.3.0" ? "0.3.0" : "unknown";
550
+ var LISM_CSS_VERSION = "0.18.0" ? "0.18.0" : "unknown";
551
+ var CLI_VERSION = "0.4.0" ? "0.4.0" : "unknown";
499
552
 
500
553
  // src/constants.ts
501
554
  var SOURCE_REPO = "lism-css/lism-css";
@@ -507,19 +560,126 @@ var UI_COMPONENTS_PATH = "packages/lism-ui/src/components";
507
560
  var UI_HELPER_PATH = "packages/lism-ui/src/helper";
508
561
  var UI_REGISTRY_INDEX_PATH = "packages/lism-ui/registry-index.json";
509
562
  var SKILL_SOURCE_PATH = "skills/lism-css-guide";
510
- var EXAMPLES_PATH = "examples";
563
+ var TEMPLATES_PATH = "templates";
511
564
 
512
- // src/commands/create.ts
565
+ // ../../templates/manifest.ts
513
566
  var TEMPLATES = [
514
567
  {
515
- name: "astro-minimal",
516
- label: { ja: "Astro (\u6700\u5C0F\u69CB\u6210)", en: "Astro (minimal)" },
568
+ slug: "minimal-astro",
569
+ kind: "project",
570
+ category: "minimal",
571
+ stack: "astro",
572
+ sourcePath: "minimal/astro",
573
+ title: { ja: "Minimal Astro", en: "Minimal Astro" },
517
574
  description: { ja: "Astro \u30D9\u30FC\u30B9\u306E\u6700\u5C0F\u69CB\u6210", en: "Minimal Astro setup" }
575
+ },
576
+ {
577
+ slug: "minimal-vite",
578
+ kind: "project",
579
+ category: "minimal",
580
+ stack: "vite",
581
+ sourcePath: "minimal/vite",
582
+ title: { ja: "Minimal Vite", en: "Minimal Vite" },
583
+ description: { ja: "Vite + React \u30D9\u30FC\u30B9\u306E\u6700\u5C0F\u69CB\u6210", en: "Minimal Vite + React setup" },
584
+ previewUrl: "https://lism-minimal-vite.pages.dev/"
585
+ },
586
+ {
587
+ slug: "blog-astro-simple",
588
+ kind: "project",
589
+ category: "blog",
590
+ variant: "simple",
591
+ variantLabel: { ja: "Simple", en: "Simple" },
592
+ stack: "astro",
593
+ sourcePath: "blog/astro/simple",
594
+ title: { ja: "Blog Astro Simple", en: "Blog Astro Simple" },
595
+ description: { ja: "\u30BF\u30B0\u306E\u307F\u306E\u30B7\u30F3\u30D7\u30EB\u306A Astro \u30D6\u30ED\u30B0", en: "Simple Astro blog with tags" },
596
+ draft: true
597
+ },
598
+ {
599
+ slug: "blog-astro-full",
600
+ kind: "project",
601
+ category: "blog",
602
+ variant: "full",
603
+ variantLabel: { ja: "Full", en: "Full" },
604
+ stack: "astro",
605
+ sourcePath: "blog/astro/full",
606
+ title: { ja: "Blog Astro Full", en: "Blog Astro Full" },
607
+ description: { ja: "\u30AB\u30C6\u30B4\u30EA\u30FB\u76EE\u6B21\u3064\u304D\u306E Astro \u30D6\u30ED\u30B0", en: "Astro blog with categories and table of contents" },
608
+ draft: true
609
+ },
610
+ {
611
+ slug: "lp-astro-minimal",
612
+ kind: "single-project-variant",
613
+ category: "lp",
614
+ stack: "astro",
615
+ variant: "minimal",
616
+ variantLabel: { ja: "Minimal", en: "Minimal" },
617
+ sourcePath: "lp/astro",
618
+ title: { ja: "LP Minimal", en: "LP Minimal" },
619
+ description: { ja: "\u30DF\u30CB\u30DE\u30EB\u306A Astro \u30E9\u30F3\u30C7\u30A3\u30F3\u30B0\u30DA\u30FC\u30B8", en: "Minimal Astro landing page" },
620
+ draft: true
621
+ },
622
+ {
623
+ slug: "lp-astro-natural",
624
+ kind: "single-project-variant",
625
+ category: "lp",
626
+ stack: "astro",
627
+ variant: "natural",
628
+ variantLabel: { ja: "Natural", en: "Natural" },
629
+ sourcePath: "lp/astro",
630
+ title: { ja: "LP Natural", en: "LP Natural" },
631
+ description: { ja: "\u30CA\u30C1\u30E5\u30E9\u30EB\u306A\u96F0\u56F2\u6C17\u306E Astro \u30E9\u30F3\u30C7\u30A3\u30F3\u30B0\u30DA\u30FC\u30B8", en: "Natural-themed Astro landing page" },
632
+ draft: true
633
+ },
634
+ {
635
+ slug: "lp-astro-ryokan",
636
+ kind: "single-project-variant",
637
+ category: "lp",
638
+ stack: "astro",
639
+ variant: "ryokan",
640
+ variantLabel: { ja: "Ryokan", en: "Ryokan" },
641
+ sourcePath: "lp/astro",
642
+ title: { ja: "LP Ryokan", en: "LP Ryokan" },
643
+ description: { ja: "\u65C5\u9928\u30FB\u5BBF\u6CCA\u696D\u5411\u3051\u306E Astro \u30E9\u30F3\u30C7\u30A3\u30F3\u30B0\u30DA\u30FC\u30B8", en: "Astro landing page for ryokan / lodging" },
644
+ draft: true
645
+ }
646
+ ];
647
+
648
+ // src/commands/create.ts
649
+ var STACK_LABELS = {
650
+ astro: { ja: "Astro", en: "Astro" },
651
+ next: { ja: "Next.js", en: "Next.js" },
652
+ vite: { ja: "Vite + React", en: "Vite + React" },
653
+ html: { ja: "Static HTML", en: "Static HTML" }
654
+ };
655
+ var CATEGORIES = [
656
+ {
657
+ id: "minimal",
658
+ label: { ja: "Minimal", en: "Minimal" }
659
+ },
660
+ {
661
+ id: "blog",
662
+ label: { ja: "Blog", en: "Blog" },
663
+ variantPromptKey: "create.promptSelectVariant.blog"
664
+ },
665
+ {
666
+ id: "lp",
667
+ label: { ja: "Landing Page", en: "Landing Page" },
668
+ variantPromptKey: "create.promptSelectVariant.lp"
669
+ },
670
+ {
671
+ id: "web",
672
+ label: { ja: "Web", en: "Web" },
673
+ variantPromptKey: "create.promptSelectVariant.web"
518
674
  }
519
675
  ];
520
676
  async function runCreate({ template, targetDir, force = false }) {
521
- const tpl = await resolveTemplate(template);
522
- const outDir = path.resolve(process.cwd(), await resolveTargetDir(targetDir, tpl.name));
677
+ await runCreateWithTemplates({ template, targetDir, force }, TEMPLATES);
678
+ }
679
+ async function runCreateWithTemplates({ template, targetDir, force = false }, templates) {
680
+ const availableTemplates = templates.filter((tpl2) => !tpl2.draft);
681
+ const tpl = await resolveTemplate(template, availableTemplates);
682
+ const outDir = path.resolve(process.cwd(), await resolveTargetDir(targetDir, tpl.slug));
523
683
  if (fs.existsSync(outDir) && fs.readdirSync(outDir).length > 0 && !force) {
524
684
  const ok = await confirm({
525
685
  message: t("create.confirmOverwrite", { dir: outDir }),
@@ -531,37 +691,68 @@ async function runCreate({ template, targetDir, force = false }) {
531
691
  }
532
692
  }
533
693
  const ref = DEFAULT_TEMPLATES_REF;
534
- logger.info(t("create.fetching", { name: tpl.name, ref }));
535
- await downloadTemplate(`github:${SOURCE_REPO}/${EXAMPLES_PATH}/${tpl.name}#${ref}`, {
536
- dir: outDir,
537
- force: true,
538
- forceClean: force
539
- });
540
- rewriteWorkspaceDeps(outDir);
694
+ logger.info(t("create.fetching", { name: tpl.slug, ref }));
695
+ await downloadTemplateSource(tpl, outDir, ref, force);
696
+ ensureTemplateDownloaded(outDir, tpl);
697
+ postProcessTemplate(outDir, tpl);
541
698
  logger.success(t("create.created", { dir: outDir }));
542
- logger.log("");
543
- logger.log(t("create.nextSteps"));
544
- const rel = path.relative(process.cwd(), outDir) || ".";
545
- logger.log(` cd ${rel}`);
546
- logger.log(" npm install # or pnpm install / yarn");
547
- logger.log(" npm run dev");
699
+ printNextSteps(outDir, tpl);
548
700
  }
549
701
  async function createCommand(targetDir, options) {
550
702
  await runCreate({ template: options.template, targetDir, force: options.force });
551
703
  }
552
- async function resolveTemplate(requested) {
704
+ async function resolveTemplate(requested, templates) {
553
705
  if (requested) {
554
- const found = TEMPLATES.find((t2) => t2.name === requested);
706
+ const found = templates.find((t2) => t2.slug === requested);
555
707
  if (!found) {
556
- throw new Error(t("create.templateNotFound", { name: requested, list: TEMPLATES.map((x) => x.name).join(", ") }));
708
+ throw new Error(t("create.templateNotFound", { name: requested, list: templates.map((x) => x.slug).join(", ") }));
557
709
  }
558
710
  return found;
559
711
  }
560
- const picked = await select({
561
- message: t("create.promptSelectTemplate"),
562
- choices: TEMPLATES.map((tpl) => ({ name: `${tOf(tpl.label)} \u2014 ${tOf(tpl.description)}`, value: tpl.name }))
712
+ const category = await select({
713
+ message: t("create.promptSelectCategory"),
714
+ choices: CATEGORIES.filter((category2) => templates.some((tpl) => tpl.category === category2.id)).map((category2) => ({
715
+ name: tOf(category2.label),
716
+ value: category2.id
717
+ }))
718
+ });
719
+ const categoryTemplates = templates.filter((tpl) => tpl.category === category);
720
+ const stack = await resolveStack(categoryTemplates);
721
+ const stackTemplates = categoryTemplates.filter((tpl) => tpl.stack === stack);
722
+ const variant = await resolveVariant(category, stackTemplates);
723
+ const variantTemplates = variant === void 0 ? stackTemplates : stackTemplates.filter((tpl) => tpl.variant === variant);
724
+ return variantTemplates[0];
725
+ }
726
+ async function resolveVariant(category, templates) {
727
+ const variants = uniqueDefined(templates.map((tpl) => tpl.variant));
728
+ if (variants.length <= 1) return variants[0];
729
+ const categoryDef = CATEGORIES.find((item) => item.id === category);
730
+ const messageKey = categoryDef?.variantPromptKey ?? "create.promptSelectVariant";
731
+ return select({
732
+ message: t(messageKey, { count: variants.length }),
733
+ choices: variants.map((variant) => {
734
+ const tpl = templates.find((item) => item.variant === variant);
735
+ return {
736
+ name: `${tOf(tpl.variantLabel ?? { ja: variant ?? "", en: variant ?? "" })} \u2014 ${tOf(tpl.description)}`,
737
+ value: variant
738
+ };
739
+ })
740
+ });
741
+ }
742
+ async function resolveStack(templates) {
743
+ const stacks = uniqueDefined(templates.map((tpl) => tpl.stack));
744
+ if (stacks.length === 1) {
745
+ const stack = stacks[0];
746
+ logger.info(t("create.usingStack", { stack: tOf(STACK_LABELS[stack]), count: stacks.length }));
747
+ return stack;
748
+ }
749
+ return select({
750
+ message: t("create.promptSelectStack", { count: stacks.length }),
751
+ choices: stacks.map((stack) => ({
752
+ name: tOf(STACK_LABELS[stack]),
753
+ value: stack
754
+ }))
563
755
  });
564
- return TEMPLATES.find((x) => x.name === picked);
565
756
  }
566
757
  async function resolveTargetDir(provided, templateName) {
567
758
  if (provided) return provided;
@@ -570,6 +761,139 @@ async function resolveTargetDir(provided, templateName) {
570
761
  default: `./${templateName}`
571
762
  });
572
763
  }
764
+ function ensureTemplateDownloaded(projectDir, tpl) {
765
+ if (tpl.kind === "static-html") {
766
+ const indexPath = path.join(projectDir, "index.html");
767
+ if (fs.existsSync(indexPath)) return;
768
+ throw new Error(t("create.templateIndexMissing", { name: tpl.slug, path: getTemplateSourcePath(tpl) }));
769
+ }
770
+ const pkgPath = path.join(projectDir, "package.json");
771
+ if (fs.existsSync(pkgPath)) return;
772
+ throw new Error(t("create.templatePackageMissing", { name: tpl.slug, path: getTemplateSourcePath(tpl) }));
773
+ }
774
+ async function downloadTemplateSource(tpl, outDir, ref, forceClean) {
775
+ if (tpl.kind === "base-overlay") {
776
+ await downloadTemplatePath(tpl.basePath, outDir, ref, forceClean);
777
+ const overlayDir = fs.mkdtempSync(path.join(os.tmpdir(), "lism-template-overlay-"));
778
+ try {
779
+ await downloadTemplatePath(tpl.overlayPath, overlayDir, ref, true);
780
+ mergeDirectory(overlayDir, outDir);
781
+ } finally {
782
+ fs.rmSync(overlayDir, { recursive: true, force: true });
783
+ }
784
+ return;
785
+ }
786
+ await downloadTemplatePath(tpl.sourcePath, outDir, ref, forceClean);
787
+ }
788
+ async function downloadTemplatePath(sourcePath, outDir, ref, forceClean) {
789
+ await downloadTemplate(`github:${SOURCE_REPO}/${TEMPLATES_PATH}/${sourcePath}#${ref}`, {
790
+ dir: outDir,
791
+ force: true,
792
+ forceClean
793
+ });
794
+ }
795
+ function postProcessTemplate(projectDir, tpl) {
796
+ if (tpl.kind === "static-html") return;
797
+ if (tpl.kind === "base-overlay" && tpl.rewritePackageName !== false) {
798
+ rewritePackageName(projectDir, tpl.slug);
799
+ }
800
+ if (tpl.kind === "single-project-variant") {
801
+ extractVariantPages(projectDir, tpl);
802
+ rewritePackageName(projectDir, tpl.packageName ?? tpl.slug);
803
+ }
804
+ cleanupDevArtifacts(projectDir);
805
+ rewriteWorkspaceDeps(projectDir);
806
+ }
807
+ function cleanupDevArtifacts(projectDir) {
808
+ const screenshotsDir = path.join(projectDir, "screenshots");
809
+ if (fs.existsSync(screenshotsDir)) {
810
+ fs.rmSync(screenshotsDir, { recursive: true, force: true });
811
+ }
812
+ const screenshotsConfig = path.join(projectDir, "screenshots.config.json");
813
+ if (fs.existsSync(screenshotsConfig)) {
814
+ fs.rmSync(screenshotsConfig, { force: true });
815
+ }
816
+ }
817
+ function extractVariantPages(projectDir, tpl) {
818
+ const pagesDir = path.join(projectDir, "src", "pages");
819
+ const variantDir = path.join(pagesDir, tpl.variant);
820
+ const variantIndex = path.join(variantDir, "index.astro");
821
+ const targetIndex = path.join(pagesDir, "index.astro");
822
+ if (!fs.existsSync(variantIndex)) {
823
+ throw new Error(
824
+ t("create.variantMissing", {
825
+ variant: tpl.variant,
826
+ path: `${formatTemplatePath(tpl.sourcePath)}/src/pages/${tpl.variant}/index.astro`
827
+ })
828
+ );
829
+ }
830
+ if (fs.existsSync(targetIndex)) {
831
+ fs.rmSync(targetIndex, { force: true });
832
+ }
833
+ fs.renameSync(variantIndex, targetIndex);
834
+ for (const entry of fs.readdirSync(pagesDir, { withFileTypes: true })) {
835
+ if (!entry.isDirectory()) continue;
836
+ fs.rmSync(path.join(pagesDir, entry.name), { recursive: true, force: true });
837
+ }
838
+ }
839
+ function printNextSteps(projectDir, tpl) {
840
+ logger.heading(t("create.nextSteps"));
841
+ const rel = path.relative(process.cwd(), projectDir) || ".";
842
+ logger.log(` cd ${rel}`);
843
+ if (tpl.kind === "static-html") {
844
+ logger.log(t("create.nextStepsHtmlOpen"));
845
+ logger.log("");
846
+ return;
847
+ }
848
+ logger.log(" npm install # or pnpm install / yarn");
849
+ logger.log(" npm run dev");
850
+ logger.log("");
851
+ }
852
+ function getTemplateSourcePath(tpl) {
853
+ if (tpl.kind === "base-overlay") return `${formatTemplatePath(tpl.basePath)} + ${formatTemplatePath(tpl.overlayPath)}`;
854
+ return formatTemplatePath(tpl.sourcePath);
855
+ }
856
+ function formatTemplatePath(sourcePath) {
857
+ return `${TEMPLATES_PATH}/${sourcePath}`;
858
+ }
859
+ function uniqueDefined(values) {
860
+ return [...new Set(values.filter((value) => value !== void 0))];
861
+ }
862
+ function mergeDirectory(fromDir, toDir) {
863
+ fs.mkdirSync(toDir, { recursive: true });
864
+ for (const entry of fs.readdirSync(fromDir, { withFileTypes: true })) {
865
+ const fromPath = path.join(fromDir, entry.name);
866
+ const toPath = path.join(toDir, entry.name);
867
+ if (entry.isDirectory()) {
868
+ if (fs.existsSync(toPath) && !fs.statSync(toPath).isDirectory()) {
869
+ fs.rmSync(toPath, { recursive: true, force: true });
870
+ }
871
+ mergeDirectory(fromPath, toPath);
872
+ continue;
873
+ }
874
+ if (fs.existsSync(toPath)) {
875
+ fs.rmSync(toPath, { recursive: true, force: true });
876
+ }
877
+ if (entry.isSymbolicLink()) {
878
+ fs.symlinkSync(fs.readlinkSync(fromPath), toPath);
879
+ } else {
880
+ fs.copyFileSync(fromPath, toPath);
881
+ }
882
+ }
883
+ }
884
+ function rewritePackageName(projectDir, name) {
885
+ const pkgPath = path.join(projectDir, "package.json");
886
+ if (!fs.existsSync(pkgPath)) return;
887
+ try {
888
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
889
+ if (pkg.name === name) return;
890
+ pkg.name = name;
891
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
892
+ logger.log(t("create.packageNameRewritten", { name }));
893
+ } catch (err) {
894
+ logger.warn(t("create.packageNameFailed", { reason: String(err) }));
895
+ }
896
+ }
573
897
  function rewriteWorkspaceDeps(projectDir) {
574
898
  const pkgPath = path.join(projectDir, "package.json");
575
899
  if (!fs.existsSync(pkgPath)) return;
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  preScanLang,
14
14
  setLang,
15
15
  t
16
- } from "./chunk-5ULZ7QME.js";
16
+ } from "./chunk-ZSHT6RXM.js";
17
17
 
18
18
  // src/createProgram.ts
19
19
  import { Command as Command3 } from "commander";
@@ -30,6 +30,45 @@ import { confirm, select as select2 } from "@inquirer/prompts";
30
30
  import fs from "fs";
31
31
  import path from "path";
32
32
  import { createJiti } from "jiti";
33
+
34
+ // src/invokeCommand.ts
35
+ function getInvokeCommand() {
36
+ const scriptPath = process.argv[1] ?? "";
37
+ const userAgent = process.env.npm_config_user_agent ?? "";
38
+ const normalizedScriptPath = normalizePath(scriptPath);
39
+ const inDlxCache = /\/_npx\//.test(normalizedScriptPath) || /\/pnpm(?:-cache)?\/(?:[^/]+\/)*dlx-[^/]+\//.test(normalizedScriptPath) || /\/\.yarn\/berry\/cache\//.test(normalizedScriptPath) || /\/\.bun\/install\/cache\//.test(normalizedScriptPath);
40
+ const inLocalDependency = isInProjectNodeModules(normalizedScriptPath) && (/\/node_modules\/\.bin\/lism(?:\.(?:cmd|ps1))?$/.test(normalizedScriptPath) || /\/node_modules\/lism-cli\/bin\/lism\.mjs$/.test(normalizedScriptPath));
41
+ if (inDlxCache) return getDlxInvokeCommand(userAgent);
42
+ if (inLocalDependency) return getLocalInvokeCommand(userAgent);
43
+ return "lism";
44
+ }
45
+ function getDlxInvokeCommand(userAgent) {
46
+ if (userAgent.startsWith("pnpm/")) return "pnpm dlx lism-cli";
47
+ if (userAgent.startsWith("yarn/")) return "yarn dlx lism-cli";
48
+ if (userAgent.startsWith("bun/")) return "bunx lism-cli";
49
+ return "npx lism-cli";
50
+ }
51
+ function getLocalInvokeCommand(userAgent) {
52
+ if (userAgent.startsWith("pnpm/")) return "pnpm exec lism";
53
+ if (userAgent.startsWith("yarn/")) return "yarn lism";
54
+ if (userAgent.startsWith("bun/")) return "bun run lism";
55
+ return "npx lism-cli";
56
+ }
57
+ function isInProjectNodeModules(scriptPath) {
58
+ let dir = normalizePath(process.cwd());
59
+ while (dir) {
60
+ if (scriptPath.startsWith(`${dir}/node_modules/`)) return true;
61
+ const parent = dir.slice(0, dir.lastIndexOf("/"));
62
+ if (parent === dir) break;
63
+ dir = parent;
64
+ }
65
+ return false;
66
+ }
67
+ function normalizePath(value) {
68
+ return value.replaceAll("\\", "/").replace(/\/+$/, "");
69
+ }
70
+
71
+ // src/config.ts
33
72
  var LEGACY_CONFIG_FILE = "lism-ui.json";
34
73
  var CONFIG_SEARCH = ["lism.config.js", "lism.config.mjs"];
35
74
  function resolvePath(filename) {
@@ -57,7 +96,7 @@ async function readConfig() {
57
96
  throw new Error(t("config.notFound"));
58
97
  }
59
98
  if (found.kind === "legacy-json") {
60
- logger.warn(t("config.legacyWarning", { filename: LEGACY_CONFIG_FILE }));
99
+ logger.warn(t("config.legacyWarning", { filename: LEGACY_CONFIG_FILE, invoke: getInvokeCommand() }));
61
100
  const raw = fs.readFileSync(found.path, "utf-8");
62
101
  const parsed = JSON.parse(raw);
63
102
  return parsed;
@@ -798,7 +837,7 @@ async function skillCheckCommand(options = {}) {
798
837
  const cwd = process.cwd();
799
838
  const installed = ALL_SKILL_TOOLS.filter((tool) => fs6.existsSync(path7.join(cwd, SKILL_PATHS[tool], "SKILL.md")));
800
839
  if (installed.length === 0) {
801
- logger.info(t("skill.check.noneInstalled"));
840
+ logger.info(t("skill.check.noneInstalled", { invoke: getInvokeCommand() }));
802
841
  return;
803
842
  }
804
843
  const ref = options.ref ?? DEFAULT_SKILL_REF;
@@ -823,7 +862,7 @@ async function skillCheckCommand(options = {}) {
823
862
  if (outdatedCount === 0) {
824
863
  logger.success(t("skill.check.allLatest"));
825
864
  } else {
826
- logger.info(t("skill.check.outdated", { count: outdatedCount }));
865
+ logger.info(t("skill.check.outdated", { count: outdatedCount, invoke: getInvokeCommand() }));
827
866
  }
828
867
  } finally {
829
868
  cleanupTempDir(remoteDir);
package/dist/lib.d.ts CHANGED
@@ -29,16 +29,16 @@ declare const messages: {
29
29
  readonly en: "Display language for the CLI (ja | en)";
30
30
  };
31
31
  readonly 'cli.create.description': {
32
- readonly ja: "examples テンプレートから新規プロジェクトを生成する";
33
- readonly en: "Create a new project from an examples template";
32
+ readonly ja: "templates から新規プロジェクトを生成する";
33
+ readonly en: "Create a new project from a template";
34
34
  };
35
35
  readonly 'cli.create.arg.targetDir': {
36
36
  readonly ja: "出力先ディレクトリ";
37
37
  readonly en: "Target directory";
38
38
  };
39
39
  readonly 'cli.create.opt.template': {
40
- readonly ja: "使用するテンプレート名(例: astro-minimal)";
41
- readonly en: "Template name to use (e.g. astro-minimal)";
40
+ readonly ja: "使用するテンプレート名(例: minimal-astro)";
41
+ readonly en: "Template name to use (e.g. minimal-astro)";
42
42
  };
43
43
  readonly 'cli.create.opt.force': {
44
44
  readonly ja: "既存ディレクトリを強制上書き";
@@ -132,9 +132,33 @@ declare const messages: {
132
132
  readonly ja: "テンプレート \"{name}\" は見つかりません。利用可能: {list}";
133
133
  readonly en: "Template \"{name}\" not found. Available: {list}";
134
134
  };
135
- readonly 'create.promptSelectTemplate': {
136
- readonly ja: "テンプレートを選択してください:";
137
- readonly en: "Select a template:";
135
+ readonly 'create.promptSelectCategory': {
136
+ readonly ja: "カテゴリを選択してください:";
137
+ readonly en: "Select a category:";
138
+ };
139
+ readonly 'create.promptSelectVariant': {
140
+ readonly ja: "バリアントを選択してください({count}件):";
141
+ readonly en: "Select a variant ({count} options):";
142
+ };
143
+ readonly 'create.promptSelectVariant.blog': {
144
+ readonly ja: "機能レベルを選択してください({count}件):";
145
+ readonly en: "Select a feature level ({count} options):";
146
+ };
147
+ readonly 'create.promptSelectVariant.lp': {
148
+ readonly ja: "業種を選択してください({count}件):";
149
+ readonly en: "Select an industry ({count} options):";
150
+ };
151
+ readonly 'create.promptSelectVariant.web': {
152
+ readonly ja: "業種を選択してください({count}件):";
153
+ readonly en: "Select an industry ({count} options):";
154
+ };
155
+ readonly 'create.promptSelectStack': {
156
+ readonly ja: "スタックを選択してください({count}件):";
157
+ readonly en: "Select a stack ({count} options):";
158
+ };
159
+ readonly 'create.usingStack': {
160
+ readonly ja: "スタックは{stack}を使用します({count}件)。";
161
+ readonly en: "Using {stack} stack ({count} option).";
138
162
  };
139
163
  readonly 'create.promptTargetDir': {
140
164
  readonly ja: "出力先ディレクトリ:";
@@ -152,6 +176,18 @@ declare const messages: {
152
176
  readonly ja: "テンプレート \"{name}\" を取得中(ref: {ref})...";
153
177
  readonly en: "Fetching template \"{name}\" (ref: {ref})...";
154
178
  };
179
+ readonly 'create.templatePackageMissing': {
180
+ readonly ja: "テンプレート\"{name}\"の取得結果にpackage.jsonがありません。取得元パスを確認してください: {path}";
181
+ readonly en: "Downloaded template \"{name}\" does not contain package.json. Check the source path: {path}";
182
+ };
183
+ readonly 'create.templateIndexMissing': {
184
+ readonly ja: "テンプレート\"{name}\"の取得結果にindex.htmlがありません。取得元パスを確認してください: {path}";
185
+ readonly en: "Downloaded template \"{name}\" does not contain index.html. Check the source path: {path}";
186
+ };
187
+ readonly 'create.variantMissing': {
188
+ readonly ja: "variant \"{variant}\" のディレクトリが見つかりません。取得元パスを確認してください: {path}";
189
+ readonly en: "Variant \"{variant}\" directory not found. Check the source path: {path}";
190
+ };
155
191
  readonly 'create.created': {
156
192
  readonly ja: "{dir} にプロジェクトを生成しました。";
157
193
  readonly en: "Generated project at {dir}.";
@@ -160,6 +196,18 @@ declare const messages: {
160
196
  readonly ja: "次のコマンドで開発を開始できます:";
161
197
  readonly en: "Next steps:";
162
198
  };
199
+ readonly 'create.nextStepsHtmlOpen': {
200
+ readonly ja: " index.htmlをブラウザで開いてください";
201
+ readonly en: " Open index.html in your browser";
202
+ };
203
+ readonly 'create.packageNameRewritten': {
204
+ readonly ja: " package.jsonのnameを\"{name}\"に変更しました。";
205
+ readonly en: " Updated package.json name to \"{name}\".";
206
+ };
207
+ readonly 'create.packageNameFailed': {
208
+ readonly ja: "package.jsonのname書き換えに失敗しました: {reason}";
209
+ readonly en: "Failed to rewrite package.json name: {reason}";
210
+ };
163
211
  readonly 'create.workspaceReplaced': {
164
212
  readonly ja: " package.json の workspace:* を ^{version} に置換しました。";
165
213
  readonly en: " Replaced workspace:* in package.json with ^{version}.";
@@ -341,8 +389,8 @@ declare const messages: {
341
389
  readonly en: " Deployed: {tool} → {path}";
342
390
  };
343
391
  readonly 'skill.check.noneInstalled': {
344
- readonly ja: "インストール済みのスキルは見つかりませんでした。`lism skill add` で配置できます。";
345
- readonly en: "No installed skills found. Run `lism skill add` to deploy them.";
392
+ readonly ja: "インストール済みのスキルは見つかりませんでした。`{invoke} skill add` で配置できます。";
393
+ readonly en: "No installed skills found. Run `{invoke} skill add` to deploy them.";
346
394
  };
347
395
  readonly 'skill.check.fetching': {
348
396
  readonly ja: "リモートスキルを取得中(ref: {ref})...";
@@ -357,8 +405,8 @@ declare const messages: {
357
405
  readonly en: "All skills are up to date.";
358
406
  };
359
407
  readonly 'skill.check.outdated': {
360
- readonly ja: "{count} 件のツールに差分があります。`lism skill update` で最新に更新できます。";
361
- readonly en: "{count} tools have changes. Run `lism skill update` to update them.";
408
+ readonly ja: "{count} 件のツールに差分があります。`{invoke} skill update` で最新に更新できます。";
409
+ readonly en: "{count} tools have changes. Run `{invoke} skill update` to update them.";
362
410
  };
363
411
  readonly 'skill.check.diffModified': {
364
412
  readonly ja: "変更 {count}";
@@ -373,8 +421,8 @@ declare const messages: {
373
421
  readonly en: "deleted {count}";
374
422
  };
375
423
  readonly 'config.legacyWarning': {
376
- readonly ja: "[deprecated] {filename} は廃止予定です。\"lism ui init\" で lism.config.js へ移行してください。";
377
- readonly en: "[deprecated] {filename} is deprecated. Run \"lism ui init\" to migrate to lism.config.js.";
424
+ readonly ja: "[deprecated] {filename} は廃止予定です。\"{invoke} ui init\" で lism.config.js へ移行してください。";
425
+ readonly en: "[deprecated] {filename} is deprecated. Run \"{invoke} ui init\" to migrate to lism.config.js.";
378
426
  };
379
427
  readonly 'config.notFound': {
380
428
  readonly ja: "lism.config.js / lism.config.mjs / lism-ui.json のいずれも見つかりません。";
package/dist/lib.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  setLang,
4
4
  t,
5
5
  tOf
6
- } from "./chunk-5ULZ7QME.js";
6
+ } from "./chunk-ZSHT6RXM.js";
7
7
  export {
8
8
  runCreate,
9
9
  setLang,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lism-cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "CLI for scaffolding projects and adding UI components for Lism CSS / Lism UI.",
5
5
  "author": {
6
6
  "name": "ddryo",