starwind 1.16.1 → 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/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.1",
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.1",
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",
@@ -724,7 +725,7 @@ async function getShadcnCommand() {
724
725
  return ["bunx", ["shadcn@3"]];
725
726
  case "npm":
726
727
  default:
727
- return ["npx", ["shadcn@3"]];
728
+ return ["npx", ["-y", "shadcn@3"]];
728
729
  }
729
730
  }
730
731
  async function installDependencies(packages, pm, dev = false, force = false) {
@@ -909,7 +910,7 @@ async function installComponent(name, options) {
909
910
  }
910
911
  }
911
912
  }
912
- const result = await copyComponent(name);
913
+ const result = await copyComponent(name, options?.overwrite);
913
914
  if (dependencyResults.length > 0) {
914
915
  return {
915
916
  ...result,
@@ -2069,11 +2070,21 @@ async function add(components, options) {
2069
2070
  };
2070
2071
  for (const registryComponent of registryComponents) {
2071
2072
  try {
2072
- p9.log.info(`Installing ${highlighter.info(registryComponent)} via shadcn...`);
2073
- await execa2(command, [...baseArgs, "add", registryComponent], {
2074
- stdio: "inherit",
2075
- cwd: process.cwd()
2076
- });
2073
+ p9.log.info(`Installing ${highlighter.info(registryComponent)}`);
2074
+ await execa2(
2075
+ command,
2076
+ [
2077
+ ...baseArgs,
2078
+ "add",
2079
+ "--yes",
2080
+ ...options?.overwrite ? ["--overwrite"] : [],
2081
+ registryComponent
2082
+ ],
2083
+ {
2084
+ stdio: "inherit",
2085
+ cwd: process.cwd()
2086
+ }
2087
+ );
2077
2088
  registryResults.success.push(registryComponent);
2078
2089
  } catch (error) {
2079
2090
  registryResults.failed.push(registryComponent);
@@ -2150,6 +2161,7 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2150
2161
  }
2151
2162
  const result = await installComponent(comp, {
2152
2163
  skipPrompts: options?.yes,
2164
+ overwrite: options?.overwrite,
2153
2165
  packageManager: options?.packageManager
2154
2166
  });
2155
2167
  if (result.dependencyResults) {
@@ -2216,32 +2228,67 @@ ${registryResults.success.map((name) => ` ${name}`).join("\n")}`
2216
2228
  }
2217
2229
  }
2218
2230
 
2219
- // src/commands/remove.ts
2231
+ // src/commands/docs.ts
2220
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";
2221
2268
  async function remove(components, options) {
2222
2269
  try {
2223
- p10.intro(highlighter.title(" Welcome to the Starwind CLI "));
2270
+ p11.intro(highlighter.title(" Welcome to the Starwind CLI "));
2224
2271
  const configExists = await fileExists(PATHS.LOCAL_CONFIG_FILE);
2225
2272
  if (!configExists) {
2226
- 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.");
2227
2274
  process.exit(1);
2228
2275
  }
2229
2276
  const config = await getConfig();
2230
2277
  const installedComponents = config.components;
2231
2278
  if (installedComponents.length === 0) {
2232
- p10.log.warn("No components are currently installed.");
2279
+ p11.log.warn("No components are currently installed.");
2233
2280
  process.exit(0);
2234
2281
  }
2235
2282
  let componentsToRemove = [];
2236
2283
  if (options?.all) {
2237
2284
  componentsToRemove = installedComponents.map((comp) => comp.name);
2238
- p10.log.info(`Removing all ${componentsToRemove.length} installed components...`);
2285
+ p11.log.info(`Removing all ${componentsToRemove.length} installed components...`);
2239
2286
  } else if (components && components.length > 0) {
2240
2287
  const invalid = components.filter(
2241
2288
  (comp) => !installedComponents.some((ic) => ic.name === comp)
2242
2289
  );
2243
2290
  if (invalid.length > 0) {
2244
- p10.log.warn(
2291
+ p11.log.warn(
2245
2292
  `${highlighter.warn("Components not found:")}
2246
2293
  ${invalid.map((name) => ` ${name}`).join("\n")}`
2247
2294
  );
@@ -2250,7 +2297,7 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2250
2297
  (comp) => installedComponents.some((ic) => ic.name === comp)
2251
2298
  );
2252
2299
  if (componentsToRemove.length === 0) {
2253
- p10.log.warn("No valid components to remove");
2300
+ p11.log.warn("No valid components to remove");
2254
2301
  process.exit(0);
2255
2302
  }
2256
2303
  } else {
@@ -2258,25 +2305,25 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2258
2305
  value: comp.name,
2259
2306
  label: comp.name
2260
2307
  }));
2261
- const selected = await p10.multiselect({
2308
+ const selected = await p11.multiselect({
2262
2309
  message: "Select components to remove",
2263
2310
  options: choices
2264
2311
  });
2265
- if (p10.isCancel(selected)) {
2266
- p10.cancel("Operation cancelled");
2312
+ if (p11.isCancel(selected)) {
2313
+ p11.cancel("Operation cancelled");
2267
2314
  process.exit(0);
2268
2315
  }
2269
2316
  componentsToRemove = selected;
2270
2317
  }
2271
2318
  if (componentsToRemove.length === 0) {
2272
- p10.log.warn("No components selected for removal");
2319
+ p11.log.warn("No components selected for removal");
2273
2320
  process.exit(0);
2274
2321
  }
2275
- const confirmed = await p10.confirm({
2322
+ const confirmed = await p11.confirm({
2276
2323
  message: `Remove ${componentsToRemove.map((comp) => highlighter.info(comp)).join(", ")} ${componentsToRemove.length > 1 ? "components" : "component"}?`
2277
2324
  });
2278
- if (!confirmed || p10.isCancel(confirmed)) {
2279
- p10.cancel("Operation cancelled");
2325
+ if (!confirmed || p11.isCancel(confirmed)) {
2326
+ p11.cancel("Operation cancelled");
2280
2327
  process.exit(0);
2281
2328
  }
2282
2329
  const results = {
@@ -2301,60 +2348,295 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2301
2348
  },
2302
2349
  { appendComponents: false }
2303
2350
  );
2304
- p10.log.message(`
2351
+ p11.log.message(`
2305
2352
 
2306
2353
  ${highlighter.underline("Removal Summary")}`);
2307
2354
  if (results.failed.length > 0) {
2308
- p10.log.error(
2355
+ p11.log.error(
2309
2356
  `${highlighter.error("Failed to remove components:")}
2310
2357
  ${results.failed.map((r) => ` ${r.name} - ${r.error}`).join("\n")}`
2311
2358
  );
2312
2359
  }
2313
2360
  if (results.removed.length > 0) {
2314
- p10.log.success(
2361
+ p11.log.success(
2315
2362
  `${highlighter.success("Successfully removed components:")}
2316
2363
  ${results.removed.map((r) => ` ${r.name}`).join("\n")}`
2317
2364
  );
2318
2365
  }
2319
2366
  await sleep(1e3);
2320
2367
  if (results.removed.length > 0) {
2321
- p10.outro("Components removed successfully \u{1F5D1}\uFE0F");
2368
+ p11.outro("Components removed successfully \u{1F5D1}\uFE0F");
2322
2369
  } else {
2323
- p10.cancel("Errors occurred while removing components");
2370
+ p11.cancel("Errors occurred while removing components");
2324
2371
  process.exit(1);
2325
2372
  }
2326
2373
  } catch (error) {
2327
- p10.log.error(error instanceof Error ? error.message : "Failed to remove components");
2328
- 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");
2329
2611
  process.exit(1);
2330
2612
  }
2331
2613
  }
2332
2614
 
2333
2615
  // src/commands/setup.ts
2334
- import * as p11 from "@clack/prompts";
2616
+ import * as p13 from "@clack/prompts";
2335
2617
  async function setup(options) {
2336
- p11.intro(highlighter.title(" Using Starwind Setup "));
2618
+ p13.intro(highlighter.title(" Using Starwind Setup "));
2337
2619
  try {
2338
2620
  const configExists = await fileExists(PATHS.LOCAL_CONFIG_FILE);
2339
2621
  if (!configExists) {
2340
- const shouldInit = options?.yes ? true : await p11.confirm({
2622
+ const shouldInit = options?.yes ? true : await p13.confirm({
2341
2623
  message: `Starwind configuration not found. Would you like to run ${highlighter.info("starwind init")} now?`,
2342
2624
  initialValue: true
2343
2625
  });
2344
- if (p11.isCancel(shouldInit)) {
2345
- p11.cancel("Operation cancelled");
2626
+ if (p13.isCancel(shouldInit)) {
2627
+ p13.cancel("Operation cancelled");
2346
2628
  process.exit(0);
2347
2629
  }
2348
2630
  if (shouldInit) {
2349
2631
  await init(true, { defaults: options?.yes, packageManager: options?.packageManager });
2350
2632
  } else {
2351
- p11.log.error(
2633
+ p13.log.error(
2352
2634
  `Please initialize starwind with ${highlighter.info("starwind init")} before running setup`
2353
2635
  );
2354
2636
  process.exit(1);
2355
2637
  }
2356
2638
  }
2357
- const tasks4 = [
2639
+ const tasks5 = [
2358
2640
  {
2359
2641
  name: "Starwind Pro",
2360
2642
  value: "pro",
@@ -2366,32 +2648,32 @@ async function setup(options) {
2366
2648
  ];
2367
2649
  const selectedTasks = [];
2368
2650
  if (options?.pro) {
2369
- const proTask = tasks4.find((t) => t.value === "pro");
2651
+ const proTask = tasks5.find((t) => t.value === "pro");
2370
2652
  if (proTask) selectedTasks.push(proTask);
2371
2653
  } else {
2372
- const proTask = tasks4.find((t) => t.value === "pro");
2654
+ const proTask = tasks5.find((t) => t.value === "pro");
2373
2655
  if (proTask) selectedTasks.push(proTask);
2374
2656
  }
2375
2657
  if (selectedTasks.length === 0) {
2376
- p11.log.warn("No setup tasks selected.");
2658
+ p13.log.warn("No setup tasks selected.");
2377
2659
  process.exit(0);
2378
2660
  }
2379
2661
  for (const task of selectedTasks) {
2380
2662
  await task.run();
2381
2663
  }
2382
2664
  } catch (error) {
2383
- p11.log.error(error instanceof Error ? error.message : "Failed to run setup");
2384
- p11.cancel("Operation cancelled");
2665
+ p13.log.error(error instanceof Error ? error.message : "Failed to run setup");
2666
+ p13.cancel("Operation cancelled");
2385
2667
  process.exit(1);
2386
2668
  }
2387
2669
  }
2388
2670
  async function runProSetup() {
2389
- p11.log.info(highlighter.info("Setting up Starwind Pro..."));
2671
+ p13.log.info(highlighter.info("Setting up Starwind Pro..."));
2390
2672
  const configTasks = [];
2391
2673
  const hasRegistry = await hasStarwindProRegistry();
2392
2674
  const hasEnv = await checkStarwindProEnv();
2393
2675
  if (hasRegistry && hasEnv) {
2394
- 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"));
2395
2677
  } else {
2396
2678
  let cssFile = PATHS.LOCAL_CSS_FILE;
2397
2679
  let baseColor = "neutral";
@@ -2425,7 +2707,7 @@ async function runProSetup() {
2425
2707
  });
2426
2708
  }
2427
2709
  if (configTasks.length > 0) {
2428
- await p11.tasks(configTasks);
2710
+ await p13.tasks(configTasks);
2429
2711
  }
2430
2712
  }
2431
2713
  await sleep(250);
@@ -2433,37 +2715,37 @@ async function runProSetup() {
2433
2715
  ${highlighter.info("npx starwind@latest add @starwind-pro/component-name")}
2434
2716
 
2435
2717
  Make sure to set your ${highlighter.infoBright("STARWIND_LICENSE_KEY")} environment variable in ${highlighter.infoBright(".env.local")}`;
2436
- p11.note(nextStepsMessage, "Next steps");
2718
+ p13.note(nextStepsMessage, "Next steps");
2437
2719
  await sleep(1e3);
2438
- p11.outro("Enjoy using Starwind UI with Pro components! \u{1F680}");
2720
+ p13.outro("Enjoy using Starwind UI with Pro components! \u{1F680}");
2439
2721
  }
2440
2722
 
2441
2723
  // src/commands/update.ts
2442
- import * as p12 from "@clack/prompts";
2724
+ import * as p14 from "@clack/prompts";
2443
2725
  async function update(components, options) {
2444
2726
  try {
2445
- p12.intro(highlighter.title(" Welcome to the Starwind CLI "));
2727
+ p14.intro(highlighter.title(" Welcome to the Starwind CLI "));
2446
2728
  const configExists = await fileExists(PATHS.LOCAL_CONFIG_FILE);
2447
2729
  if (!configExists) {
2448
- 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.");
2449
2731
  process.exit(1);
2450
2732
  }
2451
2733
  const config = await getConfig();
2452
2734
  const installedComponents = config.components;
2453
2735
  if (installedComponents.length === 0) {
2454
- p12.log.warn("No components are currently installed.");
2736
+ p14.log.warn("No components are currently installed.");
2455
2737
  process.exit(0);
2456
2738
  }
2457
2739
  let componentsToUpdate = [];
2458
2740
  if (options?.all) {
2459
2741
  componentsToUpdate = installedComponents.map((comp) => comp.name);
2460
- p12.log.info(`Checking updates for all ${componentsToUpdate.length} installed components...`);
2742
+ p14.log.info(`Checking updates for all ${componentsToUpdate.length} installed components...`);
2461
2743
  } else if (components && components.length > 0) {
2462
2744
  const invalid = components.filter(
2463
2745
  (comp) => !installedComponents.some((ic) => ic.name === comp)
2464
2746
  );
2465
2747
  if (invalid.length > 0) {
2466
- p12.log.warn(
2748
+ p14.log.warn(
2467
2749
  `${highlighter.warn("Components not found in project:")}
2468
2750
  ${invalid.map((name) => ` ${name}`).join("\n")}`
2469
2751
  );
@@ -2472,7 +2754,7 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2472
2754
  (comp) => installedComponents.some((ic) => ic.name === comp)
2473
2755
  );
2474
2756
  if (componentsToUpdate.length === 0) {
2475
- p12.log.warn("No valid components to update");
2757
+ p14.log.warn("No valid components to update");
2476
2758
  process.exit(0);
2477
2759
  }
2478
2760
  } else {
@@ -2480,18 +2762,18 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2480
2762
  value: comp.name,
2481
2763
  label: comp.name
2482
2764
  }));
2483
- const selected = await p12.multiselect({
2765
+ const selected = await p14.multiselect({
2484
2766
  message: "Select components to update",
2485
2767
  options: choices
2486
2768
  });
2487
- if (p12.isCancel(selected)) {
2488
- p12.cancel("Operation cancelled");
2769
+ if (p14.isCancel(selected)) {
2770
+ p14.cancel("Operation cancelled");
2489
2771
  process.exit(0);
2490
2772
  }
2491
2773
  componentsToUpdate = selected;
2492
2774
  }
2493
2775
  if (componentsToUpdate.length === 0) {
2494
- p12.log.warn("No components selected for update");
2776
+ p14.log.warn("No components selected for update");
2495
2777
  process.exit(0);
2496
2778
  }
2497
2779
  const results = {
@@ -2542,45 +2824,45 @@ ${invalid.map((name) => ` ${name}`).join("\n")}`
2542
2824
  { appendComponents: false }
2543
2825
  );
2544
2826
  } catch (error) {
2545
- p12.log.error(
2827
+ p14.log.error(
2546
2828
  `Failed to update config: ${error instanceof Error ? error.message : "Unknown error"}`
2547
2829
  );
2548
2830
  process.exit(1);
2549
2831
  }
2550
2832
  }
2551
- p12.log.message(`
2833
+ p14.log.message(`
2552
2834
 
2553
2835
  ${highlighter.underline("Update Summary")}`);
2554
2836
  if (results.failed.length > 0) {
2555
- p12.log.error(
2837
+ p14.log.error(
2556
2838
  `${highlighter.error("Failed to update components:")}
2557
2839
  ${results.failed.map((r) => ` ${r.name} - ${r.error}`).join("\n")}`
2558
2840
  );
2559
2841
  }
2560
2842
  if (results.skipped.length > 0) {
2561
- p12.log.info(
2843
+ p14.log.info(
2562
2844
  `${highlighter.info("Components already up to date or skipped:")}
2563
2845
  ${results.skipped.map((r) => ` ${r.name} (${r.oldVersion})`).join("\n")}`
2564
2846
  );
2565
2847
  }
2566
2848
  if (results.updated.length > 0) {
2567
- p12.log.success(
2849
+ p14.log.success(
2568
2850
  `${highlighter.success("Successfully updated components:")}
2569
2851
  ${results.updated.map((r) => ` ${r.name} (${r.oldVersion} \u2192 ${r.newVersion})`).join("\n")}`
2570
2852
  );
2571
2853
  }
2572
2854
  await sleep(1e3);
2573
2855
  if (results.updated.length > 0) {
2574
- p12.outro("Components updated successfully \u{1F680}");
2856
+ p14.outro("Components updated successfully \u{1F680}");
2575
2857
  } else if (results.skipped.length > 0 && results.failed.length === 0) {
2576
- p12.outro("Components already up to date or skipped \u2728");
2858
+ p14.outro("Components already up to date or skipped \u2728");
2577
2859
  } else {
2578
- p12.cancel("No components were updated");
2860
+ p14.cancel("No components were updated");
2579
2861
  process.exit(1);
2580
2862
  }
2581
2863
  } catch (error) {
2582
- p12.log.error(error instanceof Error ? error.message : "Failed to update components");
2583
- p12.cancel("Operation cancelled");
2864
+ p14.log.error(error instanceof Error ? error.message : "Failed to update components");
2865
+ p14.cancel("Operation cancelled");
2584
2866
  process.exit(1);
2585
2867
  }
2586
2868
  }
@@ -2588,13 +2870,30 @@ ${results.updated.map((r) => ` ${r.name} (${r.oldVersion} \u2192 ${r.newVersion
2588
2870
  // src/index.ts
2589
2871
  var program = new Command().name("starwind").description("Add beautifully designed components to your Astro applications").version(package_default.version);
2590
2872
  program.command("init").description("Initialize your project with Starwind").option("-d, --defaults", "Use default values for all prompts").option("-p, --pro", "Initialize with Starwind Pro setup").action((options) => init(false, { defaults: options.defaults, pro: options.pro }));
2591
- program.command("add").description("Add Starwind components to your project").argument("[components...]", "The components to add (space separated)").allowExcessArguments().option("-a, --all", "Add all available components").option("-y, --yes", "Skip confirmation prompts").addOption(
2873
+ program.command("add").description("Add Starwind components to your project").argument("[components...]", "The components to add (space separated)").allowExcessArguments().option("-a, --all", "Add all available components").option("-y, --yes", "Skip confirmation prompts").option("-o, --overwrite", "Overwrite existing files").addOption(
2592
2874
  new Option("-m, --package-manager <pm>", "Package manager to use").choices([
2593
2875
  "npm",
2594
2876
  "pnpm",
2595
2877
  "yarn"
2596
2878
  ])
2597
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
+ );
2598
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(
2599
2898
  new Option("-m, --package-manager <pm>", "Package manager to use").choices([
2600
2899
  "npm",