@editframe/create 0.46.2 → 0.47.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.d.ts CHANGED
@@ -1 +1,19 @@
1
- export { };
1
+ #!/usr/bin/env node
2
+ import { PackageManager } from "./utils.js";
3
+
4
+ //#region src/index.d.ts
5
+ interface SuccessOutputOptions {
6
+ directoryName: string;
7
+ pkgManager: PackageManager;
8
+ depsInstalled: boolean;
9
+ skillsInstalled: boolean;
10
+ }
11
+ declare function buildSuccessOutput({
12
+ directoryName,
13
+ pkgManager,
14
+ depsInstalled,
15
+ skillsInstalled
16
+ }: SuccessOutputOptions): string;
17
+ //#endregion
18
+ export { buildSuccessOutput };
19
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -8,6 +8,20 @@ import chalk from "chalk";
8
8
  import prompts from "prompts";
9
9
 
10
10
  //#region src/index.ts
11
+ function buildSuccessOutput({ directoryName, pkgManager, depsInstalled, skillsInstalled }) {
12
+ let output = "";
13
+ output += chalk.green.bold(`\n✓ ${directoryName} created\n`);
14
+ output += `\n${chalk.bold("Next Steps")}\n`;
15
+ output += ` ${chalk.cyan(`cd ${directoryName}`)}\n`;
16
+ if (!depsInstalled) output += ` ${chalk.cyan(`${pkgManager} install`)}\n`;
17
+ output += ` ${chalk.cyan(getStartCommand(pkgManager))}\n`;
18
+ if (skillsInstalled) {
19
+ output += `\n${chalk.green("✔")} ${chalk.bold("Agent Skills Installed")}\n`;
20
+ output += chalk.dim(` Ask your agent to "Make a video with editframe …"\n`);
21
+ }
22
+ output += "\n";
23
+ return output;
24
+ }
11
25
  function showHelp(templates) {
12
26
  const usage = `
13
27
  ${chalk.bold("Usage:")}
@@ -17,6 +31,7 @@ ${chalk.bold("Options:")}
17
31
  -d, --directory <name> Project directory name
18
32
  --skip-install Skip dependency installation
19
33
  --skip-skills Skip agent skills installation
34
+ -g, --global Install agent skills globally (~/.claude/skills, ~/.agents/skills)
20
35
  -y, --yes Skip all prompts, use defaults
21
36
  -h, --help Show this help message
22
37
 
@@ -33,6 +48,9 @@ ${chalk.bold("Examples:")}
33
48
  ${chalk.dim("# Full non-interactive")}
34
49
  npm create @editframe -- react -d my-app -y
35
50
 
51
+ ${chalk.dim("# Install skills globally")}
52
+ npm create @editframe -- react --global
53
+
36
54
  ${chalk.dim("# Skip auto-installation")}
37
55
  npm create @editframe -- react --skip-install --skip-skills
38
56
  `;
@@ -69,6 +87,11 @@ async function main() {
69
87
  type: "boolean",
70
88
  default: false
71
89
  },
90
+ global: {
91
+ type: "boolean",
92
+ short: "g",
93
+ default: false
94
+ },
72
95
  yes: {
73
96
  type: "boolean",
74
97
  short: "y",
@@ -85,6 +108,7 @@ async function main() {
85
108
  const cliDirectory = values.directory;
86
109
  const skipInstall = values.skipInstall;
87
110
  const skipSkills = values.skipSkills;
111
+ const cliGlobal = values.global;
88
112
  const nonInteractive = values.yes;
89
113
  if (cliTemplate && !templates.includes(cliTemplate)) {
90
114
  process.stderr.write(chalk.red(`Error: Template "${cliTemplate}" does not exist.\n\n`));
@@ -110,10 +134,17 @@ async function main() {
110
134
  }))
111
135
  });
112
136
  if (!skipSkills && !nonInteractive) promptQuestions.push({
113
- type: "confirm",
114
- name: "installSkills",
115
- message: "Install AI agent skills for better coding assistance?",
116
- initial: true
137
+ type: "select",
138
+ name: "skillsScope",
139
+ message: "Install AI agent skills?",
140
+ choices: [{
141
+ title: "Globally (all projects)",
142
+ value: "global"
143
+ }, {
144
+ title: "This project only",
145
+ value: "project"
146
+ }],
147
+ initial: 0
117
148
  });
118
149
  const answers = promptQuestions.length > 0 ? await prompts(promptQuestions) : {};
119
150
  if (!cliDirectory && !nonInteractive && !answers.directoryName || !cliTemplate && !nonInteractive && !answers.templateName) {
@@ -122,7 +153,9 @@ async function main() {
122
153
  }
123
154
  const directoryName = cliDirectory || answers.directoryName || "my-project";
124
155
  const templateName = cliTemplate || answers.templateName || templates[0];
125
- const installSkills = !skipSkills && (nonInteractive || answers.installSkills !== false);
156
+ const interactiveScope = answers.skillsScope;
157
+ const resolvedSkillsScope = cliGlobal ? "global" : interactiveScope ?? "global";
158
+ const installSkills = !skipSkills;
126
159
  const targetDir = path.join(process.cwd(), directoryName);
127
160
  const templateDir = path.join(__dirname, "templates", templateName);
128
161
  if (await checkDirectoryExists(targetDir)) {
@@ -143,35 +176,27 @@ async function main() {
143
176
  await cp(templateDir, targetDir, { recursive: true });
144
177
  const pkgManager = getUserPkgManager();
145
178
  let depsInstalled = false;
179
+ let depsError;
146
180
  let skillsInstalled = false;
147
- if (!skipInstall) depsInstalled = await installDependencies(targetDir);
148
- if (installSkills) skillsInstalled = await installAgentSkills(targetDir);
149
- process.stderr.write(chalk.green.bold("\n✓ Project created successfully!\n"));
150
- if (depsInstalled) process.stderr.write(chalk.green("✓ Dependencies installed\n"));
151
- if (skillsInstalled) process.stderr.write(chalk.green("✓ AI agent skills installed\n"));
152
- process.stderr.write(chalk.bold("\nYour project is ready! 🎉\n\n"));
153
- process.stderr.write(chalk.bold("Next steps:\n"));
154
- process.stderr.write(chalk.cyan(` cd ${directoryName}\n`));
155
- if (!depsInstalled) process.stderr.write(chalk.cyan(` ${pkgManager} install\n`));
156
- process.stderr.write(chalk.cyan(` ${getStartCommand(pkgManager)}\n`));
157
- if (skillsInstalled) {
158
- process.stderr.write(chalk.bold("\nAI Agent Skills installed:\n"));
159
- process.stderr.write(chalk.dim(" • editframe-composition\n"));
160
- process.stderr.write(chalk.dim(" • editframe-motion-design\n"));
161
- process.stderr.write(chalk.dim(" • editframe-brand-video-generator\n"));
162
- process.stderr.write(chalk.dim(" • editframe-editor-gui\n"));
163
- process.stderr.write(chalk.dim(" • editframe-vite-plugin\n"));
164
- process.stderr.write(chalk.dim(" • editframe-webhooks\n"));
165
- process.stderr.write(chalk.bold("\nTry asking your AI agent:\n"));
166
- process.stderr.write(chalk.dim(" \"Create a 5-second video with fade-in text\"\n"));
167
- process.stderr.write(chalk.dim(" \"Add a waveform visualization\"\n"));
168
- process.stderr.write(chalk.dim(" \"Animate this element with spring physics\"\n"));
181
+ if (!skipInstall) {
182
+ const result = await installDependencies(targetDir);
183
+ depsInstalled = result.ok;
184
+ depsError = result.errorOutput;
185
+ }
186
+ if (installSkills) skillsInstalled = await installAgentSkills(targetDir, resolvedSkillsScope);
187
+ if (depsError) {
188
+ process.stderr.write(chalk.yellow(`\n⚠ ${pkgManager} install failed\n\n`));
189
+ process.stderr.write(depsError + "\n");
169
190
  }
170
- process.stderr.write(chalk.dim("\nDocumentation: https://editframe.com/docs\n"));
171
- process.stderr.write(chalk.dim("Happy coding! 🎬\n\n"));
191
+ process.stderr.write(buildSuccessOutput({
192
+ directoryName,
193
+ pkgManager,
194
+ depsInstalled,
195
+ skillsInstalled
196
+ }));
172
197
  }
173
198
  main();
174
199
 
175
200
  //#endregion
176
- export { };
201
+ export { buildSuccessOutput };
177
202
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["path","promptQuestions: prompts.PromptObject[]"],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { access, cp, readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parseArgs } from \"node:util\";\nimport chalk from \"chalk\";\nimport prompts from \"prompts\";\nimport {\n getUserPkgManager,\n installDependencies,\n installAgentSkills,\n getStartCommand,\n} from \"./utils.js\";\n\nfunction showHelp(templates: string[]) {\n const usage = `\n${chalk.bold(\"Usage:\")}\n npm create @editframe -- [template] [options]\n\n${chalk.bold(\"Options:\")}\n -d, --directory <name> Project directory name\n --skip-install Skip dependency installation\n --skip-skills Skip agent skills installation\n -y, --yes Skip all prompts, use defaults\n -h, --help Show this help message\n\n${chalk.bold(\"Available Templates:\")}\n${templates.map((t) => ` - ${t}`).join(\"\\n\")}\n\n${chalk.bold(\"Examples:\")}\n ${chalk.dim(\"# Interactive mode (recommended)\")}\n npm create @editframe\n\n ${chalk.dim(\"# Specify template\")}\n npm create @editframe -- react\n\n ${chalk.dim(\"# Full non-interactive\")}\n npm create @editframe -- react -d my-app -y\n\n ${chalk.dim(\"# Skip auto-installation\")}\n npm create @editframe -- react --skip-install --skip-skills\n`;\n\n process.stdout.write(usage);\n}\n\nasync function checkDirectoryExists(path: string) {\n try {\n await access(path);\n return true;\n } catch (_error) {\n return false;\n }\n}\n\nasync function main() {\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n // List of available starter templates\n const templates = await readdir(path.join(__dirname, \"templates\"));\n\n // Parse command line arguments\n const { values, positionals } = parseArgs({\n args: process.argv.slice(2),\n options: {\n help: {\n type: \"boolean\",\n short: \"h\",\n default: false,\n },\n directory: {\n type: \"string\",\n short: \"d\",\n },\n skipInstall: {\n type: \"boolean\",\n default: false,\n },\n skipSkills: {\n type: \"boolean\",\n default: false,\n },\n yes: {\n type: \"boolean\",\n short: \"y\",\n default: false,\n },\n },\n allowPositionals: true,\n });\n\n // Show help if requested\n if (values.help) {\n showHelp(templates);\n process.exit(0);\n }\n\n // Extract CLI arguments\n const cliTemplate = positionals[0];\n const cliDirectory = values.directory;\n const skipInstall = values.skipInstall;\n const skipSkills = values.skipSkills;\n const nonInteractive = values.yes;\n\n // Validate template if provided\n if (cliTemplate && !templates.includes(cliTemplate)) {\n process.stderr.write(chalk.red(`Error: Template \"${cliTemplate}\" does not exist.\\n\\n`));\n process.stderr.write(chalk.bold(\"Available templates:\\n\"));\n for (const t of templates) {\n process.stderr.write(` - ${t}\\n`);\n }\n process.stderr.write(chalk.dim(\"\\nRun with --help for more information.\\n\"));\n process.exit(1);\n }\n\n // Build prompts array - ask ALL questions upfront before any network calls\n const promptQuestions: prompts.PromptObject[] = [];\n\n if (!cliDirectory && !nonInteractive) {\n promptQuestions.push({\n type: \"text\",\n name: \"directoryName\",\n message: \"Enter the name of the directory to generate into:\",\n initial: \"my-project\",\n });\n }\n\n if (!cliTemplate && !nonInteractive) {\n promptQuestions.push({\n type: \"select\",\n name: \"templateName\",\n message: \"Choose a starter template:\",\n choices: templates.map((template) => ({\n title: template,\n value: template,\n })),\n });\n }\n\n // Ask about agent skills upfront (unless skipped via CLI)\n if (!skipSkills && !nonInteractive) {\n promptQuestions.push({\n type: \"confirm\",\n name: \"installSkills\",\n message: \"Install AI agent skills for better coding assistance?\",\n initial: true,\n });\n }\n\n // Prompt for all missing information at once\n const answers = promptQuestions.length > 0 ? await prompts(promptQuestions) : {};\n\n // Handle user cancellation\n if (\n (!cliDirectory && !nonInteractive && !answers.directoryName) ||\n (!cliTemplate && !nonInteractive && !answers.templateName)\n ) {\n process.stderr.write(chalk.red(\"\\nCancelled\\n\"));\n process.exit(1);\n }\n\n // Use CLI args or prompted values (with defaults for non-interactive mode)\n const directoryName = cliDirectory || answers.directoryName || \"my-project\";\n const templateName = cliTemplate || answers.templateName || templates[0];\n\n // Determine if skills should be installed\n const installSkills = !skipSkills && (nonInteractive || answers.installSkills !== false);\n\n const targetDir = path.join(process.cwd(), directoryName);\n const templateDir = path.join(__dirname, \"templates\", templateName);\n\n const exists = await checkDirectoryExists(targetDir);\n\n if (exists) {\n process.stderr.write(chalk.yellow(`Directory ${targetDir} already exists.\\n`));\n const { overwrite } = await prompts({\n type: \"confirm\",\n name: \"overwrite\",\n message: \"Directory already exists. Do you want to overwrite it?\",\n initial: false,\n });\n\n if (!overwrite) {\n process.stderr.write(chalk.red(\"Aborting...\\n\"));\n process.exit(1);\n }\n }\n\n process.stderr.write(`\\nCreating project in directory: ${targetDir}\\n`);\n process.stderr.write(`Using template: ${templateName}\\n\\n`);\n\n // Copy the selected template to the target directory\n await cp(templateDir, targetDir, { recursive: true });\n\n const pkgManager = getUserPkgManager();\n let depsInstalled = false;\n let skillsInstalled = false;\n\n // All questions have been asked - now do the work\n\n // Install dependencies unless skipped\n if (!skipInstall) {\n depsInstalled = await installDependencies(targetDir);\n }\n\n // Install agent skills unless skipped\n if (installSkills) {\n skillsInstalled = await installAgentSkills(targetDir);\n }\n\n // Success message\n process.stderr.write(chalk.green.bold(\"\\n✓ Project created successfully!\\n\"));\n\n if (depsInstalled) {\n process.stderr.write(chalk.green(\"✓ Dependencies installed\\n\"));\n }\n\n if (skillsInstalled) {\n process.stderr.write(chalk.green(\"✓ AI agent skills installed\\n\"));\n }\n\n process.stderr.write(chalk.bold(\"\\nYour project is ready! 🎉\\n\\n\"));\n\n // Next steps\n process.stderr.write(chalk.bold(\"Next steps:\\n\"));\n process.stderr.write(chalk.cyan(` cd ${directoryName}\\n`));\n\n if (!depsInstalled) {\n process.stderr.write(chalk.cyan(` ${pkgManager} install\\n`));\n }\n\n process.stderr.write(chalk.cyan(` ${getStartCommand(pkgManager)}\\n`));\n\n // Skills info\n if (skillsInstalled) {\n process.stderr.write(chalk.bold(\"\\nAI Agent Skills installed:\\n\"));\n process.stderr.write(chalk.dim(\" • editframe-composition\\n\"));\n process.stderr.write(chalk.dim(\" • editframe-motion-design\\n\"));\n process.stderr.write(chalk.dim(\" • editframe-brand-video-generator\\n\"));\n process.stderr.write(chalk.dim(\" • editframe-editor-gui\\n\"));\n process.stderr.write(chalk.dim(\" • editframe-vite-plugin\\n\"));\n process.stderr.write(chalk.dim(\" • editframe-webhooks\\n\"));\n\n process.stderr.write(chalk.bold(\"\\nTry asking your AI agent:\\n\"));\n process.stderr.write(chalk.dim(' \"Create a 5-second video with fade-in text\"\\n'));\n process.stderr.write(chalk.dim(' \"Add a waveform visualization\"\\n'));\n process.stderr.write(chalk.dim(' \"Animate this element with spring physics\"\\n'));\n }\n\n process.stderr.write(chalk.dim(\"\\nDocumentation: https://editframe.com/docs\\n\"));\n process.stderr.write(chalk.dim(\"Happy coding! 🎬\\n\\n\"));\n}\n\nmain();\n"],"mappings":";;;;;;;;;;AAeA,SAAS,SAAS,WAAqB;CACrC,MAAM,QAAQ;EACd,MAAM,KAAK,SAAS,CAAC;;;EAGrB,MAAM,KAAK,WAAW,CAAC;;;;;;;EAOvB,MAAM,KAAK,uBAAuB,CAAC;EACnC,UAAU,KAAK,MAAM,OAAO,IAAI,CAAC,KAAK,KAAK,CAAC;;EAE5C,MAAM,KAAK,YAAY,CAAC;IACtB,MAAM,IAAI,mCAAmC,CAAC;;;IAG9C,MAAM,IAAI,qBAAqB,CAAC;;;IAGhC,MAAM,IAAI,yBAAyB,CAAC;;;IAGpC,MAAM,IAAI,2BAA2B,CAAC;;;AAIxC,SAAQ,OAAO,MAAM,MAAM;;AAG7B,eAAe,qBAAqB,QAAc;AAChD,KAAI;AACF,QAAM,OAAOA,OAAK;AAClB,SAAO;UACA,QAAQ;AACf,SAAO;;;AAIX,eAAe,OAAO;CACpB,MAAM,YAAY,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;CAG9D,MAAM,YAAY,MAAM,QAAQ,KAAK,KAAK,WAAW,YAAY,CAAC;CAGlE,MAAM,EAAE,QAAQ,gBAAgB,UAAU;EACxC,MAAM,QAAQ,KAAK,MAAM,EAAE;EAC3B,SAAS;GACP,MAAM;IACJ,MAAM;IACN,OAAO;IACP,SAAS;IACV;GACD,WAAW;IACT,MAAM;IACN,OAAO;IACR;GACD,aAAa;IACX,MAAM;IACN,SAAS;IACV;GACD,YAAY;IACV,MAAM;IACN,SAAS;IACV;GACD,KAAK;IACH,MAAM;IACN,OAAO;IACP,SAAS;IACV;GACF;EACD,kBAAkB;EACnB,CAAC;AAGF,KAAI,OAAO,MAAM;AACf,WAAS,UAAU;AACnB,UAAQ,KAAK,EAAE;;CAIjB,MAAM,cAAc,YAAY;CAChC,MAAM,eAAe,OAAO;CAC5B,MAAM,cAAc,OAAO;CAC3B,MAAM,aAAa,OAAO;CAC1B,MAAM,iBAAiB,OAAO;AAG9B,KAAI,eAAe,CAAC,UAAU,SAAS,YAAY,EAAE;AACnD,UAAQ,OAAO,MAAM,MAAM,IAAI,oBAAoB,YAAY,uBAAuB,CAAC;AACvF,UAAQ,OAAO,MAAM,MAAM,KAAK,yBAAyB,CAAC;AAC1D,OAAK,MAAM,KAAK,UACd,SAAQ,OAAO,MAAM,OAAO,EAAE,IAAI;AAEpC,UAAQ,OAAO,MAAM,MAAM,IAAI,4CAA4C,CAAC;AAC5E,UAAQ,KAAK,EAAE;;CAIjB,MAAMC,kBAA0C,EAAE;AAElD,KAAI,CAAC,gBAAgB,CAAC,eACpB,iBAAgB,KAAK;EACnB,MAAM;EACN,MAAM;EACN,SAAS;EACT,SAAS;EACV,CAAC;AAGJ,KAAI,CAAC,eAAe,CAAC,eACnB,iBAAgB,KAAK;EACnB,MAAM;EACN,MAAM;EACN,SAAS;EACT,SAAS,UAAU,KAAK,cAAc;GACpC,OAAO;GACP,OAAO;GACR,EAAE;EACJ,CAAC;AAIJ,KAAI,CAAC,cAAc,CAAC,eAClB,iBAAgB,KAAK;EACnB,MAAM;EACN,MAAM;EACN,SAAS;EACT,SAAS;EACV,CAAC;CAIJ,MAAM,UAAU,gBAAgB,SAAS,IAAI,MAAM,QAAQ,gBAAgB,GAAG,EAAE;AAGhF,KACG,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,QAAQ,iBAC7C,CAAC,eAAe,CAAC,kBAAkB,CAAC,QAAQ,cAC7C;AACA,UAAQ,OAAO,MAAM,MAAM,IAAI,gBAAgB,CAAC;AAChD,UAAQ,KAAK,EAAE;;CAIjB,MAAM,gBAAgB,gBAAgB,QAAQ,iBAAiB;CAC/D,MAAM,eAAe,eAAe,QAAQ,gBAAgB,UAAU;CAGtE,MAAM,gBAAgB,CAAC,eAAe,kBAAkB,QAAQ,kBAAkB;CAElF,MAAM,YAAY,KAAK,KAAK,QAAQ,KAAK,EAAE,cAAc;CACzD,MAAM,cAAc,KAAK,KAAK,WAAW,aAAa,aAAa;AAInE,KAFe,MAAM,qBAAqB,UAAU,EAExC;AACV,UAAQ,OAAO,MAAM,MAAM,OAAO,aAAa,UAAU,oBAAoB,CAAC;EAC9E,MAAM,EAAE,cAAc,MAAM,QAAQ;GAClC,MAAM;GACN,MAAM;GACN,SAAS;GACT,SAAS;GACV,CAAC;AAEF,MAAI,CAAC,WAAW;AACd,WAAQ,OAAO,MAAM,MAAM,IAAI,gBAAgB,CAAC;AAChD,WAAQ,KAAK,EAAE;;;AAInB,SAAQ,OAAO,MAAM,oCAAoC,UAAU,IAAI;AACvE,SAAQ,OAAO,MAAM,mBAAmB,aAAa,MAAM;AAG3D,OAAM,GAAG,aAAa,WAAW,EAAE,WAAW,MAAM,CAAC;CAErD,MAAM,aAAa,mBAAmB;CACtC,IAAI,gBAAgB;CACpB,IAAI,kBAAkB;AAKtB,KAAI,CAAC,YACH,iBAAgB,MAAM,oBAAoB,UAAU;AAItD,KAAI,cACF,mBAAkB,MAAM,mBAAmB,UAAU;AAIvD,SAAQ,OAAO,MAAM,MAAM,MAAM,KAAK,sCAAsC,CAAC;AAE7E,KAAI,cACF,SAAQ,OAAO,MAAM,MAAM,MAAM,6BAA6B,CAAC;AAGjE,KAAI,gBACF,SAAQ,OAAO,MAAM,MAAM,MAAM,gCAAgC,CAAC;AAGpE,SAAQ,OAAO,MAAM,MAAM,KAAK,kCAAkC,CAAC;AAGnE,SAAQ,OAAO,MAAM,MAAM,KAAK,gBAAgB,CAAC;AACjD,SAAQ,OAAO,MAAM,MAAM,KAAK,QAAQ,cAAc,IAAI,CAAC;AAE3D,KAAI,CAAC,cACH,SAAQ,OAAO,MAAM,MAAM,KAAK,KAAK,WAAW,YAAY,CAAC;AAG/D,SAAQ,OAAO,MAAM,MAAM,KAAK,KAAK,gBAAgB,WAAW,CAAC,IAAI,CAAC;AAGtE,KAAI,iBAAiB;AACnB,UAAQ,OAAO,MAAM,MAAM,KAAK,iCAAiC,CAAC;AAClE,UAAQ,OAAO,MAAM,MAAM,IAAI,8BAA8B,CAAC;AAC9D,UAAQ,OAAO,MAAM,MAAM,IAAI,gCAAgC,CAAC;AAChE,UAAQ,OAAO,MAAM,MAAM,IAAI,wCAAwC,CAAC;AACxE,UAAQ,OAAO,MAAM,MAAM,IAAI,6BAA6B,CAAC;AAC7D,UAAQ,OAAO,MAAM,MAAM,IAAI,8BAA8B,CAAC;AAC9D,UAAQ,OAAO,MAAM,MAAM,IAAI,2BAA2B,CAAC;AAE3D,UAAQ,OAAO,MAAM,MAAM,KAAK,gCAAgC,CAAC;AACjE,UAAQ,OAAO,MAAM,MAAM,IAAI,oDAAkD,CAAC;AAClF,UAAQ,OAAO,MAAM,MAAM,IAAI,uCAAqC,CAAC;AACrE,UAAQ,OAAO,MAAM,MAAM,IAAI,mDAAiD,CAAC;;AAGnF,SAAQ,OAAO,MAAM,MAAM,IAAI,gDAAgD,CAAC;AAChF,SAAQ,OAAO,MAAM,MAAM,IAAI,uBAAuB,CAAC;;AAGzD,MAAM"}
1
+ {"version":3,"file":"index.js","names":["path","promptQuestions: prompts.PromptObject[]","interactiveScope: SkillsInstallScope | undefined","resolvedSkillsScope: SkillsInstallScope","depsError: string | undefined"],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { access, cp, readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parseArgs } from \"node:util\";\nimport chalk from \"chalk\";\nimport prompts from \"prompts\";\nimport {\n getUserPkgManager,\n installDependencies,\n installAgentSkills,\n getStartCommand,\n type PackageManager,\n type SkillsInstallScope,\n} from \"./utils.js\";\n// SkillsInstallScope is used in the main() function below\n\ninterface SuccessOutputOptions {\n directoryName: string;\n pkgManager: PackageManager;\n depsInstalled: boolean;\n skillsInstalled: boolean;\n}\n\nexport function buildSuccessOutput({\n directoryName,\n pkgManager,\n depsInstalled,\n skillsInstalled,\n}: SuccessOutputOptions): string {\n let output = \"\";\n\n // Headline: the thing that was created\n output += chalk.green.bold(`\\n✓ ${directoryName} created\\n`);\n\n // Next steps\n output += `\\n${chalk.bold(\"Next Steps\")}\\n`;\n output += ` ${chalk.cyan(`cd ${directoryName}`)}\\n`;\n if (!depsInstalled) {\n output += ` ${chalk.cyan(`${pkgManager} install`)}\\n`;\n }\n output += ` ${chalk.cyan(getStartCommand(pkgManager))}\\n`;\n\n // Agent skills\n if (skillsInstalled) {\n output += `\\n${chalk.green(\"✔\")} ${chalk.bold(\"Agent Skills Installed\")}\\n`;\n output += chalk.dim(` Ask your agent to \"Make a video with editframe …\"\\n`);\n }\n\n output += \"\\n\";\n\n return output;\n}\n\nfunction showHelp(templates: string[]) {\n const usage = `\n${chalk.bold(\"Usage:\")}\n npm create @editframe -- [template] [options]\n\n${chalk.bold(\"Options:\")}\n -d, --directory <name> Project directory name\n --skip-install Skip dependency installation\n --skip-skills Skip agent skills installation\n -g, --global Install agent skills globally (~/.claude/skills, ~/.agents/skills)\n -y, --yes Skip all prompts, use defaults\n -h, --help Show this help message\n\n${chalk.bold(\"Available Templates:\")}\n${templates.map((t) => ` - ${t}`).join(\"\\n\")}\n\n${chalk.bold(\"Examples:\")}\n ${chalk.dim(\"# Interactive mode (recommended)\")}\n npm create @editframe\n\n ${chalk.dim(\"# Specify template\")}\n npm create @editframe -- react\n\n ${chalk.dim(\"# Full non-interactive\")}\n npm create @editframe -- react -d my-app -y\n\n ${chalk.dim(\"# Install skills globally\")}\n npm create @editframe -- react --global\n\n ${chalk.dim(\"# Skip auto-installation\")}\n npm create @editframe -- react --skip-install --skip-skills\n`;\n\n process.stdout.write(usage);\n}\n\nasync function checkDirectoryExists(path: string) {\n try {\n await access(path);\n return true;\n } catch (_error) {\n return false;\n }\n}\n\nasync function main() {\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n // List of available starter templates\n const templates = await readdir(path.join(__dirname, \"templates\"));\n\n // Parse command line arguments\n const { values, positionals } = parseArgs({\n args: process.argv.slice(2),\n options: {\n help: {\n type: \"boolean\",\n short: \"h\",\n default: false,\n },\n directory: {\n type: \"string\",\n short: \"d\",\n },\n skipInstall: {\n type: \"boolean\",\n default: false,\n },\n skipSkills: {\n type: \"boolean\",\n default: false,\n },\n global: {\n type: \"boolean\",\n short: \"g\",\n default: false,\n },\n yes: {\n type: \"boolean\",\n short: \"y\",\n default: false,\n },\n },\n allowPositionals: true,\n });\n\n // Show help if requested\n if (values.help) {\n showHelp(templates);\n process.exit(0);\n }\n\n // Extract CLI arguments\n const cliTemplate = positionals[0];\n const cliDirectory = values.directory;\n const skipInstall = values.skipInstall;\n const skipSkills = values.skipSkills;\n const cliGlobal = values.global;\n const nonInteractive = values.yes;\n\n // Validate template if provided\n if (cliTemplate && !templates.includes(cliTemplate)) {\n process.stderr.write(chalk.red(`Error: Template \"${cliTemplate}\" does not exist.\\n\\n`));\n process.stderr.write(chalk.bold(\"Available templates:\\n\"));\n for (const t of templates) {\n process.stderr.write(` - ${t}\\n`);\n }\n process.stderr.write(chalk.dim(\"\\nRun with --help for more information.\\n\"));\n process.exit(1);\n }\n\n // Build prompts array - ask ALL questions upfront before any network calls\n const promptQuestions: prompts.PromptObject[] = [];\n\n if (!cliDirectory && !nonInteractive) {\n promptQuestions.push({\n type: \"text\",\n name: \"directoryName\",\n message: \"Enter the name of the directory to generate into:\",\n initial: \"my-project\",\n });\n }\n\n if (!cliTemplate && !nonInteractive) {\n promptQuestions.push({\n type: \"select\",\n name: \"templateName\",\n message: \"Choose a starter template:\",\n choices: templates.map((template) => ({\n title: template,\n value: template,\n })),\n });\n }\n\n // Ask about agent skills scope upfront (unless skipped via CLI)\n if (!skipSkills && !nonInteractive) {\n promptQuestions.push({\n type: \"select\",\n name: \"skillsScope\",\n message: \"Install AI agent skills?\",\n choices: [\n { title: \"Globally (all projects)\", value: \"global\" },\n { title: \"This project only\", value: \"project\" },\n ],\n initial: 0,\n });\n }\n\n // Prompt for all missing information at once\n const answers = promptQuestions.length > 0 ? await prompts(promptQuestions) : {};\n\n // Handle user cancellation\n if (\n (!cliDirectory && !nonInteractive && !answers.directoryName) ||\n (!cliTemplate && !nonInteractive && !answers.templateName)\n ) {\n process.stderr.write(chalk.red(\"\\nCancelled\\n\"));\n process.exit(1);\n }\n\n // Use CLI args or prompted values (with defaults for non-interactive mode)\n const directoryName = cliDirectory || answers.directoryName || \"my-project\";\n const templateName = cliTemplate || answers.templateName || templates[0];\n\n // Determine skills scope — global by default\n const interactiveScope: SkillsInstallScope | undefined = answers.skillsScope;\n const resolvedSkillsScope: SkillsInstallScope = cliGlobal\n ? \"global\"\n : (interactiveScope ?? \"global\");\n const installSkills = !skipSkills;\n\n const targetDir = path.join(process.cwd(), directoryName);\n const templateDir = path.join(__dirname, \"templates\", templateName);\n\n const exists = await checkDirectoryExists(targetDir);\n\n if (exists) {\n process.stderr.write(chalk.yellow(`Directory ${targetDir} already exists.\\n`));\n const { overwrite } = await prompts({\n type: \"confirm\",\n name: \"overwrite\",\n message: \"Directory already exists. Do you want to overwrite it?\",\n initial: false,\n });\n\n if (!overwrite) {\n process.stderr.write(chalk.red(\"Aborting...\\n\"));\n process.exit(1);\n }\n }\n\n process.stderr.write(`\\nCreating project in directory: ${targetDir}\\n`);\n process.stderr.write(`Using template: ${templateName}\\n\\n`);\n\n // Copy the selected template to the target directory\n await cp(templateDir, targetDir, { recursive: true });\n\n const pkgManager = getUserPkgManager();\n let depsInstalled = false;\n let depsError: string | undefined;\n let skillsInstalled = false;\n\n if (!skipInstall) {\n const result = await installDependencies(targetDir);\n depsInstalled = result.ok;\n depsError = result.errorOutput;\n }\n\n if (installSkills) {\n skillsInstalled = await installAgentSkills(targetDir, resolvedSkillsScope);\n }\n\n if (depsError) {\n process.stderr.write(chalk.yellow(`\\n⚠ ${pkgManager} install failed\\n\\n`));\n process.stderr.write(depsError + \"\\n\");\n }\n\n process.stderr.write(\n buildSuccessOutput({ directoryName, pkgManager, depsInstalled, skillsInstalled }),\n );\n}\n\nmain();\n"],"mappings":"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"}
@@ -7,9 +7,9 @@
7
7
  "start": "editframe preview"
8
8
  },
9
9
  "dependencies": {
10
- "@editframe/cli": "0.46.2",
11
- "@editframe/elements": "0.46.2",
12
- "@editframe/vite-plugin": "0.46.2",
10
+ "@editframe/cli": "0.47.0",
11
+ "@editframe/elements": "0.47.0",
12
+ "@editframe/vite-plugin": "0.47.0",
13
13
  "tailwindcss": "^3.4.3",
14
14
  "vite": "^6.3.5",
15
15
  "vite-plugin-singlefile": "^2.0.1"
@@ -7,9 +7,9 @@
7
7
  "start": "editframe preview"
8
8
  },
9
9
  "dependencies": {
10
- "@editframe/cli": "0.46.2",
11
- "@editframe/react": "0.46.2",
12
- "@editframe/vite-plugin": "0.46.2",
10
+ "@editframe/cli": "0.47.0",
11
+ "@editframe/react": "0.47.0",
12
+ "@editframe/vite-plugin": "0.47.0",
13
13
  "@vitejs/plugin-react": "^4.3.1",
14
14
  "tailwindcss": "^3.4.3",
15
15
  "vite": "^6.3.5",
@@ -0,0 +1,5 @@
1
+ //#region src/utils.d.ts
2
+ type PackageManager = "npm" | "pnpm" | "yarn" | "bun";
3
+ //#endregion
4
+ export { PackageManager };
5
+ //# sourceMappingURL=utils.d.ts.map
package/dist/utils.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { cp, mkdir, readdir } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- import chalk from "chalk";
4
+ import os from "node:os";
5
5
  import { execa } from "execa";
6
+ import ora from "ora";
6
7
 
7
8
  //#region src/utils.ts
8
9
  /**
@@ -19,52 +20,53 @@ function getUserPkgManager() {
19
20
  return "npm";
20
21
  }
21
22
  /**
22
- * Run the appropriate install command for the detected package manager.
23
- * Shows full output to the user so they can see progress.
24
- */
25
- async function runInstallCommand(pkgManager, projectDir) {
26
- await execa(pkgManager, ["install"], {
27
- cwd: projectDir,
28
- stdout: "inherit",
29
- stderr: "inherit"
30
- });
31
- }
32
- /**
33
23
  * Install dependencies in the project directory.
24
+ * Suppresses all output unless the install fails, in which case it
25
+ * returns the error output as a string for the caller to surface.
34
26
  */
35
27
  async function installDependencies(projectDir) {
36
28
  const pkgManager = getUserPkgManager();
29
+ const spinner = ora(`Installing dependencies with ${pkgManager}…`).start();
37
30
  try {
38
- process.stderr.write(chalk.bold(`\nInstalling dependencies with ${pkgManager}...\n\n`));
39
- await runInstallCommand(pkgManager, projectDir);
40
- process.stderr.write(chalk.green("\n✓ Dependencies installed successfully!\n"));
41
- return true;
42
- } catch (_error) {
43
- process.stderr.write(chalk.yellow("\n⚠ Dependency installation failed\n"));
44
- process.stderr.write(chalk.dim("You can install manually:\n"));
45
- process.stderr.write(chalk.cyan(` cd ${projectDir.split("/").pop()}\n`));
46
- process.stderr.write(chalk.cyan(` ${pkgManager} install\n\n`));
47
- return false;
31
+ const result = await execa(pkgManager, ["install"], {
32
+ cwd: projectDir,
33
+ all: true,
34
+ reject: false
35
+ });
36
+ if (result.exitCode !== 0) {
37
+ spinner.fail(`${pkgManager} install failed`);
38
+ return {
39
+ ok: false,
40
+ errorOutput: result.all
41
+ };
42
+ }
43
+ spinner.succeed(`${pkgManager} install`);
44
+ return { ok: true };
45
+ } catch (err) {
46
+ spinner.fail(`${pkgManager} install failed`);
47
+ return {
48
+ ok: false,
49
+ errorOutput: String(err)
50
+ };
48
51
  }
49
52
  }
50
53
  /**
51
- * Install AI agent skills by copying bundled skill files into the project.
54
+ * Install AI agent skills by copying bundled skill files.
52
55
  * Writes to both .claude/skills/ and .agents/skills/ for broad agent compatibility.
56
+ * When scope is "global", installs to the user's home directory instead of the project.
53
57
  */
54
- async function installAgentSkills(projectDir) {
58
+ async function installAgentSkills(projectDir, scope = "global") {
55
59
  try {
56
- process.stderr.write(chalk.bold("\nInstalling AI agent skills...\n\n"));
57
60
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
58
61
  const skillsSource = path.join(__dirname, "skills");
59
62
  const skills = await readdir(skillsSource);
63
+ const destRoot = scope === "global" ? os.homedir() : projectDir;
60
64
  for (const destBase of [".claude/skills", ".agents/skills"]) {
61
- await mkdir(path.join(projectDir, destBase), { recursive: true });
62
- for (const skill of skills) await cp(path.join(skillsSource, skill), path.join(projectDir, destBase, skill), { recursive: true });
65
+ await mkdir(path.join(destRoot, destBase), { recursive: true });
66
+ for (const skill of skills) await cp(path.join(skillsSource, skill), path.join(destRoot, destBase, skill), { recursive: true });
63
67
  }
64
- process.stderr.write(chalk.green("\n✓ AI agent skills installed!\n"));
65
68
  return true;
66
69
  } catch (_error) {
67
- process.stderr.write(chalk.yellow("\n⚠ Failed to install agent skills\n"));
68
70
  return false;
69
71
  }
70
72
  }
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import { cp, mkdir, readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { execa } from \"execa\";\nimport chalk from \"chalk\";\n\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\n/**\n * Detect which package manager was used to invoke the create script.\n * Uses the npm_config_user_agent environment variable set by package managers.\n */\nexport function getUserPkgManager(): PackageManager {\n const userAgent = process.env.npm_config_user_agent;\n\n if (userAgent) {\n if (userAgent.startsWith(\"yarn\")) return \"yarn\";\n if (userAgent.startsWith(\"pnpm\")) return \"pnpm\";\n if (userAgent.startsWith(\"bun\")) return \"bun\";\n }\n\n return \"npm\"; // Default fallback\n}\n\n/**\n * Run the appropriate install command for the detected package manager.\n * Shows full output to the user so they can see progress.\n */\nasync function runInstallCommand(pkgManager: PackageManager, projectDir: string): Promise<void> {\n // Show all output directly to user - no hiding behind spinners\n await execa(pkgManager, [\"install\"], {\n cwd: projectDir,\n stdout: \"inherit\",\n stderr: \"inherit\",\n });\n}\n\n/**\n * Install dependencies in the project directory.\n */\nexport async function installDependencies(projectDir: string): Promise<boolean> {\n const pkgManager = getUserPkgManager();\n\n try {\n process.stderr.write(chalk.bold(`\\nInstalling dependencies with ${pkgManager}...\\n\\n`));\n\n await runInstallCommand(pkgManager, projectDir);\n\n process.stderr.write(chalk.green(\"\\n✓ Dependencies installed successfully!\\n\"));\n\n return true;\n } catch (_error) {\n process.stderr.write(chalk.yellow(\"\\n⚠ Dependency installation failed\\n\"));\n process.stderr.write(chalk.dim(\"You can install manually:\\n\"));\n process.stderr.write(chalk.cyan(` cd ${projectDir.split(\"/\").pop()}\\n`));\n process.stderr.write(chalk.cyan(` ${pkgManager} install\\n\\n`));\n return false;\n }\n}\n\n/**\n * Install AI agent skills by copying bundled skill files into the project.\n * Writes to both .claude/skills/ and .agents/skills/ for broad agent compatibility.\n */\nexport async function installAgentSkills(projectDir: string): Promise<boolean> {\n try {\n process.stderr.write(chalk.bold(\"\\nInstalling AI agent skills...\\n\\n\"));\n\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n const skillsSource = path.join(__dirname, \"skills\");\n const skills = await readdir(skillsSource);\n\n for (const destBase of [\".claude/skills\", \".agents/skills\"]) {\n await mkdir(path.join(projectDir, destBase), { recursive: true });\n for (const skill of skills) {\n await cp(path.join(skillsSource, skill), path.join(projectDir, destBase, skill), {\n recursive: true,\n });\n }\n }\n\n process.stderr.write(chalk.green(\"\\n✓ AI agent skills installed!\\n\"));\n return true;\n } catch (_error) {\n process.stderr.write(chalk.yellow(\"\\n⚠ Failed to install agent skills\\n\"));\n return false;\n }\n}\n\n/**\n * Get the appropriate start command for the package manager.\n */\nexport function getStartCommand(pkgManager: PackageManager): string {\n return pkgManager === \"npm\" ? \"npm start\" : `${pkgManager} start`;\n}\n"],"mappings":";;;;;;;;;;;AAYA,SAAgB,oBAAoC;CAClD,MAAM,YAAY,QAAQ,IAAI;AAE9B,KAAI,WAAW;AACb,MAAI,UAAU,WAAW,OAAO,CAAE,QAAO;AACzC,MAAI,UAAU,WAAW,OAAO,CAAE,QAAO;AACzC,MAAI,UAAU,WAAW,MAAM,CAAE,QAAO;;AAG1C,QAAO;;;;;;AAOT,eAAe,kBAAkB,YAA4B,YAAmC;AAE9F,OAAM,MAAM,YAAY,CAAC,UAAU,EAAE;EACnC,KAAK;EACL,QAAQ;EACR,QAAQ;EACT,CAAC;;;;;AAMJ,eAAsB,oBAAoB,YAAsC;CAC9E,MAAM,aAAa,mBAAmB;AAEtC,KAAI;AACF,UAAQ,OAAO,MAAM,MAAM,KAAK,kCAAkC,WAAW,SAAS,CAAC;AAEvF,QAAM,kBAAkB,YAAY,WAAW;AAE/C,UAAQ,OAAO,MAAM,MAAM,MAAM,6CAA6C,CAAC;AAE/E,SAAO;UACA,QAAQ;AACf,UAAQ,OAAO,MAAM,MAAM,OAAO,uCAAuC,CAAC;AAC1E,UAAQ,OAAO,MAAM,MAAM,IAAI,8BAA8B,CAAC;AAC9D,UAAQ,OAAO,MAAM,MAAM,KAAK,QAAQ,WAAW,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AACzE,UAAQ,OAAO,MAAM,MAAM,KAAK,KAAK,WAAW,cAAc,CAAC;AAC/D,SAAO;;;;;;;AAQX,eAAsB,mBAAmB,YAAsC;AAC7E,KAAI;AACF,UAAQ,OAAO,MAAM,MAAM,KAAK,sCAAsC,CAAC;EAEvE,MAAM,YAAY,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;EAC9D,MAAM,eAAe,KAAK,KAAK,WAAW,SAAS;EACnD,MAAM,SAAS,MAAM,QAAQ,aAAa;AAE1C,OAAK,MAAM,YAAY,CAAC,kBAAkB,iBAAiB,EAAE;AAC3D,SAAM,MAAM,KAAK,KAAK,YAAY,SAAS,EAAE,EAAE,WAAW,MAAM,CAAC;AACjE,QAAK,MAAM,SAAS,OAClB,OAAM,GAAG,KAAK,KAAK,cAAc,MAAM,EAAE,KAAK,KAAK,YAAY,UAAU,MAAM,EAAE,EAC/E,WAAW,MACZ,CAAC;;AAIN,UAAQ,OAAO,MAAM,MAAM,MAAM,mCAAmC,CAAC;AACrE,SAAO;UACA,QAAQ;AACf,UAAQ,OAAO,MAAM,MAAM,OAAO,uCAAuC,CAAC;AAC1E,SAAO;;;;;;AAOX,SAAgB,gBAAgB,YAAoC;AAClE,QAAO,eAAe,QAAQ,cAAc,GAAG,WAAW"}
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import { cp, mkdir, readdir } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { execa } from \"execa\";\nimport ora from \"ora\";\n\nexport type SkillsInstallScope = \"project\" | \"global\";\n\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\n/**\n * Detect which package manager was used to invoke the create script.\n * Uses the npm_config_user_agent environment variable set by package managers.\n */\nexport function getUserPkgManager(): PackageManager {\n const userAgent = process.env.npm_config_user_agent;\n\n if (userAgent) {\n if (userAgent.startsWith(\"yarn\")) return \"yarn\";\n if (userAgent.startsWith(\"pnpm\")) return \"pnpm\";\n if (userAgent.startsWith(\"bun\")) return \"bun\";\n }\n\n return \"npm\";\n}\n\n/**\n * Install dependencies in the project directory.\n * Suppresses all output unless the install fails, in which case it\n * returns the error output as a string for the caller to surface.\n */\nexport async function installDependencies(\n projectDir: string,\n): Promise<{ ok: boolean; errorOutput?: string }> {\n const pkgManager = getUserPkgManager();\n const spinner = ora(`Installing dependencies with ${pkgManager}…`).start();\n\n try {\n const result = await execa(pkgManager, [\"install\"], {\n cwd: projectDir,\n all: true,\n reject: false,\n });\n\n if (result.exitCode !== 0) {\n spinner.fail(`${pkgManager} install failed`);\n return { ok: false, errorOutput: result.all };\n }\n\n spinner.succeed(`${pkgManager} install`);\n return { ok: true };\n } catch (err) {\n spinner.fail(`${pkgManager} install failed`);\n return { ok: false, errorOutput: String(err) };\n }\n}\n\n/**\n * Install AI agent skills by copying bundled skill files.\n * Writes to both .claude/skills/ and .agents/skills/ for broad agent compatibility.\n * When scope is \"global\", installs to the user's home directory instead of the project.\n */\nexport async function installAgentSkills(\n projectDir: string,\n scope: SkillsInstallScope = \"global\",\n): Promise<boolean> {\n try {\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n const skillsSource = path.join(__dirname, \"skills\");\n const skills = await readdir(skillsSource);\n\n const destRoot = scope === \"global\" ? os.homedir() : projectDir;\n\n for (const destBase of [\".claude/skills\", \".agents/skills\"]) {\n await mkdir(path.join(destRoot, destBase), { recursive: true });\n for (const skill of skills) {\n await cp(path.join(skillsSource, skill), path.join(destRoot, destBase, skill), {\n recursive: true,\n });\n }\n }\n\n return true;\n } catch (_error) {\n return false;\n }\n}\n\n/**\n * Get the appropriate start command for the package manager.\n */\nexport function getStartCommand(pkgManager: PackageManager): string {\n return pkgManager === \"npm\" ? \"npm start\" : `${pkgManager} start`;\n}\n"],"mappings":";;;;;;;;;;;;AAeA,SAAgB,oBAAoC;CAClD,MAAM,YAAY,QAAQ,IAAI;AAE9B,KAAI,WAAW;AACb,MAAI,UAAU,WAAW,OAAO,CAAE,QAAO;AACzC,MAAI,UAAU,WAAW,OAAO,CAAE,QAAO;AACzC,MAAI,UAAU,WAAW,MAAM,CAAE,QAAO;;AAG1C,QAAO;;;;;;;AAQT,eAAsB,oBACpB,YACgD;CAChD,MAAM,aAAa,mBAAmB;CACtC,MAAM,UAAU,IAAI,gCAAgC,WAAW,GAAG,CAAC,OAAO;AAE1E,KAAI;EACF,MAAM,SAAS,MAAM,MAAM,YAAY,CAAC,UAAU,EAAE;GAClD,KAAK;GACL,KAAK;GACL,QAAQ;GACT,CAAC;AAEF,MAAI,OAAO,aAAa,GAAG;AACzB,WAAQ,KAAK,GAAG,WAAW,iBAAiB;AAC5C,UAAO;IAAE,IAAI;IAAO,aAAa,OAAO;IAAK;;AAG/C,UAAQ,QAAQ,GAAG,WAAW,UAAU;AACxC,SAAO,EAAE,IAAI,MAAM;UACZ,KAAK;AACZ,UAAQ,KAAK,GAAG,WAAW,iBAAiB;AAC5C,SAAO;GAAE,IAAI;GAAO,aAAa,OAAO,IAAI;GAAE;;;;;;;;AASlD,eAAsB,mBACpB,YACA,QAA4B,UACV;AAClB,KAAI;EACF,MAAM,YAAY,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;EAC9D,MAAM,eAAe,KAAK,KAAK,WAAW,SAAS;EACnD,MAAM,SAAS,MAAM,QAAQ,aAAa;EAE1C,MAAM,WAAW,UAAU,WAAW,GAAG,SAAS,GAAG;AAErD,OAAK,MAAM,YAAY,CAAC,kBAAkB,iBAAiB,EAAE;AAC3D,SAAM,MAAM,KAAK,KAAK,UAAU,SAAS,EAAE,EAAE,WAAW,MAAM,CAAC;AAC/D,QAAK,MAAM,SAAS,OAClB,OAAM,GAAG,KAAK,KAAK,cAAc,MAAM,EAAE,KAAK,KAAK,UAAU,UAAU,MAAM,EAAE,EAC7E,WAAW,MACZ,CAAC;;AAIN,SAAO;UACA,QAAQ;AACf,SAAO;;;;;;AAOX,SAAgB,gBAAgB,YAAoC;AAClE,QAAO,eAAe,QAAQ,cAAc,GAAG,WAAW"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@editframe/create",
3
- "version": "0.46.2",
3
+ "version": "0.47.0",
4
4
  "description": "",
5
5
  "bin": {
6
6
  "create-editframe": "dist/index.js"
@@ -21,8 +21,9 @@
21
21
  "license": "SEE LICENSE IN LICENSE-FULL.md",
22
22
  "dependencies": {
23
23
  "chalk": "^5.3.0",
24
- "prompts": "^2.4.2",
25
- "execa": "^9.5.2"
24
+ "execa": "^9.5.2",
25
+ "ora": "^9.3.0",
26
+ "prompts": "^2.4.2"
26
27
  },
27
28
  "types": "./dist/index.d.ts",
28
29
  "exports": {