From 272adba140882a21a52e10836ea11d15ca44425b Mon Sep 17 00:00:00 2001 From: Matteo Bruni <176620+matteobruni@users.noreply.github.com> Date: Tue, 10 Mar 2026 19:53:34 +0100 Subject: [PATCH 1/7] build: updated pnpm --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd1faa8..8ade52b 100644 --- a/package.json +++ b/package.json @@ -81,5 +81,5 @@ "description": "tsParticles CLI", "main": "eslint.config.js", "author": "Matteo Bruni ", - "packageManager": "pnpm@10.31.0" + "packageManager": "pnpm@10.32.0" } From b5259d5ec9e7998deb2cd02fb8efc4a85fd121b5 Mon Sep 17 00:00:00 2001 From: Matteo Bruni <176620+matteobruni@users.noreply.github.com> Date: Tue, 10 Mar 2026 22:47:56 +0100 Subject: [PATCH 2/7] docs: map existing codebase (.planning/codebase) --- .planning/codebase/ARCHITECTURE.md | 134 ++++++++++++++++----------- .planning/codebase/CONCERNS.md | 119 ++++++++++++------------ .planning/codebase/CONVENTIONS.md | 99 ++++++++++---------- .planning/codebase/INTEGRATIONS.md | 43 +++++---- .planning/codebase/STACK.md | 68 +++++++------- .planning/codebase/STRUCTURE.md | 140 +++++++++++++++++----------- .planning/codebase/TESTING.md | 142 ++++++++++++++++------------- 7 files changed, 421 insertions(+), 324 deletions(-) diff --git a/.planning/codebase/ARCHITECTURE.md b/.planning/codebase/ARCHITECTURE.md index d0ef734..ece0635 100644 --- a/.planning/codebase/ARCHITECTURE.md +++ b/.planning/codebase/ARCHITECTURE.md @@ -1,100 +1,132 @@ # Architecture -**Analysis Date:** 2026-03-08 +**Analysis Date:** 2026-03-10 ## Pattern Overview -**Overall:** Modular CLI application structured as command modules (command-per-file) with utility layers for filesystem and template operations. +Overall: Small modular CLI application organized as command modules with utility libraries and build tooling. -**Key Characteristics:** +Key Characteristics: -- Command-oriented boundaries implemented with `commander` (commands registered in `src/cli.ts` and `src/create/*`, `src/build/*`). -- Utilities are centralized under `src/utils/` for file operations, templating, and string manipulation. -- Build-related logic is under `src/build/` and creation/template generation logic under `src/create/`. +- Single-process Node.js CLI built in TypeScript (compiled to ESM JavaScript). +- Commands are organized as independent modules and registered with a central `commander`-based entrypoint. +- Clear separation between "command" code (user-facing CLI actions) and utilities (I/O, template manipulation, subprocess execution). +- Build scripts live under `src/build` and are implemented as programmatic build tasks callable from `build` command. ## Layers -**CLI / Entry Layer:** +Command Layer: -- Purpose: Expose CLI commands and wiring. -- Location: `src/cli.ts` -- Contains: Program initialization, command registration (`build`, `create`). -- Depends on: `src/build/*`, `src/create/*`. -- Used by: End users invoking the installed binary. +- Purpose: Exposes CLI commands and their behaviors to end users. +- Location: `src/cli.ts`, `src/create/*`, `src/build/*` +- Contains: `commander` Command instances, argument parsing, user prompts. +- Depends on: `src/utils/*` for filesystem and template operations, `prompts` for interactive input. +- Used by: CLI entrypoint `src/cli.ts` registers commands for runtime. + +Core/Template Layer: -**Command Implementations:** +- Purpose: Implement the core operations that create projects and manipulate templates. +- Location: `src/create/preset/create-preset.ts`, `src/create/shape/create-shape.ts`, `src/create/plugin/create-plugin.ts`, `src/utils/template-utils.ts`, `src/utils/file-utils.ts` +- Contains: file copy, token replacement, package.json updates, npm execution, webpack/package dist adjustments. +- Depends on: `fs-extra`, `lookpath`, child_process `exec`. +- Used by: Command actions in `src/create/*`. -- Purpose: Implement individual subcommands for build and create flows. -- Location: `src/create/*` (e.g. `src/create/create.ts`, `src/create/preset/*`, `src/create/plugin/*`, `src/create/shape/*`) and `src/build/*` (e.g. `src/build/build.ts`, `src/build/build-*.ts`). -- Contains: Command definitions, argument parsing (uses `commander`), orchestration of utilities. -- Depends on: `src/utils/*` for filesystem and templating, `fs-extra`, `prettier`, `webpack` where needed. +Build Tooling Layer: -**Utilities / Core Logic:** +- Purpose: Project build and CI helpers exposed as `build` command. +- Location: `src/build/*.ts` (`src/build/build.ts`, `src/build/build-tsc.ts`, `src/build/build-bundle.ts`, etc.) +- Contains: tasks to run prettier, eslint, tsc, bundling and other project checks. +- Depends on: dev tooling in `package.json` and runtime tools (SWC, Webpack, etc.). -- Purpose: Reusable helpers for file operations, token replacement, template manipulation, and string utilities. -- Location: `src/utils/` (`file-utils.ts`, `template-utils.ts`, `string-utils.ts`). -- Contains: `replaceTokensInFile`, `runInstall`, `runBuild`, copy filter helpers, string transforms. -- Depends on: `fs-extra`, `lookpath`, `child_process` (`exec`). +Utilities Layer: -**Files & Templates:** +- Purpose: Shared helpers for string manipulation, file operations and token replacement. +- Location: `src/utils/string-utils.ts`, `src/utils/file-utils.ts`, `src/utils/template-utils.ts` +- Contains: helper functions with small focused responsibilities (e.g., `replaceTokensInFile`, `getDestinationDir`, `getRepositoryUrl`). -- Purpose: Template resources used to scaffold projects. -- Location: `files/` (e.g., `files/create-shape`, `files/create-preset`, `files/create-plugin`, `files/empty-project`). +Test Layer: + +- Purpose: Unit tests for templates and generator functions. +- Location: `tests/*.test.ts`, `vitest.config.ts` ## Data Flow -Create flow (example `create shape`): +Create command flow (example `preset`): -1. User runs CLI: `tsparticles-cli create shape ` (`src/cli.ts` -> `src/create/create.ts` -> `src/create/shape/*`). -2. Command handler calls `createShapeTemplate` in `src/create/shape/create-shape.ts`. -3. `createShapeTemplate` copies template files from `files/create-shape` to destination using `fs-extra` and `template-utils.copyEmptyTemplateFiles`. -4. Token replacement and file updates are performed using `src/utils/file-utils.ts` functions like `replaceTokensInFile` and helpers in `src/utils/template-utils.ts`. -5. Optional lifecycle commands `runInstall` and `runBuild` invoke external commands (`npm install`, `npm run build`) via `child_process.exec` if `npm` is present (checked via `lookpath`). +1. User invokes CLI: `tsparticles-cli create preset ` -> `src/cli.ts` boots and routes to `src/create/create.ts` -> `src/create/preset/preset.ts`. +2. `preset.ts` gathers interactive input via `prompts` and computes `destPath` using `src/utils/file-utils.ts:getDestinationDir`. +3. `createPresetTemplate` in `src/create/preset/create-preset.ts` runs sequence: + - copy empty template files (`src/utils/template-utils.ts:copyEmptyTemplateFiles`) -> uses `files` templates under repo + - copy project-specific files via `fs.copy` + - run a series of `replaceTokensInFile` operations (`src/utils/file-utils.ts`) to customize bundle/index/readme/package files + - run `runInstall` and `runBuild` (`src/utils/template-utils.ts`) which spawn subprocesses (`npm install`, `npm run build`) if `npm` found State Management: -- Stateless CLI; state is the filesystem and created project files. No in-memory long-lived state across runs. +- Stateless CLI operations. Functions operate on input parameters and filesystem state. There is no in-memory application-wide state beyond individual command execution. ## Key Abstractions -**Template Updater:** +Command Module: + +- Purpose: Encapsulate a single CLI command and its action handler. +- Examples: `src/create/preset/preset.ts`, `src/create/shape/shape.ts`, `src/create/plugin/plugin.ts`, `src/create/create.ts`. +- Pattern: Each command is a `commander.Command` with `argument` declarations and an `action` async function. -- Purpose: Replace tokens and update produced scaffold files. -- Examples: `src/utils/file-utils.ts` (`replaceTokensInFile`), `src/utils/template-utils.ts` (`updatePackageFile`, `updateWebpackFile`, `updatePackageDistFile`). -- Pattern: Imperative token-replacement using regexes and file writes. +Template Manipulation Utility: -**Command Modules:** +- Purpose: Replace tokens and patch files in a project template. +- Examples: `src/utils/file-utils.ts` (`replaceTokensInFile`, `replaceTokensInFiles`), `src/utils/template-utils.ts` (`updatePackageFile`, `updateWebpackFile`). -- Purpose: Each subcommand is an isolated module exposing a `Command` (from `commander`). -- Examples: `src/create/create.ts`, `src/build/build.ts`, `src/create/shape/create-shape.ts`. +Build Task Modules: + +- Purpose: Implement discrete build subtasks called from `src/build/build.ts`. +- Examples: `src/build/build-tsc.ts`, `src/build/build-bundle.ts`, `src/build/build-eslint.ts`. ## Entry Points -**CLI Entrypoint:** +CLI Entrypoint: - Location: `src/cli.ts` -- Triggers: Node process when user runs `tsparticles-cli` or package `bin` mapping. -- Responsibilities: Read package version (`package.json`), register commands and parse args. +- Triggers: Executed when package binary `dist/cli.js` is run (shebang present); `npm run build` ensures `dist/cli.js` is executable. +- Responsibilities: Read package version (`package.json`), register `build` and `create` commands and parse `process.argv`. -## Error Handling +Create Command Aggregator: + +- Location: `src/create/create.ts` +- Triggers: Registered by `src/cli.ts` as `create` command +- Responsibilities: Add subcommands `plugin`, `preset`, `shape` from their respective modules. -Strategy: +Build Aggregator: -- Try/catch around file operations and external command execution; errors logged to console with `console.error` and boolean success values returned (e.g., `src/build/*` functions return `Promise`). Examples: `src/build/build-prettier.ts`, `src/build/build-bundle.ts`. +- Location: `src/build/build.ts` +- Triggers: Registered by `src/cli.ts` as `build` command +- Responsibilities: Compose and run smaller build tasks (prettier, lint, tsc, circular deps, dist packaging). + +## Error Handling + +Strategy: Throw and bubble errors from async functions; top-level command handlers are async and do not wrap all exceptions. Some tests and callers catch errors for logging. Patterns: -- Propagate failures by throwing or returning `false` and logging details. -- `replaceTokensInFiles` performs read/replace/write with no specialized rollback. +- Synchronous validation: `getDestinationDir` checks destination existence and throws an Error if folder not empty (`src/utils/file-utils.ts:getDestinationDir`). +- Subprocess execution: `exec` wrappers (`runInstall`, `runBuild`) return Promises and reject on `exec` error; calling code awaits and therefore receives the rejection (`src/utils/template-utils.ts`). +- Tests catch and log errors selectively (`tests/*.test.ts`), but many command entrypoints do not add global try/catch. ## Cross-Cutting Concerns -Logging: `console.log`, `console.warn`, `console.error` used across `src/build/*` and `src/utils/*`. +Logging: + +- Approach: Minimal; code uses `console.error` in tests. No centralized logger present. Files: `tests/*`, most modules do not log. + +Validation: + +- Approach: Input validation is enforced by `prompts` validators and `getDestinationDir` pre-checks. See `src/create/*` for validators on required fields. -Validation: Input validation is minimal — `commander` performs CLI argument parsing; `getDestinationDir` validates destination directory emptiness in `src/utils/file-utils.ts`. +Authentication: -Authentication: Not applicable; tool is local and does not call external authenticated services. +- Approach: Not applicable to this CLI: no remote APIs or credential storage. --- -_Architecture analysis: 2026-03-08_ +_Architecture analysis: 2026-03-10_ diff --git a/.planning/codebase/CONCERNS.md b/.planning/codebase/CONCERNS.md index e0b4600..b680b14 100644 --- a/.planning/codebase/CONCERNS.md +++ b/.planning/codebase/CONCERNS.md @@ -1,102 +1,105 @@ # Codebase Concerns -**Analysis Date:** 2026-03-08 +**Analysis Date:** 2026-03-10 ## Tech Debt -1. Minimal input validation and transactional safety when writing files +**Regex-based token replacement (critical):** -- Issue: `replaceTokensInFiles` and other template-updating functions perform read/replace/write in-place without atomic writes or rollback. A failed intermediate step can leave partially updated files. -- Files: `src/utils/file-utils.ts`, `src/utils/template-utils.ts`, `src/create/shape/create-shape.ts` -- Impact: Corrupted template output when an operation fails mid-flow; harder to recover from errors. -- Fix approach: Write to temporary files and rename atomically (use `fs-extra` `outputFile` + `move`), or create the target in a staging directory and move into destination once all transformations succeed. +- Issue: `src/utils/file-utils.ts` implements `replaceTokensInFiles` and constructs a RegExp with `new RegExp(token.from, "g")` regardless of whether `token.from` is a `string` or a `RegExp`. +- Files: `src/utils/file-utils.ts`, callers in `src/utils/template-utils.ts`, `src/create/preset/create-preset.ts` (many tokens are passed as `RegExp` literals). +- Impact: When `token.from` is already a `RegExp` and flags are passed as the second argument to `RegExp` constructor, Node throws a TypeError. This makes token replacement fragile and causes runtime exceptions in template updates. Tests and callers may swallow the error (see `tests/create-preset.test.ts`) so the issue can be silent in CI but still indicate a bug. +- Fix approach: Update `replaceTokensInFiles` to detect `RegExp` values and use them directly, or construct a `RegExp` only when `token.from` is a string. Example change in `src/utils/file-utils.ts`: -2. Running external commands directly in template flow (`npm install`, `npm run build`) +```ts +const regex = token.from instanceof RegExp ? token.from : new RegExp(String(token.from), "g"); +data = data.replace(regex, token.to); +``` -- Issue: `runInstall` and `runBuild` call `exec("npm install")` and `exec("npm run build")` without timeouts or stdout/stderr piping; they rely on `lookpath` only. -- Files: `src/utils/template-utils.ts` (functions `runInstall`, `runBuild`) -- Impact: Tests or CI running on environments lacking `npm` may silently skip or hang if `lookpath` returns true but command misbehaves; poor control over failure modes. -- Fix approach: Use spawned child process with streaming logs and a configurable timeout, or provide a dry-run flag. In tests, mock these exec calls to avoid long-running operations. +Applying this fix ensures RegExp arguments are respected and avoids TypeErrors. -3. Prettier plugin compatibility workaround +**Template JSON changes performed with regex (moderate):** -- Issue: `src/build/build-prettier.ts` contains a TODO disabling Prettier check for `prettier-plugin-multiline-arrays` compatibility with Prettier 3.0.0. -- Files: `src/build/build-prettier.ts` (line with TODO) -- Impact: Formatting checks may be inconsistent across CI and local dev environments. -- Fix approach: Update dependencies to versions compatible with Prettier 3.x or pin Prettier to a compatible 2.x in CI until plugins are updated. Add a CI check that fails early with a clear error message. +- Issue: `src/utils/template-utils.ts` updates `package.json` and `package.dist.json` using regex replacements (`replaceTokensInFile`) instead of reading and writing JSON. +- Files: `src/utils/template-utils.ts`, `src/create/preset/create-preset.ts`. +- Impact: Regex-based edits are brittle: formatting differences, comments, CRLF vs LF, or unexpected matches can break JSON structure or fail to update fields correctly. +- Fix approach: Parse the JSON files with `fs.readJSON` / `fs.writeJSON` and modify the relevant fields (name, description, repository, files). This is more robust and easier to test. Example target: update `updatePackageFile` to `const pkg = await fs.readJSON(pkgPath); pkg.name = packageName; await fs.writeJSON(pkgPath, pkg, { spaces: 2 });` ## Known Bugs -None detected by static analysis in the repository. Tests pass in CI (workflow present) but no failing patterns discovered in code scan. +**RegExp constructor TypeError during replacements:** -## Security Considerations - -1. Running external commands with user-provided template inputs +- Symptoms: Token replacement throws TypeError when token pattern is a `RegExp` and code calls `new RegExp(token.from, "g")`. +- Files: `src/utils/file-utils.ts` (replacement implementation). +- Trigger: Calling any create/template flow that passes `RegExp` literals into tokens (e.g., `src/create/preset/create-preset.ts`). +- Workaround: Tests and callers often wrap calls in try/catch (see `tests/create-preset.test.ts`) so tests still assert package.json existence, masking the problem. Do not rely on that; fix the replacement implementation. -- Risk: If destination paths or template tokens contain malicious content, shell commands executed via `exec` could be abused. -- Files: `src/utils/template-utils.ts` (`runInstall`, `runBuild`), `src/utils/file-utils.ts` (token replacement using regex from code, not user input directly). -- Current mitigation: `exec` is invoked with static commands (`npm install`) and not interpolated with user-supplied strings. `replaceTokensInFile` uses regex replacements defined in code. -- Recommendation: Avoid invoking shell with interpolated user input. If needed, sanitize inputs and prefer `spawn` with argument arrays. +## Security Considerations -2. Reading git remote URL via `exec` in `getRepositoryUrl` +**Arbitrary script execution via `npm install` / `npm run build`:** -- Risk: `exec` result is returned directly; if git not present it rejects. -- Files: `src/utils/file-utils.ts` (`getRepositoryUrl`) -- Recommendation: Wrap with timeout and sanitize output before using it in template substitution. +- Area: `src/utils/template-utils.ts` functions `runInstall` and `runBuild` execute `npm install` and `npm run build` in generated projects. +- Files: `src/utils/template-utils.ts`, `src/create/*` where `runInstall` and `runBuild` are invoked (e.g., `src/create/preset/create-preset.ts`). +- Risk: Running `npm install` in a directory containing an attacker-controlled `package.json` can execute lifecycle scripts (postinstall, preinstall). The CLI currently runs installs automatically during template creation, which can execute arbitrary code on the user's machine. +- Current mitigation: `lookpath("npm")` is used to avoid running when `npm` is not available, but this does not mitigate script execution risks. +- Recommendation: Do not run `npm install` / `npm run build` automatically. Instead: + - Require an explicit flag (e.g., `--install`) to run automatic installs, or + - Use `npm ci --ignore-scripts` or `npm install --ignore-scripts` as a safer default, and clearly warn users before running scripts, or + - Prompt for confirmation before running `npm` and print the exact command being run. ## Performance Bottlenecks -1. Synchronous/serial file traversal in prettify +**Use of `child_process.exec` for long-running, high-output commands (moderate):** -- Problem: `prettier` formatting in `prettifySrc` iterates files sequentially (`for await (const file of klaw(srcPath))`), performing `prettier.resolveConfig` per file which may be expensive. -- Files: `src/build/build-prettier.ts` -- Cause: Recomputing config and formatting each file sequentially. -- Improvement path: Resolve config once outside the loop, run formatting in parallel batches, and avoid repeated IO for options. +- Area: `src/utils/template-utils.ts` and `src/utils/file-utils.ts` (the latter uses `exec` in `getRepositoryUrl`). +- Files: `src/utils/template-utils.ts` (`runInstall`, `runBuild`), `src/utils/file-utils.ts` (`getRepositoryUrl`). +- Problem: `exec` buffers the full stdout/stderr and has a default buffer size; heavy outputs (e.g., `npm install`) can overflow the buffer and cause the subprocess to fail. Also, using `exec` hides streaming logs from the user. +- Improvement path: Use `child_process.spawn` with streaming of stdout/stderr and proper error/exit-code handling. Stream logs to the console or into a logger so users see progress. ## Fragile Areas -1. Regex-based token replacement +**Broad regex replacements over multiple file types (fragile):** -- Files: `src/utils/file-utils.ts`, `src/utils/template-utils.ts`, `src/create/*` token replacement usage -- Why fragile: Regexes operate on file contents and can unintentionally match similar substrings; no schema validation after replacement. -- Safe modification: Add tests for each token replacement case, and perform replacements against structured JSON (for `package.json`) using AST parsing where possible. -- Test coverage: Token replacement used heavily but tests exercise many flows; add more unit tests for edge cases. +- Files: `src/utils/file-utils.ts`, call sites in `src/utils/template-utils.ts` and `src/create/*`. +- Why fragile: Replacing text with global regexes across files risks accidental substitution (e.g., replacing occurrences in unrelated files). It also makes reasoning about what changed difficult. +- Safe modification: Limit replacements to specific files and, where possible, use structured transforms (JSON AST edits for `package.json`, templating tools for code files) rather than blind regex. -## Scaling Limits +**No centralized logging or structured errors (minor):** -Not applicable: CLI scaffolding and local build tool; not intended for high-concurrency server workloads. +- Files: `src/cli.ts`, `src/build/*.ts`, `src/create/*` — modules log via `console` or propagate exceptions. +- Why fragile: Lack of a central logger and consistent error formatting makes debugging and user-facing error messages inconsistent. Adding a simple logging utility (e.g., `src/utils/logger.ts`) and top-level error handling in `src/cli.ts` would improve UX. ## Dependencies at Risk -1. Prettier plugin `prettier-plugin-multiline-arrays` +**Self-referential devDependency:** -- Risk: Incompatibility with Prettier 3.x noted in `src/build/build-prettier.ts` TODO. -- Impact: Formatting and CI checks could be disrupted. -- Migration plan: Upgrade plugin or pin Prettier; monitor plugin releases. +- Files: `package.json` lists `"@tsparticles/cli": "latest"` in `devDependencies`. +- Risk: This can lead to confusing local development semantics. It is common for monorepo setups but should be intentional. +- Migration plan: If not required, remove the self-reference. If needed for local testing, ensure a documented developer workflow. ## Missing Critical Features -1. No centralized logging or telemetry +**Safe-by-default template creation (missing):** -- Problem: Uses `console.*` directly; no centralized structured logs for debugging CI or for library consumers. -- Blocks: Advanced observability and consistent log levels. +- Problem: Template creation runs `npm install`/`npm run build` by default. There is no opt-in flag to skip these actions for safer, faster creation in CI or sandboxed environments. +- Blocks: CI runs, offline usage, and security-conscious users. +- Recommendation: Add a `--no-install` / `--skip-install` option to `create` commands or a top-level config, and ensure `runInstall`/`runBuild` respect that option. ## Test Coverage Gaps -1. Lack of mocks for external process execution +**Replacement function tests (high priority):** -- What's not tested: Behavior of `runInstall`/`runBuild` when `npm` present and when the commands fail. -- Files: `src/utils/template-utils.ts` and tests in `tests/` currently avoid actually running `npm` by relying on environment; but there are no unit tests mocking `exec`. -- Risk: Breakage during publish/cmd execution might not be caught in unit tests. -- Priority: Medium — add tests that stub `child_process.exec` and `lookpath` to verify behavior on success and failure. +- What's not tested: `replaceTokensInFiles` behavior when `token.from` is a `RegExp` object vs a `string` (no explicit unit tests for this edge case). +- Files: `src/utils/file-utils.ts`, tests should be added under `tests/file-utils.test.ts` or similar. +- Risk: Future regressions and silent failures in template flows. +- Priority: High — add targeted unit tests that exercise both `string` and `RegExp` token inputs and verify no exceptions are thrown and replacements occur as expected. -2. Token replacement edge cases +**Integration tests should avoid running real npm:** -- What's not tested: Regex collisions and JSON-encoded fields in `package.json` and `package.dist.json` replacements. -- Files: `src/utils/file-utils.ts`, `src/utils/template-utils.ts` -- Risk: Incorrect package metadata produced for scaffolds. -- Priority: High — add unit tests that run replacements on fixture files with edge-case tokens. +- What's not tested safely: `createPresetTemplate` currently calls `runInstall` and `runBuild` which invoke `npm` and may perform network operations in CI. +- Files: `tests/create-preset.test.ts`, `src/utils/template-utils.ts`. +- Recommendation: Mock `lookpath` and `child_process.exec` in tests, or refactor `runInstall`/`runBuild` to accept an injectable runner (dependency injection) so tests can inject a no-op runner. --- -_Concerns audit: 2026-03-08_ +_Concerns audit: 2026-03-10_ diff --git a/.planning/codebase/CONVENTIONS.md b/.planning/codebase/CONVENTIONS.md index 8c829d2..e3b9f55 100644 --- a/.planning/codebase/CONVENTIONS.md +++ b/.planning/codebase/CONVENTIONS.md @@ -1,96 +1,91 @@ # Coding Conventions -**Analysis Date:** 2026-03-08 +**Analysis Date:** 2026-03-10 ## Naming Patterns Files: -- Source files are placed under feature directories (e.g., `src/create/shape/create-shape.ts`). Use descriptive names matching the feature. +- Pattern: kebab-case for source filenames and CLI commands + - Examples: `src/create/create.ts`, `src/create/preset/create-preset.ts`, `src/build/build-tsc.ts` Functions: -- Use camelCase for function names (e.g., `createShapeTemplate` in `src/create/shape/create-shape.ts`, `replaceTokensInFile` in `src/utils/file-utils.ts`). +- Pattern: camelCase for free functions and helpers + - Examples: `replaceTokensInFile` in `src/utils/file-utils.ts`, `createPresetTemplate` in `src/create/preset/create-preset.ts` Variables: -- Use camelCase for variables and constants. TypeScript types use PascalCase. +- Pattern: camelCase for local variables and constants; use `const` when value is not reassigned + - Examples: `destPath`, `camelizedName` in `src/create/shape/create-shape.ts` -Types: +Types / Interfaces: -- Interfaces and types use PascalCase (e.g., `ReplaceTokensOptions`, `ReplaceTokensData` in `src/utils/file-utils.ts`). +- Pattern: PascalCase for interfaces and type names + - Examples: `ReplaceTokensOptions`, `ReplaceTokensData` in `src/utils/file-utils.ts` + +Exports: + +- Pattern: named exports from modules (no default exports observed) + - Examples: `export async function replaceTokensInFiles` in `src/utils/file-utils.ts` ## Code Style Formatting: -- Prettier is the formatting tool; root `package.json` sets `prettier` to `@tsparticles/prettier-config`. Formatting settings are applied in `src/build/build-prettier.ts` (printWidth 120, tabWidth 2, endOfLine lf). +- Prettier is used via the package `prettier` and project config referenced in `package.json` (`prettier": "@tsparticles/prettier-config"`). + - Scripts: `prettify:src`, `prettify:readme`, `prettify:ci:src` in `package.json` Linting: -- ESLint config in `eslint.config.js` extends `@tsparticles/eslint-config`. Linting is enforced in `package.json` scripts (`lint`, `lint:ci`) and CI runs `pnpm run lint:ci` in `node.js-ci.yml`. - -## Import Organization - -Order: - -1. Node built-ins (e.g., `path`, `fs-extra` import as `fs`) -2. External dependencies (e.g., `commander`, `prompts`) -3. Internal modules (relative imports under `src/`) - -Examples: `src/cli.ts` imports `buildCommand` and `createCommand` from local modules after Node imports. - -Path Aliases: - -- None detected. Imports use relative paths and package names. Keep using relative imports within `src/`. +- ESLint is configured in `eslint.config.js` and reuses `@tsparticles/eslint-config` (see `eslint.config.js`). + - Scripts: `lint` (auto-fix) and `lint:ci` in `package.json` + - Rule note: `no-console` is disabled in `eslint.config.js` to allow `console` usage in CLI code and tests. -## Error Handling - -Patterns: - -- Use try/catch around file system operations and external command execution; log errors with `console.error` (see `src/build/*.ts`, `src/utils/*`). -- Functions that perform operations return boolean success flags (`Promise`) where appropriate (e.g., `src/build/build-prettier.ts`, `src/build/build-bundle.ts`). - -## Logging +TypeScript: -Framework: console +- Strict TypeScript settings are enabled in `tsconfig.json` (many `strict` flags set: `strict`, `noImplicitAny`, `noUnusedLocals`, etc.). -Patterns: +Doc comments: -- Use `console.log` for informational messages, `console.warn` for warnings, `console.error` for errors. Follow existing use in `src/build/*` and `src/utils/*`. +- Use JSDoc/TSDoc style comments on exported functions and complex helpers. + - Examples: function headers in `src/utils/string-utils.ts`, `src/utils/template-utils.ts`. -## Comments - -When to Comment: +## Import Organization -- Use JSDoc/TSDoc comments for exported functions and modules. Code contains JSDoc-style function headers (e.g., `src/build/build-prettier.ts`). +- Pattern observed: third-party packages first, then Node built-ins, then local relative imports. + - Example from `src/create/preset/create-preset.ts`: + - `import { camelize, capitalize, dash } from "../../utils/string-utils.js";` + - `import fs from "fs-extra"`; `import path from "node:path"`; -JSDoc/TSDoc: +Path aliases: -- Use TSDoc/JSDoc annotations for function parameters and return values on public utilities. +- Not detected. Imports use relative paths (e.g., `../../utils/*`) and explicit `.js` extension when imported from tests or other ESM contexts. -## Function Design +## Error Handling -Size: +- Pattern: functions either throw synchronous errors (`throw new Error(...)`) for validation or reject Promises when asynchronous operations fail. + - Example: `getDestinationDir` throws `new Error("Destination folder already exists and is not empty")` in `src/utils/file-utils.ts`. + - Example: `runInstall`/`runBuild` use the `exec` callback to `reject(error)` in `src/utils/template-utils.ts`. -- Functions typically remain under ~200 lines and perform a single responsibility (e.g., `createShapeTemplate` orchestrates template copying and updates but delegates to small helpers). +## Logging -Parameters: +- Pattern: CLI code and tests use `console` for informational output and debugging. ESLint `no-console` is turned off to permit this. + - Files: `src/cli.ts`, tests in `tests/*.test.ts` (see `tests/file-utils.test.ts` where `console.log`/`console.error` is used). -- Prefer explicit parameters and typed signatures. Existing functions are strongly typed (see `tsconfig.json` with `strict: true`). +## Comments and Documentation -Return Values: +- Public helpers include JSDoc comments (examples in `src/utils/*`). Maintain comments for exported functions to describe parameters and return values. -- Use typed return values (`Promise`, `Promise`) and avoid implicit `any`. +## Function & Module Design -## Module Design +- Small single-responsibility functions are the norm (examples: `replaceTokensInFiles`, `updatePackageFile`, `copyEmptyTemplateFiles`). +- Modules export multiple named helpers rather than a default export (see `src/utils/template-utils.ts`). -Exports: +## Barrel files -- Modules export named functions (e.g., `export async function createShapeTemplate ...` in `src/create/shape/create-shape.ts`). Prefer named exports. - Barrel Files: -- Not used. Add explicit exports per-file instead of index barrel files unless a clear grouping is required. +- Not used. Individual modules are imported with relative paths. --- -_Convention analysis: 2026-03-08_ +_Convention analysis: 2026-03-10_ diff --git a/.planning/codebase/INTEGRATIONS.md b/.planning/codebase/INTEGRATIONS.md index 1b6992a..a245cde 100644 --- a/.planning/codebase/INTEGRATIONS.md +++ b/.planning/codebase/INTEGRATIONS.md @@ -1,73 +1,82 @@ # External Integrations -**Analysis Date:** 2026-03-08 +**Analysis Date:** 2026-03-10 ## APIs & External Services -No cloud SDKs (Stripe, AWS, Supabase, etc.) detected in `src/` imports. Searches for common providers returned no matches. +This project is a local CLI tool focused on scaffolding and building tsParticles-related packages. There are minimal external service integrations. + +**Repository / Git:** + +- Git: CLI uses the `git` binary when available to obtain repository URL (`src/utils/file-utils.ts` uses `lookpath("git")` and executes `git config --get remote.origin.url`). No other GitHub API integration detected. + +**NPM Registry:** + +- Publishing: GitHub Actions workflow publishes packages to npm registry (`.github/workflows/npm-publish.yml`) using `pnpm publish` against `https://registry.npmjs.org`. + - Auth: CI uses OIDC/GitHub Actions environment for authentication as configured in `.github/workflows/npm-publish.yml` (permissions include `id-token: write`). ## Data Storage **Databases:** -- Not detected. No database clients (pg/mysql/mongodb) are imported in `src/`. +- Not detected. The CLI operates on the local filesystem; no database clients (e.g. PostgreSQL, MongoDB) are referenced in `src/`. **File Storage:** -- Local filesystem via `fs-extra` used throughout (`src/utils/file-utils.ts`, `src/utils/template-utils.ts`, `src/create/*`) to read/write project templates and package files. +- Local filesystem via `fs-extra` (`src/utils/file-utils.ts` and many create/template helpers). Templates are copied from `files/*` into target directories (`src/create/*`, e.g. `src/create/plugin/create-plugin.ts` uses `files/create-plugin`). **Caching:** -- None detected. +- Not detected. No Redis or in-process caching libraries observed. ## Authentication & Identity **Auth Provider:** -- Not applicable. This is a local CLI tool and does not integrate with external auth providers. +- None for runtime. CI publishes to npm using GitHub Actions OIDC flow (see `.github/workflows/npm-publish.yml`). There are no runtime OAuth or Identity providers integrated into the CLI. ## Monitoring & Observability **Error Tracking:** -- None detected (no Sentry / Datadog / Rollbar SDK imports). +- Not detected. No Sentry, Datadog, or similar SDKs in dependencies. **Logs:** -- Standard console logging (`console.log`, `console.error`, `console.warn`) used throughout build and template utilities (e.g., `src/build/*`, `src/utils/*`). +- Console logging used throughout the CLI (`console.log`, `console.warn`, `console.error`). See `src/build/*` and `src/create/*` for examples (e.g. `src/build/build.ts`, `src/build/build-prettier.ts`). ## CI/CD & Deployment **Hosting:** -- NPM registry publishes defined in `.github/workflows/npm-publish.yml` (publishes on tags `v*`). +- NPM registry for package distribution. Source is maintained in GitHub and CI runs on GitHub Actions (`.github/workflows/*`). **CI Pipeline:** -- GitHub Actions workflows: - - `/.github/workflows/node.js-ci.yml` runs on push and pull_request for `main`, executes `pnpm install`, `pnpm run build:ci`, and `pnpm test`. - - `/.github/workflows/npm-publish.yml` publishes package on version tags using OIDC-based authentication. +- GitHub Actions pipelines: + - `Node.js CI` (`.github/workflows/node.js-ci.yml`) runs on push and PRs to `main`: installs via `pnpm install`, runs `pnpm run build:ci` and `pnpm test`. + - `Publish Packages` (`.github/workflows/npm-publish.yml`) publishes tags `v*` to npm, using OIDC-based auth and `pnpm publish`. ## Environment Configuration **Required env vars:** -- No application runtime env vars detected in source. CI workflows rely on GitHub OIDC and standard GitHub Actions environment variables. +- Not enforced in repo code. CI publishing relies on GitHub Actions OIDC configured in workflow; no runtime environment variables are required by the CLI itself. **Secrets location:** -- No secrets files in repo. GitHub publishing uses built-in OIDC and repository permissions configured in the workflow (`id-token: write`). +- Not present in repo. CI uses OIDC in the publish workflow. No local secrets files detected (no `.env`). ## Webhooks & Callbacks **Incoming:** -- None detected. +- Not detected. This is a CLI tool; it does not expose HTTP endpoints. **Outgoing:** -- None detected. +- Not detected. The CLI does not make outbound HTTP API calls; templates and README files reference public CDNs (jsDelivr) and GitHub URLs but no HTTP client libraries are used. --- -_Integration audit: 2026-03-08_ +_Integration audit: 2026-03-10_ diff --git a/.planning/codebase/STACK.md b/.planning/codebase/STACK.md index 7c8743a..9f10166 100644 --- a/.planning/codebase/STACK.md +++ b/.planning/codebase/STACK.md @@ -1,85 +1,91 @@ # Technology Stack -**Analysis Date:** 2026-03-08 +**Analysis Date:** 2026-03-10 ## Languages **Primary:** -- TypeScript (>=5.x) - used across the entire codebase in `src/` (e.g. `src/cli.ts`, `src/create/*`, `src/build/*`) +- TypeScript 5.x (project uses `typescript` ^5.9.3) - used across CLI source under `src/` (`src/**/*.ts`). See `package.json` and `tsconfig.json` (`package.json`: `dependencies`/`devDependencies`, `tsconfig.json`: `compilerOptions`). **Secondary:** -- JavaScript (Node) - runtime JS emitted to `dist/` (package `type` set to `module` in `package.json`) +- JavaScript (Node ESM runtime output in `dist/` / CLI entry `dist/cli.js`) - `package.json` `type: "module"` and `bin` field (`package.json`). ## Runtime **Environment:** -- Node.js 24 (CI uses `actions/setup-node` with `node-version: "24"` in `.github/workflows/node.js-ci.yml`) +- Node.js (ES module, NodeNext resolution). CI workflows use Node 24 (`.github/workflows/node.js-ci.yml`). `tsconfig.json` `module: "NodeNext"`, `target: "ESNext"`. **Package Manager:** -- pnpm (declared in `package.json` via `packageManager`: `pnpm@10.31.0`) -- Lockfile present: `pnpm-lock.yaml` +- pnpm (project declares `packageManager: "pnpm@10.32.0"` in `package.json`, lock file `pnpm-lock.yaml` present). +- Lockfile: `pnpm-lock.yaml` (present). ## Frameworks **Core:** -- None web-framework specific. This is a CLI application built with Node and TypeScript. Entry point: `src/cli.ts`. - -**CLI/Command parsing:** - -- `commander` (`src/cli.ts`, `src/create/create.ts`, `src/build/*`) - used to declare commands and subcommands. +- None web-framework-specific. This is a CLI application built with Node and TypeScript. CLI command framework: `commander` (`package.json` -> `dependencies`), commands live in `src/cli.ts`, `src/build/*`, `src/create/*`. **Testing:** -- `vitest` (configured in `vitest.config.ts`, tests in `tests/*.test.ts`) +- Vitest (`vitest` ^4.x) - config file: `vitest.config.ts`, tests located in `tests/*.test.ts`. **Build/Dev:** -- `typescript` for compilation (`tsc -p src`, see `package.json` scripts) -- `webpack` used by some build tasks (see `src/build/build-bundle.ts` importing `webpack`) -- `swc` (`@swc/core`) is listed as dependency (used by some tooling or downstream tasks) +- TypeScript compiler (`tsc`) is used for building (`scripts.build:ts*` in `package.json`, `tsconfig.json` and `src/tsconfig.json`). +- Prettier for formatting (configured via dependency `@tsparticles/prettier-config` referenced in `package.json`). Prettier is run by `src/build/build-prettier.ts` and scripts in `package.json`. +- ESLint (`eslint`) with `@tsparticles/eslint-config` - linting run in `src/build/build-eslint.ts` and via `package.json` scripts. +- Webpack used for bundling (dependency `webpack`, `swc-loader`, `@swc/core`) - bundling logic in `src/build/build-bundle.ts`. +- dependency-cruiser used for circular dependency checks - config `.dependency-cruiser.cjs` and script `circular-deps` in `package.json`. ## Key Dependencies **Critical:** -- `commander` - command-line parsing (`src/cli.ts`) -- `fs-extra` - filesystem utilities used widely (`src/utils/*`, `src/create/*`, `src/build/*`) -- `prettier` - formatting (`src/build/build-prettier.ts`) -- `typescript` - language (dev dependency and build target) +- `typescript` ^5.9.3 - primary language toolchain (`package.json`). +- `commander` ^14.x - CLI command framework (`src/cli.ts`, `package.json`). +- `fs-extra` ^11.x - filesystem utilities used widely (`src/utils/file-utils.ts`, `package.json`). +- `prettier` ^3.8.x - formatting; project references `@tsparticles/prettier-config` (`package.json`). +- `eslint` ^10.x and TypeScript ESLint tooling (`package.json`, `src/build/build-eslint.ts`). + +**Infrastructure / Build:** + +- `webpack` ^5.x, `swc-loader`, `@swc/core` - bundling and fast transpilation (`package.json`, `src/build/build-bundle.ts`). +- `vitest` ^4.x - test runner (`vitest.config.ts`, `package.json`). +- `klaw` - used by prettier tooling to walk folders (`src/build/build-prettier.ts`). -**Infrastructure / Tooling:** +**Utilities:** -- `prompts` - interactive prompts for the `create` subcommands (`src/create/*`) -- `lookpath` - used to detect external commands (`src/utils/template-utils.ts`, `src/utils/file-utils.ts`) -- `webpack` - bundling (`src/build/build-bundle.ts`) -- `vitest` - testing runner (`tests/*.test.ts`, `vitest.config.ts`) +- `prompts` - interactive prompts used in templates/generator code (`package.json`, `src/create/*`). +- `lookpath` - used to detect `git` presence in `src/utils/file-utils.ts`. ## Configuration **Environment:** -- No `.env` usage detected. CI sets Node version and runs pnpm in GitHub workflows (`.github/workflows/*.yml`). +- No project-level `.env` files detected. The CLI uses the local environment (executes `git` where available). See `src/utils/file-utils.ts` (calls `lookpath("git")` and runs `git config --get remote.origin.url`). **Build:** -- TypeScript config: `tsconfig.json` (root) and `src/tsconfig.json` included via `eslint.config.js` (parserOptions.project). -- Build scripts are defined in `package.json` (e.g. `pnpm run build`, `pnpm run build:ci`, `pnpm run build:ts:cjs`) +- TypeScript config: `tsconfig.json` (root) and `src/tsconfig.json` (per-source) - `module: NodeNext`, `target: ESNext`, strict compiler options. +- Linting config is provided by `@tsparticles/eslint-config` (referenced in `package.json`). A dependency-cruiser configuration is present at `.dependency-cruiser.cjs`. +- Prettier config is supplied via `@tsparticles/prettier-config` and `package.json` scripts rely on `src/build/build-prettier.ts`. ## Platform Requirements **Development:** -- Node.js 24+, pnpm (v10+), git - used by scripts and utilities (`src/utils/file-utils.ts` uses `git` if available) +- Node.js >= 24 recommended (CI uses Node 24 in `.github/workflows/node.js-ci.yml`). +- pnpm >= 10.x (project `packageManager` sets `pnpm@10.32.0`). +- Git CLI for repository URL resolution used by templates (`src/utils/file-utils.ts`). -**Production / Distribution:** +**Production / Publishing:** -- Packaged as npm package (`publishConfig` in `package.json` and `npm-publish` workflow). Outputs are placed under `dist/` and CLI binary `dist/cli.js` (`bin` in `package.json`). +- Packages are published to npm registry (see `.github/workflows/npm-publish.yml`). The CI uses GitHub Actions and OIDC for auth when publishing (`.github/workflows/npm-publish.yml`). --- -_Stack analysis: 2026-03-08_ +_Stack analysis: 2026-03-10_ diff --git a/.planning/codebase/STRUCTURE.md b/.planning/codebase/STRUCTURE.md index 1fa867f..3a17672 100644 --- a/.planning/codebase/STRUCTURE.md +++ b/.planning/codebase/STRUCTURE.md @@ -1,104 +1,138 @@ # Codebase Structure -**Analysis Date:** 2026-03-08 +**Analysis Date:** 2026-03-10 ## Directory Layout ``` [project-root]/ -├── src/ # TypeScript source for the CLI -│ ├── build/ # Build command implementations and helpers -│ ├── create/ # Create command implementations (preset, plugin, shape) -│ └── utils/ # Shared utilities (file, template, string helpers) -├── files/ # Template files used by create commands -├── tests/ # Vitest unit tests for utilities and create flows -├── dist/ # Build output (generated, should be ignored) -├── package.json # NPM package config and scripts -├── pnpm-lock.yaml # Lockfile for pnpm -├── tsconfig.json # TypeScript compiler options -└── .github/workflows/ # CI and publish workflows +├── src/ # TypeScript source for CLI and build tasks +│ ├── cli.ts # CLI entrypoint (registers commands) +│ ├── create/ # "create" command and subcommands +│ │ ├── create.ts +│ │ ├── plugin/ +│ │ │ ├── plugin.ts +│ │ │ └── create-plugin.ts +│ │ ├── preset/ +│ │ │ ├── preset.ts +│ │ │ └── create-preset.ts +│ │ └── shape/ +│ │ ├── shape.ts +│ │ └── create-shape.ts +│ ├── build/ # Build helper commands/tasks +│ │ ├── build.ts +│ │ ├── build-tsc.ts +│ │ ├── build-bundle.ts +│ │ └── ... +│ └── utils/ # Shared utilities +│ ├── file-utils.ts +│ ├── template-utils.ts +│ └── string-utils.ts +├── files/ # Template files used by generators (not under src/ but referenced) +├── tests/ # Vitest unit tests +├── dist/ # Compiled ESM output (generated) +├── package.json +├── pnpm-lock.yaml +├── tsconfig.json +└── .planning/ # Mapping and planning docs ``` ## Directory Purposes -**`src/`**: +**src/**: -- Purpose: Primary implementation in TypeScript. -- Contains: `src/cli.ts`, `src/build/*`, `src/create/*`, `src/utils/*`. -- Key files: `src/cli.ts` (entry), `src/create/create.ts`, `src/build/build.ts`, `src/utils/file-utils.ts`. +- Purpose: Source code for the CLI tool and internal build tasks. +- Contains: Command modules (`src/create/*`), build tasks (`src/build/*`), utilities (`src/utils/*`). +- Key files: `src/cli.ts`, `src/create/create.ts`, `src/create/preset/create-preset.ts`. -**`files/`**: +**src/create/**: -- Purpose: Scaffolding templates used by the create commands. -- Contains: `files/create-shape`, `files/create-preset`, `files/create-plugin`, `files/empty-project`. +- Purpose: Implements the `create` command and its subcommands. +- Contains: `plugin`, `preset`, `shape` subfolders each exposing a `Command` instance and a template-creation implementation (`create-*.ts`). +- Key files: `src/create/preset/preset.ts`, `src/create/preset/create-preset.ts`. -**`tests/`**: +**src/build/**: -- Purpose: Unit tests executed by `vitest`. -- Contains: tests validating template creation and utility behavior (e.g., `tests/create-shape.test.ts`, `tests/file-utils.test.ts`). +- Purpose: Build and CI helper tasks used by `pnpm run build` and `build` CLI command. +- Contains: modular build steps: `build-prettier.ts`, `build-eslint.ts`, `build-tsc.ts`, bundling helpers. +- Key files: `src/build/build.ts` (aggregator), `src/build/build-tsc.ts`. -**`dist/`**: +**src/utils/**: -- Purpose: Output of compilation/build process. Generated; not committed. +- Purpose: Shared helpers for filesystem operations, string handling, and template updates. +- Contains: `file-utils.ts` (`replaceTokensInFile`, `getDestinationDir`), `template-utils.ts` (`runInstall`, `runBuild`, `updatePackageFile`). + +**files/**: + +- Purpose: Template projects that are copied into new destinations by `create` commands. +- Note: Referenced by `src/create/*` code via relative paths (e.g., `path.join(__dirname, "..", "..", "files", "create-preset")` in `src/create/preset/create-preset.ts`). + +**tests/**: + +- Purpose: Unit tests using Vitest for template creation behavior. +- Contains: `tests/create-shape.test.ts`, `tests/create-preset.test.ts`. ## Key File Locations -**Entry Points:** +Entry Points: -- `src/cli.ts`: CLI program creation and command registration. +- `src/cli.ts`: boots the program, reads package version from `package.json`, registers `build` and `create` commands. -**Configuration:** +Create commands: -- `package.json`: scripts, dependencies, package metadata. -- `tsconfig.json`: TypeScript configuration. -- `vitest.config.ts`: Test runner configuration. +- `src/create/create.ts`: aggregates subcommands. +- `src/create/preset/preset.ts`: CLI surface for `preset` command. +- `src/create/preset/create-preset.ts`: implementation that writes files and runs install/build. -**Core Logic:** +Utilities: -- `src/utils/file-utils.ts`: token replacement, destination directory checks, git repository lookup. -- `src/utils/template-utils.ts`: template transformers, copy helpers, npm build/install invocations. +- `src/utils/file-utils.ts`: token replacement helpers and repository detection. +- `src/utils/template-utils.ts`: file copying, package updates and running `npm` commands. -**Commands:** +Build tasks: -- `src/create/*`: `src/create/create.ts`, `src/create/preset/*`, `src/create/plugin/*`, `src/create/shape/*`. -- `src/build/*`: `build.ts`, `build-prettier.ts`, `build-bundle.ts`, `build-tsc.ts`, `build-eslint.ts`, `build-distfiles.ts`, `build-diststats.ts`. +- `src/build/build.ts`: orchestration of build steps called both in CI and local `pnpm run build`. ## Naming Conventions Files: -- Kebab-case for templates/files under `files/`. -- Source files in `src/` use `camelCase` or `kebab-case` depending on purpose; commands grouped into directories named by feature. +- Pattern: kebab-case for file names that represent commands or grouped concerns (e.g., `create-preset.ts`, `build-tsc.ts`). +- Source modules are TypeScript (`.ts`) compiled to ESM JS in `dist/`. Directories: -- Feature directories under `src/` (e.g., `create`, `build`, `utils`). +- Pattern: singular, descriptive names (`create`, `build`, `utils`, `files`). ## Where to Add New Code -New Feature (command): -New Component/Module: +New Feature (CLI command): -- Implementation: `src/utils/` for shared helpers, or `src//` if feature-specific. -- Export public helpers from their files; avoid adding global side-effects. +- Primary code: add a new command module under `src//` or create a subcommand under `src/create/`. +- Registration: register the new `Command` in `src/cli.ts` or in `src/create/create.ts` for `create`-subcommands. +- Tests: add unit tests under `tests/` following existing patterns (`tests/.test.ts`). -Utilities: +New Utility: + +- Implementation: add new helper in `src/utils/` and export named functions; reuse in command modules. +- Examples: `src/utils/new-util.ts` and update `src/utils/index.ts` (if created) to re-export it. + +Templates and Files: -- Shared helpers: `src/utils/`. -- If utility is generic, add tests in `tests/` and export clearly-typed interfaces. +- Add new templates under `files/` and reference them from create implementations using `path.join(__dirname, "..", "..", "files", "