@framed-dev/cli 0.1.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 +176 -0
- package/dist/index.js.map +1 -0
- package/package.json +42 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import fs2 from 'fs-extra';
|
|
4
|
+
import path2 from 'path';
|
|
5
|
+
import prompts from 'prompts';
|
|
6
|
+
import pc from 'picocolors';
|
|
7
|
+
|
|
8
|
+
async function detectProject(cwd) {
|
|
9
|
+
const packageJsonPath = path2.join(cwd, "package.json");
|
|
10
|
+
if (!await fs2.pathExists(packageJsonPath)) {
|
|
11
|
+
return { type: "unknown", srcDir: false };
|
|
12
|
+
}
|
|
13
|
+
const pkg = await fs2.readJson(packageJsonPath);
|
|
14
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
15
|
+
if (deps["next"]) {
|
|
16
|
+
const hasAppDir = await fs2.pathExists(path2.join(cwd, "app")) || await fs2.pathExists(path2.join(cwd, "src/app"));
|
|
17
|
+
const srcDir = await fs2.pathExists(path2.join(cwd, "src"));
|
|
18
|
+
return {
|
|
19
|
+
type: hasAppDir ? "next-app" : "next-pages",
|
|
20
|
+
srcDir
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (deps["vite"]) {
|
|
24
|
+
return { type: "vite", srcDir: await fs2.pathExists(path2.join(cwd, "src")) };
|
|
25
|
+
}
|
|
26
|
+
return { type: "unknown", srcDir: false };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/templates/index.ts
|
|
30
|
+
function getTemplates(type) {
|
|
31
|
+
return {
|
|
32
|
+
dashboard: `import { FramedProvider, FramedDashboard } from '@framed-dev/react';
|
|
33
|
+
|
|
34
|
+
export default function FramedPage() {
|
|
35
|
+
return (
|
|
36
|
+
<FramedProvider config={{ mode: 'local' }}>
|
|
37
|
+
<FramedDashboard />
|
|
38
|
+
</FramedProvider>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
`,
|
|
42
|
+
review: `import { FramedProvider, FramedReview } from '@framed-dev/react';
|
|
43
|
+
|
|
44
|
+
export default function ReviewPage() {
|
|
45
|
+
return (
|
|
46
|
+
<FramedProvider config={{ mode: 'local' }}>
|
|
47
|
+
<FramedReview />
|
|
48
|
+
</FramedProvider>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
`,
|
|
52
|
+
build: `import { FramedProvider, FramedBuild } from '@framed-dev/react';
|
|
53
|
+
|
|
54
|
+
export default function BuildPage() {
|
|
55
|
+
return (
|
|
56
|
+
<FramedProvider config={{ mode: 'local' }}>
|
|
57
|
+
<FramedBuild />
|
|
58
|
+
</FramedProvider>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
`,
|
|
62
|
+
manage: `import { FramedProvider, FramedManage } from '@framed-dev/react';
|
|
63
|
+
|
|
64
|
+
export default function ManagePage() {
|
|
65
|
+
return (
|
|
66
|
+
<FramedProvider config={{ mode: 'local' }}>
|
|
67
|
+
<FramedManage />
|
|
68
|
+
</FramedProvider>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
`,
|
|
72
|
+
env: `# Framed Configuration
|
|
73
|
+
# Get your license key at https://framed.dev/dashboard
|
|
74
|
+
|
|
75
|
+
# Optional: For AI features (task parsing, SEO analysis)
|
|
76
|
+
NEXT_PUBLIC_FRAMED_LICENSE_KEY=
|
|
77
|
+
|
|
78
|
+
# Optional: Connect your own Supabase for data persistence
|
|
79
|
+
NEXT_PUBLIC_SUPABASE_URL=
|
|
80
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=
|
|
81
|
+
`,
|
|
82
|
+
layoutSnippet: `
|
|
83
|
+
// app/layout.tsx
|
|
84
|
+
import { FramedProvider, FeedbackWidget } from '@framed-dev/react';
|
|
85
|
+
|
|
86
|
+
export default function RootLayout({ children }) {
|
|
87
|
+
return (
|
|
88
|
+
<html>
|
|
89
|
+
<body>
|
|
90
|
+
<FramedProvider config={{ mode: 'local' }}>
|
|
91
|
+
{children}
|
|
92
|
+
<FeedbackWidget />
|
|
93
|
+
</FramedProvider>
|
|
94
|
+
</body>
|
|
95
|
+
</html>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
`
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/init.ts
|
|
103
|
+
async function init(options) {
|
|
104
|
+
const cwd = process.cwd();
|
|
105
|
+
console.log(pc.cyan("\n\u{1F5BC}\uFE0F Framed Setup\n"));
|
|
106
|
+
const { type, srcDir } = await detectProject(cwd);
|
|
107
|
+
if (type === "unknown") {
|
|
108
|
+
console.log(pc.red("Could not detect project type. Make sure you have a package.json."));
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
console.log(pc.green(`\u2713 Detected: ${formatType(type)}${srcDir ? " (src directory)" : ""}`));
|
|
112
|
+
if (type === "next-pages" || type === "vite") {
|
|
113
|
+
console.log(pc.yellow("\nCurrently only Next.js App Router is supported."));
|
|
114
|
+
console.log("Support for Pages Router and Vite coming soon.\n");
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
const appDir = srcDir ? "src/app" : "app";
|
|
118
|
+
const framedDir = path2.join(cwd, appDir, "framed");
|
|
119
|
+
if (await fs2.pathExists(framedDir) && !options.force) {
|
|
120
|
+
const { overwrite } = await prompts({
|
|
121
|
+
type: "confirm",
|
|
122
|
+
name: "overwrite",
|
|
123
|
+
message: "/framed directory already exists. Overwrite?",
|
|
124
|
+
initial: false
|
|
125
|
+
});
|
|
126
|
+
if (!overwrite) {
|
|
127
|
+
console.log(pc.yellow("Aborted."));
|
|
128
|
+
process.exit(0);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const templates = getTemplates();
|
|
132
|
+
await fs2.ensureDir(framedDir);
|
|
133
|
+
await fs2.writeFile(path2.join(framedDir, "page.tsx"), templates.dashboard);
|
|
134
|
+
console.log(pc.green(`\u2713 Created: ${appDir}/framed/page.tsx`));
|
|
135
|
+
await fs2.ensureDir(path2.join(framedDir, "review"));
|
|
136
|
+
await fs2.writeFile(path2.join(framedDir, "review/page.tsx"), templates.review);
|
|
137
|
+
console.log(pc.green(`\u2713 Created: ${appDir}/framed/review/page.tsx`));
|
|
138
|
+
await fs2.ensureDir(path2.join(framedDir, "build"));
|
|
139
|
+
await fs2.writeFile(path2.join(framedDir, "build/page.tsx"), templates.build);
|
|
140
|
+
console.log(pc.green(`\u2713 Created: ${appDir}/framed/build/page.tsx`));
|
|
141
|
+
await fs2.ensureDir(path2.join(framedDir, "manage"));
|
|
142
|
+
await fs2.writeFile(path2.join(framedDir, "manage/page.tsx"), templates.manage);
|
|
143
|
+
console.log(pc.green(`\u2713 Created: ${appDir}/framed/manage/page.tsx`));
|
|
144
|
+
const envPath = path2.join(cwd, ".env.example");
|
|
145
|
+
if (!await fs2.pathExists(envPath)) {
|
|
146
|
+
await fs2.writeFile(envPath, templates.env);
|
|
147
|
+
console.log(pc.green(`\u2713 Created: .env.example`));
|
|
148
|
+
}
|
|
149
|
+
console.log(pc.cyan("\n\u2728 Framed setup complete!\n"));
|
|
150
|
+
console.log("Next steps:");
|
|
151
|
+
console.log(pc.dim(" 1. Add FramedProvider to your root layout"));
|
|
152
|
+
console.log(pc.dim(" 2. Copy .env.example to .env.local and fill in values"));
|
|
153
|
+
console.log(pc.dim(" 3. Visit /framed to get started\n"));
|
|
154
|
+
console.log("Add to your layout.tsx:");
|
|
155
|
+
console.log(pc.dim(templates.layoutSnippet));
|
|
156
|
+
}
|
|
157
|
+
function formatType(type) {
|
|
158
|
+
switch (type) {
|
|
159
|
+
case "next-app":
|
|
160
|
+
return "Next.js (App Router)";
|
|
161
|
+
case "next-pages":
|
|
162
|
+
return "Next.js (Pages Router)";
|
|
163
|
+
case "vite":
|
|
164
|
+
return "Vite";
|
|
165
|
+
default:
|
|
166
|
+
return "Unknown";
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// src/index.ts
|
|
171
|
+
var program = new Command();
|
|
172
|
+
program.name("framed").description("CLI for setting up Framed in your project").version("0.1.0");
|
|
173
|
+
program.command("init").description("Initialize Framed in your project").option("--force", "Overwrite existing files").action(init);
|
|
174
|
+
program.parse();
|
|
175
|
+
//# sourceMappingURL=index.js.map
|
|
176
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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 { 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 // 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.0');\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
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@framed-dev/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI tool for setting up Framed SDK",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"framed": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": ["dist"],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup",
|
|
12
|
+
"dev": "tsup --watch",
|
|
13
|
+
"type-check": "tsc --noEmit",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"test:watch": "vitest",
|
|
16
|
+
"clean": "rm -rf dist"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@framed-dev/core": "workspace:*",
|
|
20
|
+
"commander": "^12.1.0",
|
|
21
|
+
"picocolors": "^1.1.0",
|
|
22
|
+
"prompts": "^2.4.2",
|
|
23
|
+
"fs-extra": "^11.2.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/fs-extra": "^11.0.4",
|
|
27
|
+
"@types/prompts": "^2.4.9",
|
|
28
|
+
"tsup": "^8.3.5",
|
|
29
|
+
"typescript": "^5.7.0",
|
|
30
|
+
"vitest": "^2.1.0"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/framed-dev/framed-widget.git",
|
|
39
|
+
"directory": "packages/cli"
|
|
40
|
+
},
|
|
41
|
+
"keywords": ["framed", "feedback", "cli", "setup"]
|
|
42
|
+
}
|