@fluojs/cli 1.0.6 → 1.1.0
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.
- package/README.ko.md +15 -7
- package/README.md +15 -7
- package/dist/commands/scripts.d.ts.map +1 -1
- package/dist/commands/scripts.js +5 -2
- package/dist/dev-runner/node-restart-runner.d.ts.map +1 -1
- package/dist/dev-runner/node-restart-runner.js +33 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/run-cli.d.ts +16 -0
- package/dist/run-cli.d.ts.map +1 -0
- package/dist/run-cli.js +16 -0
- package/dist/studio/sidecar.d.ts.map +1 -1
- package/dist/studio/sidecar.js +42 -22
- package/dist/types.d.ts +6 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/update-check.d.ts.map +1 -1
- package/dist/update-check.js +21 -4
- package/package.json +3 -3
package/README.ko.md
CHANGED
|
@@ -32,7 +32,7 @@ pnpm dlx @fluojs/cli new my-app
|
|
|
32
32
|
|
|
33
33
|
- `@fluojs/cli`는 intended publish surface에 포함되는 공개 패키지입니다.
|
|
34
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 ...`)입니다.
|
|
35
|
-
- 배포되는 `fluo` bin은 `package.json`에 선언된 dist 빌드 CLI
|
|
35
|
+
- 배포되는 `fluo` bin은 `package.json`에 선언된 `./bin/fluo.mjs` wrapper이며, 이 wrapper가 dist 빌드 CLI 엔트리포인트인 `../dist/cli.js`를 로드합니다.
|
|
36
36
|
|
|
37
37
|
## 버전 확인
|
|
38
38
|
|
|
@@ -153,7 +153,7 @@ fluo generate service users --dry-run
|
|
|
153
153
|
|
|
154
154
|
자동 등록되는 generator는 `controller`, `service`, `repo`, `guard`, `interceptor`, `middleware`입니다. 파일만 생성하는 generator는 `e2e`, `module`, `request-dto`, `response-dto`, `resource`입니다.
|
|
155
155
|
|
|
156
|
-
`fluo generate module <name> --with-test`는 작성한 module을 `createTestingModule({ rootModule })`로 컴파일하는 `*.slice.test.ts`를 추가합니다. `fluo generate resource <name>`는 module, controller, service, repository, request DTO, response DTO, test를 포함하는 완전한 feature slice를 생성합니다. `--with-slice-test`를 추가하면 provider override와 service resolution을 보여 주는 resource-level slice test도 포함합니다. 생성된 resource module은 parent module에 자동으로 연결하지
|
|
156
|
+
`fluo generate module <name> --with-test`는 작성한 module을 `createTestingModule({ rootModule })`로 컴파일하는 `*.slice.test.ts`를 추가합니다. `fluo generate resource <name>`는 module, controller, service, repository, request DTO, response DTO, test를 포함하는 완전한 feature slice를 생성합니다. `--with-slice-test`를 추가하면 provider override와 service resolution을 보여 주는 resource-level slice test도 포함합니다. 이 명령은 파일만 생성하고 수동 활성화를 요구하는 generator입니다. 생성된 resource module은 parent module에 자동으로 연결하지 않으며, route를 자동 활성화하는 `nest g resource` 동등 명령으로 보면 안 됩니다. Slice를 활성화할 준비가 되었을 때 직접 import하세요.
|
|
157
157
|
|
|
158
158
|
`fluo generate e2e <name>`는 generated starter와 같은 app-level test 영역에 request-pipeline test를 두도록 `createTestApp({ rootModule: AppModule })`을 사용하는 `test/<name>.e2e.test.ts`를 작성하고, 기본 starter root module인 `../src/app`에서 `AppModule`을 import합니다. 생성된 unit test는 직접 class 동작 검증에, slice test는 DI wiring과 override 검증에, e2e test는 virtual app을 통과하는 route, guard, interceptor, DTO validation, response writing 검증에 사용하세요.
|
|
159
159
|
|
|
@@ -161,7 +161,7 @@ Request DTO 생성은 feature 디렉터리와 DTO 클래스 이름을 분리해
|
|
|
161
161
|
|
|
162
162
|
`--dry-run`을 추가하면 실제 실행과 같은 타깃 해석, 기존 파일 건너뛰기 또는 덮어쓰기 판단, 모듈 자동 등록 계획, 파일만 생성하는 wiring 상태, 다음 단계 힌트를 미리 볼 수 있습니다. 이 모드는 디렉터리 생성, 파일 쓰기, 모듈 갱신을 수행하지 않습니다. `--force`는 내용이 달라질 기존 파일의 계획 항목을 `SKIP`에서 `OVERWRITE`로 바꾸며, `--target-directory`는 실제 실행과 동일하게 지정한 소스 디렉터리 기준으로 preview 범위를 제한합니다.
|
|
163
163
|
|
|
164
|
-
Generator discovery는 의도적으로 built-in `@fluojs/cli/builtin` collection으로 제한됩니다. 외부 package-owned 또는 app-local generator collection은 보류되어 있습니다. `fluo generate`는 config file을 스캔하거나, 임의 package를 로드하거나, workspace-owned collection code를 실행하지 않습니다. 이 경계는 shipped generator 계약을 보존하면서 generator metadata, option schema, help output, file-write boundary를 결정적이고 테스트 가능하게 유지합니다.
|
|
164
|
+
Generator discovery는 의도적으로 built-in `@fluojs/cli/builtin` collection으로 제한됩니다. 외부 package-owned 또는 app-local generator collection은 보류되어 있습니다. `fluo generate`는 config file을 스캔하거나, 임의 package를 로드하거나, package discovery convention을 따르거나, workspace-owned collection code를 실행하지 않습니다. 이 경계는 shipped generator 계약을 보존하면서 generator metadata, option schema, help output, file-write boundary를 결정적이고 테스트 가능하게 유지합니다.
|
|
165
165
|
|
|
166
166
|
## 주요 패턴
|
|
167
167
|
|
|
@@ -194,7 +194,7 @@ fluo dev --studio --studio-port 51234
|
|
|
194
194
|
fluo dev --studio --dry-run
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
CLI는 local Studio sidecar를 시작하고, tokenized URL을 출력하며, restart lifecycle event를 sidecar로 계속 전달하고, 앱이 `@fluojs/runtime`을 import하기 전에 명시적인 Studio config를 Node 앱 child에 주입합니다. Optional package인 `@fluojs/studio`가 설치되어 있으면 sidecar는 패키징된 `@fluojs/studio/viewer` React app을 제공합니다. Runtime package source는 `process.env`를 직접 읽지 않으며, CLI가 주입한 Studio config가 있을 때만 live graph/routes/request/timing/diagnostic event를 전송합니다.
|
|
197
|
+
CLI는 local Studio sidecar를 시작하고, tokenized URL을 출력하며, restart lifecycle event를 sidecar로 계속 전달하고, 앱이 `@fluojs/runtime`을 import하기 전에 명시적인 Studio config를 Node 앱 child에 주입합니다. Studio live mode는 fluo가 소유한 Node restart runner를 요구합니다. 따라서 lifecycle event가 CLI restart boundary와 분리되지 않도록 `fluo dev --studio`는 `--raw-watch`, `--runner native`, `FLUO_DEV_RUNNER=native`를 거부합니다. Optional package인 `@fluojs/studio`가 설치되어 있으면 sidecar는 패키징된 `@fluojs/studio/viewer` React app을 제공합니다. Runtime package source는 `process.env`를 직접 읽지 않으며, CLI가 주입한 Studio config가 있을 때만 live graph/routes/request/timing/diagnostic event를 전송합니다.
|
|
198
198
|
|
|
199
199
|
보안 기본값은 local-only입니다. Sidecar는 `127.0.0.1`에 bind되고, runtime ingestion 및 browser state/SSE API는 generated token을 요구하며, CORS는 기본적으로 활성화하지 않고, request body는 기본적으로 수집하지 않습니다.
|
|
200
200
|
|
|
@@ -251,6 +251,8 @@ fluo migrate ./src --skip tests
|
|
|
251
251
|
|
|
252
252
|
CI 작업, 대시보드, migration report에서 안정적인 machine-readable 결과가 필요하면 `--json`을 사용하세요. 사람을 위한 출력은 기본값으로 유지됩니다. JSON 모드는 성공 시 stdout에 structured report만 기록하고, parser 오류나 잘못된 flag 조합은 기존처럼 stderr에 메시지를 기록한 뒤 exit code `1`을 반환하며 partial JSON을 출력하지 않습니다. Report에는 `mode`(`dry-run` 또는 `apply`), `dryRun`, `apply`, 활성화된 `transforms`, `scannedFiles`, `changedFiles`, 전체 `warningCount`, 그리고 `filePath`, `changed`, `appliedTransforms`, `warningCount`, category label과 source line number가 포함된 warnings per-file metadata가 포함됩니다.
|
|
253
253
|
|
|
254
|
+
`--apply`로 다시 실행하기 전에는 모든 warning을 검토하세요. Warning은 자동 rewrite를 그대로 수락해도 된다는 뜻이 아니라 수동 follow-up 항목입니다. Warning category별 post-codemod checklist는 [NestJS migration guide](../../docs/getting-started/migrate-from-nestjs.ko.md)를 기준으로 확인하세요.
|
|
255
|
+
|
|
254
256
|
**주요 변환 사항:**
|
|
255
257
|
- `@nestjs/common` 임포트를 `@fluojs/core` 또는 `@fluojs/http`로 재작성합니다.
|
|
256
258
|
- bootstrap 패턴을 재작성하고 지원되는 `listen(port)` 호출을 fluo runtime startup 규칙으로 접습니다.
|
|
@@ -302,12 +304,18 @@ Studio가 없으면 CI와 non-interactive 실행은 prompt나 package manager
|
|
|
302
304
|
| `runNewCommand(argv, options?)` | 프로젝트 스캐폴딩 로직에 대한 프로그래밍적 접근을 제공합니다. |
|
|
303
305
|
| `NewCommandRuntimeOptions` | prompt, filesystem write, dependency install, git initialization 같은 `runNewCommand(...)` runtime override 타입입니다. |
|
|
304
306
|
| `CliPromptCancelledError` | 호출자가 제공한 prompt hook이 정상 취소를 알리기 위해 throw할 수 있는 안정적인 sentinel입니다. |
|
|
307
|
+
| `runGenerateCommand(kind, name, baseDirectory, options?)` | built-in schematic generator와 module auto-registration planner에 대한 프로그래밍적 접근을 제공합니다. |
|
|
305
308
|
| `GenerateOptions` | 프로그래밍 방식 generator 옵션 타입입니다. |
|
|
306
|
-
| `
|
|
309
|
+
| `GenerateResult` | 변경된 파일, dry-run plan entry, module wiring metadata, next-step hint를 포함하는 generator 결과 타입입니다. |
|
|
310
|
+
| `GeneratePlanEntry` / `GeneratePlanAction` | `runGenerateCommand(...)`가 반환하는 dry-run 및 write-plan path action 타입입니다. |
|
|
311
|
+
| `GeneratedFile` | write 전 생성된 파일 경로와 in-memory content를 설명하는 타입입니다. |
|
|
307
312
|
| `GeneratorKind` | 지원되는 모든 생성기 유형(예: `'controller'`, `'service'`)의 유니온 타입입니다. |
|
|
308
|
-
| `ModuleRegistration` | generator 실행의 module wiring
|
|
313
|
+
| `ModuleRegistration` | generator 실행의 controller, provider, middleware module wiring metadata를 설명하는 타입입니다. |
|
|
314
|
+
| `inspectUsage()` | help surface와 test에서 사용하는 현재 `fluo inspect` usage text를 반환합니다. |
|
|
315
|
+
| `runInspectCommand(argv, options?)` | inspect orchestration, JSON/report emission, Studio Mermaid delegation에 대한 프로그래밍적 접근을 제공합니다. |
|
|
316
|
+
| `InspectCommandRuntimeOptions` | cwd, stream, prompt, Studio renderer loading 같은 `runInspectCommand(...)`와 `runCli(...)` inspect runtime override 타입입니다. |
|
|
309
317
|
|
|
310
|
-
프로그래밍 방식 진입점은 호출자 프로세스의 소유권을 보존합니다. `runCli(...)
|
|
318
|
+
프로그래밍 방식 진입점은 호출자 프로세스의 소유권을 보존합니다. `runCli(...)`, `runNewCommand(...)`, `runInspectCommand(...)`는 `process.exit(...)`를 호출하지 않고 숫자 exit code를 반환하며, prompt 취소는 command runner를 통해 exit code `0`으로 해석됩니다. dependency 설치나 git 초기화 같은 setup 작업은 해석된 `fluo new` 옵션이 요청한 경우에만 실행됩니다. `runGenerateCommand(...)`는 구조화된 `GenerateResult`를 반환합니다. 파일 쓰기 없이 생성 파일과 module-wiring action을 미리 보려면 `dryRun: true`를 전달하세요. 호출자가 제공한 prompt hook은 공개 패키지 엔트리포인트의 `CliPromptCancelledError`를 throw해 CLI 내부 파일에 의존하지 않고 정상 취소를 표현할 수 있습니다.
|
|
311
319
|
|
|
312
320
|
## 관련 패키지
|
|
313
321
|
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ pnpm dlx @fluojs/cli new my-app
|
|
|
32
32
|
|
|
33
33
|
- `@fluojs/cli` is a public package in the intended publish surface.
|
|
34
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 ...`).
|
|
35
|
-
- The published `fluo` bin is
|
|
35
|
+
- The published `fluo` bin is the `./bin/fluo.mjs` wrapper declared in `package.json`; that wrapper loads the dist-built CLI entrypoint at `../dist/cli.js`.
|
|
36
36
|
|
|
37
37
|
## Version Inspection
|
|
38
38
|
|
|
@@ -153,7 +153,7 @@ Supported generator kinds and aliases are `controller`/`co`, `e2e`, `guard`/`gu`
|
|
|
153
153
|
|
|
154
154
|
Auto-registered generators are `controller`, `service`, `repo`, `guard`, `interceptor`, and `middleware`. Files-only generators are `e2e`, `module`, `request-dto`, `response-dto`, and `resource`.
|
|
155
155
|
|
|
156
|
-
`fluo generate module <name> --with-test` adds a `*.slice.test.ts` that compiles the authored module with `createTestingModule({ rootModule })`. `fluo generate resource <name>` creates a complete feature slice with a module, controller, service, repository, request DTO, response DTO, and tests; add `--with-slice-test` to include a resource-level slice test that demonstrates provider override and service resolution. It does not wire the resource module into a parent module automatically
|
|
156
|
+
`fluo generate module <name> --with-test` adds a `*.slice.test.ts` that compiles the authored module with `createTestingModule({ rootModule })`. `fluo generate resource <name>` creates a complete feature slice with a module, controller, service, repository, request DTO, response DTO, and tests; add `--with-slice-test` to include a resource-level slice test that demonstrates provider override and service resolution. It is a files-only/manual-activation generator: it does not wire the resource module into a parent module automatically, and it should not be treated as a `nest g resource` equivalent that activates routes for you. Import the generated module when you are ready to activate the slice.
|
|
157
157
|
|
|
158
158
|
`fluo generate e2e <name>` writes `test/<name>.e2e.test.ts` with `createTestApp({ rootModule: AppModule })` and imports `AppModule` from the default starter root module at `../src/app`, so request-pipeline tests live in the same app-level test area as generated starters. Use generated unit tests for direct class behavior, slice tests for DI wiring and overrides, and e2e tests for routes, guards, interceptors, DTO validation, and response writing through the virtual app.
|
|
159
159
|
|
|
@@ -161,7 +161,7 @@ Request DTO generation accepts the feature directory separately from the DTO cla
|
|
|
161
161
|
|
|
162
162
|
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.
|
|
163
163
|
|
|
164
|
-
Generator discovery is intentionally limited to the built-in `@fluojs/cli/builtin` collection. External package-owned or app-local generator collections are deferred: `fluo generate` does not scan config files, load arbitrary packages, or execute workspace-owned collection code. This keeps generator metadata, option schemas, help output, and file-write boundaries deterministic and testable while preserving the shipped generator contract.
|
|
164
|
+
Generator discovery is intentionally limited to the built-in `@fluojs/cli/builtin` collection. External package-owned or app-local generator collections are deferred: `fluo generate` does not scan config files, load arbitrary packages, follow package discovery conventions, or execute workspace-owned collection code. This keeps generator metadata, option schemas, help output, and file-write boundaries deterministic and testable while preserving the shipped generator contract.
|
|
165
165
|
|
|
166
166
|
## Common Patterns
|
|
167
167
|
|
|
@@ -194,7 +194,7 @@ fluo dev --studio --studio-port 51234
|
|
|
194
194
|
fluo dev --studio --dry-run
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
The CLI starts a local Studio sidecar, prints a tokenized URL, keeps restart lifecycle events flowing through the sidecar, and injects an explicit Studio config into the Node app child before the app imports `@fluojs/runtime`. The sidecar serves the packaged `@fluojs/studio/viewer` React app when that optional package is installed. Runtime package source never reads `process.env` directly; it publishes live graph/routes/request/timing/diagnostic events only when CLI-injected Studio config is present.
|
|
197
|
+
The CLI starts a local Studio sidecar, prints a tokenized URL, keeps restart lifecycle events flowing through the sidecar, and injects an explicit Studio config into the Node app child before the app imports `@fluojs/runtime`. Studio live mode requires the fluo-owned Node restart runner; `fluo dev --studio` rejects `--raw-watch`, `--runner native`, and `FLUO_DEV_RUNNER=native` so lifecycle events cannot be split from the CLI restart boundary. The sidecar serves the packaged `@fluojs/studio/viewer` React app when that optional package is installed. Runtime package source never reads `process.env` directly; it publishes live graph/routes/request/timing/diagnostic events only when CLI-injected Studio config is present.
|
|
198
198
|
|
|
199
199
|
Security defaults are local-only: the sidecar binds `127.0.0.1`, runtime ingestion and browser state/SSE APIs require generated tokens, CORS is not enabled by default, and request bodies are not captured by default.
|
|
200
200
|
|
|
@@ -251,6 +251,8 @@ fluo migrate ./src --skip tests
|
|
|
251
251
|
|
|
252
252
|
Use `--json` when CI jobs, dashboards, or migration reports need a stable machine-readable result. Human output remains the default. JSON mode writes only the structured report to stdout on success, while parser errors and invalid flag combinations still write their message to stderr and return exit code `1` without partial JSON output. The report includes `mode` (`dry-run` or `apply`), `dryRun`, `apply`, enabled `transforms`, `scannedFiles`, `changedFiles`, aggregate `warningCount`, and per-file metadata with `filePath`, `changed`, `appliedTransforms`, `warningCount`, and warnings including category labels and source line numbers.
|
|
253
253
|
|
|
254
|
+
Review every warning before rerunning with `--apply`. Warnings are manual follow-up items rather than permission for an automatic rewrite to be accepted blindly; use the [NestJS migration guide](../../docs/getting-started/migrate-from-nestjs.md) as the post-codemod checklist for each warning category.
|
|
255
|
+
|
|
254
256
|
**Key Transformations:**
|
|
255
257
|
- Rewrites imports from `@nestjs/common` to `@fluojs/core` or `@fluojs/http`.
|
|
256
258
|
- Rewrites bootstrap patterns and folds supported `listen(port)` calls into fluo runtime startup conventions.
|
|
@@ -302,12 +304,18 @@ The package can be used programmatically to trigger CLI actions from within othe
|
|
|
302
304
|
| `runNewCommand(argv, options?)` | Programmatic access to the project scaffolding logic. |
|
|
303
305
|
| `NewCommandRuntimeOptions` | Type for `runNewCommand(...)` runtime overrides such as prompts, filesystem writes, dependency installation, and git initialization. |
|
|
304
306
|
| `CliPromptCancelledError` | Stable sentinel that caller-supplied prompt hooks can throw to report normal cancellation. |
|
|
307
|
+
| `runGenerateCommand(kind, name, baseDirectory, options?)` | Programmatic access to the built-in schematic generator and module auto-registration planner. |
|
|
305
308
|
| `GenerateOptions` | Type for programmatic generator options. |
|
|
306
|
-
| `
|
|
309
|
+
| `GenerateResult` | Type for generator results, including changed files, dry-run plan entries, module wiring metadata, and next-step hints. |
|
|
310
|
+
| `GeneratePlanEntry` / `GeneratePlanAction` | Types for dry-run and write-plan path actions returned by `runGenerateCommand(...)`. |
|
|
311
|
+
| `GeneratedFile` | Type describing generated file paths and in-memory content before writes. |
|
|
307
312
|
| `GeneratorKind` | Union type of all supported generator types (e.g., `'controller'`, `'service'`). |
|
|
308
|
-
| `ModuleRegistration` | Type describing module wiring
|
|
313
|
+
| `ModuleRegistration` | Type describing controller, provider, or middleware module wiring metadata from generator runs. |
|
|
314
|
+
| `inspectUsage()` | Returns the current `fluo inspect` usage text for help surfaces and tests. |
|
|
315
|
+
| `runInspectCommand(argv, options?)` | Programmatic access to inspect orchestration, JSON/report emission, and Studio Mermaid delegation. |
|
|
316
|
+
| `InspectCommandRuntimeOptions` | Type for `runInspectCommand(...)` and `runCli(...)` inspect runtime overrides such as cwd, streams, prompts, and Studio renderer loading. |
|
|
309
317
|
|
|
310
|
-
Programmatic entry points preserve caller process ownership. `runCli(...)` and `
|
|
318
|
+
Programmatic entry points preserve caller process ownership. `runCli(...)`, `runNewCommand(...)`, and `runInspectCommand(...)` return numeric exit codes instead of calling `process.exit(...)`; prompt cancellation resolves as exit code `0` through the command runner, and setup actions such as dependency installation or git initialization only run when the resolved `fluo new` options request them. `runGenerateCommand(...)` returns a structured `GenerateResult`; pass `dryRun: true` to preview generated file and module-wiring actions without writing files. Caller-supplied prompt hooks can throw `CliPromptCancelledError` from the public package entrypoint to express normal cancellation without depending on CLI-internal files.
|
|
311
319
|
|
|
312
320
|
## Related Packages
|
|
313
321
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scripts.d.ts","sourceRoot":"","sources":["../../src/commands/scripts.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAiD,MAAM,sBAAsB,CAAC;AAGzG,KAAK,SAAS,GAAG;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAMF,KAAK,mBAAmB,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClG,kBAAkB,CAAC,EAAE,OAAO,kBAAkB,CAAC;IAC/C,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAGF,KAAK,aAAa,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"scripts.d.ts","sourceRoot":"","sources":["../../src/commands/scripts.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAiD,MAAM,sBAAsB,CAAC;AAGzG,KAAK,SAAS,GAAG;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAMF,KAAK,mBAAmB,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClG,kBAAkB,CAAC,EAAE,OAAO,kBAAkB,CAAC;IAC/C,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAGF,KAAK,aAAa,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;AA2lB/C;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAqB1D;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsFlI"}
|
package/dist/commands/scripts.js
CHANGED
|
@@ -390,7 +390,7 @@ function projectRuntimeToStudioRuntime(runtime) {
|
|
|
390
390
|
function projectDisplayName(project) {
|
|
391
391
|
return typeof project.manifest.name === 'string' && project.manifest.name.length > 0 ? project.manifest.name : project.directory.split(/[\\/]/).filter(Boolean).at(-1) ?? 'fluo-app';
|
|
392
392
|
}
|
|
393
|
-
function assertStudioSupport(command, studio, projectRuntime,
|
|
393
|
+
function assertStudioSupport(command, studio, projectRuntime, devRunner, rawWatch) {
|
|
394
394
|
if (!studio) {
|
|
395
395
|
return;
|
|
396
396
|
}
|
|
@@ -400,6 +400,9 @@ function assertStudioSupport(command, studio, projectRuntime, _devRunner) {
|
|
|
400
400
|
if (projectRuntime !== 'node') {
|
|
401
401
|
throw new Error(`fluo dev --studio currently supports Node dev runner projects only. ${projectRuntime} Studio support remains experimental until a dedicated bridge is implemented and verified.`);
|
|
402
402
|
}
|
|
403
|
+
if (devRunner !== 'fluo' || rawWatch) {
|
|
404
|
+
throw new Error('fluo dev --studio requires the fluo-owned Node restart runner. Remove --raw-watch and use --runner fluo so Studio lifecycle events stay attached to the CLI restart boundary.');
|
|
405
|
+
}
|
|
403
406
|
}
|
|
404
407
|
function withStudioDryRunEnv(env, project, projectRuntime) {
|
|
405
408
|
return {
|
|
@@ -619,7 +622,7 @@ export async function runScriptCommand(command, argv, runtime = {}) {
|
|
|
619
622
|
throw new Error('--runner is only supported for fluo dev. Use -- to forward --runner to the child command.');
|
|
620
623
|
}
|
|
621
624
|
const devRunner = command === 'dev' ? resolveDevRunnerPreference(parsed, env, projectRuntime) : 'fluo';
|
|
622
|
-
assertStudioSupport(command, parsed.studio, projectRuntime, devRunner);
|
|
625
|
+
assertStudioSupport(command, parsed.studio, projectRuntime, devRunner, rawWatch);
|
|
623
626
|
const runnerSteps = buildProjectRunner(command, projectRuntime, parsed.passThrough, {
|
|
624
627
|
devRunner,
|
|
625
628
|
rawWatch
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-restart-runner.d.ts","sourceRoot":"","sources":["../../src/dev-runner/node-restart-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,EAA0D,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAKjG,KAAK,mBAAmB,GAAG;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEF,KAAK,mBAAmB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,KAAK,YAAY,CAAC;AACjJ,2EAA2E;AAC3E,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,oBAAoB,GAAG,MAAM,GAAG,MAAM,CAAC;AAE9E,KAAK,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE1C,KAAK,mBAAmB,GAAG;IACzB,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;IAC1D,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;CAC5D,CAAC;AAEF,KAAK,qBAAqB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,iBAAiB,EAAE;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,KAAK,IAAI,KAAK,SAAS,CAAC;AAE1O,KAAK,iBAAiB,GAAG;IACvB,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAC9C,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC;CACvD,CAAC;AAEF,uFAAuF;AACvF,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC,CAAC;
|
|
1
|
+
{"version":3,"file":"node-restart-runner.d.ts","sourceRoot":"","sources":["../../src/dev-runner/node-restart-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,EAA0D,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAKjG,KAAK,mBAAmB,GAAG;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEF,KAAK,mBAAmB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,KAAK,YAAY,CAAC;AACjJ,2EAA2E;AAC3E,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,oBAAoB,GAAG,MAAM,GAAG,MAAM,CAAC;AAE9E,KAAK,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE1C,KAAK,mBAAmB,GAAG;IACzB,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;IAC1D,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;CAC5D,CAAC;AAEF,KAAK,qBAAqB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,iBAAiB,EAAE;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,KAAK,IAAI,KAAK,SAAS,CAAC;AAE1O,KAAK,iBAAiB,GAAG;IACvB,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAC9C,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC;CACvD,CAAC;AAEF,uFAAuF;AACvF,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC,CAAC;AA6NF;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,gBAAgB,EAAE,MAAM,EAAE,cAAc,GAAE,MAAM,EAAoB,GAAG,iBAAiB,CAuB/H;AAkFD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmP7F"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
3
|
import { existsSync, readdirSync, readFileSync, statSync, watch } from 'node:fs';
|
|
4
4
|
import { basename, dirname, join, relative, sep } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
@@ -16,6 +16,7 @@ const DEFAULT_IGNORES = ['.cache', '.fluo', '.git', '.turbo', 'coverage', 'dist'
|
|
|
16
16
|
const WATCH_FILES = ['.env', 'package.json', 'tsconfig.json', 'tsconfig.build.json'];
|
|
17
17
|
const SHOW_NODE_RESTART_NOTICE_ENV = 'FLUO_DEV_SHOW_RESTART_NOTICE';
|
|
18
18
|
const CLEAR_SCREEN = '\u001B[2J\u001B[3J\u001B[H';
|
|
19
|
+
const STUDIO_EPOCH_ENV = 'FLUO_STUDIO_EPOCH';
|
|
19
20
|
function isEnabledEnvironmentFlag(value) {
|
|
20
21
|
return value === '1' || value === 'true' || value === 'yes';
|
|
21
22
|
}
|
|
@@ -41,6 +42,34 @@ function resolveStudioIngestEndpoint(env) {
|
|
|
41
42
|
return undefined;
|
|
42
43
|
}
|
|
43
44
|
}
|
|
45
|
+
function hasStudioDevtoolsConfig(env) {
|
|
46
|
+
return isEnabledEnvironmentFlag(env.FLUO_STUDIO) && Boolean(env.FLUO_STUDIO_TOKEN);
|
|
47
|
+
}
|
|
48
|
+
function createStudioEpoch() {
|
|
49
|
+
return randomUUID();
|
|
50
|
+
}
|
|
51
|
+
function ensureStudioEpoch(env) {
|
|
52
|
+
if (!hasStudioDevtoolsConfig(env)) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
env[STUDIO_EPOCH_ENV] ??= createStudioEpoch();
|
|
56
|
+
return env[STUDIO_EPOCH_ENV];
|
|
57
|
+
}
|
|
58
|
+
function advanceStudioEpoch(env) {
|
|
59
|
+
if (!hasStudioDevtoolsConfig(env)) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
const epoch = createStudioEpoch();
|
|
63
|
+
env[STUDIO_EPOCH_ENV] = epoch;
|
|
64
|
+
return epoch;
|
|
65
|
+
}
|
|
66
|
+
function withStudioEpoch(env, payload) {
|
|
67
|
+
const epoch = ensureStudioEpoch(env);
|
|
68
|
+
return epoch ? {
|
|
69
|
+
...payload,
|
|
70
|
+
epoch
|
|
71
|
+
} : payload;
|
|
72
|
+
}
|
|
44
73
|
function publishStudioLifecycleEvent(env, runtime, type, payload) {
|
|
45
74
|
const endpoint = resolveStudioIngestEndpoint(env);
|
|
46
75
|
if (!endpoint || typeof globalThis.fetch !== 'function') {
|
|
@@ -48,7 +77,7 @@ function publishStudioLifecycleEvent(env, runtime, type, payload) {
|
|
|
48
77
|
}
|
|
49
78
|
void globalThis.fetch(endpoint, {
|
|
50
79
|
body: JSON.stringify({
|
|
51
|
-
payload,
|
|
80
|
+
payload: withStudioEpoch(env, payload),
|
|
52
81
|
source: {
|
|
53
82
|
appId: env.FLUO_STUDIO_APP_ID ?? basename(process.cwd()),
|
|
54
83
|
runtime: studioRuntimeName(runtime)
|
|
@@ -278,6 +307,7 @@ export async function runNodeRestartRunner(options) {
|
|
|
278
307
|
let restarting = false;
|
|
279
308
|
let stopping = false;
|
|
280
309
|
const startChild = (resolveExitCode, cleanup) => {
|
|
310
|
+
ensureStudioEpoch(env);
|
|
281
311
|
const appCommand = buildAppCommand(runnerRuntime, env, appArgs);
|
|
282
312
|
publishStudioLifecycleEvent(env, runnerRuntime, 'restart', {
|
|
283
313
|
phase: 'starting',
|
|
@@ -341,6 +371,7 @@ export async function runNodeRestartRunner(options) {
|
|
|
341
371
|
if (env[SHOW_NODE_RESTART_NOTICE_ENV] === '1') {
|
|
342
372
|
stdout.write(`[fluo] restarting after content change: ${relative(projectDirectory, restartPaths[restartPaths.length - 1] ?? projectDirectory)}\n`);
|
|
343
373
|
}
|
|
374
|
+
advanceStudioEpoch(env);
|
|
344
375
|
publishStudioLifecycleEvent(env, runnerRuntime, 'restart', {
|
|
345
376
|
phase: 'scheduled',
|
|
346
377
|
reason: `content changed: ${relative(projectDirectory, restartPaths[restartPaths.length - 1] ?? projectDirectory)}`
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export { runCli, type CliRuntimeOptions } from './cli.js';
|
|
1
|
+
export { runCli, type CliRuntimeOptions } from './run-cli.js';
|
|
2
|
+
export { runGenerateCommand, type GeneratePlanAction, type GeneratePlanEntry, type GenerateResult } from './commands/generate.js';
|
|
3
|
+
export { inspectUsage, runInspectCommand, type InspectCommandRuntimeOptions } from './commands/inspect.js';
|
|
2
4
|
export { newUsage, runNewCommand, type NewCommandRuntimeOptions } from './commands/new.js';
|
|
3
5
|
export { CliPromptCancelledError } from './prompt-cancel.js';
|
|
4
6
|
export type { GenerateOptions, GeneratedFile, GeneratorKind, ModuleRegistration } from './types.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAClI,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,KAAK,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAC3G,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
export { runCli } from './cli.js';
|
|
1
|
+
export { runCli } from './run-cli.js';
|
|
2
|
+
export { runGenerateCommand } from './commands/generate.js';
|
|
3
|
+
export { inspectUsage, runInspectCommand } from './commands/inspect.js';
|
|
2
4
|
export { newUsage, runNewCommand } from './commands/new.js';
|
|
3
5
|
export { CliPromptCancelledError } from './prompt-cancel.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CliRuntimeOptions } from './cli.js';
|
|
2
|
+
import type { InspectCommandRuntimeOptions } from './commands/inspect.js';
|
|
3
|
+
import type { NewCommandRuntimeOptions } from './commands/new.js';
|
|
4
|
+
export type { CliRuntimeOptions } from './cli.js';
|
|
5
|
+
/**
|
|
6
|
+
* Runs the top-level CLI command dispatcher through a lazy implementation import.
|
|
7
|
+
*
|
|
8
|
+
* This keeps the package root embeddable for tools that only need lightweight helpers while preserving
|
|
9
|
+
* the same `runCli(...)` behavior as the published `fluo` binary when callers execute it.
|
|
10
|
+
*
|
|
11
|
+
* @param argv Argument vector to execute. Defaults to the current process arguments inside the dispatcher.
|
|
12
|
+
* @param runtime Optional runtime overrides shared by the top-level dispatcher and delegated commands.
|
|
13
|
+
* @returns `0` when the command completes successfully, otherwise the delegated command exit code.
|
|
14
|
+
*/
|
|
15
|
+
export declare function runCli(argv?: string[], runtime?: CliRuntimeOptions & NewCommandRuntimeOptions & InspectCommandRuntimeOptions): Promise<number>;
|
|
16
|
+
//# sourceMappingURL=run-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../src/run-cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAElE,YAAY,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAElD;;;;;;;;;GASG;AACH,wBAAsB,MAAM,CAC1B,IAAI,CAAC,EAAE,MAAM,EAAE,EACf,OAAO,GAAE,iBAAiB,GAAG,wBAAwB,GAAG,4BAAiC,GACxF,OAAO,CAAC,MAAM,CAAC,CAGjB"}
|
package/dist/run-cli.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs the top-level CLI command dispatcher through a lazy implementation import.
|
|
3
|
+
*
|
|
4
|
+
* This keeps the package root embeddable for tools that only need lightweight helpers while preserving
|
|
5
|
+
* the same `runCli(...)` behavior as the published `fluo` binary when callers execute it.
|
|
6
|
+
*
|
|
7
|
+
* @param argv Argument vector to execute. Defaults to the current process arguments inside the dispatcher.
|
|
8
|
+
* @param runtime Optional runtime overrides shared by the top-level dispatcher and delegated commands.
|
|
9
|
+
* @returns `0` when the command completes successfully, otherwise the delegated command exit code.
|
|
10
|
+
*/
|
|
11
|
+
export async function runCli(argv, runtime = {}) {
|
|
12
|
+
const {
|
|
13
|
+
runCli: runCliImplementation
|
|
14
|
+
} = await import('./cli.js');
|
|
15
|
+
return runCliImplementation(argv, runtime);
|
|
16
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidecar.d.ts","sourceRoot":"","sources":["../../src/studio/sidecar.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;
|
|
1
|
+
{"version":3,"file":"sidecar.d.ts","sourceRoot":"","sources":["../../src/studio/sidecar.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAwQD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,aAAa,CAAC,CAmLnG"}
|
package/dist/studio/sidecar.js
CHANGED
|
@@ -31,6 +31,24 @@ function isRestartEpochBoundary(incoming) {
|
|
|
31
31
|
}
|
|
32
32
|
return incoming.payload.phase === 'scheduled' || incoming.payload.phase === 'starting';
|
|
33
33
|
}
|
|
34
|
+
function resolveRestartEpoch(incoming) {
|
|
35
|
+
if (!isRestartEpochBoundary(incoming)) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const payload = isRecord(incoming.payload) ? incoming.payload : undefined;
|
|
39
|
+
const requestedEpoch = payload?.epoch;
|
|
40
|
+
return typeof requestedEpoch === 'string' && requestedEpoch.length > 0 ? requestedEpoch : createEpoch();
|
|
41
|
+
}
|
|
42
|
+
function createStudioSidecarEnv(options) {
|
|
43
|
+
return {
|
|
44
|
+
FLUO_STUDIO: '1',
|
|
45
|
+
FLUO_STUDIO_APP_ID: options.appId,
|
|
46
|
+
FLUO_STUDIO_EPOCH: options.epoch,
|
|
47
|
+
FLUO_STUDIO_RUNTIME: options.runtime,
|
|
48
|
+
FLUO_STUDIO_TOKEN: options.token,
|
|
49
|
+
FLUO_STUDIO_URL: options.url
|
|
50
|
+
};
|
|
51
|
+
}
|
|
34
52
|
function createToken() {
|
|
35
53
|
return randomBytes(24).toString('base64url');
|
|
36
54
|
}
|
|
@@ -222,8 +240,9 @@ export async function startStudioSidecar(options = {}) {
|
|
|
222
240
|
let sequence = 0;
|
|
223
241
|
const startedAt = performance.now();
|
|
224
242
|
const publish = incoming => {
|
|
225
|
-
|
|
226
|
-
|
|
243
|
+
const restartEpoch = resolveRestartEpoch(incoming);
|
|
244
|
+
if (restartEpoch) {
|
|
245
|
+
epoch = restartEpoch;
|
|
227
246
|
}
|
|
228
247
|
sequence += 1;
|
|
229
248
|
const source = isRecord(incoming.source) ? incoming.source : undefined;
|
|
@@ -333,6 +352,19 @@ export async function startStudioSidecar(options = {}) {
|
|
|
333
352
|
error: 'Unknown Studio sidecar route.'
|
|
334
353
|
});
|
|
335
354
|
});
|
|
355
|
+
await new Promise((resolve, reject) => {
|
|
356
|
+
server.once('error', reject);
|
|
357
|
+
server.listen(options.port ?? 0, host, () => {
|
|
358
|
+
server.off('error', reject);
|
|
359
|
+
resolve();
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
const address = server.address();
|
|
363
|
+
if (!address || typeof address === 'string') {
|
|
364
|
+
await closeServer(server, clients, undefined);
|
|
365
|
+
throw new Error('Failed to resolve Studio sidecar address.');
|
|
366
|
+
}
|
|
367
|
+
const url = `http://${host}:${String(address.port)}`;
|
|
336
368
|
const heartbeat = options.heartbeatMs === 0 ? undefined : setInterval(() => {
|
|
337
369
|
publish({
|
|
338
370
|
payload: {
|
|
@@ -346,31 +378,19 @@ export async function startStudioSidecar(options = {}) {
|
|
|
346
378
|
});
|
|
347
379
|
}, options.heartbeatMs ?? DEFAULT_HEARTBEAT_MS);
|
|
348
380
|
heartbeat?.unref();
|
|
349
|
-
await new Promise((resolve, reject) => {
|
|
350
|
-
server.once('error', reject);
|
|
351
|
-
server.listen(options.port ?? 0, host, () => {
|
|
352
|
-
server.off('error', reject);
|
|
353
|
-
resolve();
|
|
354
|
-
});
|
|
355
|
-
});
|
|
356
|
-
const address = server.address();
|
|
357
|
-
if (!address || typeof address === 'string') {
|
|
358
|
-
await closeServer(server, clients, heartbeat);
|
|
359
|
-
throw new Error('Failed to resolve Studio sidecar address.');
|
|
360
|
-
}
|
|
361
|
-
const url = `http://${host}:${String(address.port)}`;
|
|
362
381
|
return {
|
|
363
382
|
appId,
|
|
364
383
|
get epoch() {
|
|
365
384
|
return epoch;
|
|
366
385
|
},
|
|
367
|
-
env
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
386
|
+
get env() {
|
|
387
|
+
return createStudioSidecarEnv({
|
|
388
|
+
appId,
|
|
389
|
+
epoch,
|
|
390
|
+
runtime,
|
|
391
|
+
token,
|
|
392
|
+
url
|
|
393
|
+
});
|
|
374
394
|
},
|
|
375
395
|
host,
|
|
376
396
|
port: address.port,
|
package/dist/types.d.ts
CHANGED
|
@@ -4,9 +4,14 @@ export type { GenerateOptions, GeneratedFile } from './generator-types.js';
|
|
|
4
4
|
export type GeneratorKind = ManifestGeneratorKind;
|
|
5
5
|
/**
|
|
6
6
|
* Minimal registration metadata used by tests and helper utilities that reason about module wiring.
|
|
7
|
+
*
|
|
8
|
+
* @remarks Middleware registrations target the module `middleware` array; controllers and providers
|
|
9
|
+
* target their matching module metadata arrays.
|
|
7
10
|
*/
|
|
8
11
|
export interface ModuleRegistration {
|
|
12
|
+
/** Class name inserted into the target module metadata array. */
|
|
9
13
|
className: string;
|
|
10
|
-
kind
|
|
14
|
+
/** Module metadata kind used by the generated class. */
|
|
15
|
+
kind: 'controller' | 'provider' | 'middleware';
|
|
11
16
|
}
|
|
12
17
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEvF,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE3E,0EAA0E;AAC1E,MAAM,MAAM,aAAa,GAAG,qBAAqB,CAAC;AAElD
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEvF,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE3E,0EAA0E;AAC1E,MAAM,MAAM,aAAa,GAAG,qBAAqB,CAAC;AAElD;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,IAAI,EAAE,YAAY,GAAG,UAAU,GAAG,YAAY,CAAC;CAChD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"AAQA,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;AAcF;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IACE,MAAM,EAAE,UAAU,CAAC;CACpB,GACD;IACE,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEN;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,yDAAyD;AACzD,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAEnE;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,MAAM,EAAE,SAAS,CAAC;CACnB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnE,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,kBAAkB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC1E,cAAc,CAAC,EAAE,CAAC,cAAc,EAAE,oBAAoB,EAAE,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1G,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAieD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAcnG;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,4BAAiC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAmEjI"}
|
package/dist/update-check.js
CHANGED
|
@@ -35,6 +35,20 @@ const UPDATE_PACKAGE_MANAGERS = new Set(['bun', 'npm', 'pnpm', 'yarn']);
|
|
|
35
35
|
function isRecord(value) {
|
|
36
36
|
return typeof value === 'object' && value !== null;
|
|
37
37
|
}
|
|
38
|
+
function isReadableStream(value) {
|
|
39
|
+
if (!value || !isRecord(value)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const candidate = value;
|
|
43
|
+
return typeof candidate.on === 'function' && typeof candidate.pause === 'function' && typeof candidate.resume === 'function';
|
|
44
|
+
}
|
|
45
|
+
function isWritableStream(value) {
|
|
46
|
+
if (!value || !isRecord(value)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const candidate = value;
|
|
50
|
+
return typeof candidate.write === 'function' && typeof candidate.on === 'function' && typeof candidate.once === 'function' && typeof candidate.emit === 'function' && typeof candidate.removeListener === 'function';
|
|
51
|
+
}
|
|
38
52
|
function isTruthyEnvValue(value) {
|
|
39
53
|
if (!value) {
|
|
40
54
|
return false;
|
|
@@ -325,11 +339,11 @@ function resolveInstallCommand(packageName, latestVersion, packageManager) {
|
|
|
325
339
|
display: `npm install -g ${packageSpecifier}`
|
|
326
340
|
};
|
|
327
341
|
}
|
|
328
|
-
async function defaultPromptConfirm(message, defaultValue) {
|
|
342
|
+
async function defaultPromptConfirm(message, defaultValue, io = {}) {
|
|
329
343
|
const promptSuffix = defaultValue ? 'Y/n' : 'y/N';
|
|
330
344
|
const readline = createInterface({
|
|
331
|
-
input: process.stdin,
|
|
332
|
-
output: process.stdout
|
|
345
|
+
input: isReadableStream(io.stdin) ? io.stdin : process.stdin,
|
|
346
|
+
output: isWritableStream(io.stdout) ? io.stdout : process.stdout
|
|
333
347
|
});
|
|
334
348
|
try {
|
|
335
349
|
const answer = (await readline.question(`${message} (${promptSuffix}) `)).trim().toLowerCase();
|
|
@@ -439,7 +453,10 @@ export async function runCliUpdateCheck(argv, options = {}) {
|
|
|
439
453
|
}
|
|
440
454
|
stderr.write(`A newer ${packageName} version is available: ${currentVersion} -> ${latestVersion}.\n`);
|
|
441
455
|
const prompt = options.prompt ?? {
|
|
442
|
-
confirm: defaultPromptConfirm
|
|
456
|
+
confirm: (message, defaultValue) => defaultPromptConfirm(message, defaultValue, {
|
|
457
|
+
stdin: options.stdin,
|
|
458
|
+
stdout
|
|
459
|
+
})
|
|
443
460
|
};
|
|
444
461
|
const shouldInstall = await prompt.confirm(`Install ${packageName}@${latestVersion} now and restart this command?`, false);
|
|
445
462
|
if (!shouldInstall) {
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"migration",
|
|
10
10
|
"diagnostics"
|
|
11
11
|
],
|
|
12
|
-
"version": "1.0
|
|
12
|
+
"version": "1.1.0",
|
|
13
13
|
"private": false,
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"ejs": "^3.1.10",
|
|
45
45
|
"tsx": "^4.20.4",
|
|
46
46
|
"typescript": "^6.0.2",
|
|
47
|
-
"@fluojs/runtime": "^1.1.
|
|
47
|
+
"@fluojs/runtime": "^1.1.8"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@fluojs/studio": "^1.0.
|
|
50
|
+
"@fluojs/studio": "^1.0.7"
|
|
51
51
|
},
|
|
52
52
|
"peerDependenciesMeta": {
|
|
53
53
|
"@fluojs/studio": {
|