starwind 1.16.2 → 2.0.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
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Create animated websites in record time.**
6
6
 
7
- Starwind UI is a collection of 45+ beautifully designed, animated, and accessible components built purely with Astro and vanilla JS. Inspired by [shadcn/ui](https://ui.shadcn.com/), components are added directly to your codebase, giving you full ownership and complete control.
7
+ Starwind UI is a collection of 49+ beautifully designed, animated, and accessible components built purely with Astro and vanilla JS. Inspired by [shadcn/ui](https://ui.shadcn.com/), components are added directly to your codebase, giving you full ownership and complete control.
8
8
 
9
9
  **[Get Started →](https://starwind.dev/docs/getting-started/installation/)**  |  **[Explore Components](https://starwind.dev/docs/components/)**
10
10
 
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command, Option } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "starwind",
9
- version: "1.16.2",
9
+ version: "2.0.0",
10
10
  description: "Add beautifully designed components to your Astro applications",
11
11
  license: "MIT",
12
12
  homepage: "https://starwind.dev/",
@@ -44,7 +44,7 @@ var package_default = {
44
44
  scripts: {
45
45
  build: "tsup",
46
46
  dev: "tsup --watch",
47
- "cli:link": "pnpm link --global",
47
+ "cli:link": "pnpm add --global . --ignore-scripts",
48
48
  "cli:unlink": "pnpm rm --global starwind",
49
49
  "cli:yalc:link": "yalc publish && yalc link @starwind-ui/core",
50
50
  "cli:yalc:unlink": "yalc remove @starwind-ui/core && yalc remove starwind",
@@ -60,7 +60,7 @@ var package_default = {
60
60
  },
61
61
  dependencies: {
62
62
  "@clack/prompts": "^0.11.0",
63
- "@starwind-ui/core": "1.16.2",
63
+ "@starwind-ui/core": "2.0.0",
64
64
  chalk: "^5.6.2",
65
65
  commander: "^14.0.2",
66
66
  execa: "^9.6.0",
@@ -76,7 +76,7 @@ var package_default = {
76
76
  tsup: "^8.5.1"
77
77
  },
78
78
  engines: {
79
- node: "^20.6.0 || >=22.0.0"
79
+ node: ">=22.12.0"
80
80
  }
81
81
  };
82
82
 
@@ -90,6 +90,7 @@ var PATHS = {
90
90
  STARWIND_CORE: "@starwind-ui/core",
91
91
  STARWIND_CORE_COMPONENTS: "src/components",
92
92
  STARWIND_CORE_UTILS: "src/lib/utils",
93
+ STARWIND_DOCS_BASE_URL: "https://starwind.dev/docs/components",
93
94
  STARWIND_REMOTE_COMPONENT_REGISTRY: "https://starwind.dev/registry.json",
94
95
  STARWIND_PRO_REGISTRY: "https://pro.starwind.dev/r/{name}",
95
96
  LOCAL_CSS_FILE: "src/styles/starwind.css",
@@ -2227,32 +2228,67 @@ ${registryResults.success.map((name) => ` ${name}`).join("\n")}`
2227
2228
  }
2228
2229
  }
2229
2230
 
2230
- // src/commands/remove.ts
2231
+ // src/commands/docs.ts
2231
2232
  import * as p10 from "@clack/prompts";
2233
+ var DOCS_BASE_URL = "https://starwind.dev/docs/components";
2234
+ async function docs(components, options) {
2235
+ if (!options?.json) {
2236
+ p10.intro(highlighter.title(" Starwind Docs "));
2237
+ }
2238
+ try {
2239
+ const registry = await getAllComponents();
2240
+ const results = [];
2241
+ for (const name of components) {
2242
+ const exists = registry.find((c) => c.name === name);
2243
+ if (!exists) {
2244
+ p10.log.error(`Component ${highlighter.info(name)} not found in the Starwind registry.`);
2245
+ process.exit(1);
2246
+ }
2247
+ results.push({ component: name, url: `${DOCS_BASE_URL}/${name}/` });
2248
+ }
2249
+ if (options?.json) {
2250
+ console.log(JSON.stringify(results, null, 2));
2251
+ return;
2252
+ }
2253
+ const maxNameLength = Math.max(...results.map((r) => r.component.length));
2254
+ p10.log.message(highlighter.underline("Documentation links"));
2255
+ for (const { component, url } of results) {
2256
+ p10.log.info(` ${highlighter.info(component.padEnd(maxNameLength + 2))}${url}`);
2257
+ }
2258
+ p10.outro(`Found docs for ${results.length} component${results.length === 1 ? "" : "s"}`);
2259
+ } catch (error) {
2260
+ p10.log.error(error instanceof Error ? error.message : "Failed to fetch documentation");
2261
+ p10.cancel("Operation cancelled");
2262
+ process.exit(1);
2263
+ }
2264
+ }
2265
+
2266
+ // src/commands/remove.ts
2267
+ import * as p11 from "@clack/prompts";
2232
2268
  async function remove(components, options) {
2233
2269
  try {
2234
- p10.intro(highlighter.title(" Welcome to the Starwind CLI "));
2270
+ p11.intro(highlighter.title(" Welcome to the Starwind CLI "));
2235
2271
  const configExists = await fileExists(PATHS.LOCAL_CONFIG_FILE);
2236
2272
  if (!configExists) {
2237
- p10.log.error("No Starwind configuration found. Please run starwind init first.");
2273
+ p11.log.error("No Starwind configuration found. Please run starwind init first.");
2238
2274
  process.exit(1);
2239
2275
  }
2240
2276
  const config = await getConfig();
2241
2277
  const installedComponents = config.components;
2242
2278
  if (installedComponents.length === 0) {
2243
- p10.log.warn("No components are currently installed.");
2279
+ p11.log.warn("No components are currently installed.");
2244
2280
  process.exit(0);
2245
2281
  }
2246
2282
  let componentsToRemove = [];
2247
2283
  if (options?.all) {
2248
2284
  componentsToRemove = installedComponents.map((comp) => comp.name);
2249
- p10.log.info(`Removing all ${componentsToRemove.length} installed components...`);
2285
+ p11.log.info(`Removing all ${componentsToRemove.length} installed components...`);
2250
2286
  } else if (components && components.length > 0) {
2251
2287
  const invalid = components.filter(
2252
2288
  (comp) => !installedComponents.some((ic) => ic.name === comp)
2253
2289
  );
2254
2290
  if (invalid.length > 0) {
2255
- p10.log.warn(
2291
+ p11.log.warn(
2256
2292
  `${highlighter.warn("Components not found:")}
2257
2293
  ${invalid.map((name) => ` ${name}`).join("\n")}`
2258
2294
  );
@@ -2261,7 +2297,7 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2261
2297
  (comp) => installedComponents.some((ic) => ic.name === comp)
2262
2298
  );
2263
2299
  if (componentsToRemove.length === 0) {
2264
- p10.log.warn("No valid components to remove");
2300
+ p11.log.warn("No valid components to remove");
2265
2301
  process.exit(0);
2266
2302
  }
2267
2303
  } else {
@@ -2269,25 +2305,25 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2269
2305
  value: comp.name,
2270
2306
  label: comp.name
2271
2307
  }));
2272
- const selected = await p10.multiselect({
2308
+ const selected = await p11.multiselect({
2273
2309
  message: "Select components to remove",
2274
2310
  options: choices
2275
2311
  });
2276
- if (p10.isCancel(selected)) {
2277
- p10.cancel("Operation cancelled");
2312
+ if (p11.isCancel(selected)) {
2313
+ p11.cancel("Operation cancelled");
2278
2314
  process.exit(0);
2279
2315
  }
2280
2316
  componentsToRemove = selected;
2281
2317
  }
2282
2318
  if (componentsToRemove.length === 0) {
2283
- p10.log.warn("No components selected for removal");
2319
+ p11.log.warn("No components selected for removal");
2284
2320
  process.exit(0);
2285
2321
  }
2286
- const confirmed = await p10.confirm({
2322
+ const confirmed = await p11.confirm({
2287
2323
  message: `Remove ${componentsToRemove.map((comp) => highlighter.info(comp)).join(", ")} ${componentsToRemove.length > 1 ? "components" : "component"}?`
2288
2324
  });
2289
- if (!confirmed || p10.isCancel(confirmed)) {
2290
- p10.cancel("Operation cancelled");
2325
+ if (!confirmed || p11.isCancel(confirmed)) {
2326
+ p11.cancel("Operation cancelled");
2291
2327
  process.exit(0);
2292
2328
  }
2293
2329
  const results = {
@@ -2312,60 +2348,295 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2312
2348
  },
2313
2349
  { appendComponents: false }
2314
2350
  );
2315
- p10.log.message(`
2351
+ p11.log.message(`
2316
2352
 
2317
2353
  ${highlighter.underline("Removal Summary")}`);
2318
2354
  if (results.failed.length > 0) {
2319
- p10.log.error(
2355
+ p11.log.error(
2320
2356
  `${highlighter.error("Failed to remove components:")}
2321
2357
  ${results.failed.map((r) => ` ${r.name} - ${r.error}`).join("\n")}`
2322
2358
  );
2323
2359
  }
2324
2360
  if (results.removed.length > 0) {
2325
- p10.log.success(
2361
+ p11.log.success(
2326
2362
  `${highlighter.success("Successfully removed components:")}
2327
2363
  ${results.removed.map((r) => ` ${r.name}`).join("\n")}`
2328
2364
  );
2329
2365
  }
2330
2366
  await sleep(1e3);
2331
2367
  if (results.removed.length > 0) {
2332
- p10.outro("Components removed successfully \u{1F5D1}\uFE0F");
2368
+ p11.outro("Components removed successfully \u{1F5D1}\uFE0F");
2333
2369
  } else {
2334
- p10.cancel("Errors occurred while removing components");
2370
+ p11.cancel("Errors occurred while removing components");
2335
2371
  process.exit(1);
2336
2372
  }
2337
2373
  } catch (error) {
2338
- p10.log.error(error instanceof Error ? error.message : "Failed to remove components");
2339
- p10.cancel("Operation cancelled");
2374
+ p11.log.error(error instanceof Error ? error.message : "Failed to remove components");
2375
+ p11.cancel("Operation cancelled");
2376
+ process.exit(1);
2377
+ }
2378
+ }
2379
+
2380
+ // src/commands/search.ts
2381
+ import * as p12 from "@clack/prompts";
2382
+
2383
+ // src/utils/pro-manifest.ts
2384
+ import { z as z2 } from "zod";
2385
+ var manifestBlockSchema = z2.object({
2386
+ id: z2.string(),
2387
+ name: z2.string(),
2388
+ description: z2.string(),
2389
+ categories: z2.array(z2.string()),
2390
+ keywords: z2.array(z2.string()),
2391
+ plan: z2.enum(["free", "pro"]),
2392
+ installCommand: z2.string(),
2393
+ previewUrl: z2.string()
2394
+ });
2395
+ var manifestSchema = z2.object({
2396
+ $schema: z2.string().optional(),
2397
+ name: z2.string(),
2398
+ version: z2.string(),
2399
+ generatedAt: z2.string(),
2400
+ baseUrl: z2.string(),
2401
+ totalBlocks: z2.number(),
2402
+ categories: z2.array(z2.string()),
2403
+ blocks: z2.array(manifestBlockSchema)
2404
+ });
2405
+ var MANIFEST_URL = "https://pro.starwind.dev/r/manifest.json";
2406
+ var CACHE_TTL_MS = 60 * 60 * 1e3;
2407
+ var manifestCache = null;
2408
+ async function getProManifest() {
2409
+ if (manifestCache && Date.now() < manifestCache.expiresAt) {
2410
+ return { manifest: manifestCache.data, source: "cache" };
2411
+ }
2412
+ try {
2413
+ const response = await fetch(MANIFEST_URL);
2414
+ if (!response.ok) {
2415
+ throw new Error(`Failed to fetch manifest: ${response.status} ${response.statusText}`);
2416
+ }
2417
+ const raw = await response.json();
2418
+ const manifest = manifestSchema.parse(raw);
2419
+ manifestCache = {
2420
+ data: manifest,
2421
+ timestamp: Date.now(),
2422
+ expiresAt: Date.now() + CACHE_TTL_MS
2423
+ };
2424
+ return { manifest, source: "network" };
2425
+ } catch (error) {
2426
+ const message = error instanceof Error ? error.message : "Unknown error";
2427
+ throw new Error(`Error fetching Starwind Pro manifest: ${message}`);
2428
+ }
2429
+ }
2430
+ function scoreBlockMatch(block, query) {
2431
+ const q = query.toLowerCase();
2432
+ let score = 0;
2433
+ if (block.name.toLowerCase() === q) score += 100;
2434
+ else if (block.name.toLowerCase().includes(q)) score += 50;
2435
+ if (block.id.toLowerCase().includes(q)) score += 40;
2436
+ if (block.keywords.some((k) => k.toLowerCase() === q)) score += 30;
2437
+ if (block.keywords.some((k) => k.toLowerCase().includes(q))) score += 20;
2438
+ if (block.description.toLowerCase().includes(q)) score += 10;
2439
+ if (block.categories.some((c) => c.toLowerCase().includes(q))) score += 15;
2440
+ return score;
2441
+ }
2442
+ async function searchProBlocks(options = {}) {
2443
+ const { query, category, plan, limit = 50, offset = 0 } = options;
2444
+ const { manifest } = await getProManifest();
2445
+ let results = [...manifest.blocks];
2446
+ if (category) {
2447
+ const catLower = category.toLowerCase();
2448
+ results = results.filter((b) => b.categories.some((c) => c.toLowerCase() === catLower));
2449
+ }
2450
+ if (plan) {
2451
+ results = results.filter((b) => b.plan === plan);
2452
+ }
2453
+ if (query) {
2454
+ const scored = results.map((block) => ({ block, score: scoreBlockMatch(block, query) })).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score);
2455
+ results = scored.map(({ block }) => block);
2456
+ }
2457
+ const effectiveLimit = Math.min(Math.max(1, limit), 50);
2458
+ const effectiveOffset = Math.max(0, offset);
2459
+ return results.slice(effectiveOffset, effectiveOffset + effectiveLimit);
2460
+ }
2461
+
2462
+ // src/commands/search.ts
2463
+ async function search(query, options) {
2464
+ if (!options?.json) {
2465
+ p12.intro(highlighter.title(" Starwind Search "));
2466
+ }
2467
+ try {
2468
+ const proOnly = !!(options?.category || options?.plan);
2469
+ let proBlocks = [];
2470
+ let matchedComponents = [];
2471
+ if (options?.json) {
2472
+ proBlocks = await searchProBlocks({
2473
+ query,
2474
+ category: options?.category,
2475
+ plan: options?.plan,
2476
+ limit: options?.limit ?? 20,
2477
+ offset: options?.offset ?? 0
2478
+ });
2479
+ if (!proOnly) {
2480
+ const coreComponents = await getAllComponents();
2481
+ if (query) {
2482
+ const q = query.toLowerCase();
2483
+ matchedComponents = coreComponents.filter(
2484
+ (c) => c.name.toLowerCase().includes(q) || (c.dependencies ?? []).some((dep) => dep.toLowerCase().includes(q))
2485
+ );
2486
+ } else {
2487
+ matchedComponents = coreComponents;
2488
+ }
2489
+ }
2490
+ } else {
2491
+ const searchTasks = [
2492
+ {
2493
+ title: "Searching Starwind Pro blocks",
2494
+ task: async () => {
2495
+ proBlocks = await searchProBlocks({
2496
+ query,
2497
+ category: options?.category,
2498
+ plan: options?.plan,
2499
+ limit: options?.limit ?? 20,
2500
+ offset: options?.offset ?? 0
2501
+ });
2502
+ return `Found ${proBlocks.length} Pro block${proBlocks.length === 1 ? "" : "s"}`;
2503
+ }
2504
+ }
2505
+ ];
2506
+ if (!proOnly) {
2507
+ searchTasks.push({
2508
+ title: "Searching core components",
2509
+ task: async () => {
2510
+ const coreComponents = await getAllComponents();
2511
+ if (query) {
2512
+ const q = query.toLowerCase();
2513
+ matchedComponents = coreComponents.filter(
2514
+ (c) => c.name.toLowerCase().includes(q) || (c.dependencies ?? []).some((dep) => dep.toLowerCase().includes(q))
2515
+ );
2516
+ } else {
2517
+ matchedComponents = coreComponents;
2518
+ }
2519
+ return `Found ${matchedComponents.length} core component${matchedComponents.length === 1 ? "" : "s"}`;
2520
+ }
2521
+ });
2522
+ }
2523
+ await p12.tasks(searchTasks);
2524
+ }
2525
+ if (options?.json) {
2526
+ console.log(
2527
+ JSON.stringify(
2528
+ {
2529
+ query: query || null,
2530
+ filters: {
2531
+ category: options?.category || null,
2532
+ plan: options?.plan || null,
2533
+ limit: options?.limit ?? 20
2534
+ },
2535
+ proBlocks: {
2536
+ total: proBlocks.length,
2537
+ results: proBlocks.map((b) => ({
2538
+ id: b.id,
2539
+ name: b.name,
2540
+ description: b.description,
2541
+ categories: b.categories,
2542
+ plan: b.plan,
2543
+ installCommand: b.installCommand + " --yes"
2544
+ }))
2545
+ },
2546
+ coreComponents: {
2547
+ total: matchedComponents.length,
2548
+ results: matchedComponents.map((c) => ({
2549
+ name: c.name,
2550
+ version: c.version,
2551
+ dependencies: c.dependencies,
2552
+ docsUrl: `${PATHS.STARWIND_DOCS_BASE_URL}/${c.name}/`
2553
+ }))
2554
+ },
2555
+ proSetupTip: "Run `starwind setup` to enable Starwind Pro blocks"
2556
+ },
2557
+ null,
2558
+ 2
2559
+ )
2560
+ );
2561
+ return;
2562
+ }
2563
+ const hasPro = proBlocks.length > 0;
2564
+ const hasCore = matchedComponents.length > 0;
2565
+ if (!hasPro && !hasCore) {
2566
+ p12.log.warn("No results found for your search.");
2567
+ p12.outro("Try a different query or browse all categories.");
2568
+ return;
2569
+ }
2570
+ if (hasPro) {
2571
+ p12.log.message(highlighter.underline("Pro Blocks"));
2572
+ const maxNameLen = Math.max(...proBlocks.map((b) => b.name.length));
2573
+ for (const block of proBlocks) {
2574
+ const planBadge = block.plan === "pro" ? highlighter.info("[pro] ") : highlighter.success("[free]");
2575
+ const paddedName = block.name.padEnd(maxNameLen + 2);
2576
+ p12.log.info(` ${highlighter.info(paddedName)}${planBadge} ${block.installCommand}`);
2577
+ }
2578
+ console.log();
2579
+ }
2580
+ if (hasCore) {
2581
+ p12.log.message(highlighter.underline("Core Components"));
2582
+ const maxNameLen = Math.max(...matchedComponents.map((c) => c.name.length));
2583
+ for (const comp of matchedComponents) {
2584
+ const paddedName = comp.name.padEnd(maxNameLen + 2);
2585
+ p12.log.info(` ${highlighter.info(paddedName)}starwind add ${comp.name}`);
2586
+ }
2587
+ console.log();
2588
+ }
2589
+ if (proBlocks.length > 0) {
2590
+ const proConfigured = await hasStarwindProRegistry();
2591
+ const hasPaidBlocks = proBlocks.some((b) => b.plan === "pro");
2592
+ if (!proConfigured) {
2593
+ p12.note(
2594
+ `Pro blocks require Starwind Pro setup.
2595
+ Run ${highlighter.info("starwind setup")} to configure.`,
2596
+ "Pro Tip"
2597
+ );
2598
+ } else if (hasPaidBlocks) {
2599
+ p12.note(
2600
+ `Unlock premium blocks at ${highlighter.info("https://pro.starwind.dev/")}`,
2601
+ "Pro Tip"
2602
+ );
2603
+ }
2604
+ }
2605
+ p12.outro(
2606
+ `Found ${proBlocks.length + matchedComponents.length} result${proBlocks.length + matchedComponents.length === 1 ? "" : "s"} \u{1F50E}`
2607
+ );
2608
+ } catch (error) {
2609
+ p12.log.error(error instanceof Error ? error.message : "Failed to search");
2610
+ p12.cancel("Operation cancelled");
2340
2611
  process.exit(1);
2341
2612
  }
2342
2613
  }
2343
2614
 
2344
2615
  // src/commands/setup.ts
2345
- import * as p11 from "@clack/prompts";
2616
+ import * as p13 from "@clack/prompts";
2346
2617
  async function setup(options) {
2347
- p11.intro(highlighter.title(" Using Starwind Setup "));
2618
+ p13.intro(highlighter.title(" Using Starwind Setup "));
2348
2619
  try {
2349
2620
  const configExists = await fileExists(PATHS.LOCAL_CONFIG_FILE);
2350
2621
  if (!configExists) {
2351
- const shouldInit = options?.yes ? true : await p11.confirm({
2622
+ const shouldInit = options?.yes ? true : await p13.confirm({
2352
2623
  message: `Starwind configuration not found. Would you like to run ${highlighter.info("starwind init")} now?`,
2353
2624
  initialValue: true
2354
2625
  });
2355
- if (p11.isCancel(shouldInit)) {
2356
- p11.cancel("Operation cancelled");
2626
+ if (p13.isCancel(shouldInit)) {
2627
+ p13.cancel("Operation cancelled");
2357
2628
  process.exit(0);
2358
2629
  }
2359
2630
  if (shouldInit) {
2360
2631
  await init(true, { defaults: options?.yes, packageManager: options?.packageManager });
2361
2632
  } else {
2362
- p11.log.error(
2633
+ p13.log.error(
2363
2634
  `Please initialize starwind with ${highlighter.info("starwind init")} before running setup`
2364
2635
  );
2365
2636
  process.exit(1);
2366
2637
  }
2367
2638
  }
2368
- const tasks4 = [
2639
+ const tasks5 = [
2369
2640
  {
2370
2641
  name: "Starwind Pro",
2371
2642
  value: "pro",
@@ -2377,32 +2648,32 @@ async function setup(options) {
2377
2648
  ];
2378
2649
  const selectedTasks = [];
2379
2650
  if (options?.pro) {
2380
- const proTask = tasks4.find((t) => t.value === "pro");
2651
+ const proTask = tasks5.find((t) => t.value === "pro");
2381
2652
  if (proTask) selectedTasks.push(proTask);
2382
2653
  } else {
2383
- const proTask = tasks4.find((t) => t.value === "pro");
2654
+ const proTask = tasks5.find((t) => t.value === "pro");
2384
2655
  if (proTask) selectedTasks.push(proTask);
2385
2656
  }
2386
2657
  if (selectedTasks.length === 0) {
2387
- p11.log.warn("No setup tasks selected.");
2658
+ p13.log.warn("No setup tasks selected.");
2388
2659
  process.exit(0);
2389
2660
  }
2390
2661
  for (const task of selectedTasks) {
2391
2662
  await task.run();
2392
2663
  }
2393
2664
  } catch (error) {
2394
- p11.log.error(error instanceof Error ? error.message : "Failed to run setup");
2395
- p11.cancel("Operation cancelled");
2665
+ p13.log.error(error instanceof Error ? error.message : "Failed to run setup");
2666
+ p13.cancel("Operation cancelled");
2396
2667
  process.exit(1);
2397
2668
  }
2398
2669
  }
2399
2670
  async function runProSetup() {
2400
- p11.log.info(highlighter.info("Setting up Starwind Pro..."));
2671
+ p13.log.info(highlighter.info("Setting up Starwind Pro..."));
2401
2672
  const configTasks = [];
2402
2673
  const hasRegistry = await hasStarwindProRegistry();
2403
2674
  const hasEnv = await checkStarwindProEnv();
2404
2675
  if (hasRegistry && hasEnv) {
2405
- p11.log.info(highlighter.info("Starwind Pro registry and environment already configured"));
2676
+ p13.log.info(highlighter.info("Starwind Pro registry and environment already configured"));
2406
2677
  } else {
2407
2678
  let cssFile = PATHS.LOCAL_CSS_FILE;
2408
2679
  let baseColor = "neutral";
@@ -2436,7 +2707,7 @@ async function runProSetup() {
2436
2707
  });
2437
2708
  }
2438
2709
  if (configTasks.length > 0) {
2439
- await p11.tasks(configTasks);
2710
+ await p13.tasks(configTasks);
2440
2711
  }
2441
2712
  }
2442
2713
  await sleep(250);
@@ -2444,37 +2715,37 @@ async function runProSetup() {
2444
2715
  ${highlighter.info("npx starwind@latest add @starwind-pro/component-name")}
2445
2716
 
2446
2717
  Make sure to set your ${highlighter.infoBright("STARWIND_LICENSE_KEY")} environment variable in ${highlighter.infoBright(".env.local")}`;
2447
- p11.note(nextStepsMessage, "Next steps");
2718
+ p13.note(nextStepsMessage, "Next steps");
2448
2719
  await sleep(1e3);
2449
- p11.outro("Enjoy using Starwind UI with Pro components! \u{1F680}");
2720
+ p13.outro("Enjoy using Starwind UI with Pro components! \u{1F680}");
2450
2721
  }
2451
2722
 
2452
2723
  // src/commands/update.ts
2453
- import * as p12 from "@clack/prompts";
2724
+ import * as p14 from "@clack/prompts";
2454
2725
  async function update(components, options) {
2455
2726
  try {
2456
- p12.intro(highlighter.title(" Welcome to the Starwind CLI "));
2727
+ p14.intro(highlighter.title(" Welcome to the Starwind CLI "));
2457
2728
  const configExists = await fileExists(PATHS.LOCAL_CONFIG_FILE);
2458
2729
  if (!configExists) {
2459
- p12.log.error("No Starwind configuration found. Please run starwind init first.");
2730
+ p14.log.error("No Starwind configuration found. Please run starwind init first.");
2460
2731
  process.exit(1);
2461
2732
  }
2462
2733
  const config = await getConfig();
2463
2734
  const installedComponents = config.components;
2464
2735
  if (installedComponents.length === 0) {
2465
- p12.log.warn("No components are currently installed.");
2736
+ p14.log.warn("No components are currently installed.");
2466
2737
  process.exit(0);
2467
2738
  }
2468
2739
  let componentsToUpdate = [];
2469
2740
  if (options?.all) {
2470
2741
  componentsToUpdate = installedComponents.map((comp) => comp.name);
2471
- p12.log.info(`Checking updates for all ${componentsToUpdate.length} installed components...`);
2742
+ p14.log.info(`Checking updates for all ${componentsToUpdate.length} installed components...`);
2472
2743
  } else if (components && components.length > 0) {
2473
2744
  const invalid = components.filter(
2474
2745
  (comp) => !installedComponents.some((ic) => ic.name === comp)
2475
2746
  );
2476
2747
  if (invalid.length > 0) {
2477
- p12.log.warn(
2748
+ p14.log.warn(
2478
2749
  `${highlighter.warn("Components not found in project:")}
2479
2750
  ${invalid.map((name) => ` ${name}`).join("\n")}`
2480
2751
  );
@@ -2483,7 +2754,7 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2483
2754
  (comp) => installedComponents.some((ic) => ic.name === comp)
2484
2755
  );
2485
2756
  if (componentsToUpdate.length === 0) {
2486
- p12.log.warn("No valid components to update");
2757
+ p14.log.warn("No valid components to update");
2487
2758
  process.exit(0);
2488
2759
  }
2489
2760
  } else {
@@ -2491,18 +2762,18 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2491
2762
  value: comp.name,
2492
2763
  label: comp.name
2493
2764
  }));
2494
- const selected = await p12.multiselect({
2765
+ const selected = await p14.multiselect({
2495
2766
  message: "Select components to update",
2496
2767
  options: choices
2497
2768
  });
2498
- if (p12.isCancel(selected)) {
2499
- p12.cancel("Operation cancelled");
2769
+ if (p14.isCancel(selected)) {
2770
+ p14.cancel("Operation cancelled");
2500
2771
  process.exit(0);
2501
2772
  }
2502
2773
  componentsToUpdate = selected;
2503
2774
  }
2504
2775
  if (componentsToUpdate.length === 0) {
2505
- p12.log.warn("No components selected for update");
2776
+ p14.log.warn("No components selected for update");
2506
2777
  process.exit(0);
2507
2778
  }
2508
2779
  const results = {
@@ -2553,45 +2824,45 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2553
2824
  { appendComponents: false }
2554
2825
  );
2555
2826
  } catch (error) {
2556
- p12.log.error(
2827
+ p14.log.error(
2557
2828
  `Failed to update config: ${error instanceof Error ? error.message : "Unknown error"}`
2558
2829
  );
2559
2830
  process.exit(1);
2560
2831
  }
2561
2832
  }
2562
- p12.log.message(`
2833
+ p14.log.message(`
2563
2834
 
2564
2835
  ${highlighter.underline("Update Summary")}`);
2565
2836
  if (results.failed.length > 0) {
2566
- p12.log.error(
2837
+ p14.log.error(
2567
2838
  `${highlighter.error("Failed to update components:")}
2568
2839
  ${results.failed.map((r) => ` ${r.name} - ${r.error}`).join("\n")}`
2569
2840
  );
2570
2841
  }
2571
2842
  if (results.skipped.length > 0) {
2572
- p12.log.info(
2843
+ p14.log.info(
2573
2844
  `${highlighter.info("Components already up to date or skipped:")}
2574
2845
  ${results.skipped.map((r) => ` ${r.name} (${r.oldVersion})`).join("\n")}`
2575
2846
  );
2576
2847
  }
2577
2848
  if (results.updated.length > 0) {
2578
- p12.log.success(
2849
+ p14.log.success(
2579
2850
  `${highlighter.success("Successfully updated components:")}
2580
2851
  ${results.updated.map((r) => ` ${r.name} (${r.oldVersion} \u2192 ${r.newVersion})`).join("\n")}`
2581
2852
  );
2582
2853
  }
2583
2854
  await sleep(1e3);
2584
2855
  if (results.updated.length > 0) {
2585
- p12.outro("Components updated successfully \u{1F680}");
2856
+ p14.outro("Components updated successfully \u{1F680}");
2586
2857
  } else if (results.skipped.length > 0 && results.failed.length === 0) {
2587
- p12.outro("Components already up to date or skipped \u2728");
2858
+ p14.outro("Components already up to date or skipped \u2728");
2588
2859
  } else {
2589
- p12.cancel("No components were updated");
2860
+ p14.cancel("No components were updated");
2590
2861
  process.exit(1);
2591
2862
  }
2592
2863
  } catch (error) {
2593
- p12.log.error(error instanceof Error ? error.message : "Failed to update components");
2594
- p12.cancel("Operation cancelled");
2864
+ p14.log.error(error instanceof Error ? error.message : "Failed to update components");
2865
+ p14.cancel("Operation cancelled");
2595
2866
  process.exit(1);
2596
2867
  }
2597
2868
  }
@@ -2606,6 +2877,23 @@ program.command("add").description("Add Starwind components to your project").ar
2606
2877
  "yarn"
2607
2878
  ])
2608
2879
  ).action(add);
2880
+ program.command("docs").description("Open documentation for Starwind components").argument("[components...]", "The components to look up (space separated)").allowExcessArguments().option("--json", "Output as JSON").action(docs);
2881
+ program.command("search").description("Search Starwind components and Pro blocks").argument("[query]", "Search query string").allowExcessArguments().option("-p, --plan <plan>", "Filter Pro blocks by plan type (free or pro)").option("-c, --category <category>", "Filter Pro blocks by category").option("-l, --limit <number>", "Maximum number of Pro blocks to display", "20").option("-o, --offset <number>", "Offset for paginating Pro block results", "0").option("--json", "Output as JSON").action(
2882
+ async (query, opts) => {
2883
+ const parsedLimit = Math.min(Math.max(parseInt(opts.limit, 10) || 20, 1), 50);
2884
+ const parsedOffset = Math.max(parseInt(opts.offset, 10) || 0, 0);
2885
+ if (opts.plan && opts.plan !== "free" && opts.plan !== "pro") {
2886
+ program.error(`Invalid plan "${opts.plan}". Must be "free" or "pro".`);
2887
+ }
2888
+ await search(query, {
2889
+ plan: opts.plan,
2890
+ category: opts.category,
2891
+ limit: parsedLimit,
2892
+ offset: parsedOffset,
2893
+ json: opts.json
2894
+ });
2895
+ }
2896
+ );
2609
2897
  program.command("update").description("Update Starwind components to their latest versions").argument("[components...]", "The components to update (space separated)").allowExcessArguments().option("-a, --all", "Update all installed components").option("-y, --yes", "Skip confirmation prompts").addOption(
2610
2898
  new Option("-m, --package-manager <pm>", "Package manager to use").choices([
2611
2899
  "npm",