create-claudecraft 1.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/LICENSE +21 -0
- package/README.md +194 -0
- package/bin/cli.js +2 -0
- package/dist/constants.d.ts +71 -0
- package/dist/constants.js +128 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +229 -0
- package/dist/ink-prompts.d.ts +12 -0
- package/dist/ink-prompts.js +363 -0
- package/dist/prompts.d.ts +16 -0
- package/dist/prompts.js +434 -0
- package/dist/scaffold.d.ts +19 -0
- package/dist/scaffold.js +303 -0
- package/dist/ui.d.ts +27 -0
- package/dist/ui.js +254 -0
- package/package.json +74 -0
- package/templates/app/App.tsx +21 -0
- package/templates/base/CLAUDE.md +332 -0
- package/templates/base/eslint.config.js +28 -0
- package/templates/base/index.html +17 -0
- package/templates/base/package.json +43 -0
- package/templates/base/postcss.config.js +6 -0
- package/templates/base/tailwind.config.js +81 -0
- package/templates/base/tsconfig.json +25 -0
- package/templates/base/vite.config.ts +16 -0
- package/templates/commands/brainstorm.md +6 -0
- package/templates/commands/build.md +41 -0
- package/templates/commands/execute-plan.md +6 -0
- package/templates/commands/lint.md +41 -0
- package/templates/commands/ralph.md +113 -0
- package/templates/commands/typecheck.md +44 -0
- package/templates/commands/write-plan.md +6 -0
- package/templates/components/ErrorBoundary.tsx +49 -0
- package/templates/components/ui/Button.tsx +60 -0
- package/templates/components/ui/CodeBlock.tsx +46 -0
- package/templates/components/ui/CopyCommand.tsx +38 -0
- package/templates/components/ui/FilePreview.tsx +46 -0
- package/templates/components/ui/SkipLink.tsx +7 -0
- package/templates/components/ui/ThemeSelector.tsx +41 -0
- package/templates/components/ui/UICarousel.tsx +309 -0
- package/templates/context/ThemeContext.tsx +61 -0
- package/templates/homepage/HomePage.tsx +534 -0
- package/templates/homepage/NotFoundPage.tsx +17 -0
- package/templates/hooks/README.md +82 -0
- package/templates/hooks/check-branch.js +27 -0
- package/templates/hooks/typecheck-after-edit.js +51 -0
- package/templates/index.css +67 -0
- package/templates/lib/utils.ts +9 -0
- package/templates/main.tsx +16 -0
- package/templates/settings/MCP_SETUP.md +76 -0
- package/templates/settings/settings.json +16 -0
- package/templates/settings/settings.local.json +37 -0
- package/templates/skills/design/a11y-audit/SKILL.md +173 -0
- package/templates/skills/design/design-polish/SKILL.md +75 -0
- package/templates/skills/design/figma-to-code/SKILL.md +157 -0
- package/templates/skills/design/json-ld/SKILL.md +125 -0
- package/templates/skills/design/microcopy/SKILL.md +197 -0
- package/templates/skills/design/og-image/SKILL.md +157 -0
- package/templates/skills/design/ralph-wiggum-loops/SKILL.md +299 -0
- package/templates/skills/design/react-best-practices/SKILL.md +106 -0
- package/templates/skills/design/react-best-practices/references/react-performance-guidelines.md +143 -0
- package/templates/skills/design/seo-review/SKILL.md +96 -0
- package/templates/skills/design/sitemap-generator/SKILL.md +66 -0
- package/templates/skills/design/testing-patterns/SKILL.md +276 -0
- package/templates/skills/design/ui-skills/SKILL.md +85 -0
- package/templates/skills/design/visual-iteration/SKILL.md +88 -0
- package/templates/skills/workflow/brainstorming/SKILL.md +54 -0
- package/templates/skills/workflow/dispatching-parallel-agents/SKILL.md +180 -0
- package/templates/skills/workflow/executing-plans/SKILL.md +76 -0
- package/templates/skills/workflow/finishing-a-development-branch/SKILL.md +200 -0
- package/templates/skills/workflow/receiving-code-review/SKILL.md +213 -0
- package/templates/skills/workflow/requesting-code-review/SKILL.md +105 -0
- package/templates/skills/workflow/requesting-code-review/code-reviewer.md +146 -0
- package/templates/skills/workflow/subagent-driven-development/SKILL.md +240 -0
- package/templates/skills/workflow/subagent-driven-development/code-quality-reviewer-prompt.md +20 -0
- package/templates/skills/workflow/subagent-driven-development/implementer-prompt.md +78 -0
- package/templates/skills/workflow/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/templates/skills/workflow/systematic-debugging/CREATION-LOG.md +119 -0
- package/templates/skills/workflow/systematic-debugging/SKILL.md +296 -0
- package/templates/skills/workflow/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/templates/skills/workflow/systematic-debugging/condition-based-waiting.md +115 -0
- package/templates/skills/workflow/systematic-debugging/defense-in-depth.md +122 -0
- package/templates/skills/workflow/systematic-debugging/find-polluter.sh +63 -0
- package/templates/skills/workflow/systematic-debugging/root-cause-tracing.md +169 -0
- package/templates/skills/workflow/systematic-debugging/test-academic.md +14 -0
- package/templates/skills/workflow/systematic-debugging/test-pressure-1.md +58 -0
- package/templates/skills/workflow/systematic-debugging/test-pressure-2.md +68 -0
- package/templates/skills/workflow/systematic-debugging/test-pressure-3.md +69 -0
- package/templates/skills/workflow/test-driven-development/SKILL.md +371 -0
- package/templates/skills/workflow/test-driven-development/testing-anti-patterns.md +299 -0
- package/templates/skills/workflow/using-git-worktrees/SKILL.md +217 -0
- package/templates/skills/workflow/using-superpowers/SKILL.md +87 -0
- package/templates/skills/workflow/verification-before-completion/SKILL.md +139 -0
- package/templates/skills/workflow/writing-plans/SKILL.md +116 -0
- package/templates/skills/workflow/writing-skills/SKILL.md +655 -0
- package/templates/skills/workflow/writing-skills/anthropic-best-practices.md +1150 -0
- package/templates/skills/workflow/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
- package/templates/skills/workflow/writing-skills/graphviz-conventions.dot +172 -0
- package/templates/skills/workflow/writing-skills/persuasion-principles.md +187 -0
- package/templates/skills/workflow/writing-skills/render-graphs.js +168 -0
- package/templates/skills/workflow/writing-skills/testing-skills-with-subagents.md +384 -0
- package/templates/types/index.ts +17 -0
- package/templates/vite-env.d.ts +1 -0
package/dist/scaffold.js
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { SKILLS } from './constants.js';
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
|
|
8
|
+
export async function scaffold(choices, onProgress) {
|
|
9
|
+
const startTime = Date.now();
|
|
10
|
+
const targetDir = path.resolve(process.cwd(), choices.projectName);
|
|
11
|
+
// Check if directory exists
|
|
12
|
+
if (await fs.pathExists(targetDir)) {
|
|
13
|
+
throw new Error(`DIR_EXISTS:${choices.projectName}`);
|
|
14
|
+
}
|
|
15
|
+
// Create directory
|
|
16
|
+
await fs.ensureDir(targetDir);
|
|
17
|
+
// Copy base template
|
|
18
|
+
onProgress('scaffolding', 10, 'base files');
|
|
19
|
+
const baseDir = path.join(TEMPLATES_DIR, 'base');
|
|
20
|
+
if (await fs.pathExists(baseDir)) {
|
|
21
|
+
await fs.copy(baseDir, targetDir);
|
|
22
|
+
}
|
|
23
|
+
// Ensure .claude directories exist
|
|
24
|
+
const claudeDir = path.join(targetDir, '.claude');
|
|
25
|
+
const skillsDir = path.join(claudeDir, 'skills');
|
|
26
|
+
const commandsDir = path.join(claudeDir, 'commands');
|
|
27
|
+
await fs.ensureDir(skillsDir);
|
|
28
|
+
await fs.ensureDir(commandsDir);
|
|
29
|
+
// Copy selected skills
|
|
30
|
+
onProgress('scaffolding', 30, 'skills');
|
|
31
|
+
for (const skillName of choices.selectedSkills) {
|
|
32
|
+
const skill = SKILLS.find((s) => s.name === skillName);
|
|
33
|
+
if (!skill)
|
|
34
|
+
continue;
|
|
35
|
+
// Try workflow first, then design
|
|
36
|
+
let sourceDir = path.join(TEMPLATES_DIR, 'skills', 'workflow', skillName);
|
|
37
|
+
if (!(await fs.pathExists(sourceDir))) {
|
|
38
|
+
sourceDir = path.join(TEMPLATES_DIR, 'skills', 'design', skillName);
|
|
39
|
+
}
|
|
40
|
+
if (await fs.pathExists(sourceDir)) {
|
|
41
|
+
await fs.copy(sourceDir, path.join(skillsDir, skillName));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Copy commands
|
|
45
|
+
onProgress('scaffolding', 50, 'commands');
|
|
46
|
+
const commandsSrc = path.join(TEMPLATES_DIR, 'commands');
|
|
47
|
+
if (await fs.pathExists(commandsSrc)) {
|
|
48
|
+
await fs.copy(commandsSrc, commandsDir);
|
|
49
|
+
}
|
|
50
|
+
// Copy hooks
|
|
51
|
+
onProgress('scaffolding', 55, 'hooks');
|
|
52
|
+
const hooksSrc = path.join(TEMPLATES_DIR, 'hooks');
|
|
53
|
+
const hooksDir = path.join(claudeDir, 'hooks');
|
|
54
|
+
if (await fs.pathExists(hooksSrc)) {
|
|
55
|
+
await fs.ensureDir(hooksDir);
|
|
56
|
+
await fs.copy(hooksSrc, hooksDir);
|
|
57
|
+
}
|
|
58
|
+
// Copy settings files
|
|
59
|
+
const settingsSrc = path.join(TEMPLATES_DIR, 'settings');
|
|
60
|
+
if (await fs.pathExists(settingsSrc)) {
|
|
61
|
+
const files = await fs.readdir(settingsSrc);
|
|
62
|
+
for (const file of files) {
|
|
63
|
+
await fs.copy(path.join(settingsSrc, file), path.join(claudeDir, file));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Copy components
|
|
67
|
+
onProgress('scaffolding', 60, 'components');
|
|
68
|
+
const componentsSrc = path.join(TEMPLATES_DIR, 'components');
|
|
69
|
+
const componentsDir = path.join(targetDir, 'src', 'components');
|
|
70
|
+
if (await fs.pathExists(componentsSrc)) {
|
|
71
|
+
await fs.ensureDir(componentsDir);
|
|
72
|
+
await fs.copy(componentsSrc, componentsDir);
|
|
73
|
+
}
|
|
74
|
+
// Copy context
|
|
75
|
+
onProgress('scaffolding', 65, 'context');
|
|
76
|
+
const contextSrc = path.join(TEMPLATES_DIR, 'context');
|
|
77
|
+
const contextDir = path.join(targetDir, 'src', 'context');
|
|
78
|
+
if (await fs.pathExists(contextSrc)) {
|
|
79
|
+
await fs.ensureDir(contextDir);
|
|
80
|
+
await fs.copy(contextSrc, contextDir);
|
|
81
|
+
}
|
|
82
|
+
// Copy lib
|
|
83
|
+
const libSrc = path.join(TEMPLATES_DIR, 'lib');
|
|
84
|
+
const libDir = path.join(targetDir, 'src', 'lib');
|
|
85
|
+
if (await fs.pathExists(libSrc)) {
|
|
86
|
+
await fs.ensureDir(libDir);
|
|
87
|
+
await fs.copy(libSrc, libDir);
|
|
88
|
+
}
|
|
89
|
+
// Copy types
|
|
90
|
+
const typesSrc = path.join(TEMPLATES_DIR, 'types');
|
|
91
|
+
const typesDir = path.join(targetDir, 'src', 'types');
|
|
92
|
+
if (await fs.pathExists(typesSrc)) {
|
|
93
|
+
await fs.ensureDir(typesDir);
|
|
94
|
+
await fs.copy(typesSrc, typesDir);
|
|
95
|
+
}
|
|
96
|
+
// Copy homepage or create blank App
|
|
97
|
+
onProgress('scaffolding', 70, 'pages');
|
|
98
|
+
const pagesDir = path.join(targetDir, 'src', 'pages');
|
|
99
|
+
await fs.ensureDir(pagesDir);
|
|
100
|
+
if (choices.includeHomepage) {
|
|
101
|
+
const homepageSrc = path.join(TEMPLATES_DIR, 'homepage');
|
|
102
|
+
if (await fs.pathExists(homepageSrc)) {
|
|
103
|
+
await fs.copy(homepageSrc, pagesDir);
|
|
104
|
+
}
|
|
105
|
+
// Copy the full App.tsx that includes routing
|
|
106
|
+
const appSrc = path.join(TEMPLATES_DIR, 'app', 'App.tsx');
|
|
107
|
+
if (await fs.pathExists(appSrc)) {
|
|
108
|
+
await fs.copy(appSrc, path.join(targetDir, 'src', 'App.tsx'));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Create blank App.tsx
|
|
113
|
+
const blankApp = `export default function App() {
|
|
114
|
+
return (
|
|
115
|
+
<div className="min-h-dvh bg-base-100 text-base-content flex items-center justify-center">
|
|
116
|
+
<h1 className="text-2xl font-bold">Your mass of pixels starts here.</h1>
|
|
117
|
+
</div>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
`;
|
|
121
|
+
await fs.writeFile(path.join(targetDir, 'src', 'App.tsx'), blankApp);
|
|
122
|
+
// Create blank NotFoundPage
|
|
123
|
+
const notFound = `import { Link } from 'react-router-dom'
|
|
124
|
+
|
|
125
|
+
export function NotFoundPage() {
|
|
126
|
+
return (
|
|
127
|
+
<div className="min-h-dvh bg-base-100 text-base-content flex items-center justify-center px-6">
|
|
128
|
+
<div className="text-center max-w-md">
|
|
129
|
+
<h1 className="text-6xl font-bold mb-4">404</h1>
|
|
130
|
+
<p className="text-xl text-base-content/70 mb-8">
|
|
131
|
+
This page doesn't exist.
|
|
132
|
+
</p>
|
|
133
|
+
<Link to="/" className="btn btn-primary">
|
|
134
|
+
Back to home
|
|
135
|
+
</Link>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
`;
|
|
141
|
+
await fs.writeFile(path.join(pagesDir, 'NotFoundPage.tsx'), notFound);
|
|
142
|
+
}
|
|
143
|
+
// Update package.json with project name
|
|
144
|
+
onProgress('scaffolding', 80, 'package.json');
|
|
145
|
+
const pkgPath = path.join(targetDir, 'package.json');
|
|
146
|
+
if (await fs.pathExists(pkgPath)) {
|
|
147
|
+
const pkg = await fs.readJson(pkgPath);
|
|
148
|
+
pkg.name = choices.projectName;
|
|
149
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
150
|
+
}
|
|
151
|
+
// Copy main.tsx
|
|
152
|
+
const mainSrc = path.join(TEMPLATES_DIR, 'main.tsx');
|
|
153
|
+
if (await fs.pathExists(mainSrc)) {
|
|
154
|
+
await fs.copy(mainSrc, path.join(targetDir, 'src', 'main.tsx'));
|
|
155
|
+
}
|
|
156
|
+
// Copy index.css
|
|
157
|
+
const cssSrc = path.join(TEMPLATES_DIR, 'index.css');
|
|
158
|
+
if (await fs.pathExists(cssSrc)) {
|
|
159
|
+
await fs.copy(cssSrc, path.join(targetDir, 'src', 'index.css'));
|
|
160
|
+
}
|
|
161
|
+
// Copy vite-env.d.ts
|
|
162
|
+
const viteSrc = path.join(TEMPLATES_DIR, 'vite-env.d.ts');
|
|
163
|
+
if (await fs.pathExists(viteSrc)) {
|
|
164
|
+
await fs.copy(viteSrc, path.join(targetDir, 'src', 'vite-env.d.ts'));
|
|
165
|
+
}
|
|
166
|
+
onProgress('scaffolding', 100, 'done');
|
|
167
|
+
// Install dependencies
|
|
168
|
+
onProgress('dependencies', 0, 'bun install');
|
|
169
|
+
try {
|
|
170
|
+
execSync('bun install', { cwd: targetDir, stdio: 'pipe' });
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
throw new Error('INSTALL_FAILED');
|
|
174
|
+
}
|
|
175
|
+
onProgress('dependencies', 100, 'done');
|
|
176
|
+
// Git init
|
|
177
|
+
if (choices.initGit) {
|
|
178
|
+
onProgress('git init', 0, '.git/');
|
|
179
|
+
try {
|
|
180
|
+
execSync('git init', { cwd: targetDir, stdio: 'pipe' });
|
|
181
|
+
execSync('git add .', { cwd: targetDir, stdio: 'pipe' });
|
|
182
|
+
execSync('git commit -m "init: claudecraft scaffolding"', {
|
|
183
|
+
cwd: targetDir,
|
|
184
|
+
stdio: 'pipe',
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// Git init failed, not critical
|
|
189
|
+
}
|
|
190
|
+
onProgress('git init', 100, 'done');
|
|
191
|
+
}
|
|
192
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
193
|
+
const files = await countFiles(targetDir);
|
|
194
|
+
const diskUsage = await getDiskUsage(targetDir);
|
|
195
|
+
return {
|
|
196
|
+
files,
|
|
197
|
+
skills: choices.selectedSkills.length,
|
|
198
|
+
commands: 6,
|
|
199
|
+
time: `${elapsed}s`,
|
|
200
|
+
deps: 24,
|
|
201
|
+
disk: diskUsage,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Initialize claudecraft in an existing project
|
|
206
|
+
* Only adds .claude folder with skills, commands, hooks, settings
|
|
207
|
+
*/
|
|
208
|
+
export async function initExisting(choices, onProgress) {
|
|
209
|
+
const startTime = Date.now();
|
|
210
|
+
const targetDir = process.cwd();
|
|
211
|
+
// Ensure .claude directories exist
|
|
212
|
+
onProgress('scaffolding', 10, '.claude/');
|
|
213
|
+
const claudeDir = path.join(targetDir, '.claude');
|
|
214
|
+
const skillsDir = path.join(claudeDir, 'skills');
|
|
215
|
+
const commandsDir = path.join(claudeDir, 'commands');
|
|
216
|
+
await fs.ensureDir(skillsDir);
|
|
217
|
+
await fs.ensureDir(commandsDir);
|
|
218
|
+
// Copy selected skills
|
|
219
|
+
onProgress('scaffolding', 30, 'skills');
|
|
220
|
+
for (const skillName of choices.selectedSkills) {
|
|
221
|
+
const skill = SKILLS.find((s) => s.name === skillName);
|
|
222
|
+
if (!skill)
|
|
223
|
+
continue;
|
|
224
|
+
// Try workflow first, then design
|
|
225
|
+
let sourceDir = path.join(TEMPLATES_DIR, 'skills', 'workflow', skillName);
|
|
226
|
+
if (!(await fs.pathExists(sourceDir))) {
|
|
227
|
+
sourceDir = path.join(TEMPLATES_DIR, 'skills', 'design', skillName);
|
|
228
|
+
}
|
|
229
|
+
if (await fs.pathExists(sourceDir)) {
|
|
230
|
+
await fs.copy(sourceDir, path.join(skillsDir, skillName));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// Copy commands
|
|
234
|
+
onProgress('scaffolding', 50, 'commands');
|
|
235
|
+
const commandsSrc = path.join(TEMPLATES_DIR, 'commands');
|
|
236
|
+
if (await fs.pathExists(commandsSrc)) {
|
|
237
|
+
await fs.copy(commandsSrc, commandsDir);
|
|
238
|
+
}
|
|
239
|
+
// Copy hooks
|
|
240
|
+
onProgress('scaffolding', 70, 'hooks');
|
|
241
|
+
const hooksSrc = path.join(TEMPLATES_DIR, 'hooks');
|
|
242
|
+
const hooksDir = path.join(claudeDir, 'hooks');
|
|
243
|
+
if (await fs.pathExists(hooksSrc)) {
|
|
244
|
+
await fs.ensureDir(hooksDir);
|
|
245
|
+
await fs.copy(hooksSrc, hooksDir);
|
|
246
|
+
}
|
|
247
|
+
// Copy settings files
|
|
248
|
+
onProgress('scaffolding', 85, 'settings');
|
|
249
|
+
const settingsSrc = path.join(TEMPLATES_DIR, 'settings');
|
|
250
|
+
if (await fs.pathExists(settingsSrc)) {
|
|
251
|
+
const files = await fs.readdir(settingsSrc);
|
|
252
|
+
for (const file of files) {
|
|
253
|
+
const destPath = path.join(claudeDir, file);
|
|
254
|
+
// Don't overwrite existing settings
|
|
255
|
+
if (!(await fs.pathExists(destPath))) {
|
|
256
|
+
await fs.copy(path.join(settingsSrc, file), destPath);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Create or update CLAUDE.md if it doesn't exist
|
|
261
|
+
const claudeMdPath = path.join(targetDir, 'CLAUDE.md');
|
|
262
|
+
if (!(await fs.pathExists(claudeMdPath))) {
|
|
263
|
+
const claudeMdSrc = path.join(TEMPLATES_DIR, 'base', 'CLAUDE.md');
|
|
264
|
+
if (await fs.pathExists(claudeMdSrc)) {
|
|
265
|
+
await fs.copy(claudeMdSrc, claudeMdPath);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
onProgress('scaffolding', 100, 'done');
|
|
269
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
270
|
+
const claudeFiles = await countFiles(claudeDir);
|
|
271
|
+
return {
|
|
272
|
+
files: claudeFiles,
|
|
273
|
+
skills: choices.selectedSkills.length,
|
|
274
|
+
commands: 7,
|
|
275
|
+
time: `${elapsed}s`,
|
|
276
|
+
deps: 0,
|
|
277
|
+
disk: '~500kb',
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
async function countFiles(dir) {
|
|
281
|
+
let count = 0;
|
|
282
|
+
const items = await fs.readdir(dir, { withFileTypes: true });
|
|
283
|
+
for (const item of items) {
|
|
284
|
+
if (item.name === 'node_modules' || item.name === '.git')
|
|
285
|
+
continue;
|
|
286
|
+
if (item.isDirectory()) {
|
|
287
|
+
count += await countFiles(path.join(dir, item.name));
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
count++;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return count;
|
|
294
|
+
}
|
|
295
|
+
async function getDiskUsage(dir) {
|
|
296
|
+
try {
|
|
297
|
+
const result = execSync(`du -sh "${dir}" | cut -f1`, { encoding: 'utf-8' });
|
|
298
|
+
return result.trim();
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
return '~4mb';
|
|
302
|
+
}
|
|
303
|
+
}
|
package/dist/ui.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare function renderHeader(): string;
|
|
2
|
+
export declare function renderManifest(): string;
|
|
3
|
+
export declare function renderMiniHeader(_step?: number, _total?: number): string;
|
|
4
|
+
export declare function renderStepHeader(step: number, total: number, _title: string, _required?: boolean): string;
|
|
5
|
+
export declare function renderStepFooter(): string;
|
|
6
|
+
export declare function renderSpecs(specs: Array<{
|
|
7
|
+
label: string;
|
|
8
|
+
value: string;
|
|
9
|
+
}>): string;
|
|
10
|
+
export declare function renderAnnotation(text: string): string;
|
|
11
|
+
export declare function renderError(title: string, body: string): string;
|
|
12
|
+
export interface ProgressTask {
|
|
13
|
+
name: string;
|
|
14
|
+
status: 'done' | 'active' | 'queued';
|
|
15
|
+
progress?: number;
|
|
16
|
+
time?: string;
|
|
17
|
+
detail?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function renderProgress(tasks: ProgressTask[]): string;
|
|
20
|
+
export declare function renderProgressFooter(elapsed: string, _eta: string): string;
|
|
21
|
+
export declare function renderComplete(projectName: string, stats: Record<string, string | number>): string;
|
|
22
|
+
export declare function renderInitComplete(stats: {
|
|
23
|
+
files: number;
|
|
24
|
+
skills: number;
|
|
25
|
+
commands: number;
|
|
26
|
+
time: string;
|
|
27
|
+
}): string;
|
package/dist/ui.js
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import figlet from 'figlet';
|
|
2
|
+
import gradient from 'gradient-string';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import { TAGLINE, STACK, ASSETS, DEFAULT_THEME, DEFAULT_PORT, VERSION } from './constants.js';
|
|
5
|
+
// Split gradients for two-line logo
|
|
6
|
+
const claudeGradient = gradient(['#00ff9f', '#00b8ff']); // Green → Cyan (fresh)
|
|
7
|
+
const craftGradient = gradient(['#a855f7', '#6d28d9']); // Purple → Violet (deep)
|
|
8
|
+
// Generate ASCII art for each word separately
|
|
9
|
+
const asciiClaude = figlet.textSync('CLAUDE', { font: 'ANSI Shadow', horizontalLayout: 'fitted' });
|
|
10
|
+
const asciiCraft = figlet.textSync('CRAFT', { font: 'ANSI Shadow', horizontalLayout: 'fitted' });
|
|
11
|
+
// Get today's date for the revision block
|
|
12
|
+
const today = new Date().toISOString().split('T')[0].replace(/-/g, '.');
|
|
13
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
14
|
+
// ALIGNMENT: Frame width = 76 chars exactly
|
|
15
|
+
// Normal row: " │ │ " (7) + content (66) + "│ │" (3) = 76
|
|
16
|
+
// CAP HT row: " │ │ " (7) + content (58) + "│◀┼─ CAP HT" (11) = 76
|
|
17
|
+
// BASELINE row: " │ │ " (7) + content (56) + "│◀┼─ BASELINE" (13) = 76
|
|
18
|
+
// ASCII art: CLAUDE=49 chars, CRAFT=41 chars
|
|
19
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
20
|
+
const FRAME = 76;
|
|
21
|
+
const PREFIX = ' │ │ '; // 7 chars
|
|
22
|
+
const SUFFIX = '│ │'; // 3 chars
|
|
23
|
+
const INNER = 66; // Normal content width
|
|
24
|
+
// Pad content to exact width (strips ANSI codes for length calc)
|
|
25
|
+
const padTo = (line, width) => {
|
|
26
|
+
const visible = line.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
27
|
+
return line + ' '.repeat(Math.max(0, width - visible));
|
|
28
|
+
};
|
|
29
|
+
// Build a normal row: prefix(7) + content(66) + suffix(3) = 76 chars
|
|
30
|
+
const row = (content) => {
|
|
31
|
+
return `${pc.dim(PREFIX)}${padTo(content, INNER)}${pc.dim(SUFFIX)}`;
|
|
32
|
+
};
|
|
33
|
+
// Build a callout row with specific suffix
|
|
34
|
+
const calloutRow = (content, suffix) => {
|
|
35
|
+
const contentWidth = FRAME - PREFIX.length - suffix.length;
|
|
36
|
+
return `${pc.dim(PREFIX)}${padTo(content, contentWidth)}${pc.dim(suffix)}`;
|
|
37
|
+
};
|
|
38
|
+
export function renderHeader() {
|
|
39
|
+
// Apply gradients and filter empty lines
|
|
40
|
+
const claudeLines = claudeGradient(asciiClaude).split('\n').filter(l => l.trim());
|
|
41
|
+
const craftLines = craftGradient(asciiCraft).split('\n').filter(l => l.trim());
|
|
42
|
+
const lines = [];
|
|
43
|
+
// ═══ TOP FRAME (76 chars) ════════════════════════════════════════════════
|
|
44
|
+
// " ⊕" (3) + "─┬" (2) + dashes (68) + "┬─" (2) + "⊕" (1) = 76
|
|
45
|
+
lines.push(pc.cyan(' ⊕') + pc.dim('─┬' + '─'.repeat(68) + '┬─') + pc.cyan('⊕'));
|
|
46
|
+
// " │ ◀" (7) + dashes (28) + " 72 COLS " (9) + dashes (28) + "▶ │" (4) = 76
|
|
47
|
+
lines.push(pc.dim(' │ ◀' + '─'.repeat(28) + ' 72 COLS ' + '─'.repeat(28) + '▶ │ '));
|
|
48
|
+
// " ┌─┼" (5) + dashes (68) + "┼─┐" (3) = 76
|
|
49
|
+
lines.push(pc.dim(' ┌─┼' + '─'.repeat(68) + '┼─┐'));
|
|
50
|
+
// ═══ CONTENT AREA ════════════════════════════════════════════════════════
|
|
51
|
+
// Ruler
|
|
52
|
+
lines.push(row('┆ · · · · ┆ · · · · ┆ · · · · ┆ · · · · ┆ · · · · ┆ · · · · ┆ ·'));
|
|
53
|
+
// CLAUDE with CAP HT callout on first line
|
|
54
|
+
claudeLines.forEach((line, i) => {
|
|
55
|
+
if (i === 0) {
|
|
56
|
+
lines.push(calloutRow(line, '│◀┼─ CAP HT'));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
lines.push(row(line));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
// Baseline separator (content = 76 - 7 - 13 = 56, so 53 dashes + 2 for ├┤ = 55)
|
|
63
|
+
lines.push(calloutRow('├' + '─'.repeat(53) + '┤', '│◀┼─ BASELINE'));
|
|
64
|
+
// CRAFT
|
|
65
|
+
craftLines.forEach((line) => {
|
|
66
|
+
lines.push(row(line));
|
|
67
|
+
});
|
|
68
|
+
// Measurement ruler
|
|
69
|
+
lines.push(row('0 10 20 30 40 50 60'));
|
|
70
|
+
// ═══ BOTTOM FRAME (76 chars) ══════════════════════════════════════════════
|
|
71
|
+
// " └─┼" (5) + dashes (68) + "┼─┘" (3) = 76
|
|
72
|
+
lines.push(pc.dim(' └─┼' + '─'.repeat(68) + '┼─┘'));
|
|
73
|
+
// CMYK bar + revision block (76 chars)
|
|
74
|
+
// " │ " (7) + "■ C ■ M ■ Y ■ K" (18) + spaces (11) + rev (37) + " │" (3) = 76
|
|
75
|
+
const cmyk = pc.cyan('■') + pc.dim(' C ') + pc.magenta('■') + pc.dim(' M ') + pc.yellow('■') + pc.dim(' Y ') + pc.white('■') + pc.dim(' K');
|
|
76
|
+
const rev = pc.green(`REV ${VERSION}`) + pc.dim(` │ ${today} │ `) + pc.yellow('WORKS ON MAC');
|
|
77
|
+
lines.push(pc.dim(' │ ') + cmyk + pc.dim(' ') + rev + pc.dim(' │'));
|
|
78
|
+
// Bottom registration marks: " ⊕" (3) + "─┴" (2) + dashes (68) + "┴─" (2) + "⊕" (1) = 76
|
|
79
|
+
lines.push(pc.cyan(' ⊕') + pc.dim('─┴' + '─'.repeat(68) + '┴─') + pc.cyan('⊕'));
|
|
80
|
+
return '\n' + lines.join('\n') + '\n';
|
|
81
|
+
}
|
|
82
|
+
export function renderManifest() {
|
|
83
|
+
// Frame = 76 chars exactly
|
|
84
|
+
// Structure: " │ " (4) + content (70) + " │" (2) = 76
|
|
85
|
+
// 3-col data: col1 (22) + " │ " (3) + col2 (20) + " │ " (3) + col3 (22) = 70 ✓
|
|
86
|
+
const p = (s, len) => s.padEnd(len);
|
|
87
|
+
const D = pc.dim;
|
|
88
|
+
// Column builders: label + value, totaling exact width
|
|
89
|
+
const col1 = (label, value) => `${D(p(label, 11))}${pc.cyan(p(value, 11))}`; // 22 chars
|
|
90
|
+
const col2 = (label, value) => `${D(p(label, 10))}${pc.cyan(p(value, 10))}`; // 20 chars
|
|
91
|
+
const col3 = (label, value) => `${D(p(label, 10))}${pc.cyan(p(value, 12))}`; // 22 chars
|
|
92
|
+
// Header dividers: ─ sections must match column widths + frame chars
|
|
93
|
+
// col1 section: "─── STACK " (10) + 14 dashes = 24 (for 22 + " │" = 25... wait)
|
|
94
|
+
// Actually: between ├ and first ┬ = col1(22) + " " (1) = 23, plus ─'s for label
|
|
95
|
+
// Let me just hardcode the exact strings that work
|
|
96
|
+
const lines = [
|
|
97
|
+
` ${D('╭' + '─'.repeat(72) + '╮')}`,
|
|
98
|
+
` ${D('│')} ${D('SPECS ·')} ${p(TAGLINE, 63)}${D('│')}`,
|
|
99
|
+
` ${D('├─── STACK ────────────────┬─── ASSETS ────────────┬─── DEFAULTS ────────┤')}`,
|
|
100
|
+
` ${D('│')} ${col1('react', STACK.react)} ${D('│')} ${col2('skills', String(ASSETS.skills))} ${D('│')} ${col3('theme', DEFAULT_THEME)} ${D('│')}`,
|
|
101
|
+
` ${D('│')} ${col1('typescript', STACK.typescript)} ${D('│')} ${col2('commands', String(ASSETS.commands))} ${D('│')} ${col3('port', String(DEFAULT_PORT))} ${D('│')}`,
|
|
102
|
+
` ${D('│')} ${col1('vite', STACK.vite)} ${D('│')} ${col2('themes', String(ASSETS.themes))} ${D('│')} ${col3('tests', 'vitest')} ${D('│')}`,
|
|
103
|
+
` ${D('│')} ${col1('tailwind', STACK.tailwind)} ${D('│')} ${col2('hooks', String(ASSETS.hooks))} ${D('│')} ${col3('pkg', 'bun')} ${D('│')}`,
|
|
104
|
+
` ${D('│')} ${col1('daisyui', STACK.daisyui)} ${D('│')} ${col2('comps', String(ASSETS.components))} ${D('│')} ${col3('license', 'MIT')} ${D('│')}`,
|
|
105
|
+
` ${D('├──────────────────────────┴────────────────────────┴────────────────────┤')}`,
|
|
106
|
+
` ${D('│')} ${D('~48 files · 0 deps ·')} ${pc.cyan('/help')} ${D('for existential guidance')} ${D('│')}`,
|
|
107
|
+
` ${D('╰' + '─'.repeat(72) + '╯')}`,
|
|
108
|
+
];
|
|
109
|
+
return '\n' + lines.join('\n');
|
|
110
|
+
}
|
|
111
|
+
export function renderMiniHeader(_step, _total) {
|
|
112
|
+
// Condensed ASCII logo with measurement tick - split gradient
|
|
113
|
+
const logoGradient = gradient(['#00ff9f', '#00b8ff', '#a855f7', '#6d28d9']);
|
|
114
|
+
const logo = logoGradient('▓▒░ CLAUDECRAFT');
|
|
115
|
+
const tick = pc.dim('┆');
|
|
116
|
+
return `
|
|
117
|
+
${tick} ${logo} ${pc.dim(`v${VERSION}`)} ${tick}
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
export function renderStepHeader(step, total, _title, _required = false) {
|
|
121
|
+
return renderMiniHeader(step, total);
|
|
122
|
+
}
|
|
123
|
+
export function renderStepFooter() {
|
|
124
|
+
return '';
|
|
125
|
+
}
|
|
126
|
+
export function renderSpecs(specs) {
|
|
127
|
+
return specs.map((s) => ` ${pc.dim('│')} ${pc.dim(s.label + ':')} ${s.value}`).join('\n');
|
|
128
|
+
}
|
|
129
|
+
export function renderAnnotation(text) {
|
|
130
|
+
return ` ${pc.dim('│')} ${pc.dim(text)}`;
|
|
131
|
+
}
|
|
132
|
+
export function renderError(title, body) {
|
|
133
|
+
return `
|
|
134
|
+
${pc.dim('╭─── ERROR ────────────────────────────────────────────────────────────╮')}
|
|
135
|
+
${pc.dim('│')} ${pc.red('✗')} ${pc.bold(pc.red(title))}
|
|
136
|
+
${pc.dim('├─────────────────────────────────────────────────────────────────────┤')}
|
|
137
|
+
${body
|
|
138
|
+
.split('\n')
|
|
139
|
+
.map((line) => ` ${pc.dim('│')} ${line}`)
|
|
140
|
+
.join('\n')}
|
|
141
|
+
${pc.dim('╰─────────────────────────────────────────────────────────────────────╯')}
|
|
142
|
+
`;
|
|
143
|
+
}
|
|
144
|
+
export function renderProgress(tasks) {
|
|
145
|
+
const lines = tasks.map((t, i) => {
|
|
146
|
+
const width = 24;
|
|
147
|
+
let bar = '';
|
|
148
|
+
let statusText = '';
|
|
149
|
+
const lineNum = pc.dim(`${String(i + 1).padStart(2)}`);
|
|
150
|
+
if (t.status === 'done') {
|
|
151
|
+
bar = pc.green('█'.repeat(width));
|
|
152
|
+
statusText = pc.green('✓ done');
|
|
153
|
+
}
|
|
154
|
+
else if (t.status === 'active') {
|
|
155
|
+
const filled = Math.floor(((t.progress || 0) / 100) * width);
|
|
156
|
+
// Animated-looking bar with gradient feel
|
|
157
|
+
bar = pc.cyan('▓'.repeat(filled)) + pc.dim('░'.repeat(width - filled));
|
|
158
|
+
statusText = pc.yellow(`◐ ${t.progress}%`);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
bar = pc.dim('·'.repeat(width));
|
|
162
|
+
statusText = pc.dim('○ waiting');
|
|
163
|
+
}
|
|
164
|
+
const detail = t.detail ? pc.dim(` ${t.detail}`) : '';
|
|
165
|
+
return ` ${pc.dim('│')} ${lineNum} ${t.name.padEnd(12)} ${bar} ${statusText.padEnd(10)}${detail}`;
|
|
166
|
+
});
|
|
167
|
+
return `
|
|
168
|
+
${pc.dim('╭─── PROGRESS ─────────────────────────────────────────────────────────╮')}
|
|
169
|
+
${lines.join('\n')}
|
|
170
|
+
${pc.dim('├─────────────────────────────────────────────────────────────────────┤')}`;
|
|
171
|
+
}
|
|
172
|
+
export function renderProgressFooter(elapsed, _eta) {
|
|
173
|
+
return ` ${pc.dim('│')} elapsed: ${elapsed}
|
|
174
|
+
${pc.dim('╰─────────────────────────────────────────────────────────────────────╯')}
|
|
175
|
+
`;
|
|
176
|
+
}
|
|
177
|
+
export function renderComplete(projectName, stats) {
|
|
178
|
+
// Existential dread for designers
|
|
179
|
+
const dread = [
|
|
180
|
+
"The blank canvas awaits. It judges you silently.",
|
|
181
|
+
"You wanted this. Remember that when it's 3am.",
|
|
182
|
+
"The cursor blinks. It will outlast us all.",
|
|
183
|
+
"Another project. Another chance to mass Cmd+Z.",
|
|
184
|
+
"Ship it before the doubt sets in.",
|
|
185
|
+
"The robots built this. You still have to design it.",
|
|
186
|
+
"Perfection is the enemy. So is that deadline.",
|
|
187
|
+
"It works on localhost. That's something.",
|
|
188
|
+
"Congratulations. You've automated your anxiety.",
|
|
189
|
+
"The PRD was 'make it pop'. Good luck.",
|
|
190
|
+
"Your taste exceeds your velocity. As always.",
|
|
191
|
+
"Claude believes in you. Claude is wrong sometimes.",
|
|
192
|
+
"27 skills. 0 excuses.",
|
|
193
|
+
"The slop awaits your curation.",
|
|
194
|
+
"localhost:6969. Nice.",
|
|
195
|
+
];
|
|
196
|
+
const randomDread = dread[Math.floor(Math.random() * dread.length)];
|
|
197
|
+
// Stats with units for designer feel
|
|
198
|
+
const filesVal = String(stats.files).padEnd(4);
|
|
199
|
+
const skillsVal = String(stats.skills).padEnd(4);
|
|
200
|
+
const timeVal = String(stats.time).padEnd(6);
|
|
201
|
+
return `
|
|
202
|
+
${pc.dim('╭─── COMPLETE ─────────────────────────────────────────────────────────╮')}
|
|
203
|
+
${pc.dim('│')} ${pc.green('✓')} ${pc.bold('Ready')} ${pc.dim('·')} ${pc.dim(randomDread)}
|
|
204
|
+
${pc.dim('├─── NEXT ─────────────────────────────────────────────────────────────┤')}
|
|
205
|
+
${pc.dim('│')} ${pc.dim('01')} ${pc.cyan('$')} cd ${projectName}
|
|
206
|
+
${pc.dim('│')} ${pc.dim('02')} ${pc.cyan('$')} bun dev
|
|
207
|
+
${pc.dim('│')} ${pc.dim('03')} ${pc.cyan('$')} open http://localhost:${DEFAULT_PORT}
|
|
208
|
+
${pc.dim('├─── STATS ────────────────────────────────────────────────────────────┤')}
|
|
209
|
+
${pc.dim('│')} files ${filesVal} ${pc.dim('│')} skills ${skillsVal} ${pc.dim('│')} time ${timeVal} ${pc.dim('│')} deps 0
|
|
210
|
+
${pc.dim('├─── COMMANDS ─────────────────────────────────────────────────────────┤')}
|
|
211
|
+
${pc.dim('│')} ${pc.cyan('/build')} ${pc.dim('compile and hope')}
|
|
212
|
+
${pc.dim('│')} ${pc.cyan('/brainstorm')} ${pc.dim('poke holes in your ideas')}
|
|
213
|
+
${pc.dim('│')} ${pc.cyan('/ralph')} ${pc.dim('sleep while Claude ships')}
|
|
214
|
+
${pc.dim('│')} ${pc.cyan('/write-plan')} ${pc.dim('think before you regret')}
|
|
215
|
+
${pc.dim('├─────────────────────────────────────────────────────────────────────┤')}
|
|
216
|
+
${pc.dim('│')} ${pc.dim('github.com/raduceuca/claudecraft')} ${pc.dim('·')} ${pc.dim('MIT')} ${pc.dim('·')} ${pc.dim(`v${VERSION}`)}
|
|
217
|
+
${pc.dim('╰─────────────────────────────────────────────────────────────────────╯')}
|
|
218
|
+
`;
|
|
219
|
+
}
|
|
220
|
+
export function renderInitComplete(stats) {
|
|
221
|
+
// Existential dread for existing projects
|
|
222
|
+
const dread = [
|
|
223
|
+
"Your existing chaos now has structure. Briefly.",
|
|
224
|
+
"The slop has been organized. Alphabetically, even.",
|
|
225
|
+
"Claude will remember this project. Unfortunately.",
|
|
226
|
+
"Skills injected. Side effects may include productivity.",
|
|
227
|
+
".claude/ added. Your git diff weeps.",
|
|
228
|
+
"Now Claude knows your codebase. Be afraid.",
|
|
229
|
+
"Legacy code meets AI. Pray.",
|
|
230
|
+
"27 guardrails installed. You're still the driver.",
|
|
231
|
+
"Your technical debt now has company.",
|
|
232
|
+
];
|
|
233
|
+
const randomDread = dread[Math.floor(Math.random() * dread.length)];
|
|
234
|
+
return `
|
|
235
|
+
${pc.dim('╭─── INIT COMPLETE ────────────────────────────────────────────────────╮')}
|
|
236
|
+
${pc.dim('│')} ${pc.green('✓')} ${pc.bold('Skills injected')} ${pc.dim('·')} ${pc.dim(randomDread)}
|
|
237
|
+
${pc.dim('├─── ADDED ────────────────────────────────────────────────────────────┤')}
|
|
238
|
+
${pc.dim('│')} .claude/skills/ ${pc.dim(`${stats.skills} skills`)}
|
|
239
|
+
${pc.dim('│')} .claude/commands/ ${pc.dim(`${stats.commands} commands`)}
|
|
240
|
+
${pc.dim('│')} .claude/hooks/ ${pc.dim('2 hooks')}
|
|
241
|
+
${pc.dim('│')} .claude/settings/ ${pc.dim('config + MCP guide')}
|
|
242
|
+
${pc.dim('│')} CLAUDE.md ${pc.dim('project context (if missing)')}
|
|
243
|
+
${pc.dim('├─── FIGMA INTEGRATION ────────────────────────────────────────────────┤')}
|
|
244
|
+
${pc.dim('│')} ${pc.cyan('$')} claude mcp add --transport http figma https://mcp.figma.com/mcp
|
|
245
|
+
${pc.dim('│')} ${pc.dim('Then /mcp → figma → Authenticate')}
|
|
246
|
+
${pc.dim('├─── STATS ────────────────────────────────────────────────────────────┤')}
|
|
247
|
+
${pc.dim('│')} files ${String(stats.files).padEnd(4)} ${pc.dim('│')} skills ${String(stats.skills).padEnd(4)} ${pc.dim('│')} time ${stats.time}
|
|
248
|
+
${pc.dim('├─── NEXT ─────────────────────────────────────────────────────────────┤')}
|
|
249
|
+
${pc.dim('│')} ${pc.cyan('/brainstorm')} ${pc.dim('start a conversation')}
|
|
250
|
+
${pc.dim('│')} ${pc.cyan('/write-plan')} ${pc.dim('plan before building')}
|
|
251
|
+
${pc.dim('│')} ${pc.dim('See .claude/settings/MCP_SETUP.md for more integrations')}
|
|
252
|
+
${pc.dim('╰─────────────────────────────────────────────────────────────────────╯')}
|
|
253
|
+
`;
|
|
254
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-claudecraft",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Designer-first boilerplate for Claude Code. 27 skills, 7 commands, 32 themes. The robots are here.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-claudecraft": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"dist",
|
|
12
|
+
"templates",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"dev": "tsc --watch",
|
|
18
|
+
"start": "node bin/cli.js",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"claude",
|
|
23
|
+
"claude-code",
|
|
24
|
+
"ai",
|
|
25
|
+
"boilerplate",
|
|
26
|
+
"react",
|
|
27
|
+
"typescript",
|
|
28
|
+
"tailwind",
|
|
29
|
+
"daisyui",
|
|
30
|
+
"create",
|
|
31
|
+
"cli",
|
|
32
|
+
"designer",
|
|
33
|
+
"vite",
|
|
34
|
+
"bun",
|
|
35
|
+
"anthropic",
|
|
36
|
+
"skills",
|
|
37
|
+
"agents"
|
|
38
|
+
],
|
|
39
|
+
"author": {
|
|
40
|
+
"name": "Radu Ceuca",
|
|
41
|
+
"url": "https://x.com/raduceuca"
|
|
42
|
+
},
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/raduceuca/claudecraft.git",
|
|
47
|
+
"directory": "create-claudecraft"
|
|
48
|
+
},
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/raduceuca/claudecraft/issues"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://claudecraft.dev",
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18.0.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/figlet": "^1.5.8",
|
|
58
|
+
"@types/fs-extra": "^11.0.4",
|
|
59
|
+
"@types/gradient-string": "^1.1.6",
|
|
60
|
+
"@types/node": "^20.11.0",
|
|
61
|
+
"typescript": "^5.3.3"
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@clack/prompts": "^0.7.0",
|
|
65
|
+
"figlet": "^1.7.0",
|
|
66
|
+
"fs-extra": "^11.2.0",
|
|
67
|
+
"gradient-string": "^2.0.2",
|
|
68
|
+
"ink": "^6.6.0",
|
|
69
|
+
"ink-select-input": "^6.2.0",
|
|
70
|
+
"ink-text-input": "^6.0.0",
|
|
71
|
+
"picocolors": "^1.0.0",
|
|
72
|
+
"react": "^19.2.3"
|
|
73
|
+
}
|
|
74
|
+
}
|