@lark-apaas/fullstack-cli 1.1.59-alpha.20260722050835 → 1.1.59-alpha.20260722165429

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/dist/index.js CHANGED
@@ -8261,6 +8261,57 @@ function classTransformerStorageResolver(projectRoot) {
8261
8261
  }
8262
8262
  };
8263
8263
  }
8264
+ function projectUsesNestjsDevtools(projectRoot) {
8265
+ const distRoot = path25.join(projectRoot, "dist");
8266
+ if (!fs29.existsSync(distRoot)) return false;
8267
+ const pending = [distRoot];
8268
+ while (pending.length > 0) {
8269
+ const current = pending.pop();
8270
+ if (!current) continue;
8271
+ for (const entry of fs29.readdirSync(current, { withFileTypes: true })) {
8272
+ const entryPath = path25.join(current, entry.name);
8273
+ if (entry.isDirectory()) {
8274
+ pending.push(entryPath);
8275
+ } else if (entry.isFile() && /\.[cm]?js$/.test(entry.name)) {
8276
+ const source = fs29.readFileSync(entryPath, "utf8");
8277
+ if (source.includes("@lark-apaas/fullstack-nestjs-core") && /\bDevTools(?:V2)?Module\b/.test(source)) {
8278
+ return true;
8279
+ }
8280
+ }
8281
+ }
8282
+ }
8283
+ return false;
8284
+ }
8285
+ function previewNestjsRuntimeEntryPlugin(projectRoot) {
8286
+ const projectRequire = createRequire3(path25.join(projectRoot, "package.json"));
8287
+ let runtimeEntry;
8288
+ if (!projectUsesNestjsDevtools(projectRoot)) {
8289
+ try {
8290
+ runtimeEntry = projectRequire.resolve(
8291
+ "@lark-apaas/fullstack-nestjs-core/runtime"
8292
+ );
8293
+ } catch {
8294
+ runtimeEntry = void 0;
8295
+ }
8296
+ }
8297
+ let runtimeEntryUsed = false;
8298
+ return {
8299
+ used: () => runtimeEntryUsed,
8300
+ plugin: {
8301
+ name: "preview-nestjs-runtime-entry",
8302
+ setup(esbuild) {
8303
+ esbuild.onResolve(
8304
+ { filter: /^@lark-apaas\/fullstack-nestjs-core$/ },
8305
+ () => {
8306
+ if (!runtimeEntry) return void 0;
8307
+ runtimeEntryUsed = true;
8308
+ return { path: runtimeEntry };
8309
+ }
8310
+ );
8311
+ }
8312
+ }
8313
+ };
8314
+ }
8264
8315
  function optionalDependencyStubPlugin() {
8265
8316
  const stubbedDependencies = /* @__PURE__ */ new Set();
8266
8317
  const escapedNames = OPTIONAL_DEPENDENCY_STUBS.map(
@@ -8523,6 +8574,7 @@ async function buildPreviewServerArtifact(options) {
8523
8574
  );
8524
8575
  fs29.writeFileSync(bootstrapPath, generateBootstrap(entryPath, plugins));
8525
8576
  const optionalDependencies = optionalDependencyStubPlugin();
8577
+ const nestjsRuntimeEntry = previewNestjsRuntimeEntryPlugin(projectRoot);
8526
8578
  const buildOptions = {
8527
8579
  absWorkingDir: projectRoot,
8528
8580
  entryPoints: [bootstrapPath],
@@ -8538,6 +8590,7 @@ async function buildPreviewServerArtifact(options) {
8538
8590
  metafile: true,
8539
8591
  logLevel: "silent",
8540
8592
  plugins: [
8593
+ nestjsRuntimeEntry.plugin,
8541
8594
  classTransformerStorageResolver(projectRoot),
8542
8595
  optionalDependencies.plugin
8543
8596
  ]
@@ -8574,6 +8627,7 @@ async function buildPreviewServerArtifact(options) {
8574
8627
  closureStatus,
8575
8628
  closureRisks,
8576
8629
  stubbedOptionalDependencies,
8630
+ nestjsRuntimeEntryUsed: nestjsRuntimeEntry.used(),
8577
8631
  runtimeProbeStatus: "not-run",
8578
8632
  consumable: false,
8579
8633
  elapsedMs: Date.now() - startedAt
@@ -8623,7 +8677,7 @@ async function buildPreviewServerArtifact(options) {
8623
8677
  }
8624
8678
 
8625
8679
  // src/commands/preview-artifact/producer.ts
8626
- import * as crypto2 from "crypto";
8680
+ import * as crypto3 from "crypto";
8627
8681
  import * as fs34 from "fs";
8628
8682
  import * as path30 from "path";
8629
8683
  import { spawnSync as spawnSync8 } from "child_process";
@@ -8929,6 +8983,10 @@ function rejectSymlinks(root) {
8929
8983
  }
8930
8984
  }
8931
8985
  }
8986
+ function inspectClientArchive(archivePath) {
8987
+ archiveEntries(archivePath);
8988
+ rejectArchivedSymlinks(archivePath);
8989
+ }
8932
8990
  function isPathInside(parent, candidate) {
8933
8991
  const relative5 = path27.relative(parent, candidate);
8934
8992
  return relative5 !== "" && relative5 !== ".." && !relative5.startsWith(`..${path27.sep}`) && !path27.isAbsolute(relative5);
@@ -9004,8 +9062,7 @@ function extractClientArchive(archivePath, destination) {
9004
9062
  if (fs31.existsSync(destination)) {
9005
9063
  throw new Error("client archive destination must not already exist");
9006
9064
  }
9007
- archiveEntries(archivePath);
9008
- rejectArchivedSymlinks(archivePath);
9065
+ inspectClientArchive(archivePath);
9009
9066
  fs31.mkdirSync(destination, { recursive: true });
9010
9067
  try {
9011
9068
  const extraction = spawnSync7(
@@ -9024,6 +9081,40 @@ function extractClientArchive(archivePath, destination) {
9024
9081
  throw error;
9025
9082
  }
9026
9083
  }
9084
+ async function extractInspectedClientArchive(archivePath, destination) {
9085
+ if (fs31.existsSync(destination)) {
9086
+ throw new Error("client archive destination must not already exist");
9087
+ }
9088
+ fs31.mkdirSync(destination, { recursive: true });
9089
+ try {
9090
+ await new Promise((resolve9, reject) => {
9091
+ const extraction = spawn2(
9092
+ "unzip",
9093
+ ["-q", archivePath, "-d", destination],
9094
+ { stdio: ["ignore", "ignore", "pipe"] }
9095
+ );
9096
+ let stderr = "";
9097
+ extraction.stderr?.setEncoding("utf8");
9098
+ extraction.stderr?.on("data", (chunk) => {
9099
+ stderr = `${stderr}${String(chunk)}`.slice(-8 * 1024);
9100
+ });
9101
+ extraction.once("error", reject);
9102
+ extraction.once("close", (code) => {
9103
+ if (code === 0) resolve9();
9104
+ else
9105
+ reject(
9106
+ new Error(
9107
+ `client archive extraction failed: ${stderr.trim() || `exit ${code ?? "unknown"}`}`
9108
+ )
9109
+ );
9110
+ });
9111
+ });
9112
+ rejectSymlinks(destination);
9113
+ } catch (error) {
9114
+ fs31.rmSync(destination, { recursive: true, force: true });
9115
+ throw error;
9116
+ }
9117
+ }
9027
9118
  async function fetchUntil(url, timeoutAt) {
9028
9119
  while (Date.now() < timeoutAt) {
9029
9120
  try {
@@ -9200,6 +9291,7 @@ function previewArtifactRuntimeEnvironment(environment) {
9200
9291
  }
9201
9292
 
9202
9293
  // src/commands/preview-artifact/store.ts
9294
+ import * as crypto2 from "crypto";
9203
9295
  import * as fs33 from "fs";
9204
9296
  import * as path29 from "path";
9205
9297
  var GENERATION_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
@@ -9261,7 +9353,7 @@ function validateRegularDirectory(directoryPath, label) {
9261
9353
  ];
9262
9354
  }
9263
9355
  }
9264
- function validateGeneration(generationDir, runtime) {
9356
+ function validateGeneration(generationDir, runtime, verifyPayloads = true) {
9265
9357
  const reasons = validateRegularDirectory(
9266
9358
  generationDir,
9267
9359
  "generation directory"
@@ -9301,19 +9393,29 @@ function validateGeneration(generationDir, runtime) {
9301
9393
  if (!/^[a-f0-9]{64}$/.test(manifest.buildEnvironmentSha256)) {
9302
9394
  reasons.push("build environment identity is invalid");
9303
9395
  }
9304
- const serverPath = path29.join(generationDir, "server.bundle.cjs");
9305
- const clientPath = path29.join(generationDir, "client.zip");
9306
- try {
9307
- if (sha256File(serverPath) !== manifest.files.server.sha256) {
9308
- reasons.push("server.bundle.cjs hash does not match manifest");
9396
+ for (const [label, identity, expectedPath] of [
9397
+ ["server", manifest.files?.server, "server.bundle.cjs"],
9398
+ ["client", manifest.files?.client, "client.zip"]
9399
+ ]) {
9400
+ if (!identity || identity.path !== expectedPath || !Number.isSafeInteger(identity.bytes) || identity.bytes < 0 || !/^[a-f0-9]{64}$/.test(identity.sha256)) {
9401
+ reasons.push(`${label} file identity is invalid`);
9309
9402
  }
9310
- if (sha256File(clientPath) !== manifest.files.client.sha256) {
9311
- reasons.push("client.zip hash does not match manifest");
9403
+ }
9404
+ if (verifyPayloads && manifest.files?.server && manifest.files?.client) {
9405
+ const serverPath = path29.join(generationDir, "server.bundle.cjs");
9406
+ const clientPath = path29.join(generationDir, "client.zip");
9407
+ try {
9408
+ if (sha256File(serverPath) !== manifest.files.server.sha256) {
9409
+ reasons.push("server.bundle.cjs hash does not match manifest");
9410
+ }
9411
+ if (sha256File(clientPath) !== manifest.files.client.sha256) {
9412
+ reasons.push("client.zip hash does not match manifest");
9413
+ }
9414
+ } catch (error) {
9415
+ reasons.push(
9416
+ `generation files are unavailable: ${error instanceof Error ? error.message : String(error)}`
9417
+ );
9312
9418
  }
9313
- } catch (error) {
9314
- reasons.push(
9315
- `generation files are unavailable: ${error instanceof Error ? error.message : String(error)}`
9316
- );
9317
9419
  }
9318
9420
  if (probe.serverSha256 !== manifest.files.server.sha256 || probe.clientSha256 !== manifest.files.client.sha256) {
9319
9421
  reasons.push("probe file identity does not match manifest");
@@ -9374,7 +9476,7 @@ function publishPreviewArtifactGeneration(options) {
9374
9476
  };
9375
9477
  }
9376
9478
  }
9377
- function resolveCurrentPreviewArtifact(options) {
9479
+ function resolveCurrentPreviewArtifactMetadata(options) {
9378
9480
  const storeRoot = path29.resolve(options.storeRoot);
9379
9481
  let pointer;
9380
9482
  try {
@@ -9402,11 +9504,15 @@ function resolveCurrentPreviewArtifact(options) {
9402
9504
  "generations",
9403
9505
  pointer.generationId
9404
9506
  );
9405
- const validation = validateGeneration(generationDir, {
9406
- nodeMajor,
9407
- platform: options.platform,
9408
- arch: options.arch
9409
- });
9507
+ const validation = validateGeneration(
9508
+ generationDir,
9509
+ {
9510
+ nodeMajor,
9511
+ platform: options.platform,
9512
+ arch: options.arch
9513
+ },
9514
+ false
9515
+ );
9410
9516
  if (!validation.manifest || validation.reasons.length > 0) {
9411
9517
  return { resolved: false, reasons: validation.reasons };
9412
9518
  }
@@ -9429,11 +9535,85 @@ function resolveCurrentPreviewArtifact(options) {
9429
9535
  manifest: validation.manifest
9430
9536
  };
9431
9537
  }
9538
+ async function materializeVerifiedPreviewArtifactFile(options) {
9539
+ const source = path29.resolve(options.source);
9540
+ const destination = path29.resolve(options.destination);
9541
+ const temporary = `${destination}.${process.pid}.${Date.now()}.tmp`;
9542
+ fs33.mkdirSync(path29.dirname(destination), { recursive: true });
9543
+ if (fs33.existsSync(destination)) {
9544
+ throw new Error(
9545
+ `materialization destination already exists: ${destination}`
9546
+ );
9547
+ }
9548
+ const noFollow = fs33.constants.O_NOFOLLOW ?? 0;
9549
+ let sourceHandle;
9550
+ let destinationHandle;
9551
+ try {
9552
+ sourceHandle = await fs33.promises.open(
9553
+ source,
9554
+ fs33.constants.O_RDONLY | noFollow
9555
+ );
9556
+ const sourceStat = await sourceHandle.stat();
9557
+ if (!sourceStat.isFile()) {
9558
+ throw new Error(`${options.identity.path} is not a regular file`);
9559
+ }
9560
+ destinationHandle = await fs33.promises.open(
9561
+ temporary,
9562
+ fs33.constants.O_WRONLY | fs33.constants.O_CREAT | fs33.constants.O_EXCL,
9563
+ 384
9564
+ );
9565
+ const hash = crypto2.createHash("sha256");
9566
+ const buffer = Buffer.allocUnsafe(256 * 1024);
9567
+ let totalBytes = 0;
9568
+ for (; ; ) {
9569
+ const { bytesRead } = await sourceHandle.read(
9570
+ buffer,
9571
+ 0,
9572
+ buffer.length,
9573
+ null
9574
+ );
9575
+ if (bytesRead === 0) break;
9576
+ hash.update(buffer.subarray(0, bytesRead));
9577
+ let written = 0;
9578
+ while (written < bytesRead) {
9579
+ const result = await destinationHandle.write(
9580
+ buffer,
9581
+ written,
9582
+ bytesRead - written,
9583
+ null
9584
+ );
9585
+ if (result.bytesWritten <= 0) {
9586
+ throw new Error(
9587
+ `${options.identity.path} materialization short write`
9588
+ );
9589
+ }
9590
+ written += result.bytesWritten;
9591
+ }
9592
+ totalBytes += bytesRead;
9593
+ }
9594
+ const sha256 = hash.digest("hex");
9595
+ if (sha256 !== options.identity.sha256) {
9596
+ throw new Error(`${options.identity.path} hash does not match manifest`);
9597
+ }
9598
+ if (totalBytes !== options.identity.bytes) {
9599
+ throw new Error(`${options.identity.path} bytes do not match manifest`);
9600
+ }
9601
+ await destinationHandle.sync();
9602
+ await destinationHandle.close();
9603
+ destinationHandle = void 0;
9604
+ await fs33.promises.rename(temporary, destination);
9605
+ return { bytes: totalBytes, sha256 };
9606
+ } finally {
9607
+ await destinationHandle?.close().catch(() => void 0);
9608
+ await sourceHandle?.close().catch(() => void 0);
9609
+ await fs33.promises.rm(temporary, { force: true }).catch(() => void 0);
9610
+ }
9611
+ }
9432
9612
 
9433
9613
  // src/commands/preview-artifact/producer.ts
9434
9614
  function defaultGenerationId() {
9435
9615
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "");
9436
- return `${timestamp}-${crypto2.randomBytes(5).toString("hex")}`;
9616
+ return `${timestamp}-${crypto3.randomBytes(5).toString("hex")}`;
9437
9617
  }
9438
9618
  function defaultPreviewBundleBuildCommands(projectRootInput) {
9439
9619
  const projectRoot = path30.resolve(projectRootInput);
@@ -9957,7 +10137,7 @@ async function startPreviewArtifactRuntime(options) {
9957
10137
  const resolved = measure(
9958
10138
  timings,
9959
10139
  "metadata_validate",
9960
- () => resolveCurrentPreviewArtifact({
10140
+ () => resolveCurrentPreviewArtifactMetadata({
9961
10141
  storeRoot: options.storeRoot,
9962
10142
  nodeVersion: process.version,
9963
10143
  platform: process.platform,
@@ -9993,53 +10173,85 @@ async function startPreviewArtifactRuntime(options) {
9993
10173
  );
9994
10174
  const runtimeBundle = path32.join(runtimeDir, "server.bundle.cjs");
9995
10175
  const serverSource = path32.join(resolved.generationDir, "server.bundle.cjs");
9996
- measure(
9997
- timings,
9998
- "server_materialize",
9999
- () => fs36.copyFileSync(serverSource, runtimeBundle),
10000
- { bytes: resolved.manifest.files.server.bytes }
10001
- );
10176
+ const clientArchive = path32.join(runtimeDir, "client.zip");
10177
+ const clientSource = path32.join(resolved.generationDir, "client.zip");
10002
10178
  const clientRoot = path32.join(runtimeDir, "dist", "client");
10003
- measure(
10004
- timings,
10005
- "client_archive_inspect_extract",
10006
- () => extractClientArchive(
10007
- path32.join(resolved.generationDir, "client.zip"),
10008
- clientRoot
10009
- ),
10010
- { bytes: resolved.manifest.files.client.bytes }
10011
- );
10012
- const cachedServerPort = options.cachedServerPort === 0 ? await reservePort2() : options.cachedServerPort;
10013
- cachedRuntime = spawn3(process.execPath, [runtimeBundle], {
10014
- cwd: runtimeDir,
10015
- detached: true,
10016
- stdio: "ignore",
10017
- env: {
10018
- ...process.env,
10019
- ...previewArtifactRuntimeEnvironment(options.environment),
10020
- SERVER_PORT: String(cachedServerPort)
10021
- }
10022
- });
10023
- const cachedOrigin = `http://127.0.0.1:${cachedServerPort}`;
10024
- await measureAsync(
10025
- timings,
10026
- "backend_spawn_to_business_ready",
10027
- () => waitForCachedRuntime(
10028
- cachedOrigin,
10029
- options.appBasePath,
10030
- options.businessApiPath,
10031
- options.startupTimeoutMs ?? 3e4,
10032
- cachedRuntime
10033
- )
10034
- );
10035
- const cachedAssetFiles = measure(
10036
- timings,
10037
- "asset_index",
10038
- () => collectCachedAssetFiles(clientRoot, options.appBasePath)
10039
- );
10040
- timings[timings.length - 1].fileCount = new Set(
10041
- cachedAssetFiles.values()
10042
- ).size;
10179
+ const backendReady = (async () => {
10180
+ await measureAsync(
10181
+ timings,
10182
+ "server_materialize",
10183
+ () => materializeVerifiedPreviewArtifactFile({
10184
+ source: serverSource,
10185
+ destination: runtimeBundle,
10186
+ identity: resolved.manifest.files.server
10187
+ }),
10188
+ { bytes: resolved.manifest.files.server.bytes }
10189
+ );
10190
+ const cachedServerPort2 = options.cachedServerPort === 0 ? await reservePort2() : options.cachedServerPort;
10191
+ cachedRuntime = spawn3(process.execPath, [runtimeBundle], {
10192
+ cwd: runtimeDir,
10193
+ detached: true,
10194
+ stdio: "ignore",
10195
+ env: {
10196
+ ...process.env,
10197
+ ...previewArtifactRuntimeEnvironment(options.environment),
10198
+ SERVER_PORT: String(cachedServerPort2)
10199
+ }
10200
+ });
10201
+ const cachedOrigin = `http://127.0.0.1:${cachedServerPort2}`;
10202
+ await measureAsync(
10203
+ timings,
10204
+ "backend_spawn_to_business_ready",
10205
+ () => waitForCachedRuntime(
10206
+ cachedOrigin,
10207
+ options.appBasePath,
10208
+ options.businessApiPath,
10209
+ options.startupTimeoutMs ?? 3e4,
10210
+ cachedRuntime
10211
+ )
10212
+ );
10213
+ return cachedServerPort2;
10214
+ })();
10215
+ const assetsReady = (async () => {
10216
+ await measureAsync(
10217
+ timings,
10218
+ "client_materialize",
10219
+ () => materializeVerifiedPreviewArtifactFile({
10220
+ source: clientSource,
10221
+ destination: clientArchive,
10222
+ identity: resolved.manifest.files.client
10223
+ }),
10224
+ { bytes: resolved.manifest.files.client.bytes }
10225
+ );
10226
+ measure(
10227
+ timings,
10228
+ "client_archive_inspect",
10229
+ () => inspectClientArchive(clientArchive)
10230
+ );
10231
+ await measureAsync(
10232
+ timings,
10233
+ "client_extract",
10234
+ () => extractInspectedClientArchive(clientArchive, clientRoot)
10235
+ );
10236
+ const cachedAssetFiles2 = measure(
10237
+ timings,
10238
+ "asset_index",
10239
+ () => collectCachedAssetFiles(clientRoot, options.appBasePath)
10240
+ );
10241
+ timings[timings.length - 1].fileCount = new Set(
10242
+ cachedAssetFiles2.values()
10243
+ ).size;
10244
+ fs36.rmSync(clientArchive, { force: true });
10245
+ return cachedAssetFiles2;
10246
+ })();
10247
+ const [backendResult, assetsResult] = await Promise.allSettled([
10248
+ backendReady,
10249
+ assetsReady
10250
+ ]);
10251
+ if (assetsResult.status === "rejected") throw assetsResult.reason;
10252
+ if (backendResult.status === "rejected") throw backendResult.reason;
10253
+ const cachedServerPort = backendResult.value;
10254
+ const cachedAssetFiles = assetsResult.value;
10043
10255
  switcher = createPreviewArtifactSwitcher({
10044
10256
  listenHost: options.listenHost,
10045
10257
  listenPort: options.listenPort,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-cli",
3
- "version": "1.1.59-alpha.20260722050835",
3
+ "version": "1.1.59-alpha.20260722165429",
4
4
  "description": "CLI tool for fullstack template management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,9 +8,7 @@ const readline = require('readline');
8
8
  const {
9
9
  applyPreviewArtifactHostOverrides,
10
10
  buildListeningPortLookupArgs,
11
- closePreviewPhaseReporterWithRetry,
12
11
  createDeferredTypecheckGate,
13
- createPreviewPhaseFrameDecoder,
14
12
  createPreviewPhaseReporter,
15
13
  normalizeTcpPort,
16
14
  parseTscWatchSummary,
@@ -201,7 +199,6 @@ function startProcess({
201
199
  args,
202
200
  cleanupPort,
203
201
  phaseDetail = {},
204
- phaseChannel = false,
205
202
  onReady,
206
203
  onOutputLine,
207
204
  }) {
@@ -239,23 +236,12 @@ function startProcess({
239
236
  }
240
237
 
241
238
  while (!stopping) {
242
- const childEnv = { ...process.env };
243
- // The parent is the only outbox writer. Child processes receive a narrow
244
- // producer channel, never the filesystem destination.
245
- delete childEnv.MIAODA_PREVIEW_PHASE_OUTBOX_ROOT;
246
- if (phaseChannel) {
247
- childEnv.MIAODA_PREVIEW_PHASE_FD = '3';
248
- } else {
249
- delete childEnv.MIAODA_PREVIEW_PHASE_FD;
250
- }
251
239
  const child = spawn(command, args, {
252
240
  detached: true,
253
- stdio: phaseChannel
254
- ? ['ignore', 'pipe', 'pipe', 'pipe']
255
- : ['ignore', 'pipe', 'pipe'],
241
+ stdio: ['ignore', 'pipe', 'pipe'],
256
242
  shell: true,
257
243
  cwd: PROJECT_ROOT,
258
- env: childEnv,
244
+ env: { ...process.env },
259
245
  });
260
246
 
261
247
  entry.pid = child.pid;
@@ -321,24 +307,13 @@ function startProcess({
321
307
 
322
308
  // Pipe stdout and stderr through readline for timestamped logging
323
309
  let typecheckSummaryReported = false;
324
- let phaseReported = false;
325
- const pipeLines = (stream, allowPhaseFallback = false) => {
310
+ const pipeLines = stream => {
326
311
  const rl = readline.createInterface({
327
312
  input: stream,
328
313
  crlfDelay: Infinity,
329
314
  });
330
315
  rl.on('line', line => {
331
316
  if (onOutputLine) onOutputLine(line);
332
- const legacyPhaseCandidate =
333
- allowPhaseFallback && line.startsWith('[MiaodaPreviewPhase] ');
334
- if (legacyPhaseCandidate && !phaseReported) {
335
- phaseReported = previewPhaseReporter.ingest(line, {
336
- producer: 'vite_plugin',
337
- allowed_phases: ['vite_http_listening'],
338
- attempt,
339
- allow_legacy_stdout: true,
340
- });
341
- }
342
317
  if (name === 'server-typecheck' && !typecheckSummaryReported) {
343
318
  const summary = parseTscWatchSummary(line);
344
319
  if (summary) {
@@ -359,38 +334,11 @@ function startProcess({
359
334
  try {
360
335
  fs.writeSync(logFd, msg);
361
336
  } catch {}
362
- // Phase fallbacks are normalized by the parent reporter before they
363
- // enter the shared log. Keep the raw child claim quarantined in the
364
- // component log so collectors never observe two representations.
365
- if (!legacyPhaseCandidate) writeOutput(msg);
337
+ writeOutput(msg);
366
338
  });
367
339
  };
368
- if (child.stdout) pipeLines(child.stdout, phaseChannel);
340
+ if (child.stdout) pipeLines(child.stdout);
369
341
  if (child.stderr) pipeLines(child.stderr);
370
- if (phaseChannel && child.stdio[3]) {
371
- let oversizedPhaseFrameReported = false;
372
- const phaseDecoder = createPreviewPhaseFrameDecoder({
373
- max_bytes: 16 * 1024,
374
- on_oversized_frame: () => {
375
- if (oversizedPhaseFrameReported) return;
376
- oversizedPhaseFrameReported = true;
377
- logEvent(
378
- 'WARN',
379
- name,
380
- 'Dropped an oversized preview phase producer frame'
381
- );
382
- },
383
- on_frame: line => {
384
- if (phaseReported) return;
385
- phaseReported = previewPhaseReporter.ingest(line, {
386
- producer: 'vite_plugin',
387
- allowed_phases: ['vite_http_listening'],
388
- attempt,
389
- });
390
- },
391
- });
392
- child.stdio[3].on('data', chunk => phaseDecoder.push(chunk));
393
- }
394
342
 
395
343
  // Wait for the direct child to exit.
396
344
  // NOTE: must use 'exit', not 'close'. With shell:true, grandchild processes
@@ -520,16 +468,6 @@ async function cleanup() {
520
468
 
521
469
  logEvent('INFO', 'main', 'All processes stopped');
522
470
 
523
- const previewPhaseSealed =
524
- await closePreviewPhaseReporterWithRetry(previewPhaseReporter);
525
- if (!previewPhaseSealed) {
526
- logEvent(
527
- 'ERROR',
528
- 'main',
529
- 'Preview phase outbox did not seal after bounded shutdown retries'
530
- );
531
- }
532
-
533
471
  try {
534
472
  fs.closeSync(devStdLogFd);
535
473
  } catch {}
@@ -537,7 +475,7 @@ async function cleanup() {
537
475
  fs.closeSync(devLogFd);
538
476
  } catch {}
539
477
 
540
- process.exit(previewPhaseSealed ? 0 : 1);
478
+ process.exit(0);
541
479
  }
542
480
 
543
481
  process.on('SIGTERM', cleanup);
@@ -706,7 +644,6 @@ async function main() {
706
644
  command: 'npm',
707
645
  args: ['run', 'dev:client'],
708
646
  cleanupPort: CLIENT_DEV_PORT,
709
- phaseChannel: true,
710
647
  });
711
648
 
712
649
  writeOutput(`📋 Dev processes running. Press Ctrl+C to stop.\n`);
@@ -720,14 +657,7 @@ async function main() {
720
657
  }
721
658
  }
722
659
 
723
- main().catch(async err => {
660
+ main().catch(err => {
724
661
  console.error('Fatal error:', err);
725
- const previewPhaseSealed =
726
- await closePreviewPhaseReporterWithRetry(previewPhaseReporter);
727
- if (!previewPhaseSealed) {
728
- console.error(
729
- 'Preview phase outbox did not seal after bounded fatal-exit retries'
730
- );
731
- }
732
662
  process.exit(1);
733
663
  });