proteum 2.1.7 → 2.1.9-1

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/AGENTS.md CHANGED
@@ -26,16 +26,26 @@ After those optimization concerns, preserve explicit, typed, machine-readable co
26
26
 
27
27
  - If the user pastes raw errors without asking for a fix, do not implement changes. List likely causes and, for each one, give probability, why, and how to fix it.
28
28
  - After implementing a framework feature or change, do not stop at code edits. Boot both reference apps, exercise the affected flow with Playwright or the smallest real Proteum surface, run the relevant `proteum` diagnostics or perf commands, and confirm there is no meaningful regression in runtime behavior, performance, load size, SEO output, or coding-style expectations before finishing.
29
- - When you have finished your work, summarize in one top-level short (up to 100 characters) sentence the changes you made since the beginning of the conversation. Output as "Commit message".
29
+ - When starting a long-lived reference app dev server for framework work, prefer `npx proteum dev --session-file <path> --replace-existing --port <port>` so the session can be listed and stopped deterministically later.
30
+ - Before retrying a boot on the same app, changing ports, or finishing the task, stop every framework-started dev session with `npx proteum dev stop --session-file <path>` or `npx proteum dev stop --all --stale`.
31
+ - If the task changed the dev workflow itself, verify the final cleanup path with `npx proteum dev list --json` before finishing.
32
+ - When you have finished your work, summarize in one top-level short (up to 100 characters) sentence the changes you made since the beginning of the conversation. Strictly use the Conventional Commits specification:
33
+ ```
34
+ Commit message: <type>[optional scope]: <description>
35
+
36
+ [optional body]
37
+ ```
30
38
 
31
39
  ## Core Changes
32
40
 
33
41
  - Validate framework changes against the reference apps:
34
- - `/Users/gaetan/Desktop/Projets/crosspath/platform`
35
- - `/Users/gaetan/Desktop/Projets/unique.domains/product`
36
- - `/Users/gaetan/Desktop/Projets/unique.domains/website`
42
+ - `/Users/gaetan/Desktop/Projets/crosspath/platform`: Standalone app
43
+ - `/Users/gaetan/Desktop/Projets/unique.domains/platform`: Monorepo including the following apps:
44
+ - `/Users/gaetan/Desktop/Projets/unique.domains/platform/apps/product`
45
+ - `/Users/gaetan/Desktop/Projets/unique.domains/platform/apps/website`
37
46
  - Inspect how both apps currently use the touched feature, runtime, API, compiler behavior, or generated output before proposing or implementing changes.
38
47
  - Keep the developer-facing contract synchronized when framework work changes CLI commands, profiler capabilities, or the `proteum dev` banner. Update the live surfaces together in the same pass: CLI command/help definitions, profiler panels and dev-only endpoints, banner text/examples, and the most relevant agent docs that describe them, especially `AGENTS.md`, `agents/project/AGENTS.md`, `agents/project/diagnostics.md`, and any narrower `agents/project/**/AGENTS.md` file that mentions the changed workflow.
48
+ - Current CLI banner contract: every human-facing Proteum CLI run prints the welcome banner and includes the active Proteum installation method, while only `proteum dev` clears the interactive terminal before rendering, exposes `CTRL+R` reload plus `CTRL+C` shutdown hotkeys in its session UI, and reports connected app names plus successful connected `/ping` checks in the ready banner.
39
49
  - Keep core changes aligned with the explicit controller/page architecture in `agents/project/AGENTS.md`.
40
50
  - Prefer removing framework magic when the same result can be expressed with explicit contracts, generated code, or typed context.
41
51
  - Apply the pruning rules from `agents/project/optimizations.md`, especially for webpack plugins, Babel plugins, aliases, helpers, runtime services, and npm packages that are not meaningfully used by both apps.
@@ -54,9 +64,10 @@ After those optimization concerns, preserve explicit, typed, machine-readable co
54
64
 
55
65
  Do not stop at static analysis for routing, controllers, generated code, SSR, client runtime, services, webpack, Babel, or emitted assets.
56
66
 
57
- - Run `npx proteum dev --no-cache --port 3xxx` in both reference apps on explicit ports.
67
+ - Run `npx proteum dev --no-cache --replace-existing --session-file var/run/proteum/dev/framework-<app>.json --port 3xxx` in both reference apps on explicit ports.
58
68
  - When validating a concrete route, controller path, or failing page on a running dev server, prefer `proteum diagnose <path> --port <port>` first. Use raw `proteum trace ...` output when you need lower-level event detail beyond the diagnose summary.
59
69
  - When the issue is latency, CPU, SQL cost, render cost, or memory drift, inspect `proteum perf top`, `proteum perf request`, `proteum perf compare`, or `proteum perf memory` against the running dev server before adding custom instrumentation.
70
+ - When a framework change can affect shipped client code size, run `proteum build --prod --analyze` for static bundle artifacts or `proteum build --prod --analyze --analyze-serve --analyze-port auto` when you need a local analyzer URL.
60
71
  - For protected browser or API flows in dev, prefer `npx proteum session <email> --role <role>` to mint a dev auth cookie instead of automating the login UI. Use the login UI only when login itself is the feature under test.
61
72
  - For request-time behavior, arm traces with `proteum trace arm --capture deep`, reproduce once, then inspect `proteum trace latest` or `proteum trace show <requestId>`.
62
73
  - When the framework-facing workflow itself changed, verify the CLI surface too with `proteum verify framework-change --crosspath-port <port> --product-port <port> --website-port <port>`.
package/README.md CHANGED
@@ -323,7 +323,7 @@ Proteum ships with a compact CLI focused on the real app lifecycle:
323
323
  | `proteum typecheck` | Refresh generated typings, then run TypeScript |
324
324
  | `proteum lint` | Run ESLint for the current app |
325
325
  | `proteum check` | Refresh, typecheck, and lint in one command |
326
- | `proteum build --prod` | Produce the production server and client bundles into `bin/` |
326
+ | `proteum build --prod` | Produce the production server and client bundles into `bin/`, with optional static or served bundle analysis |
327
327
  | `proteum connect` | Inspect connected-project sources, env, cached contracts, and imported controllers |
328
328
  | `proteum doctor` | Inspect manifest diagnostics |
329
329
  | `proteum explain` | Explain routes, controllers, services, layouts, conventions, env, and connected projects |
@@ -343,8 +343,12 @@ proteum dev
343
343
  proteum refresh
344
344
  proteum check
345
345
  proteum build --prod
346
+ proteum build --prod --analyze
347
+ proteum build --prod --analyze --analyze-serve --analyze-port auto
346
348
  ```
347
349
 
350
+ Every human-facing Proteum CLI run prints the welcome banner and includes the active Proteum installation method. `proteum dev` is the only command that clears the interactive terminal before rendering its live session UI, exposes `CTRL+R` reload plus `CTRL+C` shutdown hotkeys, and prints connected app names plus successful connected `/ping` checks in the server-ready banner.
351
+
348
352
  Useful inspection commands:
349
353
 
350
354
  ```bash
@@ -16,10 +16,19 @@ Coding style source of truth: project-root `CODING_STYLE.md`.
16
16
  - Follow project-root `diagnostics.md` for diagnosis, runtime reproduction, temporary instrumentation, error-solving workflow, and verification method selection.
17
17
  - For new app or artifact boilerplate, prefer `npx proteum init ...` and `npx proteum create ...` before creating files by hand. Use `--dry-run --json` when an agent needs a machine-readable plan before writing files.
18
18
  - After running `npx proteum create ...`, adapt the generated code to the real feature instead of leaving placeholder logic in place.
19
+ - When starting a long-lived dev server for an agent task, prefer `npx proteum dev --session-file <path> --replace-existing --port <port>` so the session can be listed and stopped deterministically later.
20
+ - Do not start a second `proteum dev` server for the same app and port until the earlier tracked session has been stopped or replaced.
19
21
  - When framework work changes Proteum CLI commands, profiler panels/features, or the `proteum dev` banners, keep this file, project-root `diagnostics.md`, and any narrower area `AGENTS.md` that mentions the same workflow aligned with the live framework behavior in the same pass.
22
+ - Current CLI banner contract: every human-facing Proteum CLI run prints the welcome banner and includes the active Proteum installation method, while only `proteum dev` clears the interactive terminal before rendering, exposes `CTRL+R` reload plus `CTRL+C` shutdown hotkeys in its session UI, and reports connected app names plus successful connected `/ping` checks in the ready banner.
20
23
  - Before finishing, double-check the touched files and generated output against the applicable optimization, diagnostics, and coding-style sources: project-root `optimizations.md`, project-root `diagnostics.md`, project-root `CODING_STYLE.md`, and any narrower area `AGENTS.md`.
21
24
  - After implementing any feature or behavior change, always verify it on a running app before finishing: start the server, exercise the affected flow with Playwright or the smallest real runtime or `npx proteum` surface, run the relevant diagnostics or perf commands, and confirm there is no meaningful regression in behavior, performance, bundle/load size, SEO output, or coding style.
22
- - When you have finished your work, summarize in one top-level short (up to 100 characters) sentence ALL the changes you made since the beginning of the WHOLE conversation. Output as "Commit message".
25
+ - Before finishing a task, stop every `proteum dev` session started during the task and confirm cleanup with `npx proteum dev list --json` or an explicit `npx proteum dev stop --session-file <path>`.
26
+ - When you have finished your work, summarize in one top-level short (up to 100 characters) sentence the changes you made since the beginning of the conversation. Strictly use the Conventional Commits specification:
27
+ ```
28
+ Commit message: <type>[optional scope]: <description>
29
+
30
+ [optional body]
31
+ ```
23
32
 
24
33
  ## Project Shape
25
34
 
@@ -98,6 +107,8 @@ Prefer structured CLI surfaces over re-deriving framework facts from source:
98
107
  - `npx proteum command ...`
99
108
  - `npx proteum session ...`
100
109
  - `npx proteum create ... --dry-run --json`
110
+ - `npx proteum dev list --json`
111
+ - `npx proteum dev stop --session-file <path>`
101
112
 
102
113
  Prefer scaffold commands before hand-writing boilerplate:
103
114
 
@@ -224,7 +235,7 @@ Verify at the correct layer:
224
235
  - router or plugin changes: verify request context, auth, redirects, metrics, and validation on a running app
225
236
  - For trace-first reproduction, session-based auth setup, temporary logs, and post-fix surface checks, follow project-root `diagnostics.md`.
226
237
 
227
- Useful commands: `npx proteum init <dir> --name <name>`, `npx proteum create <kind> <target>`, `proteum dev`, `npx proteum refresh`, `npx proteum typecheck`, `npx proteum lint`, `npx proteum check`, `npx proteum build prod`, `npx proteum perf top`, `npx proteum perf request <requestId|path>`, `npx proteum perf compare --baseline yesterday --target today`, `npx proteum command <path>`, `npx proteum session <email> --role <role>`.
238
+ Useful commands: `npx proteum init <dir> --name <name>`, `npx proteum create <kind> <target>`, `proteum dev`, `proteum dev list --json`, `proteum dev stop --session-file <path>`, `npx proteum refresh`, `npx proteum typecheck`, `npx proteum lint`, `npx proteum check`, `npx proteum build prod`, `npx proteum build --prod --analyze`, `npx proteum build --prod --analyze --analyze-serve --analyze-port auto`, `npx proteum perf top`, `npx proteum perf request <requestId|path>`, `npx proteum perf compare --baseline yesterday --target today`, `npx proteum command <path>`, `npx proteum session <email> --role <role>`.
228
239
 
229
240
  ## High-Impact Files
230
241
 
@@ -12,10 +12,13 @@ This file is the canonical source of truth for diagnostics, temporary instrument
12
12
 
13
13
  ## Runtime Diagnostics
14
14
 
15
+ - For long-lived dev reproductions, start the app with `npx proteum dev --session-file <path> --replace-existing --port <port>` so the session can be listed and stopped deterministically after the repro.
16
+ - Human-facing Proteum CLI runs now print the welcome banner and include the active Proteum installation method, but only `npx proteum dev` clears the interactive terminal before rendering and reports connected app names plus successful connected `/ping` checks in the ready banner; keep that in mind when capturing or comparing command logs during diagnosis.
15
17
  - For request-time issues in dev, start with `npx proteum diagnose <path> --port <port>` when you have a concrete failing route, page, controller path, or request target. It combines owner lookup, manifest diagnostics, contract diagnostics, matching trace data, and buffered server logs in one pass.
16
18
  - For connected-project failures, confirm the consumer app resolves the expected `connect.<Namespace>.source` and `connect.<Namespace>.urlInternal` values, the producer app exposes `GET /api/__proteum/connected/ping`, and the imported controller entries show `scope=connected` in `proteum explain`.
17
19
  - Use `npx proteum explain owner <query>` when you need a fast ownership graph for a route, controller path, source file, or generated artifact before reading code.
18
20
  - For performance issues or regressions in dev, use `npx proteum perf top --since <window>` to rank hot paths, `npx proteum perf request <requestId|path>` for one request waterfall, `npx proteum perf compare --baseline <window> --target <window>` for regressions, and `npx proteum perf memory --since <window>` for heap or RSS drift.
21
+ - For bundle-size inspection, use `npx proteum build --prod --analyze` to emit `bin/bundle-analysis/client.html` and `client-stats.json`, or add `--analyze-serve --analyze-port auto` when you want a local analyzer URL instead of a static HTML file.
19
22
  - For request-time issues in dev, inspect traces before adding logs when the diagnose surface is still too coarse.
20
23
  - If a server is already running on the default port from `PORT` or `./.proteum/manifest.json`, inspect existing traces before reproducing the issue.
21
24
  - If existing traces are insufficient, arm `npx proteum trace arm --capture deep`, reproduce once, then inspect the new request with `npx proteum trace latest` or `npx proteum trace show <requestId>`.
@@ -47,6 +50,7 @@ This file is the canonical source of truth for diagnostics, temporary instrument
47
50
  - For browser regressions, prefer targeted Playwright coverage and inspect failure artifacts such as screenshots, videos, `error-context.md`, and Playwright traces.
48
51
  - Treat server startup failures, runtime errors, browser console errors or warnings, and Playwright failures as blocking unless they are clearly unrelated to the change.
49
52
  - When the touched surface can affect coding-style enforcement, run the smallest relevant project check such as `npx proteum lint` or `npx proteum check` before finishing.
53
+ - If the task started any long-lived `proteum dev` server, stop it explicitly with `npx proteum dev stop --session-file <path>` or `npx proteum dev stop --all --stale`, then confirm the remaining tracked sessions with `npx proteum dev list --json`.
50
54
  - Add `data-testid` when stable selectors are missing instead of relying on brittle text or DOM-shape selectors.
51
55
  - If an isolated test misses prerequisite state, run the smallest broader scope that reproduces the real setup.
52
56
  - After a fix, re-check traces, rendered HTML, browser console, and server output when those surfaces were part of the original failure.
@@ -13,6 +13,7 @@ When tradeoffs exist inside optimization work, optimize in this order:
13
13
  ## Bundle Size And Runtime Cost
14
14
 
15
15
  - Reduce shipped client bundle size and unnecessary runtime code.
16
+ - When you need evidence for a bundle-size regression, run `npx proteum build --prod --analyze` for static artifacts or `npx proteum build --prod --analyze --analyze-serve --analyze-port auto` for a local analyzer URL.
16
17
  - Before inventing a new helper, runtime, plugin, abstraction, primitive, parser, formatter, SDK wrapper, or build-time tool, first check whether the repo already depends on a suitable package.
17
18
  - If the repo does not already depend on one, search npm before writing a custom implementation.
18
19
  - Prefer established, flexible, well-typed, widely adopted, actively maintained packages.
package/cli/app/index.ts CHANGED
@@ -38,20 +38,34 @@ const normalizeModulePath = (value: string) => value.replace(/\\/g, '/').replace
38
38
 
39
39
  const resolveTranspileModuleDirectories = ({
40
40
  moduleNames,
41
- searchRoots,
41
+ resolvePackageRoot,
42
+ getVisiblePackageInstallRoots,
42
43
  }: {
43
44
  moduleNames: string[];
44
- searchRoots: string[];
45
+ resolvePackageRoot: (moduleName: string) => string;
46
+ getVisiblePackageInstallRoots: (moduleName: string) => string[];
45
47
  }) => {
46
48
  const directories = new Set<string>();
47
49
 
48
50
  for (const moduleName of moduleNames) {
49
- for (const searchRoot of searchRoots) {
50
- const candidate = normalizeModulePath(path.join(searchRoot, 'node_modules', moduleName));
51
+ const candidates = new Set<string>();
52
+
53
+ try {
54
+ candidates.add(normalizeModulePath(resolvePackageRoot(moduleName)));
55
+ } catch {}
56
+
57
+ for (const visibleInstallRoot of getVisiblePackageInstallRoots(moduleName)) {
58
+ candidates.add(normalizeModulePath(visibleInstallRoot));
59
+ }
60
+
61
+ for (const candidate of candidates) {
51
62
  if (!fs.existsSync(candidate)) continue;
52
63
 
53
64
  directories.add(candidate);
54
- directories.add(normalizeModulePath(fs.realpathSync(candidate)));
65
+
66
+ try {
67
+ directories.add(normalizeModulePath(fs.realpathSync(candidate)));
68
+ } catch {}
55
69
  }
56
70
  }
57
71
 
@@ -136,15 +150,25 @@ export class App {
136
150
  public get transpileModuleDirectories() {
137
151
  return resolveTranspileModuleDirectories({
138
152
  moduleNames: this.transpile,
139
- searchRoots: [this.paths.root, cli.paths.core.root],
153
+ resolvePackageRoot: (moduleName) => cli.paths.resolvePackageRoot(moduleName),
154
+ getVisiblePackageInstallRoots: (moduleName) => cli.paths.getVisiblePackageInstallRoots(moduleName),
140
155
  });
141
156
  }
142
157
 
143
158
  public isTranspileModuleFile(filepath: string) {
144
159
  const normalizedFilepath = normalizeModulePath(path.resolve(filepath));
160
+ let normalizedRealFilepath: string | undefined;
161
+
162
+ try {
163
+ normalizedRealFilepath = normalizeModulePath(fs.realpathSync(filepath));
164
+ } catch {}
145
165
 
146
166
  return this.transpileModuleDirectories.some(
147
- (directory) => normalizedFilepath === directory || normalizedFilepath.startsWith(directory + '/'),
167
+ (directory) =>
168
+ normalizedFilepath === directory ||
169
+ normalizedFilepath.startsWith(directory + '/') ||
170
+ normalizedRealFilepath === directory ||
171
+ normalizedRealFilepath?.startsWith(directory + '/') === true,
148
172
  );
149
173
  }
150
174
 
@@ -161,12 +185,12 @@ export class App {
161
185
  public aliases = {
162
186
  client: new TsAlias({
163
187
  rootDir: this.paths.root + '/client',
164
- modulesDir: [cli.paths.appRoot + '/node_modules', cli.paths.coreRoot + '/node_modules'],
188
+ modulesDir: [cli.paths.framework.appNodeModulesRoot, cli.paths.framework.frameworkNodeModulesRoot],
165
189
  debug: false,
166
190
  }),
167
191
  server: new TsAlias({
168
192
  rootDir: this.paths.root + '/server',
169
- modulesDir: [cli.paths.appRoot + '/node_modules', cli.paths.coreRoot + '/node_modules'],
193
+ modulesDir: [cli.paths.framework.appNodeModulesRoot, cli.paths.framework.frameworkNodeModulesRoot],
170
194
  debug: false,
171
195
  }),
172
196
  };
package/cli/bin.js CHANGED
@@ -2,12 +2,6 @@
2
2
 
3
3
  const path = require('path');
4
4
 
5
- const clearInteractiveConsole = () => {
6
- if (process.stdout.isTTY !== true || process.env.TERM === 'dumb') return;
7
-
8
- process.stdout.write('\x1B[2J\x1B[3J\x1B[H');
9
- };
10
-
11
5
  /*
12
6
  Why this exists (npm i vs npm link difference)
13
7
 
@@ -36,8 +30,6 @@ if (!process.env.TS_NODE_IGNORE) {
36
30
  process.env.TS_NODE_PROJECT = path.join(__dirname, 'tsconfig.json');
37
31
  process.env.TS_NODE_TRANSPILE_ONLY = '1';
38
32
 
39
- clearInteractiveConsole();
40
-
41
33
  require('ts-node/register/transpile-only');
42
34
 
43
35
  const { runCli } = require('./index.ts');
@@ -2,6 +2,8 @@
2
2
  - DEPENDANCES
3
3
  ----------------------------------*/
4
4
 
5
+ import { UsageError } from 'clipanion';
6
+
5
7
  // Core
6
8
  import cli from '..';
7
9
  import { app } from '../app';
@@ -10,15 +12,23 @@ import { app } from '../app';
10
12
  import Compiler from '../compiler';
11
13
  import type { TCompileMode } from '../compiler/common';
12
14
  import {
15
+ consumeClientBundleAnalysisServerUrl,
16
+ getBundleAnalysisMode,
17
+ getBundleAnalysisServerHost,
18
+ getBundleAnalysisServerPort,
13
19
  getClientBundleAnalysisReportPaths,
20
+ hasBundleAnalysisServerOverrides,
14
21
  waitForClientBundleAnalysisArtifacts,
15
22
  } from '../compiler/common/bundleAnalysis';
16
23
  import { refreshGeneratedTypings, runAppTypecheck } from '../utils/check';
17
24
  import { renderRows } from '../presentation/layout';
18
25
  import { renderStep, renderSuccess, renderTitle } from '../presentation/ink';
19
26
 
20
- const allowedBuildArgs = new Set(['prod', 'cache', 'analyze', 'strict']);
27
+ const allowedBuildArgs = new Set(['prod', 'cache', 'analyze', 'analyzeServe', 'strict']);
21
28
  type TBuildMultiCompiler = Awaited<ReturnType<Compiler['create']>>;
29
+ type TBuildAnalysisResult =
30
+ | { mode: 'static'; reportPath: string; statsPath: string }
31
+ | { mode: 'server'; statsPath: string; url?: string };
22
32
 
23
33
  /*----------------------------------
24
34
  - COMMAND
@@ -30,7 +40,9 @@ function resolveBuildMode(): TCompileMode {
30
40
 
31
41
  const invalidArgs = enabledArgs.filter((arg) => !allowedBuildArgs.has(arg));
32
42
  if (invalidArgs.length > 0)
33
- throw new Error(`Unknown build argument(s): ${invalidArgs.join(', ')}. Allowed values: prod, cache, analyze, strict.`);
43
+ throw new Error(
44
+ `Unknown build argument(s): ${invalidArgs.join(', ')}. Allowed values: prod, cache, analyze, analyzeServe, strict.`,
45
+ );
34
46
 
35
47
  const requestedModes = enabledArgs.filter((arg): arg is TCompileMode => arg === 'prod');
36
48
  if (requestedModes.length > 1)
@@ -39,6 +51,19 @@ function resolveBuildMode(): TCompileMode {
39
51
  return requestedModes[0] ?? 'prod';
40
52
  }
41
53
 
54
+ function assertValidBuildAnalyzerArgs() {
55
+ const analyzeEnabled = cli.args.analyze === true;
56
+ const analyzeServeEnabled = cli.args.analyzeServe === true;
57
+
58
+ if (!analyzeEnabled && (analyzeServeEnabled || hasBundleAnalysisServerOverrides())) {
59
+ throw new UsageError('Analyzer server flags require `--analyze`.');
60
+ }
61
+
62
+ if (!analyzeServeEnabled && hasBundleAnalysisServerOverrides()) {
63
+ throw new UsageError('`--analyze-host` and `--analyze-port` require `--analyze-serve`.');
64
+ }
65
+ }
66
+
42
67
  const closeMultiCompiler = async (multiCompiler: TBuildMultiCompiler) =>
43
68
  await new Promise<void>((resolve, reject) => {
44
69
  multiCompiler.close((error) => {
@@ -54,7 +79,11 @@ const closeMultiCompiler = async (multiCompiler: TBuildMultiCompiler) =>
54
79
  export const run = async (): Promise<void> => {
55
80
  const mode = resolveBuildMode();
56
81
  const strict = cli.args.strict === true;
57
- let analysisArtifacts: { reportPath: string; statsPath: string } | undefined;
82
+ assertValidBuildAnalyzerArgs();
83
+
84
+ const analyze = cli.args.analyze === true;
85
+ const analysisMode = analyze ? getBundleAnalysisMode() : undefined;
86
+ let analysisResult: TBuildAnalysisResult | undefined;
58
87
 
59
88
  console.info(
60
89
  [
@@ -69,7 +98,14 @@ export const run = async (): Promise<void> => {
69
98
  { label: 'mode', value: mode },
70
99
  { label: 'strict', value: strict ? 'enabled' : 'disabled' },
71
100
  { label: 'cache', value: cli.args.cache === true ? 'enabled' : 'disabled' },
72
- { label: 'analyze', value: cli.args.analyze === true ? 'enabled' : 'disabled' },
101
+ { label: 'analyze', value: analyze ? 'enabled' : 'disabled' },
102
+ ...(analyze ? [{ label: 'analyze mode', value: analysisMode || 'static' }] : []),
103
+ ...(analysisMode === 'server'
104
+ ? [
105
+ { label: 'analyze host', value: getBundleAnalysisServerHost() },
106
+ { label: 'analyze port', value: String(getBundleAnalysisServerPort()) },
107
+ ]
108
+ : []),
73
109
  { label: 'output', value: 'bin/' },
74
110
  ]),
75
111
  ].join('\n\n'),
@@ -103,10 +139,11 @@ export const run = async (): Promise<void> => {
103
139
  return;
104
140
  }
105
141
 
106
- if (cli.args.analyze === true) {
142
+ if (analysisMode === 'static') {
107
143
  waitForClientBundleAnalysisArtifacts(app, 'bin')
108
144
  .then(() => {
109
- analysisArtifacts = getClientBundleAnalysisReportPaths(app, 'bin');
145
+ const { reportPath, statsPath } = getClientBundleAnalysisReportPaths(app, 'bin');
146
+ analysisResult = { mode: 'static', reportPath, statsPath };
110
147
  resolve();
111
148
  })
112
149
  .catch(reject);
@@ -125,11 +162,25 @@ export const run = async (): Promise<void> => {
125
162
 
126
163
  if (buildError) throw buildError;
127
164
 
128
- if (analysisArtifacts !== undefined) {
165
+ if (analysisMode === 'server') {
166
+ const { statsPath } = getClientBundleAnalysisReportPaths(app, 'bin');
167
+ analysisResult = {
168
+ mode: 'server',
169
+ statsPath,
170
+ url: consumeClientBundleAnalysisServerUrl(),
171
+ };
172
+ }
173
+
174
+ if (analysisResult !== undefined) {
129
175
  console.info(
130
176
  renderRows([
131
- { label: 'report', value: analysisArtifacts.reportPath },
132
- { label: 'stats', value: analysisArtifacts.statsPath },
177
+ ...(analysisResult.mode === 'static' ? [{ label: 'report', value: analysisResult.reportPath }] : []),
178
+ ...(analysisResult.mode === 'server'
179
+ ? [
180
+ { label: 'server', value: analysisResult.url || 'Analyzer server started. See the analyzer log for the URL.' },
181
+ ]
182
+ : []),
183
+ { label: 'stats', value: analysisResult.statsPath },
133
184
  ]),
134
185
  );
135
186
  }