@fluojs/cli 1.0.0-beta.3 → 1.0.0-beta.5

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.
Files changed (35) hide show
  1. package/README.ko.md +63 -0
  2. package/README.md +63 -0
  3. package/dist/cli.d.ts +8 -0
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +171 -4
  6. package/dist/commands/diagnostics.d.ts +15 -0
  7. package/dist/commands/diagnostics.d.ts.map +1 -0
  8. package/dist/commands/diagnostics.js +163 -0
  9. package/dist/commands/new.js +2 -2
  10. package/dist/commands/package-manager.d.ts +9 -0
  11. package/dist/commands/package-manager.d.ts.map +1 -0
  12. package/dist/commands/package-manager.js +63 -0
  13. package/dist/commands/package-workflow.d.ts +20 -0
  14. package/dist/commands/package-workflow.d.ts.map +1 -0
  15. package/dist/commands/package-workflow.js +137 -0
  16. package/dist/commands/scripts.d.ts +38 -0
  17. package/dist/commands/scripts.d.ts.map +1 -0
  18. package/dist/commands/scripts.js +418 -0
  19. package/dist/dev-runner/node-restart-runner.d.ts +50 -0
  20. package/dist/dev-runner/node-restart-runner.d.ts.map +1 -0
  21. package/dist/dev-runner/node-restart-runner.js +248 -0
  22. package/dist/generators/manifest.d.ts +24 -0
  23. package/dist/generators/manifest.d.ts.map +1 -1
  24. package/dist/generators/manifest.js +9 -0
  25. package/dist/generators/resource.d.ts +10 -0
  26. package/dist/generators/resource.d.ts.map +1 -0
  27. package/dist/generators/resource.js +23 -0
  28. package/dist/generators/templates/controller.ts.ejs +5 -1
  29. package/dist/generators/templates/request-dto.ts.ejs +3 -0
  30. package/dist/new/scaffold.d.ts.map +1 -1
  31. package/dist/new/scaffold.js +77 -27
  32. package/dist/update-check.d.ts +1 -0
  33. package/dist/update-check.d.ts.map +1 -1
  34. package/dist/update-check.js +7 -5
  35. package/package.json +2 -2
package/README.ko.md CHANGED
@@ -7,6 +7,7 @@ fluo 공식 CLI — 새 애플리케이션 부트스트랩, 컴포넌트 생성,
7
7
  ## 목차
8
8
 
9
9
  - [설치](#설치)
10
+ - [버전 확인](#버전-확인)
10
11
  - [업데이트 확인](#업데이트-확인)
11
12
  - [사용 시점](#사용-시점)
12
13
  - [빠른 시작](#빠른-시작)
@@ -33,10 +34,22 @@ pnpm dlx @fluojs/cli new my-app
33
34
  - 지원되는 설치 경로는 전역 패키지(`npm install -g @fluojs/cli`, `pnpm add -g @fluojs/cli`, `bun add -g @fluojs/cli`, `yarn global add @fluojs/cli`)와 무설치 실행 경로(`pnpm dlx @fluojs/cli ...`)입니다.
34
35
  - 배포되는 `fluo` bin은 `package.json`에 선언된 dist 빌드 CLI 엔트리포인트를 기준으로 동작합니다.
35
36
 
37
+ ## 버전 확인
38
+
39
+ Interactive update check를 실행하지 않고 설치된 CLI 버전을 확인합니다:
40
+
41
+ ```bash
42
+ fluo version
43
+ fluo --version
44
+ fluo -v
45
+ ```
46
+
36
47
  ## 업데이트 확인
37
48
 
38
49
  `fluo`가 interactive TTY에서 실행되면 로컬 캐시를 사용해 공개 npm `latest` dist-tag의 `@fluojs/cli` 버전을 확인하므로 매 invocation마다 registry를 호출하지 않습니다. 더 새로운 버전이 있으면 CLI가 설치 여부를 묻습니다. 거절하면 현재 설치된 버전으로 기존 명령을 계속 실행하고, 승인하면 현재 설치를 소유한 것으로 보이는 package manager의 전역 업데이트 명령(`npm install -g`, `pnpm add -g`, `bun add -g`, `yarn global add`)을 사용한 뒤 같은 인자로 업데이트된 `fluo` 바이너리를 다시 시작합니다. 설치 도구를 추론할 수 없으면 Node.js 기본 전역 설치 경로를 소유하는 npm 기준으로 `npm install -g @fluojs/cli@<latest>`를 fallback으로 사용합니다.
39
50
 
51
+ `fluo new`와 alias인 `fluo create`는 일반 update-check cache가 아직 fresh하더라도 스캐폴딩 전에 interactive 최신 버전 확인을 새로 시도합니다. 이를 통해 첫 프로젝트 생성 경로가 방금 배포된 starter 동작과 더 잘 맞춰지며, `fluo dev`, `fluo build`, `fluo generate`, `fluo inspect` 같은 일상 명령은 기존처럼 일반 TTL이 만료될 때까지 cached latest-version 결과를 재사용합니다.
52
+
40
53
  업데이트 확인은 CI, non-TTY 출력, npm-script context, 업데이트 후 재실행 context, registry/network 실패, 명시적 opt-out 경로에서는 건너뜁니다. 한 번만 끄려면 `--no-update-check`(또는 compatibility alias `--no-update-notifier`)를 사용하고, 자동화에서 절대 prompt가 뜨면 안 되는 경우에는 `FLUO_NO_UPDATE_CHECK=1`을 설정하세요.
41
54
 
42
55
  ## 사용 시점
@@ -57,6 +70,10 @@ cd my-app
57
70
  pnpm dev
58
71
  ```
59
72
 
73
+ 생성된 `dev`, `build`, `start` package script는 각각 `fluo dev`, `fluo build`, `fluo start`로 위임합니다. CLI가 런타임별 lifecycle 명령을 소유하고 local toolchain binary를 실행할 때 project-local `node_modules/.bin`을 앞에 붙이며, 호출자가 명시하지 않은 경우 `dev`는 `NODE_ENV=development`, `build`/`start`는 `NODE_ENV=production`을 기본값으로 사용합니다. `fluo dev`는 TTY-aware lifecycle reporter를 사용합니다. Interactive terminal에서는 간결한 fluo-branded status를 보여주고, CI, non-TTY 출력, `--reporter stream`, `--verbose`, `FLUO_VERBOSE=1`에서는 디버깅과 자동화를 위해 raw child-process passthrough를 유지합니다. Cloudflare Workers의 `start`는 배포하지 않고 Wrangler remote preview를 열며, Cloudflare에 게시하려면 명시적인 deploy 명령을 사용하세요.
74
+
75
+ Node.js 프로젝트에서 `fluo dev`는 더 이상 곧바로 `node --watch`에 위임하지 않고 fluo가 소유한 restart boundary를 거칩니다. 이 runner는 source와 주요 config 입력을 watch하고, atomic-save event burst를 debounce하며, restart 전에 파일 content hash를 비교하고, spawn하는 각 앱 child process마다 `.env`를 로드하며, `node_modules`, `dist`, `.git`, `.fluo`, coverage, cache 폴더, editor swap file 같은 noisy output/cache 경로를 무시합니다. 파일 내용이 바뀌지 않은 Ctrl+S 저장은 앱을 재시작하지 않아야 합니다. 계획된 restart가 아닌 terminal 앱 child exit 또는 crash가 발생하면 runner는 watcher를 닫고, pending restart timer와 path를 비우며, `SIGINT`/`SIGTERM` handler를 등록 해제하고, child의 terminal code로 종료합니다. 이 동작은 여전히 full-process restart-on-watch이며 true module-level HMR이 아닙니다. Config watch reload는 별도의 in-process config 관심사이고, 향후 HMR 작업은 어떤 모듈을 안전하게 hot-swap할 수 있는지 따로 문서화해야 합니다. 디버깅을 위해 런타임 native Node watcher로 되돌리려면 `fluo dev --raw-watch` 또는 `FLUO_DEV_RAW_WATCH=1`을 사용하고, 추가 ignore 경로는 `FLUO_DEV_WATCH_IGNORE=path,pattern`으로 지정하세요.
76
+
60
77
  `fluo new`는 같은 Node 기반 설치/빌드 흐름 위에서 Node.js + Fastify, Express, raw Node.js HTTP 애플리케이션 스타터를 제공합니다.
61
78
 
62
79
  ```bash
@@ -114,12 +131,15 @@ plan preview 모드는 실제 scaffold와 같은 프로젝트 이름, shape, run
114
131
 
115
132
  ```bash
116
133
  fluo generate module users
134
+ fluo generate resource users
117
135
  fluo generate controller users
118
136
  fluo generate service users
119
137
  fluo generate request-dto users CreateUser
120
138
  fluo generate service users --dry-run
121
139
  ```
122
140
 
141
+ `fluo generate resource <name>`는 module, controller, service, repository, request DTO, response DTO, test를 포함하는 완전한 feature slice를 생성합니다. 생성된 resource module은 parent module에 자동으로 연결하지 않으므로, slice를 활성화할 준비가 되었을 때 직접 import하세요.
142
+
123
143
  Request DTO 생성은 feature 디렉터리와 DTO 클래스 이름을 분리해서 받습니다. 따라서 `CreateUser`, `UpdateUser` 같은 여러 입력 계약을 같은 `src/users/` 슬라이스 안에 둘 수 있습니다.
124
144
 
125
145
  `--dry-run`을 추가하면 실제 실행과 같은 타깃 해석, 기존 파일 건너뛰기 또는 덮어쓰기 판단, 모듈 자동 등록 계획, 파일만 생성하는 wiring 상태, 다음 단계 힌트를 미리 볼 수 있습니다. 이 모드는 디렉터리 생성, 파일 쓰기, 모듈 갱신을 수행하지 않습니다. `--force`는 내용이 달라질 기존 파일의 계획 항목을 `SKIP`에서 `OVERWRITE`로 바꾸며, `--target-directory`는 실제 실행과 동일하게 지정한 소스 디렉터리 기준으로 preview 범위를 제한합니다.
@@ -128,6 +148,49 @@ Generator discovery는 의도적으로 built-in `@fluojs/cli/builtin` collection
128
148
 
129
149
  ## 주요 패턴
130
150
 
151
+ ### 진단과 프로젝트 스크립트
152
+ 설치된 CLI, npm dist-tag, update-check cache 상태, runtime, project script를 확인해야 할 때는 `doctor`/`info`를 사용합니다:
153
+
154
+ ```bash
155
+ fluo doctor
156
+ fluo info
157
+ fluo analyze
158
+ ```
159
+
160
+ `fluo analyze`는 read-only로 동작하며 더 깊은 `inspect --report`와 `migrate --json` workflow를 안내합니다. 생성된 프로젝트에서는 `fluo dev`, `fluo build`, `fluo start`가 환경 기본값 및 project-local toolchain binary와 함께 생성 lifecycle을 직접 실행합니다. lifecycle 명령은 `--dry-run`으로 미리 확인할 수 있습니다:
161
+
162
+ ```bash
163
+ fluo dev --dry-run
164
+ fluo build --dry-run
165
+ fluo start --dry-run
166
+ ```
167
+
168
+ `fluo dev --dry-run`은 watch boundary도 함께 표시합니다. Node.js 프로젝트는 기본적으로 `Watch mode: fluo-node-restart`를 보여 주며, `--raw-watch` 또는 `FLUO_DEV_RAW_WATCH=1`을 쓰면 `Watch mode: native-watch`를 보여 줍니다. Bun, Deno, Cloudflare Workers는 계속 각 런타임의 native dev watcher를 사용합니다.
169
+
170
+ CLI process boundary를 조정해야 할 때는 런타임 앱 로깅이 아니라 reporter flag를 사용하세요:
171
+
172
+ ```bash
173
+ # TTY에서는 pretty status, CI/non-TTY에서는 raw passthrough (기본값)
174
+ fluo dev
175
+
176
+ # child process log를 디버깅하기 위한 기존 passthrough에 가까운 출력
177
+ fluo dev --reporter stream
178
+ fluo dev --verbose
179
+ FLUO_VERBOSE=1 fluo dev
180
+
181
+ # child stderr와 실패는 보존하면서 wrapper/tool status는 숨김
182
+ fluo build --reporter silent
183
+ ```
184
+
185
+ 런타임 애플리케이션 로그는 `ApplicationLogger`로 별도 설정합니다. 예를 들어 `@fluojs/runtime/node`의 `createConsoleApplicationLogger({ mode: 'minimal', level: 'warn' })` 또는 `createJsonApplicationLogger()`를 사용하세요.
186
+
187
+ first-party package 설치 shortcut에는 `fluo add <package>`를 사용하고, CLI/latest-version 및 migration 안내는 `fluo upgrade`로 확인합니다:
188
+
189
+ ```bash
190
+ fluo add studio --dev --dry-run
191
+ fluo upgrade
192
+ ```
193
+
131
194
  ### 데코레이터 코드 변환
132
195
  코드베이스를 TC39 표준 데코레이터에 맞게 조정하는 codemod를 실행합니다.
133
196
 
package/README.md CHANGED
@@ -7,6 +7,7 @@ The canonical CLI for fluo — bootstrap new applications, generate components,
7
7
  ## Table of Contents
8
8
 
9
9
  - [Installation](#installation)
10
+ - [Version Inspection](#version-inspection)
10
11
  - [Update Checks](#update-checks)
11
12
  - [When to Use](#when-to-use)
12
13
  - [Quick Start](#quick-start)
@@ -33,10 +34,22 @@ pnpm dlx @fluojs/cli new my-app
33
34
  - The supported install paths are the global package (`npm install -g @fluojs/cli`, `pnpm add -g @fluojs/cli`, `bun add -g @fluojs/cli`, or `yarn global add @fluojs/cli`) and the no-install runner (`pnpm dlx @fluojs/cli ...`).
34
35
  - The published `fluo` bin is backed by the dist-built CLI entrypoint declared in `package.json`.
35
36
 
37
+ ## Version Inspection
38
+
39
+ Check the installed CLI version without triggering the interactive update check:
40
+
41
+ ```bash
42
+ fluo version
43
+ fluo --version
44
+ fluo -v
45
+ ```
46
+
36
47
  ## Update Checks
37
48
 
38
49
  When `fluo` runs in an interactive TTY, it checks the public npm `latest` dist-tag for `@fluojs/cli` using a local cache so every invocation does not hit the registry. If a newer version is available, the CLI asks whether to install it. Declining continues the current command with the installed version; accepting updates the global CLI with the package manager that appears to own the current installation (`npm install -g`, `pnpm add -g`, `bun add -g`, or `yarn global add`) and then restarts `fluo` with the same arguments under the updated binary. If the installer cannot be inferred, the CLI falls back to `npm install -g @fluojs/cli@<latest>` because npm owns the default Node.js global installation path.
39
50
 
51
+ `fluo new` and its `fluo create` alias attempt a fresh interactive latest-version check before scaffolding, even when the normal update-check cache is still fresh. This keeps first-run project creation aligned with newly published starter behavior, while day-to-day commands such as `fluo dev`, `fluo build`, `fluo generate`, and `fluo inspect` continue to reuse the cached latest-version result until the normal TTL expires.
52
+
40
53
  The update check is skipped in CI, non-TTY output, npm-script contexts, rerun-after-update contexts, registry/network failures, and explicit opt-out paths. Use `--no-update-check` (or the compatibility alias `--no-update-notifier`) for one invocation, or set `FLUO_NO_UPDATE_CHECK=1` when automation must never prompt.
41
54
 
42
55
  ## When to Use
@@ -57,6 +70,10 @@ cd my-app
57
70
  pnpm dev
58
71
  ```
59
72
 
73
+ Generated `dev`, `build`, and `start` package scripts delegate to `fluo dev`, `fluo build`, and `fluo start`. The CLI owns the runtime-specific lifecycle command, prepends the project-local `node_modules/.bin` when invoking local toolchain binaries, and defaults `NODE_ENV` to `development` for `dev` and `production` for `build`/`start` when the caller has not set it explicitly. `fluo dev` uses a TTY-aware lifecycle reporter: interactive terminals get concise fluo-branded status while CI, non-TTY output, `--reporter stream`, `--verbose`, and `FLUO_VERBOSE=1` keep raw child-process passthrough available for debugging and automation. Cloudflare Workers `start` opens a remote Wrangler preview instead of deploying; use an explicit deploy command when you intend to publish to Cloudflare.
74
+
75
+ For Node.js projects, `fluo dev` now runs through a fluo-owned restart boundary instead of delegating directly to `node --watch`. The runner watches source and common config inputs, debounces atomic-save bursts, hashes file content before restarting, loads `.env` for each app child process it spawns, and ignores noisy output/cache paths such as `node_modules`, `dist`, `.git`, `.fluo`, coverage, cache folders, and editor swap files. Pressing Ctrl+S without changing file content should not restart the app. On terminal app child exit or crash outside a planned restart, the runner closes watchers, clears the pending restart timer and paths, unregisters its `SIGINT`/`SIGTERM` handlers, and exits with the child terminal code. This remains full-process restart-on-watch, not true module-level HMR; config watch reloads are a separate in-process config concern, and future HMR work must document which modules can be safely hot-swapped. Use `fluo dev --raw-watch` or `FLUO_DEV_RAW_WATCH=1` to restore the runtime-native Node watcher for debugging, and use `FLUO_DEV_WATCH_IGNORE=path,pattern` to add extra ignored paths.
76
+
60
77
  `fluo new` supports Node.js + Fastify, Express, and raw Node.js HTTP application starters on the same Node-oriented install/build flow:
61
78
 
62
79
  ```bash
@@ -114,12 +131,15 @@ Add a new resource with a controller and service, automatically wired into the m
114
131
 
115
132
  ```bash
116
133
  fluo generate module users
134
+ fluo generate resource users
117
135
  fluo generate controller users
118
136
  fluo generate service users
119
137
  fluo generate request-dto users CreateUser
120
138
  fluo generate service users --dry-run
121
139
  ```
122
140
 
141
+ `fluo generate resource <name>` creates a complete feature slice with a module, controller, service, repository, request DTO, response DTO, and tests. It does not wire the resource module into a parent module automatically; import the generated module when you are ready to activate the slice.
142
+
123
143
  Request DTO generation accepts the feature directory separately from the DTO class name, so multiple input contracts such as `CreateUser` and `UpdateUser` can live inside the same `src/users/` slice.
124
144
 
125
145
  Add `--dry-run` to preview the same target resolution, skipped or overwritten file decisions, module auto-registration plan, files-only wiring status, and next-step hint without creating directories, writing files, or updating modules. `--force` still changes existing-file plan entries from `SKIP` to `OVERWRITE` when content would change, and `--target-directory` scopes the preview to that source directory exactly as it does for a real run.
@@ -128,6 +148,49 @@ Generator discovery is intentionally limited to the built-in `@fluojs/cli/builti
128
148
 
129
149
  ## Common Patterns
130
150
 
151
+ ### Diagnostics and project scripts
152
+ Use `doctor`/`info` when you need to debug the installed CLI, npm dist-tags, update-check cache state, runtime, and project scripts:
153
+
154
+ ```bash
155
+ fluo doctor
156
+ fluo info
157
+ fluo analyze
158
+ ```
159
+
160
+ `fluo analyze` stays read-only and points to deeper `inspect --report` and `migrate --json` workflows. For generated projects, `fluo dev`, `fluo build`, and `fluo start` run the generated lifecycle directly with environment defaults and project-local toolchain binaries. Use `--dry-run` to preview lifecycle commands:
161
+
162
+ ```bash
163
+ fluo dev --dry-run
164
+ fluo build --dry-run
165
+ fluo start --dry-run
166
+ ```
167
+
168
+ `fluo dev --dry-run` also reports the watch boundary. Node.js projects show `Watch mode: fluo-node-restart` by default, while `--raw-watch` and `FLUO_DEV_RAW_WATCH=1` show `Watch mode: native-watch`. Bun, Deno, and Cloudflare Workers still use their runtime-native dev watchers.
169
+
170
+ Use reporter flags when you need to tune the CLI process boundary rather than runtime app logging:
171
+
172
+ ```bash
173
+ # Pretty status in TTY, raw passthrough in CI/non-TTY (default)
174
+ fluo dev
175
+
176
+ # Current passthrough-like output for debugging child process logs
177
+ fluo dev --reporter stream
178
+ fluo dev --verbose
179
+ FLUO_VERBOSE=1 fluo dev
180
+
181
+ # Suppress wrapper/tool status while keeping child stderr and failures visible
182
+ fluo build --reporter silent
183
+ ```
184
+
185
+ Runtime application logs are configured separately through `ApplicationLogger`, for example `createConsoleApplicationLogger({ mode: 'minimal', level: 'warn' })` or `createJsonApplicationLogger()` from `@fluojs/runtime/node`.
186
+
187
+ Use `fluo add <package>` for first-party package installation shortcuts and `fluo upgrade` for CLI/latest-version and migration guidance:
188
+
189
+ ```bash
190
+ fluo add studio --dev --dry-run
191
+ fluo upgrade
192
+ ```
193
+
131
194
  ### Decorator Codemods
132
195
  Run codemods to align your codebase with TC39 standard decorators.
133
196
 
package/dist/cli.d.ts CHANGED
@@ -15,6 +15,14 @@ export interface CliRuntimeOptions {
15
15
  ci?: boolean;
16
16
  cwd?: string;
17
17
  env?: NodeJS.ProcessEnv;
18
+ fetchDistTags?: (packageName: string) => Promise<Record<string, string> | undefined>;
19
+ spawnCommand?: (command: string, args: string[], options: {
20
+ cwd: string;
21
+ env: NodeJS.ProcessEnv;
22
+ stderr?: CliStream;
23
+ stdio: 'inherit' | 'pipe';
24
+ stdout?: CliStream;
25
+ }) => Promise<number>;
18
26
  stderr?: CliStream;
19
27
  stdin?: CliReadableStream;
20
28
  stdout?: CliStream;
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,4BAA4B,EAAmC,MAAM,uBAAuB,CAAC;AAE3G,OAAO,EAAE,KAAK,wBAAwB,EAA2B,MAAM,mBAAmB,CAAC;AAI3F,OAAO,EAAE,KAAK,4BAA4B,EAA6C,MAAM,mBAAmB,CAAC;AAEjH,KAAK,SAAS,GAAG;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,WAAW,CAAC,EAAE,KAAK,GAAG,4BAA4B,CAAC;CACpD;AAkRD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,MAAM,CAC1B,IAAI,WAAwB,EAC5B,OAAO,GAAE,iBAAiB,GAAG,wBAAwB,GAAG,4BAAiC,GACxF,OAAO,CAAC,MAAM,CAAC,CA2HjB"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,4BAA4B,EAAmC,MAAM,uBAAuB,CAAC;AAE3G,OAAO,EAAE,KAAK,wBAAwB,EAA2B,MAAM,mBAAmB,CAAC;AAO3F,OAAO,EAAE,KAAK,4BAA4B,EAA6C,MAAM,mBAAmB,CAAC;AAEjH,KAAK,SAAS,GAAG;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC;IACrF,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACzL,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,WAAW,CAAC,EAAE,KAAK,GAAG,4BAA4B,CAAC;CACpD;AA+VD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,MAAM,CAC1B,IAAI,WAAwB,EAC5B,OAAO,GAAE,iBAAiB,GAAG,wBAAwB,GAAG,4BAAiC,GACxF,OAAO,CAAC,MAAM,CAAC,CAsNjB"}
package/dist/cli.js CHANGED
@@ -1,10 +1,14 @@
1
- import { existsSync, readdirSync } from 'node:fs';
1
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
2
2
  import { join, resolve } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
+ import { diagnosticsUsage, runAnalyzeCommand, runDoctorCommand, runInfoCommand } from './commands/diagnostics.js';
4
5
  import { runGenerateCommand } from './commands/generate.js';
5
6
  import { inspectUsage, runInspectCommand } from './commands/inspect.js';
6
7
  import { migrateUsage, runMigrateCommand } from './commands/migrate.js';
7
8
  import { newUsage, runNewCommand } from './commands/new.js';
9
+ import { addUsage, runAddCommand, runUpgradeCommand, upgradeUsage } from './commands/package-workflow.js';
10
+ import { runScriptCommand, scriptUsage } from './commands/scripts.js';
11
+ import { runNodeRestartRunner } from './dev-runner/node-restart-runner.js';
8
12
  import { builtInGeneratorCollection, generatorManifest, generatorOptionSchemas, resolveGeneratorKind } from './generators/manifest.js';
9
13
  import { renderAliasList, renderHelpTable } from './help.js';
10
14
  import { removeUpdateCheckFlags, runCliUpdateCheck } from './update-check.js';
@@ -33,6 +37,34 @@ const TOP_LEVEL_COMMAND_HELP = [{
33
37
  aliases: ['g'],
34
38
  command: 'generate',
35
39
  description: 'Generate a schematic inside an existing fluo application.'
40
+ }, {
41
+ aliases: ['info'],
42
+ command: 'doctor',
43
+ description: 'Print CLI, registry, update-cache, runtime, and project diagnostics.'
44
+ }, {
45
+ aliases: [],
46
+ command: 'analyze',
47
+ description: 'Summarize project diagnostics and point to deeper inspection flows.'
48
+ }, {
49
+ aliases: [],
50
+ command: 'dev',
51
+ description: 'Run the generated project development lifecycle.'
52
+ }, {
53
+ aliases: [],
54
+ command: 'start',
55
+ description: 'Run the generated project production lifecycle.'
56
+ }, {
57
+ aliases: [],
58
+ command: 'build',
59
+ description: 'Run the generated project build lifecycle.'
60
+ }, {
61
+ aliases: [],
62
+ command: 'add',
63
+ description: 'Install @fluojs packages with the detected package manager.'
64
+ }, {
65
+ aliases: [],
66
+ command: 'upgrade',
67
+ description: 'Report latest CLI state and migration workflow guidance.'
36
68
  }, {
37
69
  aliases: [],
38
70
  command: 'inspect',
@@ -41,17 +73,36 @@ const TOP_LEVEL_COMMAND_HELP = [{
41
73
  aliases: [],
42
74
  command: 'migrate',
43
75
  description: 'Run NestJS-to-fluo codemods (dry-run by default).'
76
+ }, {
77
+ aliases: ['--version', '-v'],
78
+ command: 'version',
79
+ description: 'Print the installed fluo CLI version.'
44
80
  }, {
45
81
  aliases: [],
46
82
  command: 'help',
47
83
  description: 'Show top-level or command-specific help.'
48
84
  }];
85
+ const NODE_DEV_RUNNER_COMMAND = '__node-dev-runner';
49
86
  function normalizeGeneratorKind(value) {
50
87
  return resolveGeneratorKind(value);
51
88
  }
52
89
  function isHelpFlag(value) {
53
90
  return value === '--help' || value === '-h';
54
91
  }
92
+ function isVersionCommand(value) {
93
+ return value === 'version' || value === '--version' || value === '-v';
94
+ }
95
+ function isCreationCommand(value) {
96
+ return value === 'new' || value === 'create';
97
+ }
98
+ function readCliVersion() {
99
+ const packageJsonPath = fileURLToPath(new URL('../package.json', import.meta.url));
100
+ const manifest = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
101
+ if (typeof manifest !== 'object' || manifest === null || !('version' in manifest) || typeof manifest.version !== 'string') {
102
+ throw new Error('Unable to determine the installed fluo CLI version.');
103
+ }
104
+ return manifest.version;
105
+ }
55
106
  function generateUsage() {
56
107
  return ['Usage: fluo generate|g <kind> <name> [options]', ' fluo generate|g request-dto|req <feature> <name> [options]', '', 'Schematics', renderHelpTable(GENERATE_KIND_HELP, [{
57
108
  header: 'Schematic',
@@ -173,6 +224,42 @@ function parseGenerateArgs(argv) {
173
224
  }
174
225
  function parseCommand(argv) {
175
226
  const [command] = argv;
227
+ if (command === 'analyze') {
228
+ return {
229
+ argv: argv.slice(1),
230
+ command: 'analyze'
231
+ };
232
+ }
233
+ if (command === 'add') {
234
+ return {
235
+ argv: argv.slice(1),
236
+ command: 'add'
237
+ };
238
+ }
239
+ if (command === 'doctor') {
240
+ return {
241
+ argv: argv.slice(1),
242
+ command: 'doctor'
243
+ };
244
+ }
245
+ if (command === 'info') {
246
+ return {
247
+ argv: argv.slice(1),
248
+ command: 'info'
249
+ };
250
+ }
251
+ if (command === 'build' || command === 'dev' || command === 'start') {
252
+ return {
253
+ argv: argv.slice(1),
254
+ command
255
+ };
256
+ }
257
+ if (command === 'upgrade') {
258
+ return {
259
+ argv: argv.slice(1),
260
+ command: 'upgrade'
261
+ };
262
+ }
176
263
  if (command === 'new' || command === 'create') {
177
264
  return {
178
265
  argv: argv.slice(1),
@@ -225,14 +312,33 @@ export async function runCli(argv = process.argv.slice(2), runtime = {}) {
225
312
  const stdout = runtime.stdout ?? process.stdout;
226
313
  const stderr = runtime.stderr ?? process.stderr;
227
314
  const env = runtime.env ?? process.env;
315
+ const commandRuntime = {
316
+ ...runtime,
317
+ env
318
+ };
228
319
  const updateFlagResult = removeUpdateCheckFlags(argv);
229
320
  const commandArgv = updateFlagResult.argv;
230
321
  try {
322
+ if (commandArgv[0] === NODE_DEV_RUNNER_COMMAND) {
323
+ const separatorIndex = commandArgv.indexOf('--');
324
+ const appArgs = separatorIndex >= 0 ? commandArgv.slice(separatorIndex + 1) : commandArgv.slice(1);
325
+ return runNodeRestartRunner({
326
+ appArgs,
327
+ env,
328
+ stderr,
329
+ stdout
330
+ });
331
+ }
332
+ if (isVersionCommand(commandArgv[0])) {
333
+ stdout.write(`${readCliVersion()}\n`);
334
+ return 0;
335
+ }
231
336
  const updateCheckOptions = runtime.updateCheck === false ? undefined : runtime.updateCheck;
232
337
  const updateCheckResult = await runCliUpdateCheck(commandArgv, {
233
338
  ...updateCheckOptions,
234
339
  ci: runtime.ci,
235
340
  env,
341
+ bypassCache: isCreationCommand(commandArgv[0]),
236
342
  interactive: runtime.interactive,
237
343
  skip: updateFlagResult.skipUpdateCheck || runtime.updateCheck === false,
238
344
  stderr,
@@ -255,6 +361,26 @@ export async function runCli(argv = process.argv.slice(2), runtime = {}) {
255
361
  stdout.write(`${generateUsage()}\n`);
256
362
  return 0;
257
363
  }
364
+ if (topic === 'doctor' || topic === 'info') {
365
+ stdout.write(`${diagnosticsUsage('doctor')}\n`);
366
+ return 0;
367
+ }
368
+ if (topic === 'analyze') {
369
+ stdout.write(`${diagnosticsUsage('analyze')}\n`);
370
+ return 0;
371
+ }
372
+ if (topic === 'build' || topic === 'dev' || topic === 'start') {
373
+ stdout.write(`${scriptUsage(topic)}\n`);
374
+ return 0;
375
+ }
376
+ if (topic === 'add') {
377
+ stdout.write(`${addUsage()}\n`);
378
+ return 0;
379
+ }
380
+ if (topic === 'upgrade') {
381
+ stdout.write(`${upgradeUsage()}\n`);
382
+ return 0;
383
+ }
258
384
  if (topic === 'migrate') {
259
385
  stdout.write(`${migrateUsage()}\n`);
260
386
  return 0;
@@ -274,6 +400,26 @@ export async function runCli(argv = process.argv.slice(2), runtime = {}) {
274
400
  stdout.write(`${generateUsage()}\n`);
275
401
  return 0;
276
402
  }
403
+ if ((commandArgv[0] === 'doctor' || commandArgv[0] === 'info') && commandArgv.slice(1).some(isHelpFlag)) {
404
+ stdout.write(`${diagnosticsUsage('doctor')}\n`);
405
+ return 0;
406
+ }
407
+ if (commandArgv[0] === 'analyze' && commandArgv.slice(1).some(isHelpFlag)) {
408
+ stdout.write(`${diagnosticsUsage('analyze')}\n`);
409
+ return 0;
410
+ }
411
+ if ((commandArgv[0] === 'build' || commandArgv[0] === 'dev' || commandArgv[0] === 'start') && commandArgv.slice(1).some(isHelpFlag)) {
412
+ stdout.write(`${scriptUsage(commandArgv[0])}\n`);
413
+ return 0;
414
+ }
415
+ if (commandArgv[0] === 'add' && commandArgv.slice(1).some(isHelpFlag)) {
416
+ stdout.write(`${addUsage()}\n`);
417
+ return 0;
418
+ }
419
+ if (commandArgv[0] === 'upgrade' && commandArgv.slice(1).some(isHelpFlag)) {
420
+ stdout.write(`${upgradeUsage()}\n`);
421
+ return 0;
422
+ }
277
423
  if (commandArgv[0] === 'migrate' && commandArgv.slice(1).some(isHelpFlag)) {
278
424
  stdout.write(`${migrateUsage()}\n`);
279
425
  return 0;
@@ -283,14 +429,35 @@ export async function runCli(argv = process.argv.slice(2), runtime = {}) {
283
429
  return 0;
284
430
  }
285
431
  const parsedCommand = parseCommand(commandArgv);
432
+ if (parsedCommand.command === 'analyze') {
433
+ return runAnalyzeCommand(parsedCommand.argv, commandRuntime);
434
+ }
435
+ if (parsedCommand.command === 'add') {
436
+ return runAddCommand(parsedCommand.argv, commandRuntime);
437
+ }
438
+ if (parsedCommand.command === 'doctor') {
439
+ return runDoctorCommand(parsedCommand.argv, commandRuntime);
440
+ }
441
+ if (parsedCommand.command === 'info') {
442
+ return runInfoCommand(parsedCommand.argv, commandRuntime);
443
+ }
444
+ if (parsedCommand.command === 'build' || parsedCommand.command === 'dev' || parsedCommand.command === 'start') {
445
+ return runScriptCommand(parsedCommand.command, parsedCommand.argv, commandRuntime);
446
+ }
447
+ if (parsedCommand.command === 'upgrade') {
448
+ return runUpgradeCommand(parsedCommand.argv, commandRuntime);
449
+ }
286
450
  if (parsedCommand.command === 'new') {
287
- return runNewCommand(parsedCommand.argv, runtime);
451
+ return runNewCommand(parsedCommand.argv, commandRuntime);
288
452
  }
289
453
  if (parsedCommand.command === 'migrate') {
290
- return runMigrateCommand(parsedCommand.argv, runtime);
454
+ return runMigrateCommand(parsedCommand.argv, commandRuntime);
291
455
  }
292
456
  if (parsedCommand.command === 'inspect') {
293
- return runInspectCommand(parsedCommand.argv, runtime);
457
+ return runInspectCommand(parsedCommand.argv, commandRuntime);
458
+ }
459
+ if (parsedCommand.command !== 'generate') {
460
+ throw new Error(usage());
294
461
  }
295
462
  const targetDirectory = resolve(cwd, parsedCommand.parsed.targetDirectory ?? resolveDefaultTargetDirectory(cwd));
296
463
  const result = runGenerateCommand(parsedCommand.parsed.kind, parsedCommand.parsed.name, targetDirectory, parsedCommand.parsed.options);
@@ -0,0 +1,15 @@
1
+ type CliStream = {
2
+ write(message: string): unknown;
3
+ };
4
+ type DiagnosticRuntimeOptions = {
5
+ cwd?: string;
6
+ env?: NodeJS.ProcessEnv;
7
+ fetchDistTags?: (packageName: string) => Promise<Record<string, string> | undefined>;
8
+ stdout?: CliStream;
9
+ };
10
+ export declare function diagnosticsUsage(command?: 'analyze' | 'doctor' | 'info'): string;
11
+ export declare function runDoctorCommand(argv: string[], runtime?: DiagnosticRuntimeOptions): Promise<number>;
12
+ export declare function runInfoCommand(argv: string[], runtime?: DiagnosticRuntimeOptions): Promise<number>;
13
+ export declare function runAnalyzeCommand(argv: string[], runtime?: DiagnosticRuntimeOptions): Promise<number>;
14
+ export {};
15
+ //# sourceMappingURL=diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/commands/diagnostics.ts"],"names":[],"mappings":"AAKA,KAAK,SAAS,GAAG;IACf,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC;IACrF,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAuHF,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,SAAS,GAAG,QAAQ,GAAG,MAAiB,GAAG,MAAM,CAoB1F;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,MAAM,CAAC,CAgC9G;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,MAAM,CAAC,CAO5G;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,MAAM,CAAC,CAsB/G"}