@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
@@ -0,0 +1,163 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ const DEFAULT_PACKAGE_NAME = '@fluojs/cli';
6
+ const DEFAULT_REGISTRY_TIMEOUT_MS = 5_000;
7
+ const EMPTY_ENV = {};
8
+ function isRecord(value) {
9
+ return typeof value === 'object' && value !== null;
10
+ }
11
+ function readJsonFile(filePath) {
12
+ try {
13
+ const parsed = JSON.parse(readFileSync(filePath, 'utf8'));
14
+ return isRecord(parsed) ? parsed : undefined;
15
+ } catch (_error) {
16
+ return undefined;
17
+ }
18
+ }
19
+ function readCliVersion() {
20
+ const packageJsonPath = fileURLToPath(new URL('../../package.json', import.meta.url));
21
+ const manifest = readJsonFile(packageJsonPath);
22
+ return typeof manifest?.version === 'string' ? manifest.version : 'unknown';
23
+ }
24
+ function resolveCacheFile(env) {
25
+ const cacheRoot = env.XDG_CACHE_HOME ?? join(homedir(), '.cache');
26
+ return join(cacheRoot, 'fluo', 'cli-update-check.json');
27
+ }
28
+ function readUpdateCache(env) {
29
+ const cacheFile = resolveCacheFile(env);
30
+ const cache = readJsonFile(cacheFile);
31
+ const checkedAt = typeof cache?.checkedAt === 'number' ? cache.checkedAt : undefined;
32
+ return {
33
+ ageMs: checkedAt === undefined ? undefined : Date.now() - checkedAt,
34
+ checkedAt: checkedAt === undefined ? undefined : new Date(checkedAt).toISOString(),
35
+ latestVersion: typeof cache?.latestVersion === 'string' ? cache.latestVersion : undefined,
36
+ path: cacheFile
37
+ };
38
+ }
39
+ function findProjectManifest(startDirectory) {
40
+ let current = resolve(startDirectory);
41
+ while (true) {
42
+ const candidate = join(current, 'package.json');
43
+ if (existsSync(candidate)) {
44
+ return {
45
+ manifest: readJsonFile(candidate),
46
+ path: candidate
47
+ };
48
+ }
49
+ const parent = dirname(current);
50
+ if (parent === current) {
51
+ return {};
52
+ }
53
+ current = parent;
54
+ }
55
+ }
56
+ async function fetchNpmDistTags(packageName) {
57
+ const controller = new AbortController();
58
+ const timeout = setTimeout(() => controller.abort(), DEFAULT_REGISTRY_TIMEOUT_MS);
59
+ try {
60
+ const response = await fetch(`https://registry.npmjs.org/-/package/${encodeURIComponent(packageName)}/dist-tags`, {
61
+ headers: {
62
+ accept: 'application/json'
63
+ },
64
+ signal: controller.signal
65
+ });
66
+ if (!response.ok) {
67
+ return undefined;
68
+ }
69
+ const payload = await response.json();
70
+ if (!isRecord(payload)) {
71
+ return undefined;
72
+ }
73
+ const distTags = {};
74
+ for (const [key, value] of Object.entries(payload)) {
75
+ if (typeof value === 'string') {
76
+ distTags[key] = value;
77
+ }
78
+ }
79
+ return distTags;
80
+ } catch (_error) {
81
+ return undefined;
82
+ } finally {
83
+ clearTimeout(timeout);
84
+ }
85
+ }
86
+ function formatAge(ageMs) {
87
+ if (ageMs === undefined) {
88
+ return 'unknown';
89
+ }
90
+ const minutes = Math.floor(ageMs / 60_000);
91
+ if (minutes < 60) {
92
+ return `${minutes}m`;
93
+ }
94
+ return `${Math.floor(minutes / 60)}h ${minutes % 60}m`;
95
+ }
96
+ function listScripts(manifest) {
97
+ const scripts = manifest?.scripts;
98
+ if (!isRecord(scripts)) {
99
+ return [];
100
+ }
101
+ return Object.keys(scripts).sort();
102
+ }
103
+ export function diagnosticsUsage(command = 'doctor') {
104
+ if (command === 'analyze') {
105
+ return ['Usage: fluo analyze [options]', '', 'Summarize the current project and point to deeper inspect/report diagnostics.', '', 'Options', ' --help Show help for the analyze command.'].join('\n');
106
+ }
107
+ return [`Usage: fluo ${command} [options]`, '', 'Print CLI, registry, update-cache, runtime, and project diagnostics.', '', 'Options', ` --help Show help for the ${command} command.`].join('\n');
108
+ }
109
+ export async function runDoctorCommand(argv, runtime = {}) {
110
+ if (argv.includes('--help') || argv.includes('-h')) {
111
+ (runtime.stdout ?? process.stdout).write(`${diagnosticsUsage('doctor')}\n`);
112
+ return 0;
113
+ }
114
+ if (argv.length > 0) {
115
+ throw new Error(`Unknown doctor option: ${argv[0]}`);
116
+ }
117
+ const env = runtime.env ?? EMPTY_ENV;
118
+ const stdout = runtime.stdout ?? process.stdout;
119
+ const cwd = resolve(runtime.cwd ?? process.cwd());
120
+ const cache = readUpdateCache(env);
121
+ const distTags = await (runtime.fetchDistTags ?? fetchNpmDistTags)(DEFAULT_PACKAGE_NAME);
122
+ const project = findProjectManifest(cwd);
123
+ const scripts = listScripts(project.manifest);
124
+ stdout.write('fluo doctor\n');
125
+ stdout.write(` CLI version: ${readCliVersion()}\n`);
126
+ stdout.write(` Node.js: ${process.version}\n`);
127
+ stdout.write(` Platform: ${process.platform}/${process.arch}\n`);
128
+ stdout.write(` Package manager signal: ${env.npm_config_user_agent ?? 'unknown'}\n`);
129
+ stdout.write(` npm latest: ${distTags?.latest ?? 'unavailable'}\n`);
130
+ stdout.write(` npm beta: ${distTags?.beta ?? 'unavailable'}\n`);
131
+ stdout.write(` Update cache: ${cache.path}\n`);
132
+ stdout.write(` Cached latest: ${cache.latestVersion ?? 'none'}\n`);
133
+ stdout.write(` Cache checked: ${cache.checkedAt ?? 'never'} (${formatAge(cache.ageMs)} ago)\n`);
134
+ stdout.write(` Project manifest: ${project.path ?? 'not found'}\n`);
135
+ stdout.write(` Project scripts: ${scripts.length > 0 ? scripts.join(', ') : 'none'}\n`);
136
+ return 0;
137
+ }
138
+ export async function runInfoCommand(argv, runtime = {}) {
139
+ if (argv.includes('--help') || argv.includes('-h')) {
140
+ (runtime.stdout ?? process.stdout).write(`${diagnosticsUsage('info')}\n`);
141
+ return 0;
142
+ }
143
+ return runDoctorCommand(argv, runtime);
144
+ }
145
+ export async function runAnalyzeCommand(argv, runtime = {}) {
146
+ if (argv.includes('--help') || argv.includes('-h')) {
147
+ (runtime.stdout ?? process.stdout).write(`${diagnosticsUsage('analyze')}\n`);
148
+ return 0;
149
+ }
150
+ if (argv.length > 0) {
151
+ throw new Error(`Unknown analyze option: ${argv[0]}`);
152
+ }
153
+ const stdout = runtime.stdout ?? process.stdout;
154
+ const cwd = resolve(runtime.cwd ?? process.cwd());
155
+ const project = findProjectManifest(cwd);
156
+ const scripts = listScripts(project.manifest);
157
+ stdout.write('fluo analyze\n');
158
+ stdout.write(` Project manifest: ${project.path ?? 'not found'}\n`);
159
+ stdout.write(` Available scripts: ${scripts.length > 0 ? scripts.join(', ') : 'none'}\n`);
160
+ stdout.write(' Deep inspection: run `fluo inspect <module-path> --report --output <file>` for runtime graph diagnostics.\n');
161
+ stdout.write(' Migration preview: run `fluo migrate <path> --json` for codemod diagnostics.\n');
162
+ return 0;
163
+ }
@@ -264,7 +264,7 @@ export function newUsage() {
264
264
  }, {
265
265
  header: 'Description',
266
266
  render: entry => entry.description
267
- }]), '', 'Next steps:', ' cd <app-name>', ' pnpm dev # or npm run dev / yarn dev / bun run dev', '', 'Docs: https://github.com/fluojs/fluo/tree/main/docs/getting-started/quick-start.md'].join('\n');
267
+ }]), '', 'Next steps:', ' cd <app-name>', ' pnpm dev # runs fluo dev from the generated package.json script', '', 'Docs: https://github.com/fluojs/fluo/tree/main/docs/getting-started/quick-start.md'].join('\n');
268
268
  }
269
269
 
270
270
  /**
@@ -364,7 +364,7 @@ export async function runNewCommand(argv, runtime = {}) {
364
364
  clackLog.step('Dependency installation skipped');
365
365
  }
366
366
  stdout.write('Done.\n');
367
- stdout.write(`Next steps:\n cd ${answers.targetDirectory}\n ${answers.packageManager === 'npm' ? 'npm run dev' : answers.packageManager === 'bun' ? 'bun run dev' : `${answers.packageManager} dev`}\n`);
367
+ stdout.write(`Next steps:\n cd ${answers.targetDirectory}\n ${answers.packageManager === 'npm' ? 'npm run dev' : answers.packageManager === 'bun' ? 'bun run dev' : `${answers.packageManager} dev`} # runs fluo dev\n`);
368
368
  return 0;
369
369
  } catch (error) {
370
370
  if (isCliPromptCancelledError(error)) {
@@ -0,0 +1,9 @@
1
+ type JsonRecord = Record<string, unknown>;
2
+ export declare const SUPPORTED_PACKAGE_MANAGERS: Set<string>;
3
+ export declare function detectPackageManager(options: {
4
+ cwd: string;
5
+ env: NodeJS.ProcessEnv;
6
+ manifest?: JsonRecord;
7
+ }): string;
8
+ export {};
9
+ //# sourceMappingURL=package-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-manager.d.ts","sourceRoot":"","sources":["../../src/commands/package-manager.ts"],"names":[],"mappings":"AAGA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1C,eAAO,MAAM,0BAA0B,aAA0C,CAAC;AA+ClF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,UAAU,CAAA;CAAE,GAAG,MAAM,CA0BpH"}
@@ -0,0 +1,63 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ export const SUPPORTED_PACKAGE_MANAGERS = new Set(['bun', 'npm', 'pnpm', 'yarn']);
4
+ function isRecord(value) {
5
+ return typeof value === 'object' && value !== null;
6
+ }
7
+ function readJsonFile(filePath) {
8
+ try {
9
+ const parsed = JSON.parse(readFileSync(filePath, 'utf8'));
10
+ return isRecord(parsed) ? parsed : undefined;
11
+ } catch (_error) {
12
+ return undefined;
13
+ }
14
+ }
15
+ function packageManagerFromManifest(manifest) {
16
+ const packageManager = manifest.packageManager;
17
+ if (typeof packageManager !== 'string') {
18
+ return undefined;
19
+ }
20
+ const manager = packageManager.split('@')[0];
21
+ return manager && SUPPORTED_PACKAGE_MANAGERS.has(manager) ? manager : undefined;
22
+ }
23
+ function packageManagerFromLockfile(directory) {
24
+ if (existsSync(join(directory, 'pnpm-lock.yaml'))) {
25
+ return 'pnpm';
26
+ }
27
+ if (existsSync(join(directory, 'bun.lockb')) || existsSync(join(directory, 'bun.lock'))) {
28
+ return 'bun';
29
+ }
30
+ if (existsSync(join(directory, 'yarn.lock'))) {
31
+ return 'yarn';
32
+ }
33
+ if (existsSync(join(directory, 'package-lock.json')) || existsSync(join(directory, 'npm-shrinkwrap.json'))) {
34
+ return 'npm';
35
+ }
36
+ return undefined;
37
+ }
38
+ function packageManagerFromUserAgent(env) {
39
+ const userAgentName = env.npm_config_user_agent?.split(' ')[0]?.split('/')[0];
40
+ return userAgentName && SUPPORTED_PACKAGE_MANAGERS.has(userAgentName) ? userAgentName : undefined;
41
+ }
42
+ export function detectPackageManager(options) {
43
+ const startDirectory = resolve(options.cwd);
44
+ let current = startDirectory;
45
+ while (true) {
46
+ const manifestPath = join(current, 'package.json');
47
+ const manifest = current === startDirectory && options.manifest ? options.manifest : existsSync(manifestPath) ? readJsonFile(manifestPath) : undefined;
48
+ const manifestManager = manifest ? packageManagerFromManifest(manifest) : undefined;
49
+ if (manifestManager) {
50
+ return manifestManager;
51
+ }
52
+ const lockfileManager = packageManagerFromLockfile(current);
53
+ if (lockfileManager) {
54
+ return lockfileManager;
55
+ }
56
+ const parent = dirname(current);
57
+ if (parent === current) {
58
+ break;
59
+ }
60
+ current = parent;
61
+ }
62
+ return packageManagerFromUserAgent(options.env) ?? 'pnpm';
63
+ }
@@ -0,0 +1,20 @@
1
+ type CliStream = {
2
+ write(message: string): unknown;
3
+ };
4
+ type PackageWorkflowRuntimeOptions = {
5
+ cwd?: string;
6
+ env?: NodeJS.ProcessEnv;
7
+ fetchDistTags?: (packageName: string) => Promise<Record<string, string> | undefined>;
8
+ spawnCommand?: (command: string, args: string[], options: {
9
+ cwd: string;
10
+ env: NodeJS.ProcessEnv;
11
+ stdio: 'inherit';
12
+ }) => Promise<number>;
13
+ stdout?: CliStream;
14
+ };
15
+ export declare function addUsage(): string;
16
+ export declare function upgradeUsage(): string;
17
+ export declare function runAddCommand(argv: string[], runtime?: PackageWorkflowRuntimeOptions): Promise<number>;
18
+ export declare function runUpgradeCommand(argv: string[], runtime?: PackageWorkflowRuntimeOptions): Promise<number>;
19
+ export {};
20
+ //# sourceMappingURL=package-workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-workflow.d.ts","sourceRoot":"","sources":["../../src/commands/package-workflow.ts"],"names":[],"mappings":"AAGA,KAAK,SAAS,GAAG;IACf,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEF,KAAK,6BAA6B,GAAG;IACnC,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,KAAK,EAAE,SAAS,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACxI,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAgFF,wBAAgB,QAAQ,IAAI,MAAM,CAYjC;AAED,wBAAgB,YAAY,IAAI,MAAM,CASrC;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,6BAAkC,GAAG,OAAO,CAAC,MAAM,CAAC,CAkDhH;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,6BAAkC,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBpH"}
@@ -0,0 +1,137 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { detectPackageManager, SUPPORTED_PACKAGE_MANAGERS } from './package-manager.js';
3
+ const DEFAULT_PACKAGE_NAME = '@fluojs/cli';
4
+ const DEFAULT_REGISTRY_TIMEOUT_MS = 5_000;
5
+ const EMPTY_ENV = {};
6
+ function normalizeFluoPackage(packageName) {
7
+ if (packageName.startsWith('@fluojs/')) {
8
+ return packageName;
9
+ }
10
+ return `@fluojs/${packageName}`;
11
+ }
12
+ function buildAddArgs(packageManager, packages, dev) {
13
+ if (packageManager === 'npm') {
14
+ return ['install', dev ? '--save-dev' : '--save', ...packages];
15
+ }
16
+ if (packageManager === 'yarn') {
17
+ return ['add', ...(dev ? ['--dev'] : []), ...packages];
18
+ }
19
+ return ['add', ...(dev ? ['-D'] : []), ...packages];
20
+ }
21
+ function defaultSpawnCommand(command, args, options) {
22
+ return new Promise((resolveExitCode, reject) => {
23
+ const child = spawn(command, args, options);
24
+ child.on('error', reject);
25
+ child.on('exit', code => resolveExitCode(code ?? 1));
26
+ });
27
+ }
28
+ async function fetchNpmDistTags(packageName) {
29
+ const controller = new AbortController();
30
+ const timeout = setTimeout(() => controller.abort(), DEFAULT_REGISTRY_TIMEOUT_MS);
31
+ try {
32
+ const response = await fetch(`https://registry.npmjs.org/-/package/${encodeURIComponent(packageName)}/dist-tags`, {
33
+ headers: {
34
+ accept: 'application/json'
35
+ },
36
+ signal: controller.signal
37
+ });
38
+ if (!response.ok) {
39
+ return undefined;
40
+ }
41
+ const payload = await response.json();
42
+ if (typeof payload !== 'object' || payload === null) {
43
+ return undefined;
44
+ }
45
+ const distTags = {};
46
+ for (const [key, value] of Object.entries(payload)) {
47
+ if (typeof value === 'string') {
48
+ distTags[key] = value;
49
+ }
50
+ }
51
+ return distTags;
52
+ } catch (_error) {
53
+ return undefined;
54
+ } finally {
55
+ clearTimeout(timeout);
56
+ }
57
+ }
58
+ function parsePackageManager(value) {
59
+ if (!value || value.startsWith('-')) {
60
+ throw new Error('Expected --package-manager to have a value.');
61
+ }
62
+ if (!SUPPORTED_PACKAGE_MANAGERS.has(value)) {
63
+ throw new Error(`Invalid --package-manager value "${value}". Use one of: pnpm, npm, yarn, bun.`);
64
+ }
65
+ return value;
66
+ }
67
+ export function addUsage() {
68
+ return ['Usage: fluo add <package...> [options]', '', 'Install one or more @fluojs packages with the detected package manager.', '', 'Options', ' --dev Install as a development dependency.', ' --package-manager <pnpm|npm|yarn|bun> Override package-manager detection.', ' --dry-run Print the command without running it.', ' --help Show help for the add command.'].join('\n');
69
+ }
70
+ export function upgradeUsage() {
71
+ return ['Usage: fluo upgrade [options]', '', 'Report the latest CLI package state and point to migration workflows.', '', 'Options', ' --help Show help for the upgrade command.'].join('\n');
72
+ }
73
+ export async function runAddCommand(argv, runtime = {}) {
74
+ if (argv.includes('--help') || argv.includes('-h')) {
75
+ (runtime.stdout ?? process.stdout).write(`${addUsage()}\n`);
76
+ return 0;
77
+ }
78
+ let dev = false;
79
+ let dryRun = false;
80
+ let packageManager;
81
+ const packages = [];
82
+ for (let index = 0; index < argv.length; index += 1) {
83
+ const arg = argv[index];
84
+ if (arg === '--dev' || arg === '-D') {
85
+ dev = true;
86
+ continue;
87
+ }
88
+ if (arg === '--dry-run') {
89
+ dryRun = true;
90
+ continue;
91
+ }
92
+ if (arg === '--package-manager') {
93
+ packageManager = parsePackageManager(argv[index + 1]);
94
+ index += 1;
95
+ continue;
96
+ }
97
+ if (arg.startsWith('-')) {
98
+ throw new Error(`Unknown add option: ${arg}`);
99
+ }
100
+ packages.push(normalizeFluoPackage(arg));
101
+ }
102
+ if (packages.length === 0) {
103
+ throw new Error('Expected at least one package for fluo add.');
104
+ }
105
+ const env = runtime.env ?? EMPTY_ENV;
106
+ const manager = packageManager ?? detectPackageManager({
107
+ cwd: runtime.cwd ?? process.cwd(),
108
+ env
109
+ });
110
+ const args = buildAddArgs(manager, packages, dev);
111
+ if (dryRun) {
112
+ (runtime.stdout ?? process.stdout).write(`Would run: ${manager} ${args.join(' ')}\n`);
113
+ return 0;
114
+ }
115
+ return (runtime.spawnCommand ?? defaultSpawnCommand)(manager, args, {
116
+ cwd: runtime.cwd ?? process.cwd(),
117
+ env,
118
+ stdio: 'inherit'
119
+ });
120
+ }
121
+ export async function runUpgradeCommand(argv, runtime = {}) {
122
+ if (argv.includes('--help') || argv.includes('-h')) {
123
+ (runtime.stdout ?? process.stdout).write(`${upgradeUsage()}\n`);
124
+ return 0;
125
+ }
126
+ if (argv.length > 0) {
127
+ throw new Error(`Unknown upgrade option: ${argv[0]}`);
128
+ }
129
+ const distTags = await (runtime.fetchDistTags ?? fetchNpmDistTags)(DEFAULT_PACKAGE_NAME);
130
+ const stdout = runtime.stdout ?? process.stdout;
131
+ stdout.write('fluo upgrade\n');
132
+ stdout.write(` Latest CLI: ${distTags?.latest ?? 'unavailable'}\n`);
133
+ stdout.write(' To update the global CLI, run your package manager global install command for @fluojs/cli@latest.\n');
134
+ stdout.write(' To preview NestJS migration codemods, run `fluo migrate <path> --json`.\n');
135
+ stdout.write(' To inspect generated starter drift, run `fluo doctor`.\n');
136
+ return 0;
137
+ }
@@ -0,0 +1,38 @@
1
+ type CliStream = {
2
+ isTTY?: boolean;
3
+ write(message: string): unknown;
4
+ };
5
+ type SpawnCommandOptions = {
6
+ cwd: string;
7
+ env: NodeJS.ProcessEnv;
8
+ stderr?: CliStream;
9
+ stdio: 'inherit' | 'pipe';
10
+ stdout?: CliStream;
11
+ };
12
+ type ScriptRuntimeOptions = {
13
+ ci?: boolean;
14
+ cwd?: string;
15
+ env?: NodeJS.ProcessEnv;
16
+ spawnCommand?: (command: string, args: string[], options: SpawnCommandOptions) => Promise<number>;
17
+ stderr?: CliStream;
18
+ stdout?: CliStream;
19
+ };
20
+ type ScriptCommand = 'build' | 'dev' | 'start';
21
+ /**
22
+ * Renders lifecycle command help text.
23
+ *
24
+ * @param command Lifecycle command whose help text should be rendered.
25
+ * @returns Human-readable lifecycle command usage text.
26
+ */
27
+ export declare function scriptUsage(command: ScriptCommand): string;
28
+ /**
29
+ * Runs one generated-project lifecycle command through the CLI-owned runtime command matrix.
30
+ *
31
+ * @param command Lifecycle command to run.
32
+ * @param argv Command-specific arguments after the lifecycle command name.
33
+ * @param runtime Runtime dependencies used by tests, sandboxes, and embedders.
34
+ * @returns Process-style exit code from the lifecycle command.
35
+ */
36
+ export declare function runScriptCommand(command: ScriptCommand, argv: string[], runtime?: ScriptRuntimeOptions): Promise<number>;
37
+ export {};
38
+ //# sourceMappingURL=scripts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scripts.d.ts","sourceRoot":"","sources":["../../src/commands/scripts.ts"],"names":[],"mappings":"AAMA,KAAK,SAAS,GAAG;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAKF,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,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAGF,KAAK,aAAa,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;AAkU/C;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAc1D;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CA+DlI"}