@helloleo/plugins 0.1.4 → 0.1.5

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
@@ -12541,7 +12541,263 @@ var RemovePlugin = async () => {
12541
12541
  tool: { remove }
12542
12542
  };
12543
12543
  };
12544
+ // src/tools/scaffold.ts
12545
+ import { mkdir } from "fs/promises";
12546
+ import path2 from "path";
12547
+ function packageJson(name) {
12548
+ return JSON.stringify({
12549
+ name,
12550
+ private: true,
12551
+ version: "0.0.0",
12552
+ type: "module",
12553
+ scripts: {
12554
+ dev: "vite",
12555
+ start: "vite",
12556
+ build: "vite build",
12557
+ preview: "vite preview"
12558
+ },
12559
+ dependencies: {
12560
+ react: "^18.3.1",
12561
+ "react-dom": "^18.3.1",
12562
+ clsx: "^2.1.1",
12563
+ "tailwind-merge": "^2.6.0"
12564
+ },
12565
+ devDependencies: {
12566
+ "@types/react": "^18.3.12",
12567
+ "@types/react-dom": "^18.3.1",
12568
+ "@vitejs/plugin-react": "^4.3.4",
12569
+ autoprefixer: "^10.4.20",
12570
+ postcss: "^8.4.49",
12571
+ tailwindcss: "^3.4.17",
12572
+ typescript: "^5.6.3",
12573
+ vite: "^6.0.5"
12574
+ }
12575
+ }, null, 2);
12576
+ }
12577
+ function indexHtml(fontFamily) {
12578
+ const fontParam = fontFamily.replace(/\s+/g, "+");
12579
+ return `<!DOCTYPE html>
12580
+ <html lang="en">
12581
+ <head>
12582
+ <meta charset="UTF-8" />
12583
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
12584
+ <link rel="preconnect" href="https://fonts.googleapis.com">
12585
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
12586
+ <link href="https://fonts.googleapis.com/css2?family=${fontParam}:wght@400;500;600;700&display=swap" rel="stylesheet">
12587
+ <title>App</title>
12588
+ </head>
12589
+ <body>
12590
+ <div id="root"></div>
12591
+ <script type="module" src="/src/main.tsx"></script>
12592
+ </body>
12593
+ </html>`;
12594
+ }
12595
+ function viteConfig() {
12596
+ return `import { defineConfig } from 'vite'
12597
+ import react from '@vitejs/plugin-react'
12598
+ import path from 'path'
12599
+
12600
+ export default defineConfig({
12601
+ plugins: [react()],
12602
+ server: {
12603
+ allowedHosts: true,
12604
+ },
12605
+ resolve: {
12606
+ alias: {
12607
+ '@': path.resolve(__dirname, './src'),
12608
+ },
12609
+ },
12610
+ })`;
12611
+ }
12612
+ function tailwindConfig() {
12613
+ return `export default {
12614
+ darkMode: ["class"],
12615
+ content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
12616
+ theme: {
12617
+ extend: {
12618
+ colors: {
12619
+ background: "hsl(var(--background))",
12620
+ foreground: "hsl(var(--foreground))",
12621
+ card: { DEFAULT: "hsl(var(--card))", foreground: "hsl(var(--card-foreground))" },
12622
+ primary: { DEFAULT: "hsl(var(--primary))", foreground: "hsl(var(--primary-foreground))" },
12623
+ secondary: { DEFAULT: "hsl(var(--secondary))", foreground: "hsl(var(--secondary-foreground))" },
12624
+ muted: { DEFAULT: "hsl(var(--muted))", foreground: "hsl(var(--muted-foreground))" },
12625
+ accent: { DEFAULT: "hsl(var(--accent))", foreground: "hsl(var(--accent-foreground))" },
12626
+ destructive: { DEFAULT: "hsl(var(--destructive))", foreground: "hsl(var(--destructive-foreground))" },
12627
+ success: { DEFAULT: "hsl(var(--success))", foreground: "hsl(var(--success-foreground))" },
12628
+ warning: { DEFAULT: "hsl(var(--warning))", foreground: "hsl(var(--warning-foreground))" },
12629
+ border: "hsl(var(--border))",
12630
+ input: "hsl(var(--input))",
12631
+ ring: "hsl(var(--ring))",
12632
+ },
12633
+ fontFamily: {
12634
+ sans: "var(--font-sans)",
12635
+ heading: "var(--font-heading)",
12636
+ },
12637
+ borderRadius: {
12638
+ lg: "var(--radius)",
12639
+ md: "calc(var(--radius) - 2px)",
12640
+ sm: "calc(var(--radius) - 4px)",
12641
+ },
12642
+ borderWidth: {
12643
+ DEFAULT: "var(--border-width)",
12644
+ },
12645
+ boxShadow: {
12646
+ DEFAULT: "var(--shadow)",
12647
+ lg: "var(--shadow-lg)",
12648
+ },
12649
+ },
12650
+ },
12651
+ plugins: [],
12652
+ }`;
12653
+ }
12654
+ function postcssConfig() {
12655
+ return `export default {
12656
+ plugins: {
12657
+ tailwindcss: {},
12658
+ autoprefixer: {},
12659
+ },
12660
+ }`;
12661
+ }
12662
+ function indexCss(primaryColor, fontFamily, borderRadius) {
12663
+ const fontValue = `'${fontFamily}', ui-sans-serif, system-ui, sans-serif`;
12664
+ return `@tailwind base;
12665
+ @tailwind components;
12666
+ @tailwind utilities;
12667
+
12668
+ @layer base {
12669
+ :root {
12670
+ --background: 0 0% 100%;
12671
+ --foreground: 222.2 84% 4.9%;
12672
+ --card: 0 0% 100%;
12673
+ --card-foreground: 222.2 84% 4.9%;
12674
+ --primary: ${primaryColor};
12675
+ --primary-foreground: 210 40% 98%;
12676
+ --secondary: 210 40% 96.1%;
12677
+ --secondary-foreground: 222.2 47.4% 11.2%;
12678
+ --muted: 210 40% 96.1%;
12679
+ --muted-foreground: 215.4 16.3% 46.9%;
12680
+ --accent: 210 40% 96.1%;
12681
+ --accent-foreground: 222.2 47.4% 11.2%;
12682
+ --destructive: 0 84.2% 60.2%;
12683
+ --destructive-foreground: 210 40% 98%;
12684
+ --success: 142 76% 36%;
12685
+ --success-foreground: 210 40% 98%;
12686
+ --warning: 38 92% 50%;
12687
+ --warning-foreground: 222.2 47.4% 11.2%;
12688
+ --border: 214.3 31.8% 91.4%;
12689
+ --input: 214.3 31.8% 91.4%;
12690
+ --ring: 221.2 83.2% 53.3%;
12691
+ --radius: ${borderRadius};
12692
+ --border-width: 1px;
12693
+ --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
12694
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
12695
+ --font-sans: ${fontValue};
12696
+ --font-heading: ${fontValue};
12697
+ }
12698
+
12699
+ .dark {
12700
+ --background: 222.2 84% 4.9%;
12701
+ --foreground: 210 40% 98%;
12702
+ --card: 222.2 84% 4.9%;
12703
+ --card-foreground: 210 40% 98%;
12704
+ --primary: 217.2 91.2% 59.8%;
12705
+ --primary-foreground: 222.2 47.4% 11.2%;
12706
+ --secondary: 217.2 32.6% 17.5%;
12707
+ --secondary-foreground: 210 40% 98%;
12708
+ --muted: 217.2 32.6% 17.5%;
12709
+ --muted-foreground: 215 20.2% 65.1%;
12710
+ --accent: 217.2 32.6% 17.5%;
12711
+ --accent-foreground: 210 40% 98%;
12712
+ --destructive: 0 62.8% 30.6%;
12713
+ --destructive-foreground: 210 40% 98%;
12714
+ --success: 142 76% 36%;
12715
+ --success-foreground: 210 40% 98%;
12716
+ --warning: 38 92% 50%;
12717
+ --warning-foreground: 222.2 47.4% 11.2%;
12718
+ --border: 217.2 32.6% 17.5%;
12719
+ --input: 217.2 32.6% 17.5%;
12720
+ --ring: 224.3 76.3% 48%;
12721
+ --border-width: 1px;
12722
+ --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.3), 0 1px 2px -1px rgb(0 0 0 / 0.3);
12723
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.3), 0 4px 6px -4px rgb(0 0 0 / 0.3);
12724
+ --font-sans: ${fontValue};
12725
+ --font-heading: ${fontValue};
12726
+ }
12727
+ }
12728
+
12729
+ body {
12730
+ @apply bg-background text-foreground font-sans;
12731
+ }`;
12732
+ }
12733
+ function utilsTs() {
12734
+ return `import { clsx, type ClassValue } from 'clsx'
12735
+ import { twMerge } from 'tailwind-merge'
12736
+
12737
+ export function cn(...inputs: ClassValue[]) {
12738
+ return twMerge(clsx(inputs))
12739
+ }`;
12740
+ }
12741
+ function mainTsx() {
12742
+ return `import React from 'react'
12743
+ import ReactDOM from 'react-dom/client'
12744
+ import App from './App'
12745
+ import './index.css'
12746
+
12747
+ ReactDOM.createRoot(document.getElementById('root')!).render(
12748
+ <React.StrictMode>
12749
+ <App />
12750
+ </React.StrictMode>,
12751
+ )`;
12752
+ }
12753
+ var scaffold = tool({
12754
+ description: "Scaffold a new React + Vite + Tailwind CSS project with the HelloLeo design system. " + "Creates all mandatory boilerplate: package.json, index.html (with Google Fonts), " + "vite.config.js, tailwind.config.js, postcss.config.js, src/index.css (CSS variables " + "light+dark), src/lib/utils.ts (cn helper), and src/main.tsx. " + "Call this FIRST for any new project before writing App.tsx and components.",
12755
+ args: {
12756
+ name: tool.schema.string().optional().describe("Project name for package.json (default: leo-project)"),
12757
+ primaryColor: tool.schema.string().optional().describe('HSL values for primary color, e.g. "221.2 83.2% 53.3%" (default: blue)'),
12758
+ fontFamily: tool.schema.string().optional().describe('Google Font family name, e.g. "Inter", "Poppins" (default: Inter)'),
12759
+ borderRadius: tool.schema.string().optional().describe('Base border radius, e.g. "0.5rem", "0.75rem" (default: 0.5rem)')
12760
+ },
12761
+ async execute(args, context) {
12762
+ const dir = context.directory;
12763
+ const name = args.name ?? "leo-project";
12764
+ const primary = args.primaryColor ?? "221.2 83.2% 53.3%";
12765
+ const font = args.fontFamily ?? "Inter";
12766
+ const radius = args.borderRadius ?? "0.5rem";
12767
+ await mkdir(path2.join(dir, "src", "lib"), { recursive: true });
12768
+ const files = [
12769
+ ["package.json", packageJson(name)],
12770
+ ["index.html", indexHtml(font)],
12771
+ ["vite.config.js", viteConfig()],
12772
+ ["tailwind.config.js", tailwindConfig()],
12773
+ ["postcss.config.js", postcssConfig()],
12774
+ [path2.join("src", "index.css"), indexCss(primary, font, radius)],
12775
+ [path2.join("src", "lib", "utils.ts"), utilsTs()],
12776
+ [path2.join("src", "main.tsx"), mainTsx()]
12777
+ ];
12778
+ const created = [];
12779
+ for (const [filePath, content] of files) {
12780
+ await Bun.write(path2.join(dir, filePath), content);
12781
+ created.push(filePath);
12782
+ }
12783
+ return [
12784
+ `Scaffolded ${created.length} files:`,
12785
+ ...created.map((f) => ` - ${f}`),
12786
+ "",
12787
+ "Next: create src/App.tsx with your application code.",
12788
+ "The design system is ready -- use design tokens (bg-primary, text-foreground, etc.)",
12789
+ "and create UI components in src/components/ui/."
12790
+ ].join(`
12791
+ `);
12792
+ }
12793
+ });
12794
+ var ScaffoldPlugin = async () => {
12795
+ return {
12796
+ tool: { scaffold }
12797
+ };
12798
+ };
12544
12799
  export {
12800
+ ScaffoldPlugin,
12545
12801
  RemovePlugin,
12546
12802
  InspectHttpPlugin
12547
12803
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helloleo/plugins",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "OpenCode plugins for HelloLeo",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { InspectHttpPlugin } from "./tools/inspect-http.ts";
2
2
  export { RemovePlugin } from "./tools/remove.ts";
3
- // export { ScaffoldPlugin } from "./tools/scaffold.ts";
3
+ export { ScaffoldPlugin } from "./tools/scaffold.ts";
4
4
  // export { CreatePlanPlugin } from "./tools/create-plan.ts";
5
5
  // export { ListPlansPlugin } from "./tools/list-plans.ts";
6
6
  // export { ModifyPlanPlugin } from "./tools/modify-plan.ts";