@framed-dev/cli 0.1.3 → 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
@@ -9,62 +9,134 @@ import { execSync } from 'child_process';
9
9
  async function detectProject(cwd) {
10
10
  const packageJsonPath = path2.join(cwd, "package.json");
11
11
  if (!await fs2.pathExists(packageJsonPath)) {
12
- return { type: "unknown", srcDir: false };
12
+ return {
13
+ type: "unknown",
14
+ srcDir: false,
15
+ hasSupabase: false,
16
+ hasTailwind: false,
17
+ supabaseConfigured: false
18
+ };
13
19
  }
14
20
  const pkg = await fs2.readJson(packageJsonPath);
15
21
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
22
+ const hasSupabase = !!deps["@supabase/supabase-js"];
23
+ const hasTailwindDep = !!deps["tailwindcss"];
24
+ const hasTailwindConfig = await fs2.pathExists(path2.join(cwd, "tailwind.config.js")) || await fs2.pathExists(path2.join(cwd, "tailwind.config.ts")) || await fs2.pathExists(path2.join(cwd, "tailwind.config.mjs"));
25
+ const hasTailwind = hasTailwindDep || hasTailwindConfig;
26
+ let supabaseConfigured = false;
27
+ const envFiles = [".env.local", ".env", ".env.development", ".env.development.local"];
28
+ for (const envFile of envFiles) {
29
+ const envPath = path2.join(cwd, envFile);
30
+ if (await fs2.pathExists(envPath)) {
31
+ try {
32
+ const envContent = await fs2.readFile(envPath, "utf-8");
33
+ if (envContent.includes("SUPABASE_URL") || envContent.includes("NEXT_PUBLIC_SUPABASE_URL")) {
34
+ supabaseConfigured = true;
35
+ break;
36
+ }
37
+ } catch {
38
+ }
39
+ }
40
+ }
16
41
  if (deps["next"]) {
17
42
  const hasAppDir = await fs2.pathExists(path2.join(cwd, "app")) || await fs2.pathExists(path2.join(cwd, "src/app"));
18
43
  const srcDir = await fs2.pathExists(path2.join(cwd, "src"));
19
44
  return {
20
45
  type: hasAppDir ? "next-app" : "next-pages",
21
- srcDir
46
+ srcDir,
47
+ hasSupabase,
48
+ hasTailwind,
49
+ supabaseConfigured
22
50
  };
23
51
  }
24
52
  if (deps["vite"]) {
25
- return { type: "vite", srcDir: await fs2.pathExists(path2.join(cwd, "src")) };
53
+ return {
54
+ type: "vite",
55
+ srcDir: await fs2.pathExists(path2.join(cwd, "src")),
56
+ hasSupabase,
57
+ hasTailwind,
58
+ supabaseConfigured
59
+ };
26
60
  }
27
- return { type: "unknown", srcDir: false };
61
+ return {
62
+ type: "unknown",
63
+ srcDir: false,
64
+ hasSupabase,
65
+ hasTailwind,
66
+ supabaseConfigured
67
+ };
28
68
  }
29
69
 
30
70
  // src/templates/index.ts
31
71
  function getTemplates(type) {
32
72
  return {
33
- dashboard: `import { FramedProvider, FramedDashboard } from '@framed-dev/react';
73
+ dashboard: `"use client";
74
+
75
+ import { FramedProvider, FramedStarter } from '@framed-dev/react';
34
76
 
35
77
  export default function FramedPage() {
36
78
  return (
37
- <FramedProvider config={{ mode: 'local' }}>
38
- <FramedDashboard />
79
+ <FramedProvider config={{
80
+ mode: 'local',
81
+ sync: {
82
+ supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,
83
+ apiKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
84
+ },
85
+ }}>
86
+ <FramedStarter />
39
87
  </FramedProvider>
40
88
  );
41
89
  }
42
90
  `,
43
- review: `import { FramedProvider, FramedReview } from '@framed-dev/react';
91
+ review: `"use client";
92
+
93
+ import { FramedProvider, FramedReview } from '@framed-dev/react';
44
94
 
45
95
  export default function ReviewPage() {
46
96
  return (
47
- <FramedProvider config={{ mode: 'local' }}>
97
+ <FramedProvider config={{
98
+ mode: 'local',
99
+ sync: {
100
+ supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,
101
+ apiKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
102
+ },
103
+ }}>
48
104
  <FramedReview />
49
105
  </FramedProvider>
50
106
  );
51
107
  }
52
108
  `,
53
- build: `import { FramedProvider, FramedBuild } from '@framed-dev/react';
109
+ build: `"use client";
110
+
111
+ import { FramedProvider, FramedBuild } from '@framed-dev/react';
54
112
 
55
113
  export default function BuildPage() {
56
114
  return (
57
- <FramedProvider config={{ mode: 'local' }}>
115
+ <FramedProvider config={{
116
+ mode: 'local',
117
+ sync: {
118
+ supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,
119
+ apiKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
120
+ },
121
+ }}>
58
122
  <FramedBuild />
59
123
  </FramedProvider>
60
124
  );
61
125
  }
62
126
  `,
63
- manage: `import { FramedProvider, FramedManage } from '@framed-dev/react';
127
+ manage: `"use client";
128
+
129
+ import { FramedProvider, FramedManage } from '@framed-dev/react';
64
130
 
65
131
  export default function ManagePage() {
66
132
  return (
67
- <FramedProvider config={{ mode: 'local' }}>
133
+ <FramedProvider config={{
134
+ mode: 'local',
135
+ sync: {
136
+ supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,
137
+ apiKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
138
+ },
139
+ }}>
68
140
  <FramedManage />
69
141
  </FramedProvider>
70
142
  );
@@ -76,7 +148,7 @@ export default function ManagePage() {
76
148
  # Optional: For AI features (task parsing, SEO analysis)
77
149
  NEXT_PUBLIC_FRAMED_LICENSE_KEY=
78
150
 
79
- # Optional: Connect your own Supabase for data persistence
151
+ # Required: Connect your Supabase for data persistence
80
152
  NEXT_PUBLIC_SUPABASE_URL=
81
153
  NEXT_PUBLIC_SUPABASE_ANON_KEY=
82
154
  `,
@@ -88,7 +160,13 @@ export default function RootLayout({ children }) {
88
160
  return (
89
161
  <html>
90
162
  <body>
91
- <FramedProvider config={{ mode: 'local' }}>
163
+ <FramedProvider config={{
164
+ mode: 'local',
165
+ sync: {
166
+ supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,
167
+ apiKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
168
+ },
169
+ }}>
92
170
  {children}
93
171
  <FeedbackWidget />
94
172
  </FramedProvider>
@@ -104,26 +182,66 @@ export default function RootLayout({ children }) {
104
182
  async function init(options) {
105
183
  const cwd = process.cwd();
106
184
  console.log(pc.cyan("\n\u{1F5BC}\uFE0F Framed Setup\n"));
107
- const { type, srcDir } = await detectProject(cwd);
185
+ const { type, srcDir, hasSupabase, hasTailwind, supabaseConfigured } = await detectProject(cwd);
108
186
  if (type === "unknown") {
109
187
  console.log(pc.red("Could not detect project type. Make sure you have a package.json."));
110
188
  process.exit(1);
111
189
  }
112
190
  console.log(pc.green(`\u2713 Detected: ${formatType(type)}${srcDir ? " (src directory)" : ""}`));
191
+ console.log(pc.dim(` Tailwind CSS: ${hasTailwind ? pc.green("\u2713") : pc.yellow("\u25CB will install")}`));
192
+ console.log(pc.dim(` Supabase: ${hasSupabase ? pc.green("\u2713") : pc.yellow("\u25CB will install")}`));
193
+ if (hasSupabase) {
194
+ console.log(pc.dim(` Supabase configured: ${supabaseConfigured ? pc.green("\u2713") : pc.yellow("\u25CB add to .env")}`));
195
+ }
113
196
  if (type === "next-pages" || type === "vite") {
114
197
  console.log(pc.yellow("\nCurrently only Next.js App Router is supported."));
115
198
  console.log("Support for Pages Router and Vite coming soon.\n");
116
199
  process.exit(1);
117
200
  }
118
- console.log(pc.cyan("\nInstalling @framed-dev/react..."));
201
+ const useYarn = await fs2.pathExists(path2.join(cwd, "yarn.lock"));
202
+ const usePnpm = await fs2.pathExists(path2.join(cwd, "pnpm-lock.yaml"));
203
+ const cmd = usePnpm ? "pnpm add" : useYarn ? "yarn add" : "npm install";
204
+ const toInstall = ["@framed-dev/react"];
205
+ if (!hasTailwind) {
206
+ toInstall.push("tailwindcss", "postcss", "autoprefixer");
207
+ }
208
+ if (!hasSupabase) {
209
+ toInstall.push("@supabase/supabase-js");
210
+ }
211
+ console.log(pc.cyan(`
212
+ Installing ${toInstall.join(", ")}...`));
119
213
  try {
120
- const useYarn = await fs2.pathExists(path2.join(cwd, "yarn.lock"));
121
- const usePnpm = await fs2.pathExists(path2.join(cwd, "pnpm-lock.yaml"));
122
- const cmd = usePnpm ? "pnpm add" : useYarn ? "yarn add" : "npm install";
123
- execSync(`${cmd} @framed-dev/react`, { cwd, stdio: "inherit" });
124
- console.log(pc.green("\u2713 Installed @framed-dev/react\n"));
214
+ execSync(`${cmd} ${toInstall.join(" ")}`, { cwd, stdio: "inherit" });
215
+ console.log(pc.green(`\u2713 Installed dependencies
216
+ `));
125
217
  } catch (e) {
126
- console.log(pc.yellow("\u26A0 Could not auto-install. Run: npm install @framed-dev/react\n"));
218
+ console.log(pc.yellow(`\u26A0 Could not auto-install. Run: npm install ${toInstall.join(" ")}
219
+ `));
220
+ }
221
+ if (!hasTailwind) {
222
+ console.log(pc.cyan("Initializing Tailwind CSS..."));
223
+ try {
224
+ execSync("npx tailwindcss init -p", { cwd, stdio: "inherit" });
225
+ console.log(pc.green("\u2713 Initialized Tailwind CSS\n"));
226
+ const tailwindConfigPath = path2.join(cwd, "tailwind.config.js");
227
+ if (await fs2.pathExists(tailwindConfigPath)) {
228
+ let tailwindConfig = await fs2.readFile(tailwindConfigPath, "utf-8");
229
+ if (tailwindConfig.includes("content: []")) {
230
+ tailwindConfig = tailwindConfig.replace(
231
+ "content: []",
232
+ `content: [
233
+ "./src/**/*.{js,ts,jsx,tsx,mdx}",
234
+ "./app/**/*.{js,ts,jsx,tsx,mdx}",
235
+ "./node_modules/@framed-dev/react/**/*.{js,ts,jsx,tsx}",
236
+ ]`
237
+ );
238
+ await fs2.writeFile(tailwindConfigPath, tailwindConfig);
239
+ console.log(pc.green("\u2713 Updated tailwind.config.js with content paths\n"));
240
+ }
241
+ }
242
+ } catch (e) {
243
+ console.log(pc.yellow("\u26A0 Could not initialize Tailwind. Run: npx tailwindcss init -p\n"));
244
+ }
127
245
  }
128
246
  const appDir = srcDir ? "src/app" : "app";
129
247
  const framedDir = path2.join(cwd, appDir, "framed");
@@ -180,7 +298,7 @@ function formatType(type) {
180
298
 
181
299
  // src/index.ts
182
300
  var program = new Command();
183
- program.name("framed").description("CLI for setting up Framed in your project").version("0.1.1");
301
+ program.name("framed").description("CLI for setting up Framed in your project").version("0.1.4");
184
302
  program.command("init").description("Initialize Framed in your project").option("--force", "Overwrite existing files").action(init);
185
303
  program.parse();
186
304
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/detect.ts","../src/templates/index.ts","../src/init.ts","../src/index.ts"],"names":["path","fs"],"mappings":"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","file":"index.js","sourcesContent":["import fs from 'fs-extra';\nimport path from 'path';\n\nexport type ProjectType = 'next-app' | 'next-pages' | 'vite' | 'unknown';\n\nexport async function detectProject(cwd: string): Promise<{\n type: ProjectType;\n srcDir: boolean;\n}> {\n const packageJsonPath = path.join(cwd, 'package.json');\n\n if (!await fs.pathExists(packageJsonPath)) {\n return { type: 'unknown', srcDir: false };\n }\n\n const pkg = await fs.readJson(packageJsonPath);\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n // Check for Next.js\n if (deps['next']) {\n const hasAppDir = await fs.pathExists(path.join(cwd, 'app')) ||\n await fs.pathExists(path.join(cwd, 'src/app'));\n const srcDir = await fs.pathExists(path.join(cwd, 'src'));\n\n return {\n type: hasAppDir ? 'next-app' : 'next-pages',\n srcDir\n };\n }\n\n // Check for Vite\n if (deps['vite']) {\n return { type: 'vite', srcDir: await fs.pathExists(path.join(cwd, 'src')) };\n }\n\n return { type: 'unknown', srcDir: false };\n}\n","export function getTemplates(type: 'next-app') {\n return {\n dashboard: `import { FramedProvider, FramedDashboard } from '@framed-dev/react';\n\nexport default function FramedPage() {\n return (\n <FramedProvider config={{ mode: 'local' }}>\n <FramedDashboard />\n </FramedProvider>\n );\n}\n`,\n review: `import { FramedProvider, FramedReview } from '@framed-dev/react';\n\nexport default function ReviewPage() {\n return (\n <FramedProvider config={{ mode: 'local' }}>\n <FramedReview />\n </FramedProvider>\n );\n}\n`,\n build: `import { FramedProvider, FramedBuild } from '@framed-dev/react';\n\nexport default function BuildPage() {\n return (\n <FramedProvider config={{ mode: 'local' }}>\n <FramedBuild />\n </FramedProvider>\n );\n}\n`,\n manage: `import { FramedProvider, FramedManage } from '@framed-dev/react';\n\nexport default function ManagePage() {\n return (\n <FramedProvider config={{ mode: 'local' }}>\n <FramedManage />\n </FramedProvider>\n );\n}\n`,\n env: `# Framed Configuration\n# Get your license key at https://framed.dev/dashboard\n\n# Optional: For AI features (task parsing, SEO analysis)\nNEXT_PUBLIC_FRAMED_LICENSE_KEY=\n\n# Optional: Connect your own Supabase for data persistence\nNEXT_PUBLIC_SUPABASE_URL=\nNEXT_PUBLIC_SUPABASE_ANON_KEY=\n`,\n layoutSnippet: `\n// app/layout.tsx\nimport { FramedProvider, FeedbackWidget } from '@framed-dev/react';\n\nexport default function RootLayout({ children }) {\n return (\n <html>\n <body>\n <FramedProvider config={{ mode: 'local' }}>\n {children}\n <FeedbackWidget />\n </FramedProvider>\n </body>\n </html>\n );\n}\n`\n };\n}\n","import fs from 'fs-extra';\nimport path from 'path';\nimport prompts from 'prompts';\nimport pc from 'picocolors';\nimport { execSync } from 'child_process';\nimport { detectProject, ProjectType } from './detect';\nimport { getTemplates } from './templates';\n\nexport async function init(options: { force?: boolean }) {\n const cwd = process.cwd();\n\n console.log(pc.cyan('\\nšŸ–¼ļø Framed Setup\\n'));\n\n // Detect project\n const { type, srcDir } = await detectProject(cwd);\n\n if (type === 'unknown') {\n console.log(pc.red('Could not detect project type. Make sure you have a package.json.'));\n process.exit(1);\n }\n\n console.log(pc.green(`āœ“ Detected: ${formatType(type)}${srcDir ? ' (src directory)' : ''}`));\n\n if (type === 'next-pages' || type === 'vite') {\n console.log(pc.yellow('\\nCurrently only Next.js App Router is supported.'));\n console.log('Support for Pages Router and Vite coming soon.\\n');\n process.exit(1);\n }\n\n // Install @framed-dev/react\n console.log(pc.cyan('\\nInstalling @framed-dev/react...'));\n\n try {\n // Detect package manager\n const useYarn = await fs.pathExists(path.join(cwd, 'yarn.lock'));\n const usePnpm = await fs.pathExists(path.join(cwd, 'pnpm-lock.yaml'));\n\n const cmd = usePnpm ? 'pnpm add' : useYarn ? 'yarn add' : 'npm install';\n execSync(`${cmd} @framed-dev/react`, { cwd, stdio: 'inherit' });\n\n console.log(pc.green('āœ“ Installed @framed-dev/react\\n'));\n } catch (e) {\n console.log(pc.yellow('⚠ Could not auto-install. Run: npm install @framed-dev/react\\n'));\n }\n\n // Get base path\n const appDir = srcDir ? 'src/app' : 'app';\n const framedDir = path.join(cwd, appDir, 'framed');\n\n // Check if already exists\n if (await fs.pathExists(framedDir) && !options.force) {\n const { overwrite } = await prompts({\n type: 'confirm',\n name: 'overwrite',\n message: '/framed directory already exists. Overwrite?',\n initial: false\n });\n\n if (!overwrite) {\n console.log(pc.yellow('Aborted.'));\n process.exit(0);\n }\n }\n\n // Create files\n const templates = getTemplates('next-app');\n\n // Create framed pages\n await fs.ensureDir(framedDir);\n await fs.writeFile(path.join(framedDir, 'page.tsx'), templates.dashboard);\n console.log(pc.green(`āœ“ Created: ${appDir}/framed/page.tsx`));\n\n await fs.ensureDir(path.join(framedDir, 'review'));\n await fs.writeFile(path.join(framedDir, 'review/page.tsx'), templates.review);\n console.log(pc.green(`āœ“ Created: ${appDir}/framed/review/page.tsx`));\n\n await fs.ensureDir(path.join(framedDir, 'build'));\n await fs.writeFile(path.join(framedDir, 'build/page.tsx'), templates.build);\n console.log(pc.green(`āœ“ Created: ${appDir}/framed/build/page.tsx`));\n\n await fs.ensureDir(path.join(framedDir, 'manage'));\n await fs.writeFile(path.join(framedDir, 'manage/page.tsx'), templates.manage);\n console.log(pc.green(`āœ“ Created: ${appDir}/framed/manage/page.tsx`));\n\n // Create .env.example\n const envPath = path.join(cwd, '.env.example');\n if (!await fs.pathExists(envPath)) {\n await fs.writeFile(envPath, templates.env);\n console.log(pc.green(`āœ“ Created: .env.example`));\n }\n\n // Instructions\n console.log(pc.cyan('\\n✨ Framed setup complete!\\n'));\n console.log('Next steps:');\n console.log(pc.dim(' 1. Add FramedProvider to your root layout'));\n console.log(pc.dim(' 2. Copy .env.example to .env.local and fill in values'));\n console.log(pc.dim(' 3. Visit /framed to get started\\n'));\n\n console.log('Add to your layout.tsx:');\n console.log(pc.dim(templates.layoutSnippet));\n}\n\nfunction formatType(type: ProjectType): string {\n switch (type) {\n case 'next-app': return 'Next.js (App Router)';\n case 'next-pages': return 'Next.js (Pages Router)';\n case 'vite': return 'Vite';\n default: return 'Unknown';\n }\n}\n","import { Command } from 'commander';\nimport { init } from './init';\n\nconst program = new Command();\n\nprogram\n .name('framed')\n .description('CLI for setting up Framed in your project')\n .version('0.1.1');\n\nprogram\n .command('init')\n .description('Initialize Framed in your project')\n .option('--force', 'Overwrite existing files')\n .action(init);\n\nprogram.parse();\n"]}
1
+ {"version":3,"sources":["../src/detect.ts","../src/templates/index.ts","../src/init.ts","../src/index.ts"],"names":["path","fs"],"mappings":"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","file":"index.js","sourcesContent":["import fs from 'fs-extra';\nimport path from 'path';\n\nexport type ProjectType = 'next-app' | 'next-pages' | 'vite' | 'unknown';\n\nexport interface ProjectInfo {\n type: ProjectType;\n srcDir: boolean;\n hasSupabase: boolean;\n hasTailwind: boolean;\n supabaseConfigured: boolean;\n}\n\nexport async function detectProject(cwd: string): Promise<ProjectInfo> {\n const packageJsonPath = path.join(cwd, 'package.json');\n\n if (!await fs.pathExists(packageJsonPath)) {\n return {\n type: 'unknown',\n srcDir: false,\n hasSupabase: false,\n hasTailwind: false,\n supabaseConfigured: false,\n };\n }\n\n const pkg = await fs.readJson(packageJsonPath);\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n // Detect Supabase\n const hasSupabase = !!deps['@supabase/supabase-js'];\n\n // Detect Tailwind\n const hasTailwindDep = !!deps['tailwindcss'];\n const hasTailwindConfig = await fs.pathExists(path.join(cwd, 'tailwind.config.js')) ||\n await fs.pathExists(path.join(cwd, 'tailwind.config.ts')) ||\n await fs.pathExists(path.join(cwd, 'tailwind.config.mjs'));\n const hasTailwind = hasTailwindDep || hasTailwindConfig;\n\n // Check .env files for Supabase configuration\n let supabaseConfigured = false;\n const envFiles = ['.env.local', '.env', '.env.development', '.env.development.local'];\n\n for (const envFile of envFiles) {\n const envPath = path.join(cwd, envFile);\n if (await fs.pathExists(envPath)) {\n try {\n const envContent = await fs.readFile(envPath, 'utf-8');\n if (envContent.includes('SUPABASE_URL') ||\n envContent.includes('NEXT_PUBLIC_SUPABASE_URL')) {\n supabaseConfigured = true;\n break;\n }\n } catch {\n // Ignore read errors\n }\n }\n }\n\n // Check for Next.js\n if (deps['next']) {\n const hasAppDir = await fs.pathExists(path.join(cwd, 'app')) ||\n await fs.pathExists(path.join(cwd, 'src/app'));\n const srcDir = await fs.pathExists(path.join(cwd, 'src'));\n\n return {\n type: hasAppDir ? 'next-app' : 'next-pages',\n srcDir,\n hasSupabase,\n hasTailwind,\n supabaseConfigured,\n };\n }\n\n // Check for Vite\n if (deps['vite']) {\n return {\n type: 'vite',\n srcDir: await fs.pathExists(path.join(cwd, 'src')),\n hasSupabase,\n hasTailwind,\n supabaseConfigured,\n };\n }\n\n return {\n type: 'unknown',\n srcDir: false,\n hasSupabase,\n hasTailwind,\n supabaseConfigured,\n };\n}\n","export function getTemplates(type: 'next-app') {\n return {\n dashboard: `\"use client\";\n\nimport { FramedProvider, FramedStarter } from '@framed-dev/react';\n\nexport default function FramedPage() {\n return (\n <FramedProvider config={{\n mode: 'local',\n sync: {\n supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,\n apiKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,\n },\n }}>\n <FramedStarter />\n </FramedProvider>\n );\n}\n`,\n review: `\"use client\";\n\nimport { FramedProvider, FramedReview } from '@framed-dev/react';\n\nexport default function ReviewPage() {\n return (\n <FramedProvider config={{\n mode: 'local',\n sync: {\n supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,\n apiKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,\n },\n }}>\n <FramedReview />\n </FramedProvider>\n );\n}\n`,\n build: `\"use client\";\n\nimport { FramedProvider, FramedBuild } from '@framed-dev/react';\n\nexport default function BuildPage() {\n return (\n <FramedProvider config={{\n mode: 'local',\n sync: {\n supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,\n apiKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,\n },\n }}>\n <FramedBuild />\n </FramedProvider>\n );\n}\n`,\n manage: `\"use client\";\n\nimport { FramedProvider, FramedManage } from '@framed-dev/react';\n\nexport default function ManagePage() {\n return (\n <FramedProvider config={{\n mode: 'local',\n sync: {\n supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,\n apiKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,\n },\n }}>\n <FramedManage />\n </FramedProvider>\n );\n}\n`,\n env: `# Framed Configuration\n# Get your license key at https://framed.dev/dashboard\n\n# Optional: For AI features (task parsing, SEO analysis)\nNEXT_PUBLIC_FRAMED_LICENSE_KEY=\n\n# Required: Connect your Supabase for data persistence\nNEXT_PUBLIC_SUPABASE_URL=\nNEXT_PUBLIC_SUPABASE_ANON_KEY=\n`,\n layoutSnippet: `\n// app/layout.tsx\nimport { FramedProvider, FeedbackWidget } from '@framed-dev/react';\n\nexport default function RootLayout({ children }) {\n return (\n <html>\n <body>\n <FramedProvider config={{\n mode: 'local',\n sync: {\n supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,\n apiKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,\n },\n }}>\n {children}\n <FeedbackWidget />\n </FramedProvider>\n </body>\n </html>\n );\n}\n`\n };\n}\n","import fs from 'fs-extra';\nimport path from 'path';\nimport prompts from 'prompts';\nimport pc from 'picocolors';\nimport { execSync } from 'child_process';\nimport { detectProject, ProjectType } from './detect';\nimport { getTemplates } from './templates';\n\nexport async function init(options: { force?: boolean }) {\n const cwd = process.cwd();\n\n console.log(pc.cyan('\\nšŸ–¼ļø Framed Setup\\n'));\n\n // Detect project\n const { type, srcDir, hasSupabase, hasTailwind, supabaseConfigured } = await detectProject(cwd);\n\n if (type === 'unknown') {\n console.log(pc.red('Could not detect project type. Make sure you have a package.json.'));\n process.exit(1);\n }\n\n console.log(pc.green(`āœ“ Detected: ${formatType(type)}${srcDir ? ' (src directory)' : ''}`));\n\n // Show detection status\n console.log(pc.dim(` Tailwind CSS: ${hasTailwind ? pc.green('āœ“') : pc.yellow('ā—‹ will install')}`));\n console.log(pc.dim(` Supabase: ${hasSupabase ? pc.green('āœ“') : pc.yellow('ā—‹ will install')}`));\n if (hasSupabase) {\n console.log(pc.dim(` Supabase configured: ${supabaseConfigured ? pc.green('āœ“') : pc.yellow('ā—‹ add to .env')}`));\n }\n\n if (type === 'next-pages' || type === 'vite') {\n console.log(pc.yellow('\\nCurrently only Next.js App Router is supported.'));\n console.log('Support for Pages Router and Vite coming soon.\\n');\n process.exit(1);\n }\n\n // Detect package manager\n const useYarn = await fs.pathExists(path.join(cwd, 'yarn.lock'));\n const usePnpm = await fs.pathExists(path.join(cwd, 'pnpm-lock.yaml'));\n const cmd = usePnpm ? 'pnpm add' : useYarn ? 'yarn add' : 'npm install';\n\n // Build list of packages to install\n const toInstall: string[] = ['@framed-dev/react'];\n\n if (!hasTailwind) {\n toInstall.push('tailwindcss', 'postcss', 'autoprefixer');\n }\n\n if (!hasSupabase) {\n toInstall.push('@supabase/supabase-js');\n }\n\n // Install dependencies\n console.log(pc.cyan(`\\nInstalling ${toInstall.join(', ')}...`));\n\n try {\n execSync(`${cmd} ${toInstall.join(' ')}`, { cwd, stdio: 'inherit' });\n console.log(pc.green(`āœ“ Installed dependencies\\n`));\n } catch (e) {\n console.log(pc.yellow(`⚠ Could not auto-install. Run: npm install ${toInstall.join(' ')}\\n`));\n }\n\n // Initialize Tailwind if it wasn't present\n if (!hasTailwind) {\n console.log(pc.cyan('Initializing Tailwind CSS...'));\n try {\n execSync('npx tailwindcss init -p', { cwd, stdio: 'inherit' });\n console.log(pc.green('āœ“ Initialized Tailwind CSS\\n'));\n\n // Update tailwind.config.js to include framed paths\n const tailwindConfigPath = path.join(cwd, 'tailwind.config.js');\n if (await fs.pathExists(tailwindConfigPath)) {\n let tailwindConfig = await fs.readFile(tailwindConfigPath, 'utf-8');\n if (tailwindConfig.includes('content: []')) {\n tailwindConfig = tailwindConfig.replace(\n 'content: []',\n `content: [\n \"./src/**/*.{js,ts,jsx,tsx,mdx}\",\n \"./app/**/*.{js,ts,jsx,tsx,mdx}\",\n \"./node_modules/@framed-dev/react/**/*.{js,ts,jsx,tsx}\",\n ]`\n );\n await fs.writeFile(tailwindConfigPath, tailwindConfig);\n console.log(pc.green('āœ“ Updated tailwind.config.js with content paths\\n'));\n }\n }\n } catch (e) {\n console.log(pc.yellow('⚠ Could not initialize Tailwind. Run: npx tailwindcss init -p\\n'));\n }\n }\n\n // Get base path\n const appDir = srcDir ? 'src/app' : 'app';\n const framedDir = path.join(cwd, appDir, 'framed');\n\n // Check if already exists\n if (await fs.pathExists(framedDir) && !options.force) {\n const { overwrite } = await prompts({\n type: 'confirm',\n name: 'overwrite',\n message: '/framed directory already exists. Overwrite?',\n initial: false\n });\n\n if (!overwrite) {\n console.log(pc.yellow('Aborted.'));\n process.exit(0);\n }\n }\n\n // Create files\n const templates = getTemplates('next-app');\n\n // Create framed pages\n await fs.ensureDir(framedDir);\n await fs.writeFile(path.join(framedDir, 'page.tsx'), templates.dashboard);\n console.log(pc.green(`āœ“ Created: ${appDir}/framed/page.tsx`));\n\n await fs.ensureDir(path.join(framedDir, 'review'));\n await fs.writeFile(path.join(framedDir, 'review/page.tsx'), templates.review);\n console.log(pc.green(`āœ“ Created: ${appDir}/framed/review/page.tsx`));\n\n await fs.ensureDir(path.join(framedDir, 'build'));\n await fs.writeFile(path.join(framedDir, 'build/page.tsx'), templates.build);\n console.log(pc.green(`āœ“ Created: ${appDir}/framed/build/page.tsx`));\n\n await fs.ensureDir(path.join(framedDir, 'manage'));\n await fs.writeFile(path.join(framedDir, 'manage/page.tsx'), templates.manage);\n console.log(pc.green(`āœ“ Created: ${appDir}/framed/manage/page.tsx`));\n\n // Create .env.example\n const envPath = path.join(cwd, '.env.example');\n if (!await fs.pathExists(envPath)) {\n await fs.writeFile(envPath, templates.env);\n console.log(pc.green(`āœ“ Created: .env.example`));\n }\n\n // Instructions\n console.log(pc.cyan('\\n✨ Framed setup complete!\\n'));\n console.log('Next steps:');\n console.log(pc.dim(' 1. Add FramedProvider to your root layout'));\n console.log(pc.dim(' 2. Copy .env.example to .env.local and fill in values'));\n console.log(pc.dim(' 3. Visit /framed to get started\\n'));\n\n console.log('Add to your layout.tsx:');\n console.log(pc.dim(templates.layoutSnippet));\n}\n\nfunction formatType(type: ProjectType): string {\n switch (type) {\n case 'next-app': return 'Next.js (App Router)';\n case 'next-pages': return 'Next.js (Pages Router)';\n case 'vite': return 'Vite';\n default: return 'Unknown';\n }\n}\n","import { Command } from 'commander';\nimport { init } from './init';\n\nconst program = new Command();\n\nprogram\n .name('framed')\n .description('CLI for setting up Framed in your project')\n .version('0.1.4');\n\nprogram\n .command('init')\n .description('Initialize Framed in your project')\n .option('--force', 'Overwrite existing files')\n .action(init);\n\nprogram.parse();\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@framed-dev/cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "CLI tool for setting up Framed SDK",
5
5
  "type": "module",
6
6
  "bin": {