# bootstrap-rytmcms

CLI that scaffolds a new **Tuki CMS / RTM CMF** project. Run inside an empty target directory; it prompts for a project name and optional modules, then provisions directories, copies template files, and installs dependencies via `pnpm`.

## Layout

- `index.js` — the entire CLI. Single-file Node script (shebang `#!/usr/bin/env node`). Uses `prompt`, `child_process`, `fs`, `path`. No build step in dev; `npm run build` packages a binary via `vercel/pkg`.
- `templates/` — every file/dir copied into the new project lives here. Files prefixed with `_` are renamed to dotfiles on copy (`_gitignore` → `.gitignore`, `_claude/` → `.claude/`, `_mcp.json` → `.mcp.json`, etc.).
- `package.json` — declares only the runtime deps of the CLI itself (`prompt`). The dependencies the *generated* project gets are listed inline at the top of `index.js` (`DEPENDENCIES`, `DEV_DEPENDENCIES`, `MODULES_PROMPT`).

## How the bootstrap flow works

`buildProject()` in `index.js`:

1. Prompts for `project` name + each optional module in `MODULES_PROMPT`.
2. `mkdirSync` + `chmodSync` create the target directory tree under `cwd()`.
3. Template files are copied two ways:
   - `fs.copyFileSync` / `fs.cpSync` for static files and directories.
   - `fromTemplate(from, output, replace)` for files with `<%= token %>` placeholders (e.g. `<%= project_name %>`, `<%= devtoken %>`).
4. `npm run initmodules` clones the `tuki` and `rytm-docs` submodule repos (defined in `templates/package.json`).
5. `pnpm install`, then `pnpm add` for `DEV_DEPENDENCIES` and `DEPENDENCIES`, then `pnpm postinstall` (wires `.githooks`).

`__dirname` always points at this repo (the source of templates). `__PROJ_DIR = process.cwd()` is the *target* project being created. Don't mix them up when adding new copy steps.

## Adding a new template file

1. Drop the file into `templates/` (use the `_` prefix for dotfiles).
2. Add a copy step in `index.js` next to the related copies. Use `fs.copyFileSync` for plain copies and `fromTemplate(...)` when the file needs `<%= ... %>` substitution.
3. If it's a directory, use `fs.cpSync(src, dest, { recursive: true })` and ensure the dest exists (`mkdirSync` with `{ recursive: true }`).

Example (recently added, root-level config in the generated project):

```js
// ## pnpm-workspace.yaml ##
fs.copyFileSync(
  __dirname + '/templates/pnpm-workspace.yaml',
  __PROJ_DIR + "/pnpm-workspace.yaml"
)
```

## Available token replacements

Used by `fromTemplate()` — extend the `replace` array if you need more in a given file:

- `<%= project_name %>` — value from the prompt
- `<%= project_directory %>` — `path.basename(__PROJ_DIR)`
- `<%= devdbname %>`, `<%= devdbpass %>` — both default to project name
- `<%= devtoken %>`, `<%= api_key_consent_mode %>` — random 40-char tokens via `getRandomToken()`

## Scripts

- `npm start` — run the bootstrap against the current directory.
- `npm run build` — `pkg index.js -t node14 -o ./bin/bootstrap-rytmcms`. Requires `pkg` installed globally.
- `npm run push` — `git add . && git commit -a -m "$m" && git push` (set `$m` first).

## Gotchas

- The CLI targets Node 14 for `pkg` builds — keep `index.js` compatible (CommonJS `require`, no top-level await, no newer fs APIs that aren't in Node 14).
- `subProcess.execSync(...)` runs in `process.cwd()` (the new project), not this repo. Anything that needs to read from this repo must use `__dirname`.
- `fs.cpSync` requires Node 16+, which is fine at runtime but means the `pkg` target may need bumping if you add more `cpSync` usage and rebuild binaries.
- The bootstrap is **destructive in the cwd**: it `mkdirSync`s and writes files unconditionally. Always run it in an empty directory.
