@fumadocs/cli 1.6.2 → 1.7.1

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.
@@ -2,7 +2,7 @@ import { t as docs } from "./docs--WqEHTyl.js";
2
2
  import { t as ai } from "./ai-C19ZOP53.js";
3
3
  import { r as llms } from "./llms-Br0RJXXg.js";
4
4
  import { t as og } from "./og-LFlX1Bl4.js";
5
- import { t as search } from "./search-WfSdiGx-.js";
5
+ import { t as search } from "./search-BbzvfJal.js";
6
6
  import { t as mcp } from "./mcp-Ce_W93we.js";
7
7
  import { n as webmcp } from "./webmcp-DyTLrsXL.js";
8
8
  import { t as feedback } from "./feedback-Brj092vC.js";
@@ -24,4 +24,4 @@ const features = [
24
24
  //#endregion
25
25
  export { features as t };
26
26
 
27
- //# sourceMappingURL=all-BBf7I8hG.js.map
27
+ //# sourceMappingURL=all-BVSylqu2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"all-BBf7I8hG.js","names":[],"sources":["../src/features/all.ts"],"sourcesContent":["import type { AnyFeature } from '.';\nimport { docs } from './docs';\nimport { ai } from './ai';\nimport { llms } from './llms';\nimport { og } from './og';\nimport { search } from './search';\nimport { mcp } from './mcp';\nimport { webmcp } from './webmcp';\nimport { feedback } from './feedback';\nimport { epub } from './epub';\nimport { lint } from './lint';\n\nexport const features: AnyFeature[] = [\n docs,\n ai,\n llms,\n mcp,\n webmcp,\n og,\n search,\n feedback,\n epub,\n lint,\n];\n"],"mappings":";;;;;;;;;;;AAYA,MAAa,WAAyB;CACpC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
1
+ {"version":3,"file":"all-BVSylqu2.js","names":[],"sources":["../src/features/all.ts"],"sourcesContent":["import type { AnyFeature } from '.';\nimport { docs } from './docs';\nimport { ai } from './ai';\nimport { llms } from './llms';\nimport { og } from './og';\nimport { search } from './search';\nimport { mcp } from './mcp';\nimport { webmcp } from './webmcp';\nimport { feedback } from './feedback';\nimport { epub } from './epub';\nimport { lint } from './lint';\n\nexport const features: AnyFeature[] = [\n docs,\n ai,\n llms,\n mcp,\n webmcp,\n og,\n search,\n feedback,\n epub,\n lint,\n];\n"],"mappings":";;;;;;;;;;;AAYA,MAAa,WAAyB;CACpC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
@@ -1,2 +1,2 @@
1
- import { t as features } from "../all-BBf7I8hG.js";
1
+ import { t as features } from "../all-BVSylqu2.js";
2
2
  export { features };
@@ -1,2 +1,2 @@
1
- import { t as runFeature } from "../features-CXFCgOWD.js";
1
+ import { t as runFeature } from "../features-Do6x9Tsz.js";
2
2
  export { runFeature };
@@ -1,11 +1,14 @@
1
+ import { o as ReactFramework, s as SourceInfo } from "../index-DI66DoV8.js";
1
2
  import { r as Feature } from "../index-Cs7hw2un.js";
2
- import { t as SourceRef } from "../utils-CxJ7kw39.js";
3
+ import { p as FormattedRoute, t as SourceRef } from "../utils-CxJ7kw39.js";
3
4
  //#region src/features/search.d.ts
4
5
  /** how client code reads public env variables */
5
6
  interface Env {
6
7
  prefix: string;
7
8
  read: string;
8
9
  }
10
+ /** `scripts/sync-content.ts`, syncing the search indexes pre-rendered to `output` */
11
+ export declare const syncScript: (output: string, imports: string, body: string) => string;
9
12
  declare const providers: {
10
13
  'orama-cloud': {
11
14
  label: string;
@@ -18,10 +21,13 @@ declare const providers: {
18
21
  static: true;
19
22
  dialog: (env: Env) => string;
20
23
  exportIndexes: ({ ref }: SourceRef) => {
21
- imports: string;
24
+ head: string;
22
25
  documents: string;
23
26
  };
24
- sync: (env: Env) => string;
27
+ sync: (env: Env, { output }: {
28
+ dir: string;
29
+ output: string;
30
+ }) => string;
25
31
  };
26
32
  algolia: {
27
33
  label: string;
@@ -34,10 +40,32 @@ declare const providers: {
34
40
  static: true;
35
41
  dialog: (env: Env) => string;
36
42
  exportIndexes: ({ ref }: SourceRef) => {
37
- imports: string;
43
+ head: string;
38
44
  documents: string;
39
45
  };
40
- sync: (env: Env) => string;
46
+ sync: (env: Env, { output }: {
47
+ dir: string;
48
+ output: string;
49
+ }) => string;
50
+ };
51
+ meilisearch: {
52
+ label: string;
53
+ hint: string;
54
+ dependencies: {
55
+ meilisearch: null;
56
+ };
57
+ publicEnv: string[];
58
+ privateEnv: string[];
59
+ static: true;
60
+ dialog: (env: Env) => string;
61
+ exportIndexes: ({ ref }: SourceRef) => {
62
+ head: string;
63
+ documents: string;
64
+ };
65
+ sync: (env: Env, { output }: {
66
+ dir: string;
67
+ output: string;
68
+ }) => string;
41
69
  };
42
70
  typesense: {
43
71
  label: string;
@@ -50,12 +78,14 @@ declare const providers: {
50
78
  privateEnv: string[];
51
79
  static: true;
52
80
  dialog: (env: Env) => string;
53
- exportIndexes: (src: SourceRef) => {
54
- imports: string;
81
+ exportIndexes: (src: SourceRef, async: boolean) => {
82
+ head: string;
55
83
  documents: string;
56
- file: (async: boolean) => string;
57
84
  };
58
- sync: (env: Env) => string;
85
+ sync: (env: Env, { output }: {
86
+ dir: string;
87
+ output: string;
88
+ }) => string;
59
89
  };
60
90
  mixedbread: {
61
91
  label: string;
@@ -67,7 +97,10 @@ declare const providers: {
67
97
  privateEnv: string[];
68
98
  static: false;
69
99
  dialog: () => string;
70
- sync: (_env: Env, dir: string) => string;
100
+ sync: (_env: Env, { dir }: {
101
+ dir: string;
102
+ output: string;
103
+ }) => string;
71
104
  searchRoute: {
72
105
  next: string;
73
106
  'react-router': string;
@@ -77,6 +110,18 @@ declare const providers: {
77
110
  };
78
111
  };
79
112
  export type SearchProvider = keyof typeof providers;
113
+ /** pre-rendered on build to export the search indexes */
114
+ export declare const staticJson: (framework: ReactFramework) => FormattedRoute;
115
+ export declare const staticRoute: (framework: ReactFramework, head: string, documents: string) => string;
116
+ /** where `static.json` is pre-rendered on build, `config` is the Vite config of TanStack Start */
117
+ export declare function staticOutput(framework: ReactFramework, config?: string): string;
118
+ /** runs the sync script after build */
119
+ export declare const syncCommand = "node --env-file-if-exists=.env.local scripts/sync-content.ts";
120
+ /** the files written by a provider, relative to the project, `output` is where `static.json` is pre-rendered */
121
+ export declare function templates(name: SearchProvider, framework: ReactFramework, { baseDir, source }: {
122
+ baseDir: string;
123
+ source: Pick<SourceInfo, 'dynamic' | 'async' | 'dir'>;
124
+ }, output: string): [file: string, content: string][];
80
125
  export declare const search: Feature<{
81
126
  provider: SearchProvider;
82
127
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","names":[],"sources":["../../src/features/search.ts"],"mappings":";;;;UAwBU;EACR;EACA;;cA6GI;;;;;MAIc;;;;;;;;;;;;;;;;MA+CA;;;;;;;;;;;;;;;;MA+CA;MAAiB;;;;;;;;;;;;;;;;;MAgDjB;;;;;;;;;;;;;;;YAqER,8BAA8B;qBAe7B,QAAQ;EAAU,UAAU"}
1
+ {"version":3,"file":"search.d.ts","names":[],"sources":["../../src/features/search.ts"],"mappings":";;;;;UAyBU;EACR;EACA;;;qBAsEW,aAAU,gBACP,iBACC;cAqCX;;;;;MAIc;;;;;;;;;;;MATc;MAAgB;;;;;;;MAyD9B;;;;;;;;;;;MAzDc;MAAgB;;;;;;;MAyG9B;;;;;;;;;;;MAzGc;MAAgB;;;;;;;MA4J9B;MAAiB;;;;;;;;;;;MA5JH;MAAgB;;;;;;;MA4M9B;;;;;;;MA5Mc;MAAgB;;;;;;;;;;YAiRtC,8BAA8B;;qBAG7B,aAAU,WAAe,mBAAA;qBAGzB,cAAW,WAAe,gBAAc,cAAc;;wBASnD,aAAa,WAAW,gBAAgB;;qBAgB3C;;wBAGG,UACd,MAAM,gBACN,WAAW,kBACT,SAAS;EAAY;EAAiB,QAAQ,KAAK;GACrD,kBACE,cAAc;qBAmBL,QAAQ;EAAU,UAAU"}
@@ -1,2 +1,2 @@
1
- import { t as search } from "../search-WfSdiGx-.js";
2
- export { search };
1
+ import { a as syncCommand, i as staticRoute, n as staticJson, o as syncScript, r as staticOutput, s as templates, t as search } from "../search-BbzvfJal.js";
2
+ export { search, staticJson, staticOutput, staticRoute, syncCommand, syncScript, templates };
@@ -1,6 +1,6 @@
1
1
  import { g as createSourceFile } from "./codemod-auol-p4R.js";
2
2
  import { t as exists } from "./fs-D6J9dOEx.js";
3
- import { t as FumadocsComponentInstaller } from "./installer-CzhVfs7i.js";
3
+ import { t as FumadocsComponentInstaller } from "./installer-C4662Woc.js";
4
4
  import fs from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  import { x } from "tinyexec";
@@ -15,9 +15,8 @@ async function runFeature(feature, options, { project, connector, io, versions }
15
15
  const env = [];
16
16
  const notes = [];
17
17
  const installer = new FumadocsComponentInstaller(connector, project.config, cwd, {
18
- onWarn: io.log,
19
- confirmFileOverride: ({ path: file }) => io.confirmOverwrite(path.relative(cwd, file)),
20
- onFileDownloaded: ({ path: file }) => io.log(`installed ${path.relative(cwd, file)}`)
18
+ confirmFileOverride: (file) => io.confirmOverwrite(path.relative(cwd, file.output)),
19
+ onFileWritten: (file) => io.log(`installed ${path.relative(cwd, file.output)}`)
21
20
  });
22
21
  const ctx = {
23
22
  project,
@@ -72,13 +71,8 @@ async function runFeature(feature, options, { project, connector, io, versions }
72
71
  },
73
72
  async install(name, subRegistry) {
74
73
  const manager = await (await installer.install(name, subRegistry)).deps();
75
- const decode = (target, dep) => {
76
- const at = dep.indexOf("@", 1);
77
- if (at === -1) target[dep] = null;
78
- else target[dep.slice(0, at)] = dep.slice(at + 1);
79
- };
80
- for (const dep of manager.dependencies) decode(deps, dep);
81
- for (const dep of manager.devDependencies) decode(devDeps, dep);
74
+ Object.assign(deps, manager.required);
75
+ Object.assign(devDeps, manager.requiredDev);
82
76
  }
83
77
  };
84
78
  await feature.apply(ctx, options);
@@ -129,4 +123,4 @@ async function installDependencies(project, deps, devDeps, io, versions = {}) {
129
123
  //#endregion
130
124
  export { runFeature as t };
131
125
 
132
- //# sourceMappingURL=features-CXFCgOWD.js.map
126
+ //# sourceMappingURL=features-Do6x9Tsz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features-Do6x9Tsz.js","names":[],"sources":["../src/features/index.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { x } from 'tinyexec';\nimport type { RegistryConnector } from 'fuma-cli/registry/connector';\nimport type { Project } from '@/project';\nimport { createSourceFile, type SourceFile } from '@/codemod';\nimport { FumadocsComponentInstaller } from '@/registry/installer';\nimport { exists } from '@/utils/fs';\n\nexport interface SelectOption<T> {\n message: string;\n choices: { value: T; label: string; hint?: string }[];\n}\n\nexport interface ConfirmOption {\n message: string;\n initialValue?: boolean;\n}\n\nexport type FeatureOption<T> = [T] extends [boolean] ? ConfirmOption : SelectOption<T>;\n\nexport interface Feature<Options extends object = Record<never, never>> {\n id: string;\n title: string;\n description: string;\n options?: { [K in keyof Options]: FeatureOption<Options[K]> };\n /** features that must be applied first */\n requires?: AnyFeature[];\n /** whether the feature is already applied to the project */\n detect?: (project: Project) => Promise<boolean>;\n /** @returns `true` if supported, otherwise the reason */\n supports?: (project: Project) => true | string;\n apply(ctx: FeatureContext, options: Options): Promise<void>;\n}\n\nexport type AnyFeature = Omit<Feature<Record<string, unknown>>, 'options'> & {\n options?: Record<string, SelectOption<unknown> | ConfirmOption>;\n};\n\nexport interface PackageJson {\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport interface FeatureContext {\n project: Project;\n /** write a file (relative to project root), asks before overwriting */\n write: (file: string, content: string) => Promise<void>;\n /** edit a file with codemods, `false` if the file doesn't exist */\n source: (file: string, edit: (file: SourceFile) => void) => Promise<boolean>;\n /** append lines to a text file, skip lines already present */\n append: (file: string, lines: string[]) => Promise<void>;\n remove: (file: string) => Promise<void>;\n packageJson: (edit: (data: PackageJson) => void) => Promise<void>;\n /** install a registry component */\n install: (name: string, subRegistry?: string) => Promise<void>;\n /** `null` to install the latest version */\n addDependencies: (deps: Record<string, string | null>, dev?: boolean) => void;\n env: (key: string, value: string) => void;\n /** instructions to show after the feature is applied */\n note: (text: string) => void;\n log: (message: string) => void;\n}\n\nexport interface FeatureIO {\n log: (message: string) => void;\n confirmOverwrite: (file: string) => Promise<boolean>;\n /** run package manager to install dependencies, otherwise only write them into `package.json` */\n installDependencies: boolean;\n}\n\nexport interface RunOptions {\n project: Project;\n connector: RegistryConnector;\n io: FeatureIO;\n /** preferred versions of dependencies, when a feature doesn't specify one */\n versions?: Record<string, string>;\n}\n\nexport async function runFeature<O extends object>(\n feature: Omit<Feature<O>, 'options'>,\n options: O,\n { project, connector, io, versions }: RunOptions,\n): Promise<{ notes: string[] }> {\n for (const dep of feature.requires ?? []) {\n if (dep.detect && !(await dep.detect(project)))\n throw new Error(\n `\"${feature.id}\" requires \"${dep.id}\", run \\`fumadocs feature ${dep.id}\\` first.`,\n );\n }\n const supported = feature.supports?.(project) ?? true;\n if (supported !== true) throw new Error(`\"${feature.id}\" is unavailable: ${supported}`);\n\n const { cwd } = project;\n const deps: Record<string, string | null> = {};\n const devDeps: Record<string, string | null> = {};\n const env: string[] = [];\n const notes: string[] = [];\n const installer = new FumadocsComponentInstaller(connector, project.config, cwd, {\n confirmFileOverride: (file) => io.confirmOverwrite(path.relative(cwd, file.output)),\n onFileWritten: (file) => io.log(`installed ${path.relative(cwd, file.output)}`),\n });\n\n const ctx: FeatureContext = {\n project,\n log: io.log,\n note: (text) => notes.push(text),\n env: (key, value) => env.push(`${key}=${value}`),\n addDependencies(input, dev) {\n Object.assign(dev ? devDeps : deps, input);\n },\n async write(file, content) {\n const target = path.join(cwd, file);\n const current = await fs.readFile(target, 'utf-8').catch(() => null);\n if (current !== null) {\n if (current.trim() === content.trim()) return;\n if (!(await io.confirmOverwrite(file))) return;\n }\n await fs.mkdir(path.dirname(target), { recursive: true });\n await fs.writeFile(target, content);\n io.log(`${current === null ? 'created' : 'updated'} ${file}`);\n },\n async source(file, edit) {\n const target = path.join(cwd, file);\n if (!(await exists(target))) return false;\n const source = await createSourceFile(target);\n edit(source);\n if (source.s.hasChanged()) {\n await source.save();\n io.log(`updated ${file}`);\n }\n return true;\n },\n async append(file, lines) {\n const target = path.join(cwd, file);\n const current = await fs.readFile(target, 'utf-8').catch(() => '');\n const missing = lines.filter((line) => !current.includes(line));\n if (missing.length === 0) return;\n const separator = current.length === 0 || current.endsWith('\\n') ? '' : '\\n';\n await fs.mkdir(path.dirname(target), { recursive: true });\n await fs.writeFile(target, `${current}${separator}${missing.join('\\n')}\\n`);\n io.log(`updated ${file}`);\n },\n async remove(file) {\n await fs.rm(path.join(cwd, file), { force: true });\n io.log(`removed ${file}`);\n },\n async packageJson(edit) {\n const target = path.join(cwd, 'package.json');\n const data = JSON.parse(await fs.readFile(target, 'utf-8'));\n edit(data);\n await fs.writeFile(target, `${JSON.stringify(data, null, 2)}\\n`);\n io.log('updated package.json');\n },\n async install(name, subRegistry) {\n const result = await installer.install(name, subRegistry);\n const manager = await result.deps();\n Object.assign(deps, manager.required);\n Object.assign(devDeps, manager.requiredDev);\n },\n };\n\n await feature.apply(ctx, options);\n\n if (env.length > 0) await ctx.append('.env.local', env);\n await installDependencies(project, deps, devDeps, io, versions);\n return { notes };\n}\n\nasync function installDependencies(\n project: Project,\n deps: Record<string, string | null>,\n devDeps: Record<string, string | null>,\n io: FeatureIO,\n versions: Record<string, string> = {},\n) {\n const { dependencies = {}, devDependencies = {} } = project.packageJson;\n const filter = (input: Record<string, string | null>) =>\n Object.entries(input).filter(([name]) => !(name in dependencies) && !(name in devDependencies));\n const missing = filter(deps);\n const missingDev = filter(devDeps);\n if (missing.length === 0 && missingDev.length === 0) return;\n\n if (io.installDependencies) {\n const pm = project.packageManager;\n const run = async (flags: string[], entries: [string, string | null][]) => {\n if (entries.length === 0) return;\n const args = [\n 'add',\n ...flags,\n ...entries.map(([name, version]) => (version ? `${name}@${version}` : name)),\n ];\n io.log(`${pm} ${args.join(' ')}`);\n await x(pm, args, {\n nodeOptions: { cwd: project.cwd, stdio: 'inherit' },\n throwOnError: true,\n });\n };\n await run([], missing);\n await run(['-D'], missingDev);\n return;\n }\n\n const file = path.join(project.cwd, 'package.json');\n const json = JSON.parse(await fs.readFile(file, 'utf-8'));\n const write = (field: string, entries: [string, string | null][]) => {\n if (entries.length === 0) return;\n const target = (json[field] ??= {});\n for (const [name, version] of entries) target[name] = version ?? versions[name] ?? 'latest';\n };\n write('dependencies', missing);\n write('devDependencies', missingDev);\n await fs.writeFile(file, `${JSON.stringify(json, null, 2)}\\n`);\n io.log('updated package.json');\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -3,15 +3,15 @@ import { i as initConfig, n as createOrLoadConfig } from "./config-Bw0kmF01.js";
3
3
  import { T as parseSourceFile } from "./codemod-auol-p4R.js";
4
4
  import { t as exists } from "./fs-D6J9dOEx.js";
5
5
  import { i as loadProject, n as frameworks } from "./project-DwRVTm4p.js";
6
- import { n as isCancel$1, r as UIRegistries, t as FumadocsComponentInstaller } from "./installer-CzhVfs7i.js";
7
- import { t as runFeature } from "./features-CXFCgOWD.js";
8
- import { t as features } from "./all-BBf7I8hG.js";
6
+ import { n as UIRegistries, t as FumadocsComponentInstaller } from "./installer-C4662Woc.js";
7
+ import { t as runFeature } from "./features-Do6x9Tsz.js";
8
+ import { t as features } from "./all-BVSylqu2.js";
9
9
  import fs from "node:fs/promises";
10
10
  import path from "node:path";
11
11
  import { cac } from "cac";
12
12
  import picocolors from "picocolors";
13
13
  import { x } from "tinyexec";
14
- import { autocompleteMultiselect, cancel, confirm, group, intro, log, note, outro, select, spinner } from "@clack/prompts";
14
+ import { autocompleteMultiselect, cancel, confirm, group, intro, isCancel, log, note, outro, select, spinner } from "@clack/prompts";
15
15
  import { exec } from "node:child_process";
16
16
  import { promisify } from "node:util";
17
17
  import { HttpRegistryConnector, LocalRegistryConnector } from "fuma-cli/registry/connector";
@@ -66,14 +66,14 @@ async function runTree(args) {
66
66
  }
67
67
  //#endregion
68
68
  //#region package.json
69
- var version = "1.6.2";
69
+ var version = "1.7.1";
70
70
  //#endregion
71
71
  //#region src/commands/customise.ts
72
72
  async function customise(config, connector) {
73
73
  intro(picocolors.bgBlack(picocolors.whiteBright("Customize Fumadocs UI")));
74
74
  const installer = new FumadocsComponentInstaller(connector, config);
75
75
  const subRegistry = UIRegistries[config.uiLibrary];
76
- const info = await connector.fetchRegistryInfo(subRegistry);
76
+ const manifest = await installer.fetchManifest(subRegistry);
77
77
  const targetInfo = (await group({
78
78
  layout: () => select({
79
79
  message: "What do you want to customize?",
@@ -143,6 +143,33 @@ async function customise(config, connector) {
143
143
  target: (v) => {
144
144
  const selected = v.results.layout;
145
145
  if (selected.id === "home") return Promise.resolve(selected);
146
+ const slots = [];
147
+ const prefix = `layouts/${selected.id}/`;
148
+ for (const { name: id } of manifest.components) {
149
+ const [dir, name] = id.startsWith(prefix) ? id.slice(prefix.length).split("slots/") : [];
150
+ if (name === void 0) continue;
151
+ const isPage = dir === "page/";
152
+ slots.push({
153
+ label: `${isPage ? "Page" : "Layout"}: ${name}`,
154
+ hint: `only replace a part of layout${isPage ? "'s page" : ""}, useful for adjusting details`,
155
+ value: {
156
+ id,
157
+ targets: [{
158
+ subRegistry,
159
+ name: id
160
+ }],
161
+ print() {
162
+ printSlot({
163
+ at: `@/${id}`,
164
+ layoutId: selected.id,
165
+ name,
166
+ isPage,
167
+ uiLibrary: config.uiLibrary
168
+ });
169
+ }
170
+ }
171
+ });
172
+ }
146
173
  return select({
147
174
  message: "Which part do you want to customize?",
148
175
  options: [
@@ -160,54 +187,7 @@ async function customise(config, connector) {
160
187
  print: () => printLayout(config, ["fumadocs-ui/layouts/docs", "@/layouts/docs"], ["fumadocs-ui/layouts/docs/page", "@/layouts/docs/page"])
161
188
  }
162
189
  },
163
- ...info.unlistedIndexes.flatMap((index) => {
164
- const prefix = `slots/${selected.id}`;
165
- if (!index.name.startsWith(prefix)) return [];
166
- let name = index.name.slice(prefix.length + 1);
167
- if (name.startsWith("page/")) {
168
- name = name.slice(5);
169
- return {
170
- label: `Page: ${name}`,
171
- hint: "only replace a part of layout's page, useful for adjusting details",
172
- value: {
173
- id: index.name,
174
- targets: [{
175
- subRegistry,
176
- name: index.name
177
- }],
178
- print() {
179
- printSlot({
180
- at: `@/layouts/${selected.id}/page/slots/${name}`,
181
- layoutId: selected.id,
182
- name,
183
- isPage: true,
184
- uiLibrary: config.uiLibrary
185
- });
186
- }
187
- }
188
- };
189
- }
190
- return {
191
- label: `Layout: ${name}`,
192
- hint: "only replace a part of layout, useful for adjusting details",
193
- value: {
194
- id: index.name,
195
- targets: [{
196
- subRegistry,
197
- name: index.name
198
- }],
199
- print() {
200
- printSlot({
201
- at: `@/layouts/${selected.id}/slots/${name}`,
202
- layoutId: selected.id,
203
- name,
204
- isPage: false,
205
- uiLibrary: config.uiLibrary
206
- });
207
- }
208
- }
209
- };
210
- })
190
+ ...slots
211
191
  ]
212
192
  });
213
193
  }
@@ -455,6 +435,15 @@ return (
455
435
  }
456
436
  }
457
437
  //#endregion
438
+ //#region src/utils/prompt.ts
439
+ /**
440
+ * `@clack/core` narrows to its own `unique symbol`, which can't exclude the wider `symbol` that
441
+ * `@clack/prompts` returns, so a prompt result never narrows without this.
442
+ */
443
+ function isCancel$1(value) {
444
+ return isCancel(value);
445
+ }
446
+ //#endregion
458
447
  //#region src/commands/add.ts
459
448
  async function add(input, connector, config) {
460
449
  let targets;
@@ -464,14 +453,20 @@ async function add(input, connector, config) {
464
453
  const spin = spinner();
465
454
  spin.start("fetching registry");
466
455
  async function scan(subRegistry, prefix) {
467
- return (await connector.fetchRegistryInfo(subRegistry)).indexes.map((item) => ({
468
- label: `${prefix ? `${picocolors.bold(prefix)} - ` : ""}${item.title ?? item.name}`,
469
- value: {
470
- name: item.name,
471
- subRegistry
472
- },
473
- hint: item.description
474
- }));
456
+ const manifest = await installer.fetchManifest(subRegistry);
457
+ const options = [];
458
+ for (const item of manifest.components) {
459
+ if (item.unlisted) continue;
460
+ options.push({
461
+ label: `${prefix ? `${picocolors.bold(prefix)} - ` : ""}${item.title ?? item.name}`,
462
+ value: {
463
+ name: item.name,
464
+ subRegistry
465
+ },
466
+ hint: item.description
467
+ });
468
+ }
469
+ return options;
475
470
  }
476
471
  const groups = await Promise.all([
477
472
  scan(void 0, "common"),
@@ -490,10 +485,14 @@ async function add(input, connector, config) {
490
485
  return;
491
486
  }
492
487
  targets = value;
493
- } else targets = await Promise.all(input.map(async (item) => await connector.hasComponent(item) ? { name: item } : {
494
- subRegistry,
495
- name: item
496
- }));
488
+ } else {
489
+ const root = /* @__PURE__ */ new Set();
490
+ for (const item of (await installer.fetchManifest()).components) root.add(item.name);
491
+ targets = input.map((name) => root.has(name) ? { name } : {
492
+ subRegistry,
493
+ name
494
+ });
495
+ }
497
496
  for (const target of targets) await installer.installInteractive(target.name, target.subRegistry);
498
497
  outro(picocolors.bold(picocolors.greenBright("Successful")));
499
498
  }