create-mercato-app 0.6.3-develop.3857.1.da89d7530c → 0.6.3-develop.3881.1.0b590ac4eb

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-mercato-app",
3
- "version": "0.6.3-develop.3857.1.da89d7530c",
3
+ "version": "0.6.3-develop.3881.1.0b590ac4eb",
4
4
  "type": "module",
5
5
  "description": "Create a new Open Mercato application",
6
6
  "main": "./dist/index.js",
@@ -66,6 +66,17 @@ export function isIgnorableTurboShutdownLine(line) {
66
66
  || /^command (interrupted|cancelled|canceled)/i.test(plain)
67
67
  }
68
68
 
69
+ export function isIgnorableConsolidatedWatchLine(line) {
70
+ if (typeof line !== 'string') return false
71
+ const plain = normalize(line)
72
+ if (!plain.startsWith('[watch]')) return false
73
+ return /^\[watch\] consolidated watcher: /.test(plain)
74
+ || /^\[watch\] [^:]+: rebuilding\.\.\.$/.test(plain)
75
+ || /^\[watch\] [^:]+: rebuild complete$/.test(plain)
76
+ || /^\[watch\] [^:]+: no source files found, skipping rebuild$/.test(plain)
77
+ || /^\[watch\] no workspace packages with a `watch` script /.test(plain)
78
+ }
79
+
69
80
  const FAILURE_NOISE_PREDICATES = [
70
81
  isIgnorableBoxDrawingLine,
71
82
  isIgnorableEnvInjectionLine,
@@ -89,6 +100,7 @@ const TURBO_NOISE_PREDICATES = [
89
100
  isIgnorableTurboCacheCancellationLine,
90
101
  isIgnorableTurboShutdownLine,
91
102
  isIgnorableBoxDrawingLine,
103
+ isIgnorableConsolidatedWatchLine,
92
104
  ]
93
105
 
94
106
  export function isIgnorableTurboLine(line) {
@@ -0,0 +1,41 @@
1
+ import spawn from 'cross-spawn'
2
+
3
+ // Windows does not propagate signals from a parent process down to grandchildren
4
+ // the way POSIX does: child.kill('SIGTERM'/'SIGKILL') only terminates the direct
5
+ // child, leaving any further descendants (next dev, mercato generate watch, etc.)
6
+ // alive and still holding ports. taskkill with /T (tree) /F (force) is the
7
+ // platform-blessed way to terminate the whole descendant tree. On POSIX we keep
8
+ // child.kill so the existing graceful-then-forced two-phase shutdown is preserved.
9
+ export function killProcessTree(child, signal, options = {}) {
10
+ if (!child) return false
11
+
12
+ const platform = options.platform ?? process.platform
13
+ const spawnImpl = options.spawn ?? spawn
14
+
15
+ if (platform === 'win32') {
16
+ const pid = child.pid
17
+ if (typeof pid !== 'number' || Number.isNaN(pid) || pid <= 0) {
18
+ return false
19
+ }
20
+ try {
21
+ const killer = spawnImpl('taskkill', ['/pid', String(pid), '/T', '/F'], {
22
+ stdio: 'ignore',
23
+ windowsHide: true,
24
+ })
25
+ if (killer && typeof killer.on === 'function') {
26
+ killer.on('error', () => { /* best-effort: taskkill may not exist on stripped images */ })
27
+ }
28
+ return true
29
+ } catch {
30
+ return false
31
+ }
32
+ }
33
+
34
+ if (child.killed) return false
35
+ try {
36
+ child.kill(signal)
37
+ return true
38
+ } catch {
39
+ return false
40
+ }
41
+ }
@@ -23,6 +23,7 @@ import {
23
23
  stripAnsi,
24
24
  } from './dev-splash-helpers.mjs'
25
25
  import { purgeAppBuildCaches } from './dev-cache-purge.mjs'
26
+ import { killProcessTree } from './dev-shutdown-utils.mjs'
26
27
  import { resolveSpawnCommand } from './dev-spawn-utils.mjs'
27
28
  import { createDevSplashCodingFlow } from './dev-splash-coding-flow.mjs'
28
29
  import { createDevSplashGitRepoFlow } from './dev-splash-git-repo-flow.mjs'
@@ -1023,13 +1024,13 @@ function shutdown(exitCode = 0) {
1023
1024
  }
1024
1025
 
1025
1026
  for (const child of alive) {
1026
- child.kill('SIGTERM')
1027
+ killProcessTree(child, 'SIGTERM')
1027
1028
  }
1028
1029
 
1029
1030
  setTimeout(() => {
1030
1031
  for (const child of children) {
1031
1032
  if (!child.killed) {
1032
- child.kill('SIGKILL')
1033
+ killProcessTree(child, 'SIGKILL')
1033
1034
  }
1034
1035
  }
1035
1036
  closeDevLogSession()
@@ -1492,10 +1493,21 @@ async function runPassthroughStage(label, commandArgs, options = {}) {
1492
1493
  console.log(`✅ ${formatProgressLine(label, stageCurrent, stageTotal, resolveProgressPercent(stageCurrent, stageTotal))} in ${formatDuration(Date.now() - startedAt)}`)
1493
1494
  }
1494
1495
 
1496
+ function resolveWatchPackagesScript() {
1497
+ // `OM_WATCH_PACKAGES_MODE=legacy` falls back to the Turbo per-package
1498
+ // fan-out for developers who need the old behavior (debugging, or pairing
1499
+ // with `OM_PACKAGE_WATCH_MODE=persistent` for hot rebuilds at the cost of
1500
+ // ~1 GB more idle RSS). Default is the consolidated single-process watcher.
1501
+ const raw = String(process.env.OM_WATCH_PACKAGES_MODE ?? '').trim().toLowerCase()
1502
+ return raw === 'legacy' ? 'watch:packages:legacy' : 'watch:packages'
1503
+ }
1504
+
1495
1505
  function startPackageWatch() {
1506
+ const watchScript = resolveWatchPackagesScript()
1507
+
1496
1508
  if (classic) {
1497
- const child = spawnCommand(yarnCommand, ['watch:packages'], {
1498
- label: 'watch:packages',
1509
+ const child = spawnCommand(yarnCommand, [watchScript], {
1510
+ label: watchScript,
1499
1511
  logFile: getDevRunnerLog(),
1500
1512
  mirrorOutput: true,
1501
1513
  })
@@ -1529,16 +1541,7 @@ function startPackageWatch() {
1529
1541
  activity: 'Workspace package watch started',
1530
1542
  })
1531
1543
 
1532
- const child = spawnCommand(yarnCommand, [
1533
- 'turbo',
1534
- 'run',
1535
- 'watch',
1536
- '--filter=./packages/*',
1537
- '--concurrency=32',
1538
- '--output-logs=errors-only',
1539
- '--log-order=grouped',
1540
- '--log-prefix=none',
1541
- ], {
1544
+ const child = spawnCommand(yarnCommand, [watchScript], {
1542
1545
  label: 'Watching workspace packages',
1543
1546
  logFile: getDevRunnerLog(),
1544
1547
  mirrorOutput: verbose,