Skip to content

hızlı proje kurulumu ve kullanımı için gea-cli eklendi.#12

Open
hacimertgokhan wants to merge 2 commits intodashersw:mainfrom
hacimertgokhan:feat/gea-cli
Open

hızlı proje kurulumu ve kullanımı için gea-cli eklendi.#12
hacimertgokhan wants to merge 2 commits intodashersw:mainfrom
hacimertgokhan:feat/gea-cli

Conversation

@hacimertgokhan
Copy link
Copy Markdown

@hacimertgokhan hacimertgokhan commented Mar 25, 2026

gea-cli: Proje yönetimi, yeni bileşen ve store ekleme gibi geliştirici deneyimini hızlandıran komutlar eklendi.
create-gea: clack/prompts kütüphanesi kullanılarak interaktif proje kurulum arayüzüne geçildi.
şablonlar: Kurulum sırasında Standard, Mobile ve Dashboard seçeneklerinin sunulması sağlandı.

Summary by CodeRabbit

  • New Features

    • Interactive project scaffolding with template selection (default, mobile, dashboard)
    • New gea CLI commands: init, dev, add
    • Added standalone gea CLI executable and npm script to run it
  • Chores

    • Improved CLI prompts, progress spinners, and formatted output
    • Added mobile and dashboard project templates and starter app scaffolds

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 25, 2026

📝 Walkthrough

Walkthrough

Adds a new CLI package (packages/gea-cli) with gea npm script, enhances create-gea to use interactive prompts and template selection, and introduces three project templates (default, mobile, dashboard) with scaffolding, configs, and assets.

Changes

Cohort / File(s) Summary
Root npm script
package.json
Added gea script to run node packages/gea-cli/bin/gea.js.
CLI package
packages/gea-cli/bin/gea.js, packages/gea-cli/package.json
New executable CLI with init, dev, add commands; project-root detection; uses commander, @clack/prompts, execa, fs-extra, kolorist, picocolors.
create-gea CLI
packages/create-gea/bin/create-gea.js, packages/create-gea/package.json
Replaced readline with @clack/prompts, added template selection, spinner/output formatting, improved directory/template handling; added runtime deps and changed files from templatetemplates.
Default template
packages/create-gea/templates/default/*
New default scaffold: components, store, tsconfig.json, _gitignore, Vite config, and example components.
Mobile template
packages/create-gea/templates/mobile/*
New mobile scaffold: index.html, package.json, app components, store, styles, Vite config, and tsconfig.json.
Dashboard template
packages/create-gea/templates/dashboard/*
New dashboard scaffold: index.html, package.json, src/app.tsx, main.ts, styles, and Vite config (port 5190).

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant CLI as gea (packages/gea-cli)
  participant Prompts as `@clack/prompts`
  participant Shell as npm/execa
  participant FS as Filesystem

  User->>CLI: run `npx gea init [name]` or `npm run gea init`
  CLI->>Prompts: show intro / ask project name & template
  Prompts-->>CLI: project name, template
  CLI->>Shell: run `npm create gea@latest <name>` (execa)
  Shell-->>CLI: process output / exit
  CLI->>FS: create/copy files if needed (scaffold)
  CLI-->>User: show outro / next steps
Loading
sequenceDiagram
  participant User as User
  participant CLI as gea (packages/gea-cli)
  participant FS as Filesystem
  participant Spinner as Spinner/Output

  User->>CLI: run `gea add component|store <name>`
  CLI->>FS: ensure `src/` exists
  CLI->>FS: write `src/<name>.tsx` or `src/<name>.ts`
  CLI->>Spinner: show success message
  CLI-->>User: completion notice
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I dug a CLI in code so bright,
Templates sprouted in the night,
Init and add, dev to run,
Projects bloom beneath the sun,
A hopping helper—ready, light! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title in Turkish translates to 'gea-cli added for quick project setup and usage.' It directly reflects the main change: adding a new gea-cli package with init, dev, and add commands, plus interactive create-gea setup via @clack/prompts and new project templates (standard, mobile, dashboard).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@hacimertgokhan
Copy link
Copy Markdown
Author

normal bir cli olduğunun farkında olarak bu cli'ı geliştirdim. mobil vb. platformlar ın proje üretiminide aynı noktadan oluşturabilmek için tekilleştirme gereği duydum.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (2)
packages/gea-cli/package.json (1)

18-18: Remove unused picocolors dependency.

The picocolors package is declared as a dependency but never imported or used in the codebase. The CLI uses kolorist for terminal colors instead. Removing this unused dependency reduces package bloat.

♻️ Proposed fix
   "dependencies": {
     "commander": "^13.1.0",
     "@clack/prompts": "^1.1.0",
     "kolorist": "^1.8.0",
-    "picocolors": "^1.1.1",
     "execa": "^9.0.2",
     "fs-extra": "^11.3.0"
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/gea-cli/package.json` at line 18, The package.json lists an unused
dependency "picocolors" while the CLI uses "kolorist"; remove the "picocolors"
entry from package.json dependencies, update the lockfile by running the package
manager's install (npm/yarn/pnpm) to regenerate locks, and verify no import
references to "picocolors" remain by searching the codebase (look for
"picocolors" string) and ensuring all color usage comes from "kolorist" (verify
files that import kolorist).
packages/create-gea/bin/create-gea.js (1)

97-100: Prefer failing fast over silently falling back to default.

Line 99 turns a missing template folder into a successful Standard scaffold. That hides packaging mistakes and gives users the wrong project shape.

♻️ Proposed change
   const selectedTemplateDir = resolve(templatesDir, template)
 
-  const templateToUse = existsSync(selectedTemplateDir) ? template : 'default'
-  cpSync(resolve(templatesDir, templateToUse), projectRoot, { recursive: true })
+  if (!existsSync(selectedTemplateDir)) {
+    throw new Error(`Template "${template}" is not available in this build`)
+  }
+
+  cpSync(selectedTemplateDir, projectRoot, { recursive: true })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/create-gea/bin/create-gea.js` around lines 97 - 100, The current
logic silently falls back to the 'default' template when the requested template
folder is missing (selectedTemplateDir / templateToUse), which masks packaging
errors; change it to fail fast by checking existsSync(selectedTemplateDir) and,
if false, log or throw a clear error (including the requested template name and
templatesDir) and exit non‑zero instead of assigning 'default' and calling
cpSync; keep cpSync(resolve(templatesDir, template), projectRoot, { recursive:
true }) only for the success path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/create-gea/bin/create-gea.js`:
- Around line 61-70: The validator for targetDir (inside the text(...) call) is
only applied when the interactive prompt returns a truthy value, so positional
args like create-gea existing-dir bypass the non-empty check; update the flow so
after collecting input (the text(...) result and the positional arg fallback
assigned to targetDir) you run the same validation logic using
existsSync(resolve(process.cwd(), targetDir)) and
isEmptyDir(resolve(process.cwd(), targetDir)), rejecting non-empty directories
and blank strings; ensure you reuse the same error message ("Target directory is
not empty") and apply the identical check in the later code block referenced
around lines 78-95 where targetDir may be set from argv so both interactive and
positional paths are validated consistently.
- Around line 123-125: The printed "cd" in the outro message isn't shell-safe
for directories with spaces; update the template passed to outro so the cd
command quotes (or otherwise shell-escapes) targetDir. Specifically, change the
interpolation that builds the cd line (currently using targetDir) to produce cd
"targetDir" (or an escaped equivalent) so the variable targetDir is quoted in
the string passed to outro alongside installCommand and devCommand.

In `@packages/create-gea/package.json`:
- Around line 26-30: The package create-gea lists an unused dependency
"picocolors" in its package.json dependencies; remove the "picocolors" entry
from the "dependencies" object in package.json, then reinstall/update lockfiles
(run npm/yarn/pnpm install) to reflect the change and ensure no code references
remain to "picocolors" (search for "picocolors" in the package to confirm).

In `@packages/create-gea/templates/dashboard/src/styles.css`:
- Line 8: The CSS rule uses quoted font-family name 'Inter' which violates the
font-family-name-quotes lint rule; update the declaration in styles.css (the
font-family property) to remove the single quotes around Inter so it reads the
unquoted font name (keep system-ui and sans-serif unchanged) to satisfy the
linter.

In `@packages/create-gea/templates/mobile/src/styles.css`:
- Line 63: The font-family declaration using 'SFMono-Regular' violates
stylelint's font-family-name-quotes rule; update the CSS rule that contains
font-family: 'SFMono-Regular', ui-monospace, monospace; (search for that exact
string) and remove the single quotes around SFMono-Regular so it reads
SFMono-Regular, ui-monospace, monospace to satisfy the linter.

In `@packages/gea-cli/bin/gea.js`:
- Around line 59-61: The failure paths currently call cancel(...) but do not set
a non-zero exit status; update the init catch block (the catch handling errors
from init) and the "unknown type" error branch to set a non-zero exit code
(e.g., process.exitCode = 1 or call process.exit(1)) after calling cancel so the
process returns failure to CI/scripts; locate the catch around init and the
branch that reports "unknown type" and append a non-zero exit handling
statement.
- Around line 92-100: The code constructs filePath from untrusted name (used in
the component branch where type === 'component') which permits path traversal;
sanitize and validate name before forming filePath: reject names containing path
separators or parent segments (e.g. '/' or '..') or normalize the resolved path
and ensure it is inside srcDir (use path.resolve(srcDir, fileName) then verify
the resulting path starts with srcDir or that path.relative(srcDir,
resolvedPath) does not start with '..'); apply the same validation for the other
creation branch that also builds a path from name (the block creating filePath
around fileName at the later lines) and fail early with a clear error if
validation fails.
- Around line 16-24: The loop in getProjectRoot (variable current) uses while
(current !== '/') which hangs on Windows drive roots; change the logic to break
when the parent directory equals the current directory (compute parent =
dirname(current) each iteration and stop if parent === current), or use while
(parent !== current) / a bounded loop instead; keep the existing package.json
check and return current when `@geajs/core` is found, otherwise set current =
parent and continue.
- Around line 101-124: The generated scaffolds import and use the wrong API and
JSX attribute: replace the import of createStore with the correct export from
`@geajs/core` (use Store for store types) and keep Component for components;
update the store template to export a Store (e.g., export const ${name}: Store =
{ ... }) and update the component template to use the JSX attribute class (not
className) in the returned markup; locate the templates around the variables
content, filePath and fileName in the component and store branches and change
the import lines and template strings accordingly so they match `@geajs/core`
exports (Component and Store) and use class in the component JSX.

In `@packages/gea-cli/package.json`:
- Around line 2-3: This PR adds a new package "gea-cli" but lacks a changeset;
run npx changeset in the repo root, create an initial changeset that includes
the "gea-cli" package with the appropriate release type (patch/initial) and a
short summary, then commit the generated .changeset YAML file so the package is
included in the release workflow.

---

Nitpick comments:
In `@packages/create-gea/bin/create-gea.js`:
- Around line 97-100: The current logic silently falls back to the 'default'
template when the requested template folder is missing (selectedTemplateDir /
templateToUse), which masks packaging errors; change it to fail fast by checking
existsSync(selectedTemplateDir) and, if false, log or throw a clear error
(including the requested template name and templatesDir) and exit non‑zero
instead of assigning 'default' and calling cpSync; keep
cpSync(resolve(templatesDir, template), projectRoot, { recursive: true }) only
for the success path.

In `@packages/gea-cli/package.json`:
- Line 18: The package.json lists an unused dependency "picocolors" while the
CLI uses "kolorist"; remove the "picocolors" entry from package.json
dependencies, update the lockfile by running the package manager's install
(npm/yarn/pnpm) to regenerate locks, and verify no import references to
"picocolors" remain by searching the codebase (look for "picocolors" string) and
ensuring all color usage comes from "kolorist" (verify files that import
kolorist).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d6a22f02-0477-4aca-970f-2fdc3225d453

📥 Commits

Reviewing files that changed from the base of the PR and between e12c19d and ed7415d.

⛔ Files ignored due to path filters (6)
  • packages/create-gea/templates/dashboard/public/favicon.ico is excluded by !**/*.ico
  • packages/create-gea/templates/dashboard/public/logo.png is excluded by !**/*.png
  • packages/create-gea/templates/default/public/favicon.ico is excluded by !**/*.ico
  • packages/create-gea/templates/default/public/logo.png is excluded by !**/*.png
  • packages/create-gea/templates/mobile/public/favicon.ico is excluded by !**/*.ico
  • packages/create-gea/templates/mobile/public/logo.png is excluded by !**/*.png
📒 Files selected for processing (38)
  • package.json
  • packages/create-gea/bin/create-gea.js
  • packages/create-gea/package.json
  • packages/create-gea/templates/dashboard/_gitignore
  • packages/create-gea/templates/dashboard/index.html
  • packages/create-gea/templates/dashboard/package.json
  • packages/create-gea/templates/dashboard/src/app.tsx
  • packages/create-gea/templates/dashboard/src/counter-note.tsx
  • packages/create-gea/templates/dashboard/src/counter-panel.tsx
  • packages/create-gea/templates/dashboard/src/counter-store.ts
  • packages/create-gea/templates/dashboard/src/main.ts
  • packages/create-gea/templates/dashboard/src/styles.css
  • packages/create-gea/templates/dashboard/tsconfig.json
  • packages/create-gea/templates/dashboard/vite.config.ts
  • packages/create-gea/templates/default/_gitignore
  • packages/create-gea/templates/default/index.html
  • packages/create-gea/templates/default/package.json
  • packages/create-gea/templates/default/src/app.tsx
  • packages/create-gea/templates/default/src/counter-note.tsx
  • packages/create-gea/templates/default/src/counter-panel.tsx
  • packages/create-gea/templates/default/src/counter-store.ts
  • packages/create-gea/templates/default/src/main.ts
  • packages/create-gea/templates/default/src/styles.css
  • packages/create-gea/templates/default/tsconfig.json
  • packages/create-gea/templates/default/vite.config.ts
  • packages/create-gea/templates/mobile/_gitignore
  • packages/create-gea/templates/mobile/index.html
  • packages/create-gea/templates/mobile/package.json
  • packages/create-gea/templates/mobile/src/app.tsx
  • packages/create-gea/templates/mobile/src/counter-note.tsx
  • packages/create-gea/templates/mobile/src/counter-panel.tsx
  • packages/create-gea/templates/mobile/src/counter-store.ts
  • packages/create-gea/templates/mobile/src/main.ts
  • packages/create-gea/templates/mobile/src/styles.css
  • packages/create-gea/templates/mobile/tsconfig.json
  • packages/create-gea/templates/mobile/vite.config.ts
  • packages/gea-cli/bin/gea.js
  • packages/gea-cli/package.json

Comment on lines +2 to +3
"name": "gea-cli",
"version": "1.0.0",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if a changeset file exists for this PR

# Look for changeset files that might reference gea-cli
fd -e md . .changeset/ --exec cat {} \; 2>/dev/null | head -50

Repository: dashersw/gea

Length of output: 567


🏁 Script executed:

#!/bin/bash
# List all files in .changeset/ to see what exists
ls -la .changeset/ | grep -v "^total"

Repository: dashersw/gea

Length of output: 278


🏁 Script executed:

#!/bin/bash
# Check .changeset/config.json for any ignore rules or special configuration
cat .changeset/config.json

Repository: dashersw/gea

Length of output: 406


🏁 Script executed:

#!/bin/bash
# Check if there are any .md files in .changeset/ besides README.md
find .changeset -name "*.md" -not -name "README.md" | head -20

Repository: dashersw/gea

Length of output: 38


Create a changeset for this new package.

Per the project's changeset workflow, every PR that changes published package output must include a changeset file. Since this is a new package, run npx changeset to declare the initial release.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/gea-cli/package.json` around lines 2 - 3, This PR adds a new package
"gea-cli" but lacks a changeset; run npx changeset in the repo root, create an
initial changeset that includes the "gea-cli" package with the appropriate
release type (patch/initial) and a short summary, then commit the generated
.changeset YAML file so the package is included in the release workflow.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/create-gea/bin/create-gea.js`:
- Around line 1-8: The published CLI entry file create-gea.js lacks a Node
shebang so POSIX systems execute it as a shell script; fix by inserting a single
line shebang "#!/usr/bin/env node" as the very first line of
packages/create-gea/bin/create-gea.js (before the first import), keep the rest
of the file unchanged, and ensure the file has executable permissions in the
package (so the bin symlink will run with Node).

In `@packages/gea-cli/bin/gea.js`:
- Around line 106-121: The code currently writes the generated component/store
unconditionally via fs.writeFile (using fileName/filePath/content), which will
overwrite existing files; update the logic to check for an existing file at
filePath before writing (e.g., use fs.existsSync, fs.stat, or fs.pathExists) and
if the file exists, abort or prompt the user rather than calling fs.writeFile;
ensure this same guard is applied to both places that call fs.writeFile (the
component and store branches) so existing user code is not silently replaced.
- Around line 54-60: Remove the wrapper UX: do not start or stop the local
spinner or print a success/outro unconditionally around the child CLI; instead
invoke execa('npm', ['create', 'gea@latest', name], { stdio: 'inherit' }) and
only print a success message if the child process truly exited successfully
(check the resolved exit code or allow execa to throw on non-zero), or better
yet let the child CLI (create-gea) own all interactive prompts and its own outro
by deleting the spinner creation/start (spinner(), s.start(...) and s.stop(...))
and the outro(...) call so the child output is the only UX the user sees.
- Line 141: The CLI uses Commander’s synchronous parse() so async command
handlers (the dev action that calls execa and the add action that uses fs-extra)
can produce unhandled rejections; change the invocation to use
program.parseAsync() so Commander will await and surface rejections, and ensure
the async action handlers (dev and add) return/await their promises so errors
propagate through Commander’s promise chain.
- Around line 92-95: The CLI currently uses the raw `name` value as a
source-code identifier which allows inputs that produce invalid JS symbols;
update the validation and/or symbol derivation: reject `name` values that do not
match a legal JavaScript identifier (use a regex like
/^[A-Za-z_$][A-Za-z0-9_$]*$/) and check against JS reserved words, or derive a
safe identifier (e.g., convert `name` to a camelCase/PascalCase symbol, strip or
replace invalid characters, ensure it doesn't start with a digit, and fall back
to a prefix like `_` if needed). Apply this fix to the initial guard around
`name` and the other places flagged (the uses around lines 109-119 and 127-131)
so source templates never embed the raw CLI `name` as an identifier.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d36942b8-e4f5-473b-b442-fadf24e7deea

📥 Commits

Reviewing files that changed from the base of the PR and between ed7415d and 3f2f17c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • packages/create-gea/bin/create-gea.js
  • packages/create-gea/package.json
  • packages/create-gea/templates/dashboard/src/styles.css
  • packages/create-gea/templates/mobile/src/styles.css
  • packages/gea-cli/bin/gea.js
✅ Files skipped from review due to trivial changes (2)
  • packages/create-gea/templates/dashboard/src/styles.css
  • packages/create-gea/templates/mobile/src/styles.css
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/create-gea/package.json

Comment on lines +1 to +8
import { cpSync, existsSync, readdirSync, readFileSync, renameSync, writeFileSync, mkdirSync } from 'node:fs'
import { basename, dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { stdin as input, stdout as output } from 'node:process'
import { createInterface } from 'node:readline/promises'
import { intro, outro, text, select, confirm, isCancel, cancel, spinner } from '@clack/prompts'
import { cyan, gray, green, reset } from 'kolorist'

const __dirname = dirname(fileURLToPath(import.meta.url))
const templateDir = resolve(__dirname, '../template')

function printHelp() {
console.log(`create-gea
const templatesDir = resolve(__dirname, '../templates')
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, check if packages/create-gea directory exists
fd "package.json" packages/create-gea

# Then examine the package.json for bin entry
cat -n packages/create-gea/package.json

Repository: dashersw/gea

Length of output: 1082


🏁 Script executed:

# Check the current state of create-gea.js
head -20 packages/create-gea/bin/create-gea.js

Repository: dashersw/gea

Length of output: 958


🌐 Web query:

npm bin entry shebang requirement ES modules

💡 Result:

Yes, npm bin entry scripts require a shebang line (e.g., #!/usr/bin/env node) as the first line. This is a strong convention and practically required for correct execution, especially on Unix-like systems and via npx. On Unix, npm creates symlinks in node_modules/.bin to the script. Without a shebang, the OS treats it as a shell script, leading to syntax errors on JS/ESM content (e.g., "use strict: command not found"). On Windows, npm uses cmd-shim to create batch files that parse the shebang to invoke the correct interpreter (node) with arguments. Without it, the shim defaults to plain node script.js, which works for CJS but fails for ESM without "type": "module" or .mjs (syntax error on import/export). For ES modules (package.json "type": "module" or .mjs), the shebang #!/usr/bin/env node still works in modern Node.js (post-v12), as Node detects ESM via package type or extension when running the entry script. No special flags needed since v14+. Official npm docs imply executables need shebangs via examples and manpages. Community sources (SO, GitHub issues) confirm: missing shebang breaks execution, especially for ESM CLIs. Example bin script for ESM: #!/usr/bin/env node import { someFunc } from './utils.js'; someFunc; With "bin": {"mycli": "cli.js"} and "type": "module". Make executable: chmod +x cli.js. Sources confirm this across Node/npm versions up to 2026.

Citations:


Add Node shebang to the published bin entry.

packages/create-gea/package.json exposes bin/create-gea.js as an executable, but it currently starts with an import statement. Without a shebang, the symlink created on POSIX systems (Linux, macOS) will fail with "import: command not found" because the OS treats the file as a shell script instead of passing it to Node.

💡 Minimal fix
+#!/usr/bin/env node
 import { cpSync, existsSync, readdirSync, readFileSync, renameSync, writeFileSync, mkdirSync } from 'node:fs'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/create-gea/bin/create-gea.js` around lines 1 - 8, The published CLI
entry file create-gea.js lacks a Node shebang so POSIX systems execute it as a
shell script; fix by inserting a single line shebang "#!/usr/bin/env node" as
the very first line of packages/create-gea/bin/create-gea.js (before the first
import), keep the rest of the file unchanged, and ensure the file has executable
permissions in the package (so the bin symlink will run with Node).

Comment on lines +54 to +60
const s = spinner()
s.start('Initalizing project...')

await execa('npm', ['create', 'gea@latest', name], { stdio: 'inherit' })

s.stop(green('Project initialized!'))
outro(`Happy coding with ${cyan('Gea')}!`)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Let create-gea own the interactive UX here.

This wrapper starts a spinner and always prints success after npm create gea@latest, but the child CLI already renders its own prompts/outro. Since packages/create-gea/bin/create-gea.js exits with code 0 on cancel, a canceled template selection still reaches Project initialized! here.

💡 Minimal fix
-      const s = spinner()
-      s.start('Initalizing project...')
-
       await execa('npm', ['create', 'gea@latest', name], { stdio: 'inherit' })
-
-      s.stop(green('Project initialized!'))
-      outro(`Happy coding with ${cyan('Gea')}!`)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/gea-cli/bin/gea.js` around lines 54 - 60, Remove the wrapper UX: do
not start or stop the local spinner or print a success/outro unconditionally
around the child CLI; instead invoke execa('npm', ['create', 'gea@latest',
name], { stdio: 'inherit' }) and only print a success message if the child
process truly exited successfully (check the resolved exit code or allow execa
to throw on non-zero), or better yet let the child CLI (create-gea) own all
interactive prompts and its own outro by deleting the spinner creation/start
(spinner(), s.start(...) and s.stop(...)) and the outro(...) call so the child
output is the only UX the user sees.

Comment on lines +92 to +95
if (name.includes('/') || name.includes('\\') || name.includes('..')) {
console.error(yellow('Invalid name: path segments are not allowed'))
process.exit(1)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Stop reusing the raw CLI name as a source-code identifier.

The current guard only blocks path segments. Inputs like Header.tsx, my-component, or user profile still pass, but they generate invalid declarations such as class Header.tsx or const my-component. Either derive a separate safe symbol name or reject anything that is not a legal, non-conflicting JS identifier.

Also applies to: 109-119, 127-131

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/gea-cli/bin/gea.js` around lines 92 - 95, The CLI currently uses the
raw `name` value as a source-code identifier which allows inputs that produce
invalid JS symbols; update the validation and/or symbol derivation: reject
`name` values that do not match a legal JavaScript identifier (use a regex like
/^[A-Za-z_$][A-Za-z0-9_$]*$/) and check against JS reserved words, or derive a
safe identifier (e.g., convert `name` to a camelCase/PascalCase symbol, strip or
replace invalid characters, ensure it doesn't start with a digit, and fall back
to a prefix like `_` if needed). Apply this fix to the initial guard around
`name` and the other places flagged (the uses around lines 109-119 and 127-131)
so source templates never embed the raw CLI `name` as an identifier.

Comment on lines +106 to +121
const fileName = name.endsWith('.tsx') ? name : `${name}.tsx`
const filePath = resolve(srcDir, fileName)

const content = `import { Component } from '@geajs/core';

export default class ${name} extends Component {
template() {
return (
<div class="${name.toLowerCase()}">
<h2>Hello from ${name}</h2>
</div>
);
}
}
`
await fs.writeFile(filePath, content)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Guard against overwriting existing files in src/.

Both branches call fs.writeFile() unconditionally. Re-running gea add component App or gea add store counter will silently replace user code.

💡 Minimal fix
       const fileName = name.endsWith('.tsx') ? name : `${name}.tsx`
       const filePath = resolve(srcDir, fileName)
+      if (await fs.pathExists(filePath)) {
+        s.stop(yellow(`File already exists: ${gray(filePath)}`))
+        process.exit(1)
+      }
@@
       const fileName = name.endsWith('.ts') ? name : `${name}.ts`
       const filePath = resolve(srcDir, fileName)
+      if (await fs.pathExists(filePath)) {
+        s.stop(yellow(`File already exists: ${gray(filePath)}`))
+        process.exit(1)
+      }

Also applies to: 124-133

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/gea-cli/bin/gea.js` around lines 106 - 121, The code currently
writes the generated component/store unconditionally via fs.writeFile (using
fileName/filePath/content), which will overwrite existing files; update the
logic to check for an existing file at filePath before writing (e.g., use
fs.existsSync, fs.stat, or fs.pathExists) and if the file exists, abort or
prompt the user rather than calling fs.writeFile; ensure this same guard is
applied to both places that call fs.writeFile (the component and store branches)
so existing user code is not silently replaced.

}
})

program.parse()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -path "*/packages/gea-cli/bin/gea.js" -type f

Repository: dashersw/gea

Length of output: 85


🏁 Script executed:

cat -n packages/gea-cli/bin/gea.js

Repository: dashersw/gea

Length of output: 4834


🏁 Script executed:

# Also check the directory structure of the gea-cli package
find ./packages/gea-cli -type f -name "*.js" | head -20

Repository: dashersw/gea

Length of output: 85


Switch Commander to parseAsync() to handle async action rejections.

The dev and add commands are async but use program.parse(), which doesn't await them. Rejections from execa() at line 77 (dev) or fs-extra at lines 102, 121, and 133 (add) will become unhandled promise rejections instead of going through the normal CLI failure path.

💡 Minimal fix
-program.parse()
+program.parseAsync().catch((error) => {
+  cancel(error instanceof Error ? error.message : String(error))
+  process.exit(1)
+})
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
program.parse()
program.parseAsync().catch((error) => {
cancel(error instanceof Error ? error.message : String(error))
process.exit(1)
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/gea-cli/bin/gea.js` at line 141, The CLI uses Commander’s
synchronous parse() so async command handlers (the dev action that calls execa
and the add action that uses fs-extra) can produce unhandled rejections; change
the invocation to use program.parseAsync() so Commander will await and surface
rejections, and ensure the async action handlers (dev and add) return/await
their promises so errors propagate through Commander’s promise chain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant