@fireberry/cli 0.4.0 → 0.4.2

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.
@@ -3,19 +3,11 @@ name: Publish Fireberry CLI to npm
3
3
  on:
4
4
  workflow_dispatch:
5
5
  inputs:
6
- type:
7
- description: "Publish type"
8
- required: true
9
- type: choice
10
- options:
11
- - beta
12
- - production
13
6
  version:
14
- description: "Version bump (for production only)"
7
+ description: "Version bump type (ignored for beta/dev branch)"
15
8
  required: false
16
9
  type: choice
17
10
  options:
18
- - prerelease
19
11
  - patch
20
12
  - minor
21
13
  - major
@@ -25,11 +17,10 @@ jobs:
25
17
  publish:
26
18
  runs-on: ubuntu-latest
27
19
  permissions:
28
- contents: read
20
+ contents: write # Enable pushing commits and tags
29
21
  id-token: write
30
22
  environment:
31
23
  name: npm
32
- url: https://www.npmjs.com/package/@fireberry/cli/v/${{ github.event.inputs.version }}
33
24
 
34
25
  steps:
35
26
  - name: Checkout repository
@@ -46,19 +37,77 @@ jobs:
46
37
  - name: Install dependencies
47
38
  run: npm ci
48
39
 
49
- - name: Update version (Beta)
50
- if: github.event.inputs.type == 'beta'
40
+ - name: Detect release type from branch
41
+ id: detect-type
42
+ run: |
43
+ BRANCH_NAME="${GITHUB_REF#refs/heads/}"
44
+ echo "Branch: $BRANCH_NAME"
45
+ if [[ "$BRANCH_NAME" == "dev" ]]; then
46
+ echo "type=beta" >> $GITHUB_OUTPUT
47
+ echo "Detected release type: beta"
48
+ elif [[ "$BRANCH_NAME" == "main" ]]; then
49
+ echo "type=production" >> $GITHUB_OUTPUT
50
+ echo "Detected release type: production"
51
+ else
52
+ echo "Error: Workflow must be run from 'dev' or 'main' branch"
53
+ echo "Current branch: $BRANCH_NAME"
54
+ exit 1
55
+ fi
56
+
57
+ - name: Bump version (Beta)
58
+ if: steps.detect-type.outputs.type == 'beta'
59
+ id: version-beta
51
60
  run: |
52
61
  CURRENT_VERSION=$(node -p "require('./package.json').version")
62
+ echo "Current version: $CURRENT_VERSION"
63
+
53
64
  if [[ $CURRENT_VERSION == *"-beta."* ]]; then
65
+ echo "Incrementing beta prerelease version"
54
66
  npm version prerelease --preid=beta --no-git-tag-version
55
67
  else
68
+ echo "Creating new beta version from production"
56
69
  npm version prepatch --preid=beta --no-git-tag-version
57
70
  fi
58
71
 
59
- - name: Update version (Production)
60
- if: github.event.inputs.type == 'production'
61
- run: npm version ${{ github.event.inputs.version }} --no-git-tag-version
72
+ NEW_VERSION=$(node -p "require('./package.json').version")
73
+ echo "New version: $NEW_VERSION"
74
+ echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
75
+
76
+ - name: Bump version (Production)
77
+ if: steps.detect-type.outputs.type == 'production'
78
+ id: version-prod
79
+ run: |
80
+ CURRENT_VERSION=$(node -p "require('./package.json').version")
81
+ echo "Current version: $CURRENT_VERSION"
82
+
83
+ # Remove -beta suffix first if present
84
+ if [[ $CURRENT_VERSION == *"-beta."* ]]; then
85
+ echo "Removing beta suffix"
86
+ BASE_VERSION=$(echo $CURRENT_VERSION | sed 's/-beta\.[0-9]*$//')
87
+ echo "Base version: $BASE_VERSION"
88
+ npm version $BASE_VERSION --no-git-tag-version
89
+ fi
90
+
91
+ # Then apply the version bump
92
+ echo "Applying ${{ github.event.inputs.version }} bump"
93
+ npm version ${{ github.event.inputs.version }} --no-git-tag-version
94
+
95
+ NEW_VERSION=$(node -p "require('./package.json').version")
96
+ echo "New version: $NEW_VERSION"
97
+ echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
98
+
99
+ - name: Commit version bump
100
+ run: |
101
+ VERSION=${{ steps.version-beta.outputs.version || steps.version-prod.outputs.version }}
102
+ echo "Committing version: $VERSION"
103
+
104
+ git config user.name "github-actions[bot]"
105
+ git config user.email "github-actions[bot]@users.noreply.github.com"
106
+ git add package.json package-lock.json
107
+ git commit -m "chore: bump version to v${VERSION} [skip ci]"
108
+ git tag "v${VERSION}"
109
+
110
+ echo "Created commit and tag v${VERSION}"
62
111
 
63
112
  - name: Build package
64
113
  run: npm run build --if-present
@@ -69,10 +118,29 @@ jobs:
69
118
  - name: Update npm to latest version
70
119
  run: npm install -g npm@latest
71
120
 
121
+ - name: Push changes
122
+ run: |
123
+ echo "Pushing to branch: ${{ github.ref_name }}"
124
+ git push origin ${{ github.ref_name }}
125
+ git push origin --tags
126
+ echo "Successfully pushed commit and tags"
127
+
72
128
  - name: Publish to npm (Beta)
73
- if: github.event.inputs.type == 'beta'
74
- run: npm publish --tag beta --provenance --access public
129
+ if: steps.detect-type.outputs.type == 'beta'
130
+ run: |
131
+ VERSION=${{ steps.version-beta.outputs.version }}
132
+ echo "Publishing beta version $VERSION to npm"
133
+ npm publish --tag beta --provenance --access public
134
+ echo "Successfully published @fireberry/cli@$VERSION (beta tag)"
135
+ env:
136
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
75
137
 
76
138
  - name: Publish to npm (Production)
77
- if: github.event.inputs.type == 'production'
78
- run: npm publish --tag latest --provenance --access public
139
+ if: steps.detect-type.outputs.type == 'production'
140
+ run: |
141
+ VERSION=${{ steps.version-prod.outputs.version }}
142
+ echo "Publishing production version $VERSION to npm"
143
+ npm publish --tag latest --provenance --access public
144
+ echo "Successfully published @fireberry/cli@$VERSION (latest tag)"
145
+ env:
146
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/CLAUDE.md CHANGED
@@ -32,11 +32,42 @@ fireberry --help # Test the linked CLI
32
32
 
33
33
  ### Publishing
34
34
 
35
+ Releases are managed through GitHub Actions workflow with automatic version management:
36
+
37
+ **Beta Releases (from `dev` branch):**
38
+ 1. Go to GitHub Actions → "Publish Fireberry CLI to npm"
39
+ 2. Click "Run workflow" and select `dev` branch
40
+ 3. Workflow automatically:
41
+ - Increments beta version (e.g., 0.4.1-beta.0 → 0.4.1-beta.1)
42
+ - Commits version change to git
43
+ - Creates git tag (v0.4.1-beta.1)
44
+ - Builds and tests
45
+ - Publishes to npm with `beta` tag
46
+
47
+ **Production Releases (from `main` branch):**
48
+ 1. Merge `dev` → `main` after QA passes
49
+ 2. Go to GitHub Actions → "Publish Fireberry CLI to npm"
50
+ 3. Click "Run workflow" and select `main` branch
51
+ 4. Choose version bump type (patch/minor/major)
52
+ 5. Workflow automatically:
53
+ - Removes `-beta` suffix and bumps version
54
+ - Commits version change to git
55
+ - Creates git tag (v0.4.1)
56
+ - Builds and tests
57
+ - Publishes to npm with `latest` tag
58
+
59
+ **Local Publishing (Emergency Hotfixes):**
35
60
  ```bash
36
61
  npm run publish:beta # Version bump (beta) and publish to npm with beta tag
37
- npm run publish:prod # Publish to npm with latest tag
62
+ npm run publish:prod # Version bump (patch) and publish to npm with latest tag
38
63
  ```
39
64
 
65
+ **Key Features:**
66
+ - No manual version editing required
67
+ - Git tags automatically created for each release
68
+ - Version consistency maintained between git and npm
69
+ - `[skip ci]` in commit messages prevents workflow loops
70
+
40
71
  ## Architecture
41
72
 
42
73
  ### Module System
@@ -13,7 +13,13 @@ const program = new Command();
13
13
  program
14
14
  .name("fireberry")
15
15
  .description("Fireberry developer CLI")
16
- .version(packageJson.version);
16
+ .version(packageJson.version)
17
+ .configureOutput({
18
+ outputError: (str, write) => {
19
+ const formatted = str.replace(/^error:/i, 'Error:');
20
+ write(chalk.red(formatted));
21
+ }
22
+ });
17
23
  program
18
24
  .command("init")
19
25
  .argument("[tokenid]", "Fireberry token id")
@@ -23,10 +29,9 @@ program
23
29
  });
24
30
  program
25
31
  .command("create")
26
- .argument("[name...]", "App name")
27
- .description("Create a new Fireberry app")
28
- .action(async (nameArgs) => {
29
- const name = nameArgs ? nameArgs.join("-") : undefined;
32
+ .argument("[name]", "App name")
33
+ .description("Create a new Fireberry app with a component")
34
+ .action(async (name) => {
30
35
  await runCreate({ name });
31
36
  });
32
37
  program
@@ -13,6 +13,12 @@ import { HEIGHT_OPTIONS } from "../constants/height-options.js";
13
13
  const __filename = fileURLToPath(import.meta.url);
14
14
  const __dirname = path.dirname(__filename);
15
15
  const VALID_COMPONENT_TYPES = Object.values(COMPONENT_TYPE);
16
+ function sanitizeComponentName(name) {
17
+ return name
18
+ .toLowerCase()
19
+ .replace(/[^a-z0-9]+/g, "-")
20
+ .replace(/^-+|-+$/g, "");
21
+ }
16
22
  function validateComponentType(type) {
17
23
  if (!VALID_COMPONENT_TYPES.includes(type)) {
18
24
  throw new Error(`Invalid component type: "${type}". Valid types are: ${VALID_COMPONENT_TYPES.join(", ")}`);
@@ -118,17 +124,17 @@ export async function runCreateComponent({ type, name, }) {
118
124
  throw new Error(`Component with name "${componentName}" already exists in manifest.yml`);
119
125
  }
120
126
  const validatedType = validateComponentType(componentType);
127
+ const sanitizedName = sanitizeComponentName(componentName);
121
128
  const spinner = ora();
122
129
  try {
123
130
  const componentSettings = await promptForSettings(validatedType);
124
131
  spinner.text = chalk.cyan(`Creating Vite React app for "${chalk.cyan(componentName)}"...`);
125
132
  spinner.start();
126
- const componentDir = path.join(process.cwd(), "static", componentName);
133
+ const componentDir = path.join(process.cwd(), componentName);
127
134
  await fs.ensureDir(componentDir);
128
- // Create Vite app with React template
129
135
  spinner.text = `Running npm create vite@latest...`;
130
- const viteResult = spawnSync(`npm create vite@latest ${componentName} -- --template react --no-interactive`, {
131
- cwd: path.join(process.cwd(), "static"),
136
+ const viteResult = spawnSync(`npm create vite@latest ${sanitizedName} -- --template react --no-interactive`, {
137
+ cwd: process.cwd(),
132
138
  stdio: "inherit",
133
139
  shell: true,
134
140
  });
@@ -177,7 +183,7 @@ export async function runCreateComponent({ type, name, }) {
177
183
  type: validatedType,
178
184
  title: componentName,
179
185
  id: componentId,
180
- path: `static/${componentName}/dist`,
186
+ path: `${componentName}/dist`,
181
187
  settings: componentSettings,
182
188
  };
183
189
  if (!manifest.components) {
@@ -193,9 +199,9 @@ export async function runCreateComponent({ type, name, }) {
193
199
  spinner.succeed(`Successfully created component "${chalk.cyan(componentName)}"!`);
194
200
  console.log(chalk.gray(`Component ID: ${componentId}`));
195
201
  console.log(chalk.gray(`Type: ${validatedType}`));
196
- console.log(chalk.gray(`Path: static/${componentName}/dist`));
197
- console.log(chalk.green("\nšŸŽ‰ Your component is ready!"));
198
- console.log(chalk.white(` cd static/${componentName}`));
202
+ console.log(chalk.gray(`Path: ${sanitizedName}/dist`));
203
+ console.log(chalk.green(`\nYour component "${chalk.cyan(componentName)}" is ready!`));
204
+ console.log(chalk.white(` cd ${sanitizedName}`));
199
205
  console.log(chalk.white(` npm run dev # Start development server`));
200
206
  console.log(chalk.white(` npm run build # Build for production`));
201
207
  }
@@ -2,13 +2,12 @@ import inquirer from "inquirer";
2
2
  import path from "node:path";
3
3
  import fs from "fs-extra";
4
4
  import { v4 as uuidv4 } from "uuid";
5
- import { fileURLToPath } from "node:url";
5
+ import yaml from "js-yaml";
6
6
  import ora from "ora";
7
7
  import chalk from "chalk";
8
8
  import { createApp } from "../api/requests.js";
9
9
  import { getManifest } from "../utils/components.utils.js";
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = path.dirname(__filename);
10
+ import { runCreateComponent } from "./create-component.js";
12
11
  function slugifyName(name) {
13
12
  const validPattern = /^[a-zA-Z0-9_-]+$/;
14
13
  if (!validPattern.test(name)) {
@@ -20,44 +19,55 @@ export async function runCreate({ name }) {
20
19
  let appName = name;
21
20
  if (!appName) {
22
21
  const answers = await inquirer.prompt([
23
- { type: "input", name: "name", message: "App name" },
22
+ {
23
+ type: "input",
24
+ name: "name",
25
+ message: "App name:",
26
+ },
24
27
  ]);
25
28
  appName = (answers.name || "").trim();
26
29
  }
27
30
  if (!appName) {
28
- throw new Error("Missing name.");
31
+ throw new Error("Missing app name.");
29
32
  }
30
33
  const slug = slugifyName(appName);
31
34
  const appId = uuidv4();
32
- const componentId = uuidv4();
33
35
  const appDir = path.resolve(process.cwd(), slug);
36
+ const componentName = `${slug}-component`;
34
37
  if (await fs.pathExists(appDir)) {
35
38
  throw new Error(`Already exists. ${chalk.yellow(slug)}`);
36
39
  }
37
40
  const spinner = ora(`Creating app "${chalk.cyan(appName)}"...`).start();
41
+ const originalCwd = process.cwd();
38
42
  try {
39
43
  await fs.ensureDir(appDir);
40
- const templatesDir = path.join(__dirname, "..", "..", "src", "templates");
41
- const manifestTemplate = await fs.readFile(path.join(templatesDir, "manifest.yml"), "utf-8");
42
- const htmlTemplate = await fs.readFile(path.join(templatesDir, "index.html"), "utf-8");
43
- const manifestContent = manifestTemplate
44
- .replace(/{{appName}}/g, appName)
45
- .replace(/{{appId}}/g, appId)
46
- .replace(/{{componentId}}/g, componentId);
47
- const htmlContent = htmlTemplate.replace(/{{appName}}/g, appName);
48
- await fs.writeFile(path.join(appDir, "manifest.yml"), manifestContent);
49
- await fs.writeFile(path.join(appDir, "index.html"), htmlContent);
50
- const manifest = await getManifest(appDir);
51
- await createApp(manifest);
52
- spinner.succeed(`Successfully created "${chalk.cyan(appName)}" app!`);
44
+ const initialManifest = {
45
+ app: {
46
+ id: appId,
47
+ name: appName,
48
+ description: "",
49
+ },
50
+ components: [],
51
+ };
52
+ await fs.writeFile(path.join(appDir, "manifest.yml"), yaml.dump(initialManifest, { indent: 2, lineWidth: -1, noRefs: true }), "utf-8");
53
+ spinner.succeed(`App directory "${chalk.cyan(appName)}" created!`);
53
54
  console.log(chalk.gray(`šŸ“ Location: ${appDir}`));
54
55
  console.log(chalk.gray(`App ID: ${appId}`));
55
- console.log(chalk.green("\nšŸŽ‰ Your app is ready! Next steps:"));
56
+ process.chdir(appDir);
57
+ console.log(chalk.cyan(`\nAdding component "${componentName}"...`));
58
+ await runCreateComponent({ name: componentName });
59
+ spinner.start();
60
+ spinner.text = `Registering app with Fireberry...`;
61
+ await createApp(await getManifest());
62
+ spinner.succeed(`App registered with Fireberry!`);
63
+ console.log(chalk.green(`\nšŸŽ‰ Your app is ready!`));
64
+ console.log(chalk.white(`\nNext steps:`));
56
65
  console.log(chalk.white(` cd ${slug}`));
57
- console.log(chalk.white(" # Start developing your Fireberry app"));
66
+ console.log(chalk.white(` fireberry push # Push to Fireberry`));
58
67
  }
59
68
  catch (error) {
60
69
  spinner.fail(`Failed to create app "${chalk.cyan(appName)}"`);
70
+ process.chdir(originalCwd);
61
71
  throw error;
62
72
  }
63
73
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fireberry/cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Fireberry CLI tool",
5
5
  "type": "module",
6
6
  "author": "",
@@ -22,7 +22,7 @@
22
22
  "test": "node test/smoke.test.js",
23
23
  "version:beta": "npm version prerelease --preid=beta",
24
24
  "publish:beta": "npm run version:beta && npm publish --tag beta",
25
- "publish:prod": "npm publish --tag latest"
25
+ "publish:prod": "npm version patch && npm publish --tag latest"
26
26
  },
27
27
  "keywords": [
28
28
  "cli",
@@ -41,6 +41,8 @@
41
41
  "access": "public"
42
42
  },
43
43
  "dependencies": {
44
+ "@fireberry/ds": "^0.0.151",
45
+ "@fireberry/sdk": "^0.0.5",
44
46
  "axios": "^1.12.2",
45
47
  "chalk": "^5.3.0",
46
48
  "commander": "^12.1.0",
@@ -15,7 +15,13 @@ const program = new Command();
15
15
  program
16
16
  .name("fireberry")
17
17
  .description("Fireberry developer CLI")
18
- .version(packageJson.version);
18
+ .version(packageJson.version)
19
+ .configureOutput({
20
+ outputError: (str, write) => {
21
+ const formatted = str.replace(/^error:/i, 'Error:');
22
+ write(chalk.red(formatted));
23
+ }
24
+ });
19
25
 
20
26
  program
21
27
  .command("init")
@@ -27,11 +33,10 @@ program
27
33
 
28
34
  program
29
35
  .command("create")
30
- .argument("[name...]", "App name")
31
- .description("Create a new Fireberry app")
32
- .action(async (nameArgs?: string[]) => {
33
- const name = nameArgs ? nameArgs.join("-") : undefined;
34
- await runCreate({ name });
36
+ .argument("[name]", "App name")
37
+ .description("Create a new Fireberry app with a component")
38
+ .action(async (name?: string) => {
39
+ await runCreate({ name });
35
40
  });
36
41
 
37
42
  program
@@ -22,6 +22,13 @@ interface CreateComponentOptions {
22
22
 
23
23
  const VALID_COMPONENT_TYPES = Object.values(COMPONENT_TYPE);
24
24
 
25
+ function sanitizeComponentName(name: string): string {
26
+ return name
27
+ .toLowerCase()
28
+ .replace(/[^a-z0-9]+/g, "-")
29
+ .replace(/^-+|-+$/g, "");
30
+ }
31
+
25
32
  function validateComponentType(type: string): ComponentType {
26
33
  if (!VALID_COMPONENT_TYPES.includes(type as ComponentType)) {
27
34
  throw new Error(
@@ -156,6 +163,8 @@ export async function runCreateComponent({
156
163
 
157
164
  const validatedType = validateComponentType(componentType);
158
165
 
166
+ const sanitizedName = sanitizeComponentName(componentName);
167
+
159
168
  const spinner = ora();
160
169
 
161
170
  try {
@@ -166,15 +175,14 @@ export async function runCreateComponent({
166
175
  );
167
176
  spinner.start();
168
177
 
169
- const componentDir = path.join(process.cwd(), "static", componentName);
178
+ const componentDir = path.join(process.cwd(), componentName);
170
179
  await fs.ensureDir(componentDir);
171
180
 
172
- // Create Vite app with React template
173
181
  spinner.text = `Running npm create vite@latest...`;
174
182
  const viteResult = spawnSync(
175
- `npm create vite@latest ${componentName} -- --template react --no-interactive`,
183
+ `npm create vite@latest ${sanitizedName} -- --template react --no-interactive`,
176
184
  {
177
- cwd: path.join(process.cwd(), "static"),
185
+ cwd: process.cwd(),
178
186
  stdio: "inherit",
179
187
  shell: true,
180
188
  }
@@ -247,7 +255,7 @@ export async function runCreateComponent({
247
255
  type: validatedType,
248
256
  title: componentName,
249
257
  id: componentId,
250
- path: `static/${componentName}/dist`,
258
+ path: `${componentName}/dist`,
251
259
  settings: componentSettings,
252
260
  };
253
261
 
@@ -270,11 +278,15 @@ export async function runCreateComponent({
270
278
  spinner.succeed(
271
279
  `Successfully created component "${chalk.cyan(componentName)}"!`
272
280
  );
281
+
273
282
  console.log(chalk.gray(`Component ID: ${componentId}`));
274
283
  console.log(chalk.gray(`Type: ${validatedType}`));
275
- console.log(chalk.gray(`Path: static/${componentName}/dist`));
276
- console.log(chalk.green("\nšŸŽ‰ Your component is ready!"));
277
- console.log(chalk.white(` cd static/${componentName}`));
284
+ console.log(chalk.gray(`Path: ${sanitizedName}/dist`));
285
+
286
+ console.log(
287
+ chalk.green(`\nYour component "${chalk.cyan(componentName)}" is ready!`)
288
+ );
289
+ console.log(chalk.white(` cd ${sanitizedName}`));
278
290
  console.log(chalk.white(` npm run dev # Start development server`));
279
291
  console.log(chalk.white(` npm run build # Build for production`));
280
292
  } catch (error) {
@@ -2,14 +2,12 @@ import inquirer from "inquirer";
2
2
  import path from "node:path";
3
3
  import fs from "fs-extra";
4
4
  import { v4 as uuidv4 } from "uuid";
5
- import { fileURLToPath } from "node:url";
5
+ import yaml from "js-yaml";
6
6
  import ora from "ora";
7
7
  import chalk from "chalk";
8
8
  import { createApp } from "../api/requests.js";
9
9
  import { getManifest } from "../utils/components.utils.js";
10
-
11
- const __filename = fileURLToPath(import.meta.url);
12
- const __dirname = path.dirname(__filename);
10
+ import { runCreateComponent } from "./create-component.js";
13
11
 
14
12
  interface CreateOptions {
15
13
  name?: string;
@@ -31,59 +29,70 @@ export async function runCreate({ name }: CreateOptions): Promise<void> {
31
29
 
32
30
  if (!appName) {
33
31
  const answers = await inquirer.prompt([
34
- { type: "input", name: "name", message: "App name" },
32
+ {
33
+ type: "input",
34
+ name: "name",
35
+ message: "App name:",
36
+ },
35
37
  ]);
36
38
  appName = (answers.name || "").trim();
37
39
  }
40
+
38
41
  if (!appName) {
39
- throw new Error("Missing name.");
42
+ throw new Error("Missing app name.");
40
43
  }
41
44
 
42
45
  const slug = slugifyName(appName);
43
46
  const appId = uuidv4();
44
- const componentId = uuidv4();
45
47
  const appDir = path.resolve(process.cwd(), slug);
48
+ const componentName = `${slug}-component`;
46
49
 
47
50
  if (await fs.pathExists(appDir)) {
48
51
  throw new Error(`Already exists. ${chalk.yellow(slug)}`);
49
52
  }
50
53
 
51
54
  const spinner = ora(`Creating app "${chalk.cyan(appName)}"...`).start();
55
+ const originalCwd = process.cwd();
52
56
 
53
57
  try {
54
58
  await fs.ensureDir(appDir);
55
59
 
56
- const templatesDir = path.join(__dirname, "..", "..", "src", "templates");
57
- const manifestTemplate = await fs.readFile(
58
- path.join(templatesDir, "manifest.yml"),
59
- "utf-8"
60
- );
61
- const htmlTemplate = await fs.readFile(
62
- path.join(templatesDir, "index.html"),
60
+ const initialManifest = {
61
+ app: {
62
+ id: appId,
63
+ name: appName,
64
+ description: "",
65
+ },
66
+ components: [],
67
+ };
68
+
69
+ await fs.writeFile(
70
+ path.join(appDir, "manifest.yml"),
71
+ yaml.dump(initialManifest, { indent: 2, lineWidth: -1, noRefs: true }),
63
72
  "utf-8"
64
73
  );
65
74
 
66
- const manifestContent = manifestTemplate
67
- .replace(/{{appName}}/g, appName)
68
- .replace(/{{appId}}/g, appId)
69
- .replace(/{{componentId}}/g, componentId);
75
+ spinner.succeed(`App directory "${chalk.cyan(appName)}" created!`);
76
+ console.log(chalk.gray(`šŸ“ Location: ${appDir}`));
77
+ console.log(chalk.gray(`App ID: ${appId}`));
70
78
 
71
- const htmlContent = htmlTemplate.replace(/{{appName}}/g, appName);
79
+ process.chdir(appDir);
72
80
 
73
- await fs.writeFile(path.join(appDir, "manifest.yml"), manifestContent);
74
- await fs.writeFile(path.join(appDir, "index.html"), htmlContent);
75
- const manifest = await getManifest(appDir);
81
+ console.log(chalk.cyan(`\nAdding component "${componentName}"...`));
76
82
 
77
- await createApp(manifest);
83
+ await runCreateComponent({ name: componentName });
84
+ spinner.start();
85
+ spinner.text = `Registering app with Fireberry...`;
86
+ await createApp(await getManifest());
87
+ spinner.succeed(`App registered with Fireberry!`);
78
88
 
79
- spinner.succeed(`Successfully created "${chalk.cyan(appName)}" app!`);
80
- console.log(chalk.gray(`šŸ“ Location: ${appDir}`));
81
- console.log(chalk.gray(`App ID: ${appId}`));
82
- console.log(chalk.green("\nšŸŽ‰ Your app is ready! Next steps:"));
89
+ console.log(chalk.green(`\nšŸŽ‰ Your app is ready!`));
90
+ console.log(chalk.white(`\nNext steps:`));
83
91
  console.log(chalk.white(` cd ${slug}`));
84
- console.log(chalk.white(" # Start developing your Fireberry app"));
92
+ console.log(chalk.white(` fireberry push # Push to Fireberry`));
85
93
  } catch (error) {
86
94
  spinner.fail(`Failed to create app "${chalk.cyan(appName)}"`);
95
+ process.chdir(originalCwd);
87
96
  throw error;
88
97
  }
89
98
  }
@@ -1,15 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>{{appName}}</title>
8
- </head>
9
-
10
- <body>
11
- <h1>Hello World</h1>
12
- <p>Welcome to {{appName}}!</p>
13
- </body>
14
-
15
- </html>
@@ -1,14 +0,0 @@
1
- app:
2
- id: "{{appId}}"
3
- name: "{{appName}}"
4
- description: ""
5
- components:
6
- - type: record
7
- title: my-first-component
8
- id: "{{componentId}}"
9
- path: static/comp/build
10
- settings:
11
- iconName: "related-single"
12
- iconColor: "#7aae7f"
13
- objectType: 0
14
- height: "M"