@qpqjs/cli 0.2.1 → 0.4.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.
Files changed (284) hide show
  1. package/lib/commonjs/cli/commandMenu.js +5 -4
  2. package/lib/commonjs/cli/commandMenu.js.map +1 -1
  3. package/lib/commonjs/cli/runCli.js +15 -7
  4. package/lib/commonjs/cli/runCli.js.map +1 -1
  5. package/lib/commonjs/commands/checkCircular.js +15 -7
  6. package/lib/commonjs/commands/checkCircular.js.map +1 -1
  7. package/lib/commonjs/commands/clearResources.js +8 -14
  8. package/lib/commonjs/commands/clearResources.js.map +1 -1
  9. package/lib/commonjs/commands/go.js +3 -7
  10. package/lib/commonjs/commands/go.js.map +1 -1
  11. package/lib/commonjs/commands/goDev.js +4 -2
  12. package/lib/commonjs/commands/goDev.js.map +1 -1
  13. package/lib/commonjs/commands/goDevApi.js +23 -20
  14. package/lib/commonjs/commands/goDevApi.js.map +1 -1
  15. package/lib/commonjs/commands/goDevWeb.js +13 -8
  16. package/lib/commonjs/commands/goDevWeb.js.map +1 -1
  17. package/lib/commonjs/commands/goDocker.js +10 -13
  18. package/lib/commonjs/commands/goDocker.js.map +1 -1
  19. package/lib/commonjs/commands/hooks.js +4 -2
  20. package/lib/commonjs/commands/hooks.js.map +1 -1
  21. package/lib/commonjs/commands/migrate.js +11 -9
  22. package/lib/commonjs/commands/migrate.js.map +1 -1
  23. package/lib/commonjs/commands/prep.js +4 -2
  24. package/lib/commonjs/commands/prep.js.map +1 -1
  25. package/lib/commonjs/commands/publish.js +4 -7
  26. package/lib/commonjs/commands/publish.js.map +1 -1
  27. package/lib/commonjs/commands/scriptBuild.js +7 -5
  28. package/lib/commonjs/commands/scriptBuild.js.map +1 -1
  29. package/lib/commonjs/commands/scriptBuilderLayer.js +6 -4
  30. package/lib/commonjs/commands/scriptBuilderLayer.js.map +1 -1
  31. package/lib/commonjs/commands/scriptNew.js +7 -5
  32. package/lib/commonjs/commands/scriptNew.js.map +1 -1
  33. package/lib/commonjs/commands/setup.js +14 -22
  34. package/lib/commonjs/commands/setup.js.map +1 -1
  35. package/lib/commonjs/commands/synth.js +16 -20
  36. package/lib/commonjs/commands/synth.js.map +1 -1
  37. package/lib/commonjs/commands/teardown.js +8 -14
  38. package/lib/commonjs/commands/teardown.js.map +1 -1
  39. package/lib/commonjs/lib/CliError.d.ts +4 -0
  40. package/lib/commonjs/lib/CliError.js +14 -0
  41. package/lib/commonjs/lib/CliError.js.map +1 -0
  42. package/lib/commonjs/lib/circularImports.d.ts +0 -1
  43. package/lib/commonjs/lib/circularImports.js +5 -6
  44. package/lib/commonjs/lib/circularImports.js.map +1 -1
  45. package/lib/commonjs/lib/clearResourcesPlan.d.ts +0 -1
  46. package/lib/commonjs/lib/clearResourcesPlan.js +12 -13
  47. package/lib/commonjs/lib/clearResourcesPlan.js.map +1 -1
  48. package/lib/commonjs/lib/deployPrompts.d.ts +2 -1
  49. package/lib/commonjs/lib/deployPrompts.js +16 -16
  50. package/lib/commonjs/lib/deployPrompts.js.map +1 -1
  51. package/lib/commonjs/lib/devServerEntry.js +5 -4
  52. package/lib/commonjs/lib/devServerEntry.js.map +1 -1
  53. package/lib/commonjs/lib/devServerPorts.js +2 -4
  54. package/lib/commonjs/lib/devServerPorts.js.map +1 -1
  55. package/lib/commonjs/lib/discovery.d.ts +0 -2
  56. package/lib/commonjs/lib/discovery.js +11 -44
  57. package/lib/commonjs/lib/discovery.js.map +1 -1
  58. package/lib/commonjs/lib/hooks.js +5 -3
  59. package/lib/commonjs/lib/hooks.js.map +1 -1
  60. package/lib/commonjs/lib/killChildWithEscalation.js +3 -1
  61. package/lib/commonjs/lib/killChildWithEscalation.js.map +1 -1
  62. package/lib/commonjs/lib/killStaleListeners.js +24 -37
  63. package/lib/commonjs/lib/killStaleListeners.js.map +1 -1
  64. package/lib/commonjs/lib/out.d.ts +11 -0
  65. package/lib/commonjs/lib/out.js +30 -0
  66. package/lib/commonjs/lib/out.js.map +1 -0
  67. package/lib/commonjs/lib/prompts.d.ts +1 -0
  68. package/lib/commonjs/lib/prompts.js +15 -2
  69. package/lib/commonjs/lib/prompts.js.map +1 -1
  70. package/lib/commonjs/lib/qpqConfigs.js +4 -4
  71. package/lib/commonjs/lib/qpqConfigs.js.map +1 -1
  72. package/lib/commonjs/lib/requireDriverCapability.d.ts +7 -0
  73. package/lib/commonjs/lib/requireDriverCapability.js +17 -0
  74. package/lib/commonjs/lib/requireDriverCapability.js.map +1 -0
  75. package/lib/commonjs/lib/resolveAppSelection.d.ts +1 -0
  76. package/lib/commonjs/lib/resolveAppSelection.js +19 -12
  77. package/lib/commonjs/lib/resolveAppSelection.js.map +1 -1
  78. package/lib/commonjs/lib/resolveCommandContext.d.ts +12 -0
  79. package/lib/commonjs/lib/resolveCommandContext.js +26 -0
  80. package/lib/commonjs/lib/resolveCommandContext.js.map +1 -0
  81. package/lib/commonjs/lib/resolveDeployment.d.ts +0 -1
  82. package/lib/commonjs/lib/resolveDeployment.js +15 -10
  83. package/lib/commonjs/lib/resolveDeployment.js.map +1 -1
  84. package/lib/commonjs/lib/runCommand.d.ts +20 -0
  85. package/lib/commonjs/lib/runCommand.js +64 -34
  86. package/lib/commonjs/lib/runCommand.js.map +1 -1
  87. package/lib/commonjs/lib/runTasks.js +8 -4
  88. package/lib/commonjs/lib/runTasks.js.map +1 -1
  89. package/lib/commonjs/lib/timing.js +5 -3
  90. package/lib/commonjs/lib/timing.js.map +1 -1
  91. package/lib/commonjs/lib/typeWatcher.d.ts +2 -1
  92. package/lib/commonjs/lib/typeWatcher.js +6 -13
  93. package/lib/commonjs/lib/typeWatcher.js.map +1 -1
  94. package/lib/commonjs/lib/userScriptBuilderLayer.d.ts +0 -2
  95. package/lib/commonjs/lib/userScriptBuilderLayer.js +7 -8
  96. package/lib/commonjs/lib/userScriptBuilderLayer.js.map +1 -1
  97. package/lib/commonjs/lib/views.js +3 -2
  98. package/lib/commonjs/lib/views.js.map +1 -1
  99. package/lib/commonjs/lib/webAddressingEnv.d.ts +0 -2
  100. package/lib/commonjs/lib/webAddressingEnv.js +4 -4
  101. package/lib/commonjs/lib/webAddressingEnv.js.map +1 -1
  102. package/lib/commonjs/platforms/aws/awsCredentials.js +3 -1
  103. package/lib/commonjs/platforms/aws/awsCredentials.js.map +1 -1
  104. package/lib/commonjs/platforms/aws/cdkApp.js +1 -1
  105. package/lib/commonjs/platforms/aws/cdkApp.js.map +1 -1
  106. package/lib/commonjs/platforms/aws/clearResources.js +16 -26
  107. package/lib/commonjs/platforms/aws/clearResources.js.map +1 -1
  108. package/lib/commonjs/platforms/aws/getDeployEnv.d.ts +1 -0
  109. package/lib/commonjs/platforms/aws/getDeployEnv.js +12 -0
  110. package/lib/commonjs/platforms/aws/getDeployEnv.js.map +1 -0
  111. package/lib/commonjs/platforms/aws/go.js +17 -15
  112. package/lib/commonjs/platforms/aws/go.js.map +1 -1
  113. package/lib/commonjs/platforms/aws/goDocker.js +29 -26
  114. package/lib/commonjs/platforms/aws/goDocker.js.map +1 -1
  115. package/lib/commonjs/platforms/aws/goDockerManifest.js +6 -1
  116. package/lib/commonjs/platforms/aws/goDockerManifest.js.map +1 -1
  117. package/lib/commonjs/platforms/aws/publish.js +13 -11
  118. package/lib/commonjs/platforms/aws/publish.js.map +1 -1
  119. package/lib/commonjs/platforms/aws/remote.js +8 -7
  120. package/lib/commonjs/platforms/aws/remote.js.map +1 -1
  121. package/lib/commonjs/platforms/aws/setup/buildBucketNamesStep.js +4 -4
  122. package/lib/commonjs/platforms/aws/setup/buildBucketNamesStep.js.map +1 -1
  123. package/lib/commonjs/platforms/aws/setup/buildGithubDeployRoleStep.js +4 -3
  124. package/lib/commonjs/platforms/aws/setup/buildGithubDeployRoleStep.js.map +1 -1
  125. package/lib/commonjs/platforms/aws/stacks.d.ts +0 -1
  126. package/lib/commonjs/platforms/aws/stacks.js +21 -33
  127. package/lib/commonjs/platforms/aws/stacks.js.map +1 -1
  128. package/lib/commonjs/platforms/aws/teardown.js +9 -7
  129. package/lib/commonjs/platforms/aws/teardown.js.map +1 -1
  130. package/lib/commonjs/platforms/aws/viewsSync.js +23 -11
  131. package/lib/commonjs/platforms/aws/viewsSync.js.map +1 -1
  132. package/lib/commonjs/platforms/docker/go.js +20 -18
  133. package/lib/commonjs/platforms/docker/go.js.map +1 -1
  134. package/lib/commonjs/platforms/docker/index.js +5 -4
  135. package/lib/commonjs/platforms/docker/index.js.map +1 -1
  136. package/lib/commonjs/platforms/docker/parseMounts.js +3 -2
  137. package/lib/commonjs/platforms/docker/parseMounts.js.map +1 -1
  138. package/lib/commonjs/platforms/index.js +4 -2
  139. package/lib/commonjs/platforms/index.js.map +1 -1
  140. package/lib/commonjs/platforms/types.d.ts +2 -2
  141. package/lib/commonjs/platforms/types.js.map +1 -1
  142. package/lib/esm/cli/commandMenu.js +5 -4
  143. package/lib/esm/cli/commandMenu.js.map +1 -1
  144. package/lib/esm/cli/runCli.js +15 -7
  145. package/lib/esm/cli/runCli.js.map +1 -1
  146. package/lib/esm/commands/checkCircular.js +15 -7
  147. package/lib/esm/commands/checkCircular.js.map +1 -1
  148. package/lib/esm/commands/clearResources.js +8 -14
  149. package/lib/esm/commands/clearResources.js.map +1 -1
  150. package/lib/esm/commands/go.js +3 -7
  151. package/lib/esm/commands/go.js.map +1 -1
  152. package/lib/esm/commands/goDev.js +4 -2
  153. package/lib/esm/commands/goDev.js.map +1 -1
  154. package/lib/esm/commands/goDevApi.js +21 -18
  155. package/lib/esm/commands/goDevApi.js.map +1 -1
  156. package/lib/esm/commands/goDevWeb.js +12 -8
  157. package/lib/esm/commands/goDevWeb.js.map +1 -1
  158. package/lib/esm/commands/goDocker.js +10 -13
  159. package/lib/esm/commands/goDocker.js.map +1 -1
  160. package/lib/esm/commands/hooks.js +4 -2
  161. package/lib/esm/commands/hooks.js.map +1 -1
  162. package/lib/esm/commands/migrate.js +9 -7
  163. package/lib/esm/commands/migrate.js.map +1 -1
  164. package/lib/esm/commands/prep.js +4 -2
  165. package/lib/esm/commands/prep.js.map +1 -1
  166. package/lib/esm/commands/publish.js +4 -7
  167. package/lib/esm/commands/publish.js.map +1 -1
  168. package/lib/esm/commands/scriptBuild.js +7 -5
  169. package/lib/esm/commands/scriptBuild.js.map +1 -1
  170. package/lib/esm/commands/scriptBuilderLayer.js +6 -4
  171. package/lib/esm/commands/scriptBuilderLayer.js.map +1 -1
  172. package/lib/esm/commands/scriptNew.js +7 -5
  173. package/lib/esm/commands/scriptNew.js.map +1 -1
  174. package/lib/esm/commands/setup.js +14 -22
  175. package/lib/esm/commands/setup.js.map +1 -1
  176. package/lib/esm/commands/synth.js +18 -22
  177. package/lib/esm/commands/synth.js.map +1 -1
  178. package/lib/esm/commands/teardown.js +8 -14
  179. package/lib/esm/commands/teardown.js.map +1 -1
  180. package/lib/esm/lib/CliError.d.ts +4 -0
  181. package/lib/esm/lib/CliError.js +11 -0
  182. package/lib/esm/lib/CliError.js.map +1 -0
  183. package/lib/esm/lib/circularImports.d.ts +0 -1
  184. package/lib/esm/lib/circularImports.js +4 -4
  185. package/lib/esm/lib/circularImports.js.map +1 -1
  186. package/lib/esm/lib/clearResourcesPlan.d.ts +0 -1
  187. package/lib/esm/lib/clearResourcesPlan.js +12 -12
  188. package/lib/esm/lib/clearResourcesPlan.js.map +1 -1
  189. package/lib/esm/lib/deployPrompts.d.ts +2 -1
  190. package/lib/esm/lib/deployPrompts.js +17 -17
  191. package/lib/esm/lib/deployPrompts.js.map +1 -1
  192. package/lib/esm/lib/devServerEntry.js +5 -4
  193. package/lib/esm/lib/devServerEntry.js.map +1 -1
  194. package/lib/esm/lib/devServerPorts.js +2 -3
  195. package/lib/esm/lib/devServerPorts.js.map +1 -1
  196. package/lib/esm/lib/discovery.d.ts +0 -2
  197. package/lib/esm/lib/discovery.js +10 -38
  198. package/lib/esm/lib/discovery.js.map +1 -1
  199. package/lib/esm/lib/hooks.js +5 -3
  200. package/lib/esm/lib/hooks.js.map +1 -1
  201. package/lib/esm/lib/killChildWithEscalation.js +3 -1
  202. package/lib/esm/lib/killChildWithEscalation.js.map +1 -1
  203. package/lib/esm/lib/killStaleListeners.js +24 -37
  204. package/lib/esm/lib/killStaleListeners.js.map +1 -1
  205. package/lib/esm/lib/out.d.ts +11 -0
  206. package/lib/esm/lib/out.js +26 -0
  207. package/lib/esm/lib/out.js.map +1 -0
  208. package/lib/esm/lib/prompts.d.ts +1 -0
  209. package/lib/esm/lib/prompts.js +13 -1
  210. package/lib/esm/lib/prompts.js.map +1 -1
  211. package/lib/esm/lib/qpqConfigs.js +4 -4
  212. package/lib/esm/lib/qpqConfigs.js.map +1 -1
  213. package/lib/esm/lib/requireDriverCapability.d.ts +7 -0
  214. package/lib/esm/lib/requireDriverCapability.js +13 -0
  215. package/lib/esm/lib/requireDriverCapability.js.map +1 -0
  216. package/lib/esm/lib/resolveAppSelection.d.ts +1 -0
  217. package/lib/esm/lib/resolveAppSelection.js +17 -11
  218. package/lib/esm/lib/resolveAppSelection.js.map +1 -1
  219. package/lib/esm/lib/resolveCommandContext.d.ts +12 -0
  220. package/lib/esm/lib/resolveCommandContext.js +12 -0
  221. package/lib/esm/lib/resolveCommandContext.js.map +1 -0
  222. package/lib/esm/lib/resolveDeployment.d.ts +0 -1
  223. package/lib/esm/lib/resolveDeployment.js +13 -8
  224. package/lib/esm/lib/resolveDeployment.js.map +1 -1
  225. package/lib/esm/lib/runCommand.d.ts +20 -0
  226. package/lib/esm/lib/runCommand.js +52 -31
  227. package/lib/esm/lib/runCommand.js.map +1 -1
  228. package/lib/esm/lib/runTasks.js +8 -4
  229. package/lib/esm/lib/runTasks.js.map +1 -1
  230. package/lib/esm/lib/timing.js +5 -3
  231. package/lib/esm/lib/timing.js.map +1 -1
  232. package/lib/esm/lib/typeWatcher.d.ts +2 -1
  233. package/lib/esm/lib/typeWatcher.js +6 -13
  234. package/lib/esm/lib/typeWatcher.js.map +1 -1
  235. package/lib/esm/lib/userScriptBuilderLayer.d.ts +0 -2
  236. package/lib/esm/lib/userScriptBuilderLayer.js +5 -5
  237. package/lib/esm/lib/userScriptBuilderLayer.js.map +1 -1
  238. package/lib/esm/lib/views.js +3 -2
  239. package/lib/esm/lib/views.js.map +1 -1
  240. package/lib/esm/lib/webAddressingEnv.d.ts +0 -2
  241. package/lib/esm/lib/webAddressingEnv.js +1 -1
  242. package/lib/esm/lib/webAddressingEnv.js.map +1 -1
  243. package/lib/esm/platforms/aws/awsCredentials.js +3 -1
  244. package/lib/esm/platforms/aws/awsCredentials.js.map +1 -1
  245. package/lib/esm/platforms/aws/cdkApp.js +1 -1
  246. package/lib/esm/platforms/aws/cdkApp.js.map +1 -1
  247. package/lib/esm/platforms/aws/clearResources.js +16 -25
  248. package/lib/esm/platforms/aws/clearResources.js.map +1 -1
  249. package/lib/esm/platforms/aws/getDeployEnv.d.ts +1 -0
  250. package/lib/esm/platforms/aws/getDeployEnv.js +8 -0
  251. package/lib/esm/platforms/aws/getDeployEnv.js.map +1 -0
  252. package/lib/esm/platforms/aws/go.js +17 -15
  253. package/lib/esm/platforms/aws/go.js.map +1 -1
  254. package/lib/esm/platforms/aws/goDocker.js +29 -26
  255. package/lib/esm/platforms/aws/goDocker.js.map +1 -1
  256. package/lib/esm/platforms/aws/goDockerManifest.js +6 -1
  257. package/lib/esm/platforms/aws/goDockerManifest.js.map +1 -1
  258. package/lib/esm/platforms/aws/publish.js +13 -11
  259. package/lib/esm/platforms/aws/publish.js.map +1 -1
  260. package/lib/esm/platforms/aws/remote.js +9 -7
  261. package/lib/esm/platforms/aws/remote.js.map +1 -1
  262. package/lib/esm/platforms/aws/setup/buildBucketNamesStep.js +2 -2
  263. package/lib/esm/platforms/aws/setup/buildBucketNamesStep.js.map +1 -1
  264. package/lib/esm/platforms/aws/setup/buildGithubDeployRoleStep.js +4 -3
  265. package/lib/esm/platforms/aws/setup/buildGithubDeployRoleStep.js.map +1 -1
  266. package/lib/esm/platforms/aws/stacks.d.ts +0 -1
  267. package/lib/esm/platforms/aws/stacks.js +22 -30
  268. package/lib/esm/platforms/aws/stacks.js.map +1 -1
  269. package/lib/esm/platforms/aws/teardown.js +9 -7
  270. package/lib/esm/platforms/aws/teardown.js.map +1 -1
  271. package/lib/esm/platforms/aws/viewsSync.js +22 -10
  272. package/lib/esm/platforms/aws/viewsSync.js.map +1 -1
  273. package/lib/esm/platforms/docker/go.js +21 -19
  274. package/lib/esm/platforms/docker/go.js.map +1 -1
  275. package/lib/esm/platforms/docker/index.js +5 -4
  276. package/lib/esm/platforms/docker/index.js.map +1 -1
  277. package/lib/esm/platforms/docker/parseMounts.js +3 -2
  278. package/lib/esm/platforms/docker/parseMounts.js.map +1 -1
  279. package/lib/esm/platforms/index.js +4 -2
  280. package/lib/esm/platforms/index.js.map +1 -1
  281. package/lib/esm/platforms/types.d.ts +2 -2
  282. package/lib/esm/platforms/types.js.map +1 -1
  283. package/package.json +28 -15
  284. package/templates/user-script/README.md +1 -1
@@ -1,10 +1,12 @@
1
- // `qpq check:circular` — scan every workspace's src for circular imports (the
1
+ // `qpq check:circular`, scan every workspace's src for circular imports (the
2
2
  // class of bug that TDZ-crashes ESM bundles and silently drops exports under
3
- // CJS). Cycles fail the command (exit 1) — they are never acceptable; --warn or
3
+ // CJS). Cycles fail the command (exit 1), they are never acceptable; --warn or
4
4
  // QPQ_CIRCULAR_DEPS_WARN=1 is a temporary escape hatch that reports without
5
5
  // failing while fixing.
6
6
  import { findWorkspaceImportCycles } from '../lib/circularImports';
7
7
  import { getRoot } from '../lib/discovery';
8
+ import { createOutput } from '../lib/out';
9
+ const out = createOutput('check:circular');
8
10
  // madge reports every distinct loop path; one tangled module can produce dozens
9
11
  // of chains through the same files. Merge chains that share any file into one
10
12
  // group so the report shows each tangle once, with its full blast radius.
@@ -20,13 +22,19 @@ const groupCycles = (cycles) => {
20
22
  return rootFile;
21
23
  };
22
24
  for (const cycle of cycles) {
25
+ const [first] = cycle;
26
+ if (first === undefined)
27
+ continue;
23
28
  for (const file of cycle) {
24
- parent.set(find(file), find(cycle[0]));
29
+ parent.set(find(file), find(first));
25
30
  }
26
31
  }
27
32
  const groups = new Map();
28
33
  for (const cycle of cycles) {
29
- const key = find(cycle[0]);
34
+ const [first] = cycle;
35
+ if (first === undefined)
36
+ continue;
37
+ const key = find(first);
30
38
  const group = groups.get(key) ?? { files: [], chainCount: 0 };
31
39
  group.chainCount += 1;
32
40
  group.files = [...new Set([...group.files, ...cycle])];
@@ -38,16 +46,16 @@ export const checkCircularCommand = async (argv) => {
38
46
  const warnOnly = argv.includes('--warn') || !!process.env.QPQ_CIRCULAR_DEPS_WARN;
39
47
  const cycles = await findWorkspaceImportCycles(getRoot());
40
48
  if (cycles.length === 0) {
41
- console.log('check:circular: no circular imports found');
49
+ out.log('check:circular: no circular imports found');
42
50
  return;
43
51
  }
44
52
  const groups = groupCycles(cycles);
45
53
  const colour = warnOnly ? '\x1b[33m' : '\x1b[31m';
46
54
  for (const group of groups) {
47
55
  const chainNote = group.chainCount > 1 ? `, ${group.chainCount} distinct loops` : '';
48
- console.warn(`${colour}Circular imports (${group.files.length} files${chainNote}):\n ${group.files.join('\n ')}\x1b[0m`);
56
+ out.warn(`${colour}Circular imports (${group.files.length} files${chainNote}):\n ${group.files.join('\n ')}\x1b[0m`);
49
57
  }
50
- console.warn(`${colour}check:circular: ${groups.length} circular import group(s) found (${cycles.length} loops)\x1b[0m`);
58
+ out.warn(`${colour}check:circular: ${groups.length} circular import group(s) found (${cycles.length} loops)\x1b[0m`);
51
59
  if (!warnOnly) {
52
60
  process.exitCode = 1;
53
61
  }
@@ -1 +1 @@
1
- {"version":3,"file":"checkCircular.js","sourceRoot":"","sources":["../../../src/commands/checkCircular.ts"],"names":[],"mappings":"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","sourcesContent":["// `qpq check:circular` — scan every workspace's src for circular imports (the\n// class of bug that TDZ-crashes ESM bundles and silently drops exports under\n// CJS). Cycles fail the command (exit 1) — they are never acceptable; --warn or\n// QPQ_CIRCULAR_DEPS_WARN=1 is a temporary escape hatch that reports without\n// failing while fixing.\nimport { findWorkspaceImportCycles, ImportCycle } from '../lib/circularImports';\nimport { getRoot } from '../lib/discovery';\n\ntype CycleGroup = { files: string[]; chainCount: number };\n\n// madge reports every distinct loop path; one tangled module can produce dozens\n// of chains through the same files. Merge chains that share any file into one\n// group so the report shows each tangle once, with its full blast radius.\nconst groupCycles = (cycles: ImportCycle[]): CycleGroup[] => {\n const parent = new Map<string, string>();\n\n const find = (file: string): string => {\n const found = parent.get(file) ?? file;\n if (found === file) {\n return file;\n }\n const rootFile = find(found);\n parent.set(file, rootFile);\n return rootFile;\n };\n\n for (const cycle of cycles) {\n for (const file of cycle) {\n parent.set(find(file), find(cycle[0]));\n }\n }\n\n const groups = new Map<string, CycleGroup>();\n for (const cycle of cycles) {\n const key = find(cycle[0]);\n const group = groups.get(key) ?? { files: [], chainCount: 0 };\n group.chainCount += 1;\n group.files = [...new Set([...group.files, ...cycle])];\n groups.set(key, group);\n }\n\n return [...groups.values()];\n};\n\nexport const checkCircularCommand = async (argv: string[]): Promise<void> => {\n const warnOnly = argv.includes('--warn') || !!process.env.QPQ_CIRCULAR_DEPS_WARN;\n\n const cycles = await findWorkspaceImportCycles(getRoot());\n\n if (cycles.length === 0) {\n console.log('check:circular: no circular imports found');\n return;\n }\n\n const groups = groupCycles(cycles);\n\n const colour = warnOnly ? '\\x1b[33m' : '\\x1b[31m';\n for (const group of groups) {\n const chainNote = group.chainCount > 1 ? `, ${group.chainCount} distinct loops` : '';\n console.warn(`${colour}Circular imports (${group.files.length} files${chainNote}):\\n ${group.files.join('\\n ')}\\x1b[0m`);\n }\n console.warn(`${colour}check:circular: ${groups.length} circular import group(s) found (${cycles.length} loops)\\x1b[0m`);\n\n if (!warnOnly) {\n process.exitCode = 1;\n }\n};\n"]}
1
+ {"version":3,"file":"checkCircular.js","sourceRoot":"","sources":["../../../src/commands/checkCircular.ts"],"names":[],"mappings":"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","sourcesContent":["// `qpq check:circular`, scan every workspace's src for circular imports (the\n// class of bug that TDZ-crashes ESM bundles and silently drops exports under\n// CJS). Cycles fail the command (exit 1), they are never acceptable; --warn or\n// QPQ_CIRCULAR_DEPS_WARN=1 is a temporary escape hatch that reports without\n// failing while fixing.\nimport { findWorkspaceImportCycles, ImportCycle } from '../lib/circularImports';\nimport { getRoot } from '../lib/discovery';\nimport { createOutput } from '../lib/out';\n\nconst out = createOutput('check:circular');\n\ntype CycleGroup = { files: string[]; chainCount: number };\n\n// madge reports every distinct loop path; one tangled module can produce dozens\n// of chains through the same files. Merge chains that share any file into one\n// group so the report shows each tangle once, with its full blast radius.\nconst groupCycles = (cycles: ImportCycle[]): CycleGroup[] => {\n const parent = new Map<string, string>();\n\n const find = (file: string): string => {\n const found = parent.get(file) ?? file;\n if (found === file) {\n return file;\n }\n const rootFile = find(found);\n parent.set(file, rootFile);\n return rootFile;\n };\n\n for (const cycle of cycles) {\n const [first] = cycle;\n if (first === undefined) continue;\n for (const file of cycle) {\n parent.set(find(file), find(first));\n }\n }\n\n const groups = new Map<string, CycleGroup>();\n for (const cycle of cycles) {\n const [first] = cycle;\n if (first === undefined) continue;\n const key = find(first);\n const group = groups.get(key) ?? { files: [], chainCount: 0 };\n group.chainCount += 1;\n group.files = [...new Set([...group.files, ...cycle])];\n groups.set(key, group);\n }\n\n return [...groups.values()];\n};\n\nexport const checkCircularCommand = async (argv: string[]): Promise<void> => {\n const warnOnly = argv.includes('--warn') || !!process.env.QPQ_CIRCULAR_DEPS_WARN;\n\n const cycles = await findWorkspaceImportCycles(getRoot());\n\n if (cycles.length === 0) {\n out.log('check:circular: no circular imports found');\n return;\n }\n\n const groups = groupCycles(cycles);\n\n const colour = warnOnly ? '\\x1b[33m' : '\\x1b[31m';\n for (const group of groups) {\n const chainNote = group.chainCount > 1 ? `, ${group.chainCount} distinct loops` : '';\n out.warn(`${colour}Circular imports (${group.files.length} files${chainNote}):\\n ${group.files.join('\\n ')}\\x1b[0m`);\n }\n out.warn(`${colour}check:circular: ${groups.length} circular import group(s) found (${cycles.length} loops)\\x1b[0m`);\n\n if (!warnOnly) {\n process.exitCode = 1;\n }\n};\n"]}
@@ -1,23 +1,17 @@
1
- // `qpq clear-resources` — interactively EMPTY selected data resources (storage
1
+ // `qpq clear-resources`, interactively EMPTY selected data resources (storage
2
2
  // drive buckets, key value store tables) without touching the stacks: the
3
3
  // "reset my data" counterpart to `qpq teardown`. Resolves the app +
4
4
  // deployment the same way as go/teardown, enumerates the app's owned
5
5
  // resources from its live qpq configs, multi-selects what to empty (with a
6
- // typed confirmation — this deletes stored data), then hands off to the
6
+ // typed confirmation, this deletes stored data), then hands off to the
7
7
  // platform driver.
8
8
  import { promptClearResourcesPlan } from '../lib/clearResourcesPlan';
9
- import { resolveAppSelection } from '../lib/resolveAppSelection';
10
- import { resolveDeployment } from '../lib/resolveDeployment';
11
- import { getPlatformDriver } from '../platforms';
9
+ import { requireDriverCapability } from '../lib/requireDriverCapability';
10
+ import { resolveCommandContext } from '../lib/resolveCommandContext';
12
11
  export const clearResourcesCommand = async (argv) => {
13
- const appName = await resolveAppSelection({ argv, envVar: 'DEPLOY_APP_NAME' });
14
- const { deployment } = await resolveDeployment(argv, appName);
15
- const driver = getPlatformDriver(deployment.platform);
16
- if (!driver.clearResources) {
17
- console.error(`The '${deployment.platform}' platform has no clear-resources strategy.`);
18
- process.exit(1);
19
- }
20
- const plan = await promptClearResourcesPlan(appName);
21
- await driver.clearResources(appName, plan);
12
+ const context = await resolveCommandContext(argv);
13
+ const clearResources = requireDriverCapability(context, 'clearResources');
14
+ const plan = await promptClearResourcesPlan(context.appName);
15
+ await clearResources(context.appName, plan);
22
16
  };
23
17
  //# sourceMappingURL=clearResources.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"clearResources.js","sourceRoot":"","sources":["../../../src/commands/clearResources.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,0EAA0E;AAC1E,oEAAoE;AACpE,qEAAqE;AACrE,2EAA2E;AAC3E,wEAAwE;AACxE,mBAAmB;AACnB,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EAAE,IAAc,EAAiB,EAAE;IAC3E,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC/E,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEtD,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC3B,OAAO,CAAC,KAAK,CAAC,QAAQ,UAAU,CAAC,QAAQ,6CAA6C,CAAC,CAAC;QACxF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,CAAC;IAErD,MAAM,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC,CAAC","sourcesContent":["// `qpq clear-resources` — interactively EMPTY selected data resources (storage\n// drive buckets, key value store tables) without touching the stacks: the\n// \"reset my data\" counterpart to `qpq teardown`. Resolves the app +\n// deployment the same way as go/teardown, enumerates the app's owned\n// resources from its live qpq configs, multi-selects what to empty (with a\n// typed confirmation — this deletes stored data), then hands off to the\n// platform driver.\nimport { promptClearResourcesPlan } from '../lib/clearResourcesPlan';\nimport { resolveAppSelection } from '../lib/resolveAppSelection';\nimport { resolveDeployment } from '../lib/resolveDeployment';\nimport { getPlatformDriver } from '../platforms';\n\nexport const clearResourcesCommand = async (argv: string[]): Promise<void> => {\n const appName = await resolveAppSelection({ argv, envVar: 'DEPLOY_APP_NAME' });\n const { deployment } = await resolveDeployment(argv, appName);\n const driver = getPlatformDriver(deployment.platform);\n\n if (!driver.clearResources) {\n console.error(`The '${deployment.platform}' platform has no clear-resources strategy.`);\n process.exit(1);\n }\n\n const plan = await promptClearResourcesPlan(appName);\n\n await driver.clearResources(appName, plan);\n};\n"]}
1
+ {"version":3,"file":"clearResources.js","sourceRoot":"","sources":["../../../src/commands/clearResources.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0EAA0E;AAC1E,oEAAoE;AACpE,qEAAqE;AACrE,2EAA2E;AAC3E,uEAAuE;AACvE,mBAAmB;AACnB,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EAAE,IAAc,EAAiB,EAAE;IAC3E,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,uBAAuB,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAE1E,MAAM,IAAI,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAE7D,MAAM,cAAc,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC,CAAC","sourcesContent":["// `qpq clear-resources`, interactively EMPTY selected data resources (storage\n// drive buckets, key value store tables) without touching the stacks: the\n// \"reset my data\" counterpart to `qpq teardown`. Resolves the app +\n// deployment the same way as go/teardown, enumerates the app's owned\n// resources from its live qpq configs, multi-selects what to empty (with a\n// typed confirmation, this deletes stored data), then hands off to the\n// platform driver.\nimport { promptClearResourcesPlan } from '../lib/clearResourcesPlan';\nimport { requireDriverCapability } from '../lib/requireDriverCapability';\nimport { resolveCommandContext } from '../lib/resolveCommandContext';\n\nexport const clearResourcesCommand = async (argv: string[]): Promise<void> => {\n const context = await resolveCommandContext(argv);\n const clearResources = requireDriverCapability(context, 'clearResources');\n\n const plan = await promptClearResourcesPlan(context.appName);\n\n await clearResources(context.appName, plan);\n};\n"]}
@@ -1,14 +1,10 @@
1
- // `qpq go` — interactive deploy. Resolves the app + deployment (whose entry in
1
+ // `qpq go`, interactive deploy. Resolves the app + deployment (whose entry in
2
2
  // apps/<app>/deploy.config.json names the platform), asks the deploy plan, then
3
3
  // hands off to the platform driver.
4
4
  import { buildDeployPlanFromArgs, promptDeployPlan } from '../lib/deployPrompts';
5
- import { resolveAppSelection } from '../lib/resolveAppSelection';
6
- import { resolveDeployment } from '../lib/resolveDeployment';
7
- import { getPlatformDriver } from '../platforms';
5
+ import { resolveCommandContext } from '../lib/resolveCommandContext';
8
6
  export const goCommand = async (argv) => {
9
- const appName = await resolveAppSelection({ argv, envVar: 'DEPLOY_APP_NAME' });
10
- const { deployment } = await resolveDeployment(argv, appName);
11
- const driver = getPlatformDriver(deployment.platform);
7
+ const { appName, driver } = await resolveCommandContext(argv);
12
8
  // Positional args (`qpq go all all`) run prompt-free; otherwise ask.
13
9
  const plan = buildDeployPlanFromArgs(appName, argv) ?? (await promptDeployPlan(appName));
14
10
  await driver.go(appName, plan);
@@ -1 +1 @@
1
- {"version":3,"file":"go.js","sourceRoot":"","sources":["../../../src/commands/go.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,gFAAgF;AAChF,oCAAoC;AACpC,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAAE,IAAc,EAAiB,EAAE;IAC/D,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC/E,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEtD,qEAAqE;IACrE,MAAM,IAAI,GAAG,uBAAuB,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzF,MAAM,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC,CAAC","sourcesContent":["// `qpq go` — interactive deploy. Resolves the app + deployment (whose entry in\n// apps/<app>/deploy.config.json names the platform), asks the deploy plan, then\n// hands off to the platform driver.\nimport { buildDeployPlanFromArgs, promptDeployPlan } from '../lib/deployPrompts';\nimport { resolveAppSelection } from '../lib/resolveAppSelection';\nimport { resolveDeployment } from '../lib/resolveDeployment';\nimport { getPlatformDriver } from '../platforms';\n\nexport const goCommand = async (argv: string[]): Promise<void> => {\n const appName = await resolveAppSelection({ argv, envVar: 'DEPLOY_APP_NAME' });\n const { deployment } = await resolveDeployment(argv, appName);\n const driver = getPlatformDriver(deployment.platform);\n\n // Positional args (`qpq go all all`) run prompt-free; otherwise ask.\n const plan = buildDeployPlanFromArgs(appName, argv) ?? (await promptDeployPlan(appName));\n\n await driver.go(appName, plan);\n};\n"]}
1
+ {"version":3,"file":"go.js","sourceRoot":"","sources":["../../../src/commands/go.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,gFAAgF;AAChF,oCAAoC;AACpC,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAAE,IAAc,EAAiB,EAAE;IAC/D,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAE9D,qEAAqE;IACrE,MAAM,IAAI,GAAG,uBAAuB,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzF,MAAM,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC,CAAC","sourcesContent":["// `qpq go`, interactive deploy. Resolves the app + deployment (whose entry in\n// apps/<app>/deploy.config.json names the platform), asks the deploy plan, then\n// hands off to the platform driver.\nimport { buildDeployPlanFromArgs, promptDeployPlan } from '../lib/deployPrompts';\nimport { resolveCommandContext } from '../lib/resolveCommandContext';\n\nexport const goCommand = async (argv: string[]): Promise<void> => {\n const { appName, driver } = await resolveCommandContext(argv);\n\n // Positional args (`qpq go all all`) run prompt-free; otherwise ask.\n const plan = buildDeployPlanFromArgs(appName, argv) ?? (await promptDeployPlan(appName));\n\n await driver.go(appName, plan);\n};\n"]}
@@ -1,4 +1,4 @@
1
- // `qpq go:dev` — the whole local dev stack in one process: the API dev server
1
+ // `qpq go:dev`, the whole local dev stack in one process: the API dev server
2
2
  // (go:dev:api) plus every views dev server (go:dev:web), so a single ctrl+c
3
3
  // tears it all down. A background tsc watcher keeps workspace declaration
4
4
  // output fresh for the editor (--no-types to skip it). The app is resolved
@@ -6,11 +6,13 @@
6
6
  // likewise via DEPLOY_NAME, so neither asks again; their output shares the terminal.
7
7
  import { getAllViews } from '@qpqjs/deploy-rspack';
8
8
  import { getRoot } from '../lib/discovery';
9
+ import { createOutput } from '../lib/out';
9
10
  import { resolveAppSelection } from '../lib/resolveAppSelection';
10
11
  import { resolveDeployment } from '../lib/resolveDeployment';
11
12
  import { startTypeWatcher } from '../lib/typeWatcher';
12
13
  import { goDevApiCommand } from './goDevApi';
13
14
  import { goDevWebCommand } from './goDevWeb';
15
+ const out = createOutput('go:dev');
14
16
  export const goDevCommand = async (argv) => {
15
17
  const appName = await resolveAppSelection({ argv, envVar: 'QPQ_DEV_APP' });
16
18
  process.env.QPQ_DEV_APP = appName;
@@ -25,7 +27,7 @@ export const goDevCommand = async (argv) => {
25
27
  // the background of this process.
26
28
  await goDevApiCommand(argv);
27
29
  if (getAllViews(getRoot(), appName).length === 0) {
28
- console.log('No views projects found. Running the API dev server only.');
30
+ out.log('No views projects found. Running the API dev server only.');
29
31
  return;
30
32
  }
31
33
  await goDevWebCommand(argv, { hideStartedStatus: true });
@@ -1 +1 @@
1
- {"version":3,"file":"goDev.js","sourceRoot":"","sources":["../../../src/commands/goDev.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,0EAA0E;AAC1E,2EAA2E;AAC3E,4EAA4E;AAC5E,qFAAqF;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,IAAc,EAAiB,EAAE;IAClE,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,OAAO,CAAC;IAClC,MAAM,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAEvC,uEAAuE;IACvE,8DAA8D;IAC9D,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC;IACrF,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,0EAA0E;IAC1E,kCAAkC;IAClC,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAE5B,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;QACzE,OAAO;IACT,CAAC;IAED,MAAM,eAAe,CAAC,IAAI,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3D,CAAC,CAAC","sourcesContent":["// `qpq go:dev` — the whole local dev stack in one process: the API dev server\n// (go:dev:api) plus every views dev server (go:dev:web), so a single ctrl+c\n// tears it all down. A background tsc watcher keeps workspace declaration\n// output fresh for the editor (--no-types to skip it). The app is resolved\n// once here and handed to both sub-commands via QPQ_DEV_APP, the deployment\n// likewise via DEPLOY_NAME, so neither asks again; their output shares the terminal.\nimport { getAllViews } from '@qpqjs/deploy-rspack';\n\nimport { getRoot } from '../lib/discovery';\nimport { resolveAppSelection } from '../lib/resolveAppSelection';\nimport { resolveDeployment } from '../lib/resolveDeployment';\nimport { startTypeWatcher } from '../lib/typeWatcher';\nimport { goDevApiCommand } from './goDevApi';\nimport { goDevWebCommand } from './goDevWeb';\n\nexport const goDevCommand = async (argv: string[]): Promise<void> => {\n const appName = await resolveAppSelection({ argv, envVar: 'QPQ_DEV_APP' });\n process.env.QPQ_DEV_APP = appName;\n await resolveDeployment(argv, appName);\n\n // Editor/type freshness only: the rspack builds below bundle workspace\n // source directly, so the dev loop itself never waits on tsc.\n const typeWatcher = argv.includes('--no-types') ? null : startTypeWatcher(getRoot());\n if (typeWatcher) {\n process.on('exit', () => typeWatcher.kill());\n }\n\n // Kicks off the rspack watch and returns; the API server keeps running in\n // the background of this process.\n await goDevApiCommand(argv);\n\n if (getAllViews(getRoot(), appName).length === 0) {\n console.log('No views projects found. Running the API dev server only.');\n return;\n }\n\n await goDevWebCommand(argv, { hideStartedStatus: true });\n};\n"]}
1
+ {"version":3,"file":"goDev.js","sourceRoot":"","sources":["../../../src/commands/goDev.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,4EAA4E;AAC5E,0EAA0E;AAC1E,2EAA2E;AAC3E,4EAA4E;AAC5E,qFAAqF;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;AAEnC,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,IAAc,EAAiB,EAAE;IAClE,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,OAAO,CAAC;IAClC,MAAM,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAEvC,uEAAuE;IACvE,8DAA8D;IAC9D,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC;IACrF,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,0EAA0E;IAC1E,kCAAkC;IAClC,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAE5B,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjD,GAAG,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;QACrE,OAAO;IACT,CAAC;IAED,MAAM,eAAe,CAAC,IAAI,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3D,CAAC,CAAC","sourcesContent":["// `qpq go:dev`, the whole local dev stack in one process: the API dev server\n// (go:dev:api) plus every views dev server (go:dev:web), so a single ctrl+c\n// tears it all down. A background tsc watcher keeps workspace declaration\n// output fresh for the editor (--no-types to skip it). The app is resolved\n// once here and handed to both sub-commands via QPQ_DEV_APP, the deployment\n// likewise via DEPLOY_NAME, so neither asks again; their output shares the terminal.\nimport { getAllViews } from '@qpqjs/deploy-rspack';\n\nimport { getRoot } from '../lib/discovery';\nimport { createOutput } from '../lib/out';\nimport { resolveAppSelection } from '../lib/resolveAppSelection';\nimport { resolveDeployment } from '../lib/resolveDeployment';\nimport { startTypeWatcher } from '../lib/typeWatcher';\nimport { goDevApiCommand } from './goDevApi';\nimport { goDevWebCommand } from './goDevWeb';\n\nconst out = createOutput('go:dev');\n\nexport const goDevCommand = async (argv: string[]): Promise<void> => {\n const appName = await resolveAppSelection({ argv, envVar: 'QPQ_DEV_APP' });\n process.env.QPQ_DEV_APP = appName;\n await resolveDeployment(argv, appName);\n\n // Editor/type freshness only: the rspack builds below bundle workspace\n // source directly, so the dev loop itself never waits on tsc.\n const typeWatcher = argv.includes('--no-types') ? null : startTypeWatcher(getRoot());\n if (typeWatcher) {\n process.on('exit', () => typeWatcher.kill());\n }\n\n // Kicks off the rspack watch and returns; the API server keeps running in\n // the background of this process.\n await goDevApiCommand(argv);\n\n if (getAllViews(getRoot(), appName).length === 0) {\n out.log('No views projects found. Running the API dev server only.');\n return;\n }\n\n await goDevWebCommand(argv, { hideStartedStatus: true });\n};\n"]}
@@ -1,4 +1,4 @@
1
- // `qpq go:dev:api` — boots the QPQ local dev server. Resolves the app,
1
+ // `qpq go:dev:api`, boots the QPQ local dev server. Resolves the app,
2
2
  // generates the dev-server entry, builds the rspack config, then runs rspack
3
3
  // in watch mode, restarting the server process on every successful rebuild.
4
4
  //
@@ -8,10 +8,10 @@
8
8
  //
9
9
  // The one thing NOT hot-reloaded is the qpq configs themselves: each service's
10
10
  // infrastructure.ts is evaluated once at launch and baked into the
11
- // `quidproquo-dynamic-loader` virtual module — config changes need a full
11
+ // `quidproquo-dynamic-loader` virtual module, config changes need a full
12
12
  // `go:dev:api` restart.
13
+ import { getDevServerDistPath } from '@qpqjs/core';
13
14
  import { getAppServiceQpqConfigs, getDevServerRspackConfig } from '@qpqjs/deploy-rspack';
14
- import { spawn } from 'child_process';
15
15
  import path from 'path';
16
16
  import { rspack } from '@rspack/core';
17
17
  import { hasArgFlag } from '../lib/args';
@@ -21,51 +21,54 @@ import { getRoot } from '../lib/discovery';
21
21
  import { KEEP_OTHER_DEV_SERVERS_FLAG } from '../lib/keepOtherDevServersFlag';
22
22
  import { killChildWithEscalation } from '../lib/killChildWithEscalation';
23
23
  import { killOtherQpqDevProcesses, killStaleListeners, reportPortHolders } from '../lib/killStaleListeners';
24
+ import { createOutput } from '../lib/out';
24
25
  import { resolveAppSelection } from '../lib/resolveAppSelection';
25
26
  import { resolveDeployment } from '../lib/resolveDeployment';
27
+ import { spawnCommand } from '../lib/runCommand';
28
+ const out = createOutput('go:dev:api');
26
29
  // 8080/8888 are set in the generated entry; 3001 is the @qpqjs/dev-server
27
30
  // file-storage (secure URL) default port.
28
31
  const getDevServerPortList = (appName) => Object.values(readDevServerPorts(appName));
29
- const DEV_SERVER_BUNDLE_PATH = path.join('dist', 'qpq', 'dev-server', 'main.js');
32
+ const getDevServerBundlePath = (root) => path.join(getDevServerDistPath(root), 'main.js');
30
33
  export const goDevApiCommand = async (argv) => {
31
34
  const root = getRoot();
32
35
  const appName = await resolveAppSelection({ argv, envVar: 'QPQ_DEV_APP' });
33
36
  process.env.QPQ_DEV_APP = appName;
34
37
  await resolveDeployment(argv, appName);
35
- console.log(`Dev server for app [${appName}]`);
38
+ out.log(`Dev server for app [${appName}]`);
36
39
  // The sweep matches on a RELATIVE bundle path, so every checkout's dev
37
40
  // server looks like ours and a sibling worktree gets taken down with it.
38
41
  // Opting out spares it, at the cost of this one not starting: the ports are
39
42
  // the same either way, so what you get instead is EADDRINUSE. Report who
40
43
  // holds them, or that failure says nothing about the cause.
41
44
  if (hasArgFlag(argv, KEEP_OTHER_DEV_SERVERS_FLAG)) {
42
- console.log(`${KEEP_OTHER_DEV_SERVERS_FLAG}: leaving other dev servers alone.`);
45
+ out.log(`${KEEP_OTHER_DEV_SERVERS_FLAG}: leaving other dev servers alone.`);
43
46
  reportPortHolders(getDevServerPortList(appName));
44
47
  }
45
48
  else {
46
49
  // Catches a lingering watcher from a previous run even if its spawned
47
- // child already exited (see killOtherQpqDevProcesses) — then the usual
50
+ // child already exited (see killOtherQpqDevProcesses), then the usual
48
51
  // port-based sweep for anything else still bound to our ports.
49
52
  killOtherQpqDevProcesses(root);
50
- killStaleListeners(getDevServerPortList(appName), (command) => command.includes(DEV_SERVER_BUNDLE_PATH));
53
+ killStaleListeners(getDevServerPortList(appName), (command) => command.includes(getDevServerBundlePath(root)));
51
54
  }
52
55
  const qpqConfigs = getAppServiceQpqConfigs(root, appName);
53
56
  const entry = writeDevServerEntry(root, appName);
54
57
  const userScriptChildEntry = writeUserScriptChildEntry(root);
55
58
  const rspackConfig = getDevServerRspackConfig({ root, entry, userScriptChildEntry, qpqConfigs });
56
- const bundlePath = path.join(root, DEV_SERVER_BUNDLE_PATH);
57
- const env = { ...process.env, QPQ_DEV_APP: appName };
59
+ const bundlePath = getDevServerBundlePath(root);
60
+ const env = { QPQ_DEV_APP: appName };
58
61
  // The long-lived server process (HTTP 8080 / WS 8888), restarted per rebuild.
59
62
  let child = null;
60
63
  let restartQueued = false;
61
64
  const startServer = () => {
62
- child = spawn('node', [bundlePath], { stdio: 'inherit', env });
65
+ child = spawnCommand('node', [bundlePath], { env });
63
66
  child.on('exit', (code) => {
64
67
  child = null;
65
68
  if (!restartQueued) {
66
- // Crashed (or exited) on its own — leave it down; the next successful
69
+ // Crashed (or exited) on its own, leave it down; the next successful
67
70
  // rebuild (i.e. the next file save) brings it back up.
68
- console.log(`Dev server exited with code ${code}. Save a file to restart it.`);
71
+ out.log(`Dev server exited with code ${code}. Save a file to restart it.`);
69
72
  }
70
73
  });
71
74
  };
@@ -86,17 +89,17 @@ export const goDevApiCommand = async (argv) => {
86
89
  // the exit is what keeps the ports free for the replacement.
87
90
  void killChildWithEscalation(child);
88
91
  };
89
- console.log('Bundling dev server (watch mode)...');
92
+ out.log('Bundling dev server (watch mode)...');
90
93
  let lastHash;
91
94
  const compiler = rspack(rspackConfig);
92
95
  compiler.watch({ aggregateTimeout: 200 }, (err, stats) => {
93
96
  if (err) {
94
- console.error(err);
97
+ out.error(err);
95
98
  return;
96
99
  }
97
100
  if (stats?.hasErrors()) {
98
- console.error(stats.toString({ colors: true, chunks: false, modules: false }));
99
- console.log('Build failed — dev server not restarted. Fix the error and save again.');
101
+ out.error(stats.toString({ colors: true, chunks: false, modules: false }));
102
+ out.log('Build failed — dev server not restarted. Fix the error and save again.');
100
103
  return;
101
104
  }
102
105
  // Skip no-op rebuilds (e.g. the virtual-module-triggered second compile at
@@ -105,7 +108,7 @@ export const goDevApiCommand = async (argv) => {
105
108
  return;
106
109
  }
107
110
  lastHash = stats?.hash;
108
- console.log(child ? 'Rebuilt. Restarting dev server...' : 'Dev server bundled. Starting...');
111
+ out.log(child ? 'Rebuilt. Restarting dev server...' : 'Dev server bundled. Starting...');
109
112
  restartServer();
110
113
  });
111
114
  // Wait for the server to finish draining before tearing the watcher down and
@@ -1 +1 @@
1
- {"version":3,"file":"goDevApi.js","sourceRoot":"","sources":["../../../src/commands/goDevApi.ts"],"names":[],"mappings":"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","sourcesContent":["// `qpq go:dev:api` — boots the QPQ local dev server. Resolves the app,\n// generates the dev-server entry, builds the rspack config, then runs rspack\n// in watch mode, restarting the server process on every successful rebuild.\n//\n// A restart is not instant: the server drains in-flight work and checkpoints\n// its stores on the way out (typically tens of ms, 5s worst case), and this\n// command waits for that before starting the replacement.\n//\n// The one thing NOT hot-reloaded is the qpq configs themselves: each service's\n// infrastructure.ts is evaluated once at launch and baked into the\n// `quidproquo-dynamic-loader` virtual module — config changes need a full\n// `go:dev:api` restart.\nimport { getAppServiceQpqConfigs, getDevServerRspackConfig } from '@qpqjs/deploy-rspack';\n\nimport { ChildProcess, spawn } from 'child_process';\nimport fs from 'fs';\nimport path from 'path';\nimport { rspack } from '@rspack/core';\n\nimport { hasArgFlag } from '../lib/args';\nimport { writeDevServerEntry, writeUserScriptChildEntry } from '../lib/devServerEntry';\nimport { readDevServerPorts } from '../lib/devServerPorts';\nimport { getRoot } from '../lib/discovery';\nimport { KEEP_OTHER_DEV_SERVERS_FLAG } from '../lib/keepOtherDevServersFlag';\nimport { killChildWithEscalation } from '../lib/killChildWithEscalation';\nimport { killOtherQpqDevProcesses, killStaleListeners, reportPortHolders } from '../lib/killStaleListeners';\nimport { resolveAppSelection } from '../lib/resolveAppSelection';\nimport { resolveDeployment } from '../lib/resolveDeployment';\n\n// 8080/8888 are set in the generated entry; 3001 is the @qpqjs/dev-server\n// file-storage (secure URL) default port.\nconst getDevServerPortList = (appName: string): number[] => Object.values(readDevServerPorts(appName));\nconst DEV_SERVER_BUNDLE_PATH = path.join('dist', 'qpq', 'dev-server', 'main.js');\n\nexport const goDevApiCommand = async (argv: string[]): Promise<void> => {\n const root = getRoot();\n const appName = await resolveAppSelection({ argv, envVar: 'QPQ_DEV_APP' });\n process.env.QPQ_DEV_APP = appName;\n await resolveDeployment(argv, appName);\n console.log(`Dev server for app [${appName}]`);\n\n // The sweep matches on a RELATIVE bundle path, so every checkout's dev\n // server looks like ours and a sibling worktree gets taken down with it.\n // Opting out spares it, at the cost of this one not starting: the ports are\n // the same either way, so what you get instead is EADDRINUSE. Report who\n // holds them, or that failure says nothing about the cause.\n if (hasArgFlag(argv, KEEP_OTHER_DEV_SERVERS_FLAG)) {\n console.log(`${KEEP_OTHER_DEV_SERVERS_FLAG}: leaving other dev servers alone.`);\n reportPortHolders(getDevServerPortList(appName));\n } else {\n // Catches a lingering watcher from a previous run even if its spawned\n // child already exited (see killOtherQpqDevProcesses) — then the usual\n // port-based sweep for anything else still bound to our ports.\n killOtherQpqDevProcesses(root);\n killStaleListeners(getDevServerPortList(appName), (command) => command.includes(DEV_SERVER_BUNDLE_PATH));\n }\n\n const qpqConfigs = getAppServiceQpqConfigs(root, appName);\n const entry = writeDevServerEntry(root, appName);\n const userScriptChildEntry = writeUserScriptChildEntry(root);\n const rspackConfig = getDevServerRspackConfig({ root, entry, userScriptChildEntry, qpqConfigs });\n const bundlePath = path.join(root, DEV_SERVER_BUNDLE_PATH);\n const env = { ...process.env, QPQ_DEV_APP: appName };\n\n // The long-lived server process (HTTP 8080 / WS 8888), restarted per rebuild.\n let child: ChildProcess | null = null;\n let restartQueued = false;\n\n const startServer = (): void => {\n child = spawn('node', [bundlePath], { stdio: 'inherit', env });\n child.on('exit', (code) => {\n child = null;\n if (!restartQueued) {\n // Crashed (or exited) on its own — leave it down; the next successful\n // rebuild (i.e. the next file save) brings it back up.\n console.log(`Dev server exited with code ${code}. Save a file to restart it.`);\n }\n });\n };\n\n const restartServer = (): void => {\n if (restartQueued) return;\n if (!child) {\n startServer();\n return;\n }\n restartQueued = true;\n child.once('exit', () => {\n restartQueued = false;\n startServer();\n });\n\n // Not a bare kill: the server drains in-flight work before it exits, so it\n // needs asking properly and then a hard backstop if it wedges. Waiting for\n // the exit is what keeps the ports free for the replacement.\n void killChildWithEscalation(child);\n };\n\n console.log('Bundling dev server (watch mode)...');\n let lastHash: string | null | undefined;\n const compiler = rspack(rspackConfig);\n compiler.watch({ aggregateTimeout: 200 }, (err, stats) => {\n if (err) {\n console.error(err);\n return;\n }\n if (stats?.hasErrors()) {\n console.error(stats.toString({ colors: true, chunks: false, modules: false }));\n console.log('Build failed — dev server not restarted. Fix the error and save again.');\n return;\n }\n // Skip no-op rebuilds (e.g. the virtual-module-triggered second compile at\n // startup): only restart when the output actually changed.\n if (stats?.hash === lastHash && child) {\n return;\n }\n lastHash = stats?.hash;\n console.log(child ? 'Rebuilt. Restarting dev server...' : 'Dev server bundled. Starting...');\n restartServer();\n });\n\n // Wait for the server to finish draining before tearing the watcher down and\n // exiting: closing the compiler first would exit the parent while the child\n // is still writing, which is the race this whole path exists to close.\n //\n // SIGTERM as well as SIGINT, and it is load-bearing rather than symmetry for\n // its own sake. This process is a WRAPPER: the dev server that handles\n // signals and drains its work is the child it spawned. Without a handler\n // here, SIGTERM (what `docker stop` sends, and what any script stopping this\n // programmatically sends) kills the wrapper outright on the default\n // disposition, the child never gets asked to stop, and every guarantee the\n // dev server's shutdown sequence makes is bypassed. go:dev:web already\n // handles both.\n let shuttingDown = false;\n\n const handleShutdownSignal = async (): Promise<void> => {\n if (shuttingDown) {\n return;\n }\n shuttingDown = true;\n\n restartQueued = true; // suppress the crash log / rebuild-restart on our own kill\n\n if (child) {\n await killChildWithEscalation(child);\n }\n\n compiler.close(() => process.exit(0));\n };\n\n process.on('SIGINT', () => {\n void handleShutdownSignal();\n });\n\n process.on('SIGTERM', () => {\n void handleShutdownSignal();\n });\n};\n"]}
1
+ {"version":3,"file":"goDevApi.js","sourceRoot":"","sources":["../../../src/commands/goDevApi.ts"],"names":[],"mappings":"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","sourcesContent":["// `qpq go:dev:api`, boots the QPQ local dev server. Resolves the app,\n// generates the dev-server entry, builds the rspack config, then runs rspack\n// in watch mode, restarting the server process on every successful rebuild.\n//\n// A restart is not instant: the server drains in-flight work and checkpoints\n// its stores on the way out (typically tens of ms, 5s worst case), and this\n// command waits for that before starting the replacement.\n//\n// The one thing NOT hot-reloaded is the qpq configs themselves: each service's\n// infrastructure.ts is evaluated once at launch and baked into the\n// `quidproquo-dynamic-loader` virtual module, config changes need a full\n// `go:dev:api` restart.\nimport { getDevServerDistPath, Nullable } from '@qpqjs/core';\nimport { getAppServiceQpqConfigs, getDevServerRspackConfig } from '@qpqjs/deploy-rspack';\n\nimport { ChildProcess } from 'child_process';\nimport path from 'path';\nimport { rspack } from '@rspack/core';\n\nimport { hasArgFlag } from '../lib/args';\nimport { writeDevServerEntry, writeUserScriptChildEntry } from '../lib/devServerEntry';\nimport { readDevServerPorts } from '../lib/devServerPorts';\nimport { getRoot } from '../lib/discovery';\nimport { KEEP_OTHER_DEV_SERVERS_FLAG } from '../lib/keepOtherDevServersFlag';\nimport { killChildWithEscalation } from '../lib/killChildWithEscalation';\nimport { killOtherQpqDevProcesses, killStaleListeners, reportPortHolders } from '../lib/killStaleListeners';\nimport { createOutput } from '../lib/out';\nimport { resolveAppSelection } from '../lib/resolveAppSelection';\nimport { resolveDeployment } from '../lib/resolveDeployment';\nimport { spawnCommand } from '../lib/runCommand';\n\nconst out = createOutput('go:dev:api');\n\n// 8080/8888 are set in the generated entry; 3001 is the @qpqjs/dev-server\n// file-storage (secure URL) default port.\nconst getDevServerPortList = (appName: string): number[] => Object.values(readDevServerPorts(appName));\nconst getDevServerBundlePath = (root: string): string => path.join(getDevServerDistPath(root), 'main.js');\n\nexport const goDevApiCommand = async (argv: string[]): Promise<void> => {\n const root = getRoot();\n const appName = await resolveAppSelection({ argv, envVar: 'QPQ_DEV_APP' });\n process.env.QPQ_DEV_APP = appName;\n await resolveDeployment(argv, appName);\n out.log(`Dev server for app [${appName}]`);\n\n // The sweep matches on a RELATIVE bundle path, so every checkout's dev\n // server looks like ours and a sibling worktree gets taken down with it.\n // Opting out spares it, at the cost of this one not starting: the ports are\n // the same either way, so what you get instead is EADDRINUSE. Report who\n // holds them, or that failure says nothing about the cause.\n if (hasArgFlag(argv, KEEP_OTHER_DEV_SERVERS_FLAG)) {\n out.log(`${KEEP_OTHER_DEV_SERVERS_FLAG}: leaving other dev servers alone.`);\n reportPortHolders(getDevServerPortList(appName));\n } else {\n // Catches a lingering watcher from a previous run even if its spawned\n // child already exited (see killOtherQpqDevProcesses), then the usual\n // port-based sweep for anything else still bound to our ports.\n killOtherQpqDevProcesses(root);\n killStaleListeners(getDevServerPortList(appName), (command) => command.includes(getDevServerBundlePath(root)));\n }\n\n const qpqConfigs = getAppServiceQpqConfigs(root, appName);\n const entry = writeDevServerEntry(root, appName);\n const userScriptChildEntry = writeUserScriptChildEntry(root);\n const rspackConfig = getDevServerRspackConfig({ root, entry, userScriptChildEntry, qpqConfigs });\n const bundlePath = getDevServerBundlePath(root);\n const env = { QPQ_DEV_APP: appName };\n\n // The long-lived server process (HTTP 8080 / WS 8888), restarted per rebuild.\n let child: Nullable<ChildProcess> = null;\n let restartQueued = false;\n\n const startServer = (): void => {\n child = spawnCommand('node', [bundlePath], { env });\n child.on('exit', (code) => {\n child = null;\n if (!restartQueued) {\n // Crashed (or exited) on its own, leave it down; the next successful\n // rebuild (i.e. the next file save) brings it back up.\n out.log(`Dev server exited with code ${code}. Save a file to restart it.`);\n }\n });\n };\n\n const restartServer = (): void => {\n if (restartQueued) return;\n if (!child) {\n startServer();\n return;\n }\n restartQueued = true;\n child.once('exit', () => {\n restartQueued = false;\n startServer();\n });\n\n // Not a bare kill: the server drains in-flight work before it exits, so it\n // needs asking properly and then a hard backstop if it wedges. Waiting for\n // the exit is what keeps the ports free for the replacement.\n void killChildWithEscalation(child);\n };\n\n out.log('Bundling dev server (watch mode)...');\n let lastHash: string | null | undefined;\n const compiler = rspack(rspackConfig);\n compiler.watch({ aggregateTimeout: 200 }, (err, stats) => {\n if (err) {\n out.error(err);\n return;\n }\n if (stats?.hasErrors()) {\n out.error(stats.toString({ colors: true, chunks: false, modules: false }));\n out.log('Build failed — dev server not restarted. Fix the error and save again.');\n return;\n }\n // Skip no-op rebuilds (e.g. the virtual-module-triggered second compile at\n // startup): only restart when the output actually changed.\n if (stats?.hash === lastHash && child) {\n return;\n }\n lastHash = stats?.hash;\n out.log(child ? 'Rebuilt. Restarting dev server...' : 'Dev server bundled. Starting...');\n restartServer();\n });\n\n // Wait for the server to finish draining before tearing the watcher down and\n // exiting: closing the compiler first would exit the parent while the child\n // is still writing, which is the race this whole path exists to close.\n //\n // SIGTERM as well as SIGINT, and it is load-bearing rather than symmetry for\n // its own sake. This process is a WRAPPER: the dev server that handles\n // signals and drains its work is the child it spawned. Without a handler\n // here, SIGTERM (what `docker stop` sends, and what any script stopping this\n // programmatically sends) kills the wrapper outright on the default\n // disposition, the child never gets asked to stop, and every guarantee the\n // dev server's shutdown sequence makes is bypassed. go:dev:web already\n // handles both.\n let shuttingDown = false;\n\n const handleShutdownSignal = async (): Promise<void> => {\n if (shuttingDown) {\n return;\n }\n shuttingDown = true;\n\n restartQueued = true; // suppress the crash log / rebuild-restart on our own kill\n\n if (child) {\n await killChildWithEscalation(child);\n }\n\n compiler.close(() => process.exit(0));\n };\n\n process.on('SIGINT', () => {\n void handleShutdownSignal();\n });\n\n process.on('SIGTERM', () => {\n void handleShutdownSignal();\n });\n};\n"]}
@@ -1,7 +1,7 @@
1
- // `qpq go:dev:web` — boots every views microfrontend's Rspack dev server
1
+ // `qpq go:dev:web`, boots every views microfrontend's Rspack dev server
2
2
  // in-process (shell is the MF host app, plus all remotes on their own ports).
3
3
  // Everything is served dynamically; remotes resolve at runtime via
4
- // mf-manifest.json on localhost ports. Programmatic — no per-views
4
+ // mf-manifest.json on localhost ports. Programmatic, no per-views
5
5
  // rspack.config.ts or npm serve script needed.
6
6
  //
7
7
  // Usage:
@@ -18,9 +18,11 @@ import { readDevServerPorts } from '../lib/devServerPorts';
18
18
  import { getRoot } from '../lib/discovery';
19
19
  import { KEEP_OTHER_DEV_SERVERS_FLAG } from '../lib/keepOtherDevServersFlag';
20
20
  import { isQpqCliCommand, killStaleListeners, reportPortHolders } from '../lib/killStaleListeners';
21
+ import { createOutput } from '../lib/out';
21
22
  import { resolveAppSelection } from '../lib/resolveAppSelection';
22
23
  import { resolveDeployment } from '../lib/resolveDeployment';
23
24
  import { setWebAddressingEnv } from '../lib/webAddressingEnv';
25
+ const out = createOutput('go:dev:web');
24
26
  export const goDevWebCommand = async (argv, options = {}) => {
25
27
  const root = getRoot();
26
28
  const appName = await resolveAppSelection({ argv, envVar: 'QPQ_DEV_APP' });
@@ -41,7 +43,7 @@ export const goDevWebCommand = async (argv, options = {}) => {
41
43
  if (only)
42
44
  views = views.filter((v) => only.includes(v.service));
43
45
  if (views.length === 0) {
44
- console.error('No views projects found.');
46
+ out.error('No views projects found.');
45
47
  process.exit(1);
46
48
  }
47
49
  // See goDevApi for why this is opt-out rather than always-on.
@@ -52,14 +54,14 @@ export const goDevWebCommand = async (argv, options = {}) => {
52
54
  killStaleListeners(views.map((v) => v.port), isQpqCliCommand);
53
55
  }
54
56
  // Every RspackDevServer.start() registers its own SIGINT/SIGTERM handler on
55
- // process — with a dozen views servers in one process that trips node's
57
+ // process, with a dozen views servers in one process that trips node's
56
58
  // default 10-listener warning. Size the limit to the fleet.
57
59
  process.setMaxListeners(Math.max(process.getMaxListeners(), views.length * 2 + 10));
58
60
  // Service names are padded to a common width so the "(started)" chips align.
59
61
  const serviceColumnWidth = Math.max(...views.map((v) => v.service.length));
60
- console.log(`Starting ${views.length} views dev servers for [${appName}]:`);
62
+ out.log(`Starting ${views.length} views dev servers for [${appName}]:`);
61
63
  for (const v of views)
62
- console.log(` http://localhost:${v.port} ${v.service.padEnd(serviceColumnWidth)}`);
64
+ out.log(` http://localhost:${v.port} ${v.service.padEnd(serviceColumnWidth)}`);
63
65
  const servers = [];
64
66
  let shuttingDown = false;
65
67
  const shutdown = (code) => {
@@ -74,11 +76,13 @@ export const goDevWebCommand = async (argv, options = {}) => {
74
76
  // below it MUST go through logBelowList to keep the offset accurate.
75
77
  let linesBelowList = 0;
76
78
  const logBelowList = (line) => {
77
- console.log(line);
79
+ out.log(line);
78
80
  linesBelowList += 1;
79
81
  };
80
82
  const markStarted = (index) => {
81
83
  const v = views[index];
84
+ if (!v)
85
+ return;
82
86
  if (!process.stdout.isTTY) {
83
87
  logBelowList(` ${v.service} started`);
84
88
  return;
@@ -93,7 +97,7 @@ export const goDevWebCommand = async (argv, options = {}) => {
93
97
  return;
94
98
  const req = http.get({
95
99
  host: 'localhost',
96
- port: views[index].port,
100
+ port: views[index]?.port,
97
101
  path: '/',
98
102
  timeout: 1000,
99
103
  }, (res) => {
@@ -1 +1 @@
1
- {"version":3,"file":"goDevWeb.js","sourceRoot":"","sources":["../../../src/commands/goDevWeb.ts"],"names":[],"mappings":"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","sourcesContent":["// `qpq go:dev:web` — boots every views microfrontend's Rspack dev server\n// in-process (shell is the MF host app, plus all remotes on their own ports).\n// Everything is served dynamically; remotes resolve at runtime via\n// mf-manifest.json on localhost ports. Programmatic — no per-views\n// rspack.config.ts or npm serve script needed.\n//\n// Usage:\n// qpq go:dev:web\n// qpq go:dev:web --only shell,design\n// qpq go:dev:web --app <name>\nimport { getAllViews, getAppServiceQpqConfigs, getViewsRspackConfig } from '@qpqjs/deploy-rspack';\n\nimport http from 'http';\nimport { rspack } from '@rspack/core';\nimport { RspackDevServer } from '@rspack/dev-server';\n\nimport { getArgValue } from '../lib/args';\nimport { hasArgFlag } from '../lib/args';\nimport { readDevServerPorts } from '../lib/devServerPorts';\nimport { getRoot } from '../lib/discovery';\nimport { KEEP_OTHER_DEV_SERVERS_FLAG } from '../lib/keepOtherDevServersFlag';\nimport { isQpqCliCommand, killStaleListeners, reportPortHolders } from '../lib/killStaleListeners';\nimport { resolveAppSelection } from '../lib/resolveAppSelection';\nimport { resolveDeployment } from '../lib/resolveDeployment';\nimport { setWebAddressingEnv } from '../lib/webAddressingEnv';\n\nexport type GoDevWebOptions = {\n // The in-place \"(started)\" chip rewrite assumes this command owns the\n // terminal; when stdout is shared with the API dev server (combined\n // `qpq go:dev`) the cursor math breaks. The plain-line fallback is just a\n // wall of \" auth started\" noise interleaved with the API output, so drop\n // the ready status altogether there.\n hideStartedStatus?: boolean;\n};\n\nexport const goDevWebCommand = async (argv: string[], options: GoDevWebOptions = {}): Promise<void> => {\n const root = getRoot();\n const appName = await resolveAppSelection({ argv, envVar: 'QPQ_DEV_APP' });\n\n process.env.LOCAL_DEV_SERVER = 'true';\n process.env.NODE_ENV = 'development';\n await resolveDeployment(argv, appName);\n\n // Local pages address the api dev server and each other by port on localhost.\n const devServerPorts = readDevServerPorts(appName);\n setWebAddressingEnv(getAppServiceQpqConfigs(root, appName), {\n api: devServerPorts.api,\n webSocket: devServerPorts.webSocket,\n mapHostPort: (port) => port,\n });\n\n const only = getArgValue(argv, '--only')\n ?.split(',')\n .map((s) => s.trim());\n\n let views = getAllViews(root, appName);\n if (only) views = views.filter((v) => only.includes(v.service));\n if (views.length === 0) {\n console.error('No views projects found.');\n process.exit(1);\n }\n\n // See goDevApi for why this is opt-out rather than always-on.\n if (hasArgFlag(argv, KEEP_OTHER_DEV_SERVERS_FLAG)) {\n reportPortHolders(views.map((v) => v.port));\n } else {\n killStaleListeners(\n views.map((v) => v.port),\n isQpqCliCommand,\n );\n }\n\n // Every RspackDevServer.start() registers its own SIGINT/SIGTERM handler on\n // process — with a dozen views servers in one process that trips node's\n // default 10-listener warning. Size the limit to the fleet.\n process.setMaxListeners(Math.max(process.getMaxListeners(), views.length * 2 + 10));\n\n // Service names are padded to a common width so the \"(started)\" chips align.\n const serviceColumnWidth = Math.max(...views.map((v) => v.service.length));\n\n console.log(`Starting ${views.length} views dev servers for [${appName}]:`);\n for (const v of views) console.log(` http://localhost:${v.port} ${v.service.padEnd(serviceColumnWidth)}`);\n\n const servers: RspackDevServer[] = [];\n let shuttingDown = false;\n\n const shutdown = (code: number): void => {\n if (shuttingDown) return;\n shuttingDown = true;\n Promise.allSettled(servers.map((server) => server.stop())).then(() => process.exit(code));\n };\n\n // The URL list above gets a yellow \"(started)\" chip appended in place as\n // each dev server begins answering HTTP. The in-place rewrite moves the\n // cursor up past everything printed since the list, so every line printed\n // below it MUST go through logBelowList to keep the offset accurate.\n let linesBelowList = 0;\n\n const logBelowList = (line: string): void => {\n console.log(line);\n linesBelowList += 1;\n };\n\n const markStarted = (index: number): void => {\n const v = views[index];\n if (!process.stdout.isTTY) {\n logBelowList(` ${v.service} started`);\n return;\n }\n const line = ` http://localhost:${v.port} ${v.service.padEnd(serviceColumnWidth)} \\x1b[33m(started)\\x1b[0m`;\n const up = linesBelowList + (views.length - index);\n process.stdout.write(`\\x1b[${up}F\\x1b[2K${line}\\x1b[${up}E`);\n };\n\n const pollUntilStarted = (index: number): void => {\n const attempt = (): void => {\n if (shuttingDown) return;\n const req = http.get(\n {\n host: 'localhost',\n port: views[index].port,\n path: '/',\n timeout: 1000,\n },\n (res) => {\n res.resume();\n markStarted(index);\n },\n );\n req.on('error', () => setTimeout(attempt, 500));\n req.on('timeout', () => req.destroy());\n };\n attempt();\n };\n\n for (const [index, view] of views.entries()) {\n const config = getViewsRspackConfig(view.viewsDir);\n const compiler = rspack(config);\n const server = new RspackDevServer(config.devServer || { port: view.port }, compiler);\n servers.push(server);\n\n try {\n await server.start();\n } catch (e) {\n logBelowList(` [${view.service}] failed to start: ${(e as Error).message} — shutting down all views servers.`);\n shutdown(1);\n return;\n }\n\n // markStarted is the only consumer of the ready signal, so there is\n // nothing to poll for when the status is hidden.\n if (!options.hideStartedStatus) pollUntilStarted(index);\n }\n\n process.on('SIGINT', () => shutdown(0));\n process.on('SIGTERM', () => shutdown(0));\n};\n"]}
1
+ {"version":3,"file":"goDevWeb.js","sourceRoot":"","sources":["../../../src/commands/goDevWeb.ts"],"names":[],"mappings":"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","sourcesContent":["// `qpq go:dev:web`, boots every views microfrontend's Rspack dev server\n// in-process (shell is the MF host app, plus all remotes on their own ports).\n// Everything is served dynamically; remotes resolve at runtime via\n// mf-manifest.json on localhost ports. Programmatic, no per-views\n// rspack.config.ts or npm serve script needed.\n//\n// Usage:\n// qpq go:dev:web\n// qpq go:dev:web --only shell,design\n// qpq go:dev:web --app <name>\nimport { getAllViews, getAppServiceQpqConfigs, getViewsRspackConfig } from '@qpqjs/deploy-rspack';\n\nimport http from 'http';\nimport { rspack } from '@rspack/core';\nimport { RspackDevServer } from '@rspack/dev-server';\n\nimport { getArgValue } from '../lib/args';\nimport { hasArgFlag } from '../lib/args';\nimport { readDevServerPorts } from '../lib/devServerPorts';\nimport { getRoot } from '../lib/discovery';\nimport { KEEP_OTHER_DEV_SERVERS_FLAG } from '../lib/keepOtherDevServersFlag';\nimport { isQpqCliCommand, killStaleListeners, reportPortHolders } from '../lib/killStaleListeners';\nimport { createOutput } from '../lib/out';\nimport { resolveAppSelection } from '../lib/resolveAppSelection';\nimport { resolveDeployment } from '../lib/resolveDeployment';\nimport { setWebAddressingEnv } from '../lib/webAddressingEnv';\n\nconst out = createOutput('go:dev:web');\n\nexport type GoDevWebOptions = {\n // The in-place \"(started)\" chip rewrite assumes this command owns the\n // terminal; when stdout is shared with the API dev server (combined\n // `qpq go:dev`) the cursor math breaks. The plain-line fallback is just a\n // wall of \" auth started\" noise interleaved with the API output, so drop\n // the ready status altogether there.\n hideStartedStatus?: boolean;\n};\n\nexport const goDevWebCommand = async (argv: string[], options: GoDevWebOptions = {}): Promise<void> => {\n const root = getRoot();\n const appName = await resolveAppSelection({ argv, envVar: 'QPQ_DEV_APP' });\n\n process.env.LOCAL_DEV_SERVER = 'true';\n process.env.NODE_ENV = 'development';\n await resolveDeployment(argv, appName);\n\n // Local pages address the api dev server and each other by port on localhost.\n const devServerPorts = readDevServerPorts(appName);\n setWebAddressingEnv(getAppServiceQpqConfigs(root, appName), {\n api: devServerPorts.api,\n webSocket: devServerPorts.webSocket,\n mapHostPort: (port) => port,\n });\n\n const only = getArgValue(argv, '--only')\n ?.split(',')\n .map((s) => s.trim());\n\n let views = getAllViews(root, appName);\n if (only) views = views.filter((v) => only.includes(v.service));\n if (views.length === 0) {\n out.error('No views projects found.');\n process.exit(1);\n }\n\n // See goDevApi for why this is opt-out rather than always-on.\n if (hasArgFlag(argv, KEEP_OTHER_DEV_SERVERS_FLAG)) {\n reportPortHolders(views.map((v) => v.port));\n } else {\n killStaleListeners(\n views.map((v) => v.port),\n isQpqCliCommand,\n );\n }\n\n // Every RspackDevServer.start() registers its own SIGINT/SIGTERM handler on\n // process, with a dozen views servers in one process that trips node's\n // default 10-listener warning. Size the limit to the fleet.\n process.setMaxListeners(Math.max(process.getMaxListeners(), views.length * 2 + 10));\n\n // Service names are padded to a common width so the \"(started)\" chips align.\n const serviceColumnWidth = Math.max(...views.map((v) => v.service.length));\n\n out.log(`Starting ${views.length} views dev servers for [${appName}]:`);\n for (const v of views) out.log(` http://localhost:${v.port} ${v.service.padEnd(serviceColumnWidth)}`);\n\n const servers: RspackDevServer[] = [];\n let shuttingDown = false;\n\n const shutdown = (code: number): void => {\n if (shuttingDown) return;\n shuttingDown = true;\n Promise.allSettled(servers.map((server) => server.stop())).then(() => process.exit(code));\n };\n\n // The URL list above gets a yellow \"(started)\" chip appended in place as\n // each dev server begins answering HTTP. The in-place rewrite moves the\n // cursor up past everything printed since the list, so every line printed\n // below it MUST go through logBelowList to keep the offset accurate.\n let linesBelowList = 0;\n\n const logBelowList = (line: string): void => {\n out.log(line);\n linesBelowList += 1;\n };\n\n const markStarted = (index: number): void => {\n const v = views[index];\n if (!v) return;\n if (!process.stdout.isTTY) {\n logBelowList(` ${v.service} started`);\n return;\n }\n const line = ` http://localhost:${v.port} ${v.service.padEnd(serviceColumnWidth)} \\x1b[33m(started)\\x1b[0m`;\n const up = linesBelowList + (views.length - index);\n process.stdout.write(`\\x1b[${up}F\\x1b[2K${line}\\x1b[${up}E`);\n };\n\n const pollUntilStarted = (index: number): void => {\n const attempt = (): void => {\n if (shuttingDown) return;\n const req = http.get(\n {\n host: 'localhost',\n port: views[index]?.port,\n path: '/',\n timeout: 1000,\n },\n (res) => {\n res.resume();\n markStarted(index);\n },\n );\n req.on('error', () => setTimeout(attempt, 500));\n req.on('timeout', () => req.destroy());\n };\n attempt();\n };\n\n for (const [index, view] of views.entries()) {\n const config = getViewsRspackConfig(view.viewsDir);\n const compiler = rspack(config);\n const server = new RspackDevServer(config.devServer || { port: view.port }, compiler);\n servers.push(server);\n\n try {\n await server.start();\n } catch (e) {\n logBelowList(` [${view.service}] failed to start: ${(e as Error).message} — shutting down all views servers.`);\n shutdown(1);\n return;\n }\n\n // markStarted is the only consumer of the ready signal, so there is\n // nothing to poll for when the status is hidden.\n if (!options.hideStartedStatus) pollUntilStarted(index);\n }\n\n process.on('SIGINT', () => shutdown(0));\n process.on('SIGTERM', () => shutdown(0));\n};\n"]}
@@ -1,29 +1,26 @@
1
- // `qpq go:docker` — asks the same questions as `qpq go`, then runs the
1
+ // `qpq go:docker`, asks the same questions as `qpq go`, then runs the
2
2
  // platform driver's parallel containerized deploy (drivers without a docker
3
3
  // strategy don't offer one). `--build-only` and `--from-build` split that run
4
4
  // into a build half and a deploy half that can run on different machines.
5
5
  import { buildDeployPlanFromArgs, promptDeployPlan } from '../lib/deployPrompts';
6
6
  import { BUILD_ONLY_FLAG, FROM_BUILD_FLAG, resolveGoDockerMode } from '../lib/goDockerMode';
7
- import { resolveAppSelection } from '../lib/resolveAppSelection';
8
- import { resolveDeployment } from '../lib/resolveDeployment';
9
- import { getPlatformDriver } from '../platforms';
7
+ import { createOutput } from '../lib/out';
8
+ import { requireDriverCapability } from '../lib/requireDriverCapability';
9
+ import { resolveCommandContext } from '../lib/resolveCommandContext';
10
+ const out = createOutput('go:docker');
10
11
  export const goDockerCommand = async (argv) => {
11
12
  const mode = resolveGoDockerMode(argv);
12
- const appName = await resolveAppSelection({ argv, envVar: 'DEPLOY_APP_NAME' });
13
- const { deployment } = await resolveDeployment(argv, appName);
14
- const driver = getPlatformDriver(deployment.platform);
15
- if (!driver.goDocker) {
16
- console.error(`Platform '${deployment.platform}' has no dockerized deploy — use qpq go instead.`);
17
- process.exit(1);
18
- }
13
+ const context = await resolveCommandContext(argv);
14
+ const goDocker = requireDriverCapability(context, 'goDocker', 'Use qpq go instead.');
15
+ const { appName } = context;
19
16
  // Positional args (`qpq go:docker all all`) run prompt-free; otherwise ask.
20
17
  const plan = buildDeployPlanFromArgs(appName, argv) ?? (await promptDeployPlan(appName));
21
18
  // account, domain and bootstrap stacks deploy host-side through the workspace
22
19
  // CDK app in one step; there is no saved build to split them across.
23
20
  if (mode !== 'full' && (plan.kind === 'account' || plan.kind === 'bootstrap')) {
24
- console.error(`${BUILD_ONLY_FLAG} and ${FROM_BUILD_FLAG} apply to service deploys only; account, domain and bootstrap deploy in one step.`);
21
+ out.error(`${BUILD_ONLY_FLAG} and ${FROM_BUILD_FLAG} apply to service deploys only; account, domain and bootstrap deploy in one step.`);
25
22
  process.exit(1);
26
23
  }
27
- await driver.goDocker(appName, plan, mode);
24
+ await goDocker(appName, plan, mode);
28
25
  };
29
26
  //# sourceMappingURL=goDocker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"goDocker.js","sourceRoot":"","sources":["../../../src/commands/goDocker.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,4EAA4E;AAC5E,8EAA8E;AAC9E,0EAA0E;AAC1E,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC5F,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,IAAc,EAAiB,EAAE;IACrE,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC/E,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEtD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,OAAO,CAAC,KAAK,CAAC,aAAa,UAAU,CAAC,QAAQ,kDAAkD,CAAC,CAAC;QAClG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,4EAA4E;IAC5E,MAAM,IAAI,GAAG,uBAAuB,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzF,8EAA8E;IAC9E,qEAAqE;IACrE,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,CAAC;QAC9E,OAAO,CAAC,KAAK,CAAC,GAAG,eAAe,QAAQ,eAAe,mFAAmF,CAAC,CAAC;QAC5I,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC,CAAC","sourcesContent":["// `qpq go:docker` — asks the same questions as `qpq go`, then runs the\n// platform driver's parallel containerized deploy (drivers without a docker\n// strategy don't offer one). `--build-only` and `--from-build` split that run\n// into a build half and a deploy half that can run on different machines.\nimport { buildDeployPlanFromArgs, promptDeployPlan } from '../lib/deployPrompts';\nimport { BUILD_ONLY_FLAG, FROM_BUILD_FLAG, resolveGoDockerMode } from '../lib/goDockerMode';\nimport { resolveAppSelection } from '../lib/resolveAppSelection';\nimport { resolveDeployment } from '../lib/resolveDeployment';\nimport { getPlatformDriver } from '../platforms';\n\nexport const goDockerCommand = async (argv: string[]): Promise<void> => {\n const mode = resolveGoDockerMode(argv);\n const appName = await resolveAppSelection({ argv, envVar: 'DEPLOY_APP_NAME' });\n const { deployment } = await resolveDeployment(argv, appName);\n const driver = getPlatformDriver(deployment.platform);\n\n if (!driver.goDocker) {\n console.error(`Platform '${deployment.platform}' has no dockerized deploy — use qpq go instead.`);\n process.exit(1);\n }\n\n // Positional args (`qpq go:docker all all`) run prompt-free; otherwise ask.\n const plan = buildDeployPlanFromArgs(appName, argv) ?? (await promptDeployPlan(appName));\n\n // account, domain and bootstrap stacks deploy host-side through the workspace\n // CDK app in one step; there is no saved build to split them across.\n if (mode !== 'full' && (plan.kind === 'account' || plan.kind === 'bootstrap')) {\n console.error(`${BUILD_ONLY_FLAG} and ${FROM_BUILD_FLAG} apply to service deploys only; account, domain and bootstrap deploy in one step.`);\n process.exit(1);\n }\n\n await driver.goDocker(appName, plan, mode);\n};\n"]}
1
+ {"version":3,"file":"goDocker.js","sourceRoot":"","sources":["../../../src/commands/goDocker.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,4EAA4E;AAC5E,8EAA8E;AAC9E,0EAA0E;AAC1E,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC5F,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;AAEtC,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,IAAc,EAAiB,EAAE;IACrE,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,uBAAuB,CAAC,OAAO,EAAE,UAAU,EAAE,qBAAqB,CAAC,CAAC;IACrF,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAE5B,4EAA4E;IAC5E,MAAM,IAAI,GAAG,uBAAuB,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzF,8EAA8E;IAC9E,qEAAqE;IACrE,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,CAAC;QAC9E,GAAG,CAAC,KAAK,CAAC,GAAG,eAAe,QAAQ,eAAe,mFAAmF,CAAC,CAAC;QACxI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACtC,CAAC,CAAC","sourcesContent":["// `qpq go:docker`, asks the same questions as `qpq go`, then runs the\n// platform driver's parallel containerized deploy (drivers without a docker\n// strategy don't offer one). `--build-only` and `--from-build` split that run\n// into a build half and a deploy half that can run on different machines.\nimport { buildDeployPlanFromArgs, promptDeployPlan } from '../lib/deployPrompts';\nimport { BUILD_ONLY_FLAG, FROM_BUILD_FLAG, resolveGoDockerMode } from '../lib/goDockerMode';\nimport { createOutput } from '../lib/out';\nimport { requireDriverCapability } from '../lib/requireDriverCapability';\nimport { resolveCommandContext } from '../lib/resolveCommandContext';\n\nconst out = createOutput('go:docker');\n\nexport const goDockerCommand = async (argv: string[]): Promise<void> => {\n const mode = resolveGoDockerMode(argv);\n const context = await resolveCommandContext(argv);\n const goDocker = requireDriverCapability(context, 'goDocker', 'Use qpq go instead.');\n const { appName } = context;\n\n // Positional args (`qpq go:docker all all`) run prompt-free; otherwise ask.\n const plan = buildDeployPlanFromArgs(appName, argv) ?? (await promptDeployPlan(appName));\n\n // account, domain and bootstrap stacks deploy host-side through the workspace\n // CDK app in one step; there is no saved build to split them across.\n if (mode !== 'full' && (plan.kind === 'account' || plan.kind === 'bootstrap')) {\n out.error(`${BUILD_ONLY_FLAG} and ${FROM_BUILD_FLAG} apply to service deploys only; account, domain and bootstrap deploy in one step.`);\n process.exit(1);\n }\n\n await goDocker(appName, plan, mode);\n};\n"]}
@@ -1,4 +1,4 @@
1
- // `qpq hooks <name>` — run the `qpq:<name>` script (or the plain `<name>`
1
+ // `qpq hooks <name>`, run the `qpq:<name>` script (or the plain `<name>`
2
2
  // script when no qpq:-prefixed one exists) of every app and workspace package
3
3
  // that defines one, in dependency order with parallel execution.
4
4
  // Wire the root package.json's lifecycle to it, e.g.
@@ -6,7 +6,9 @@
6
6
  import { getArgValue } from '../lib/args';
7
7
  import { getDefaultHookJobs } from '../lib/getDefaultHookJobs';
8
8
  import { runHookForAllPackages } from '../lib/hooks';
9
+ import { createOutput } from '../lib/out';
9
10
  import { assertNoFailures } from '../lib/runTasks';
11
+ const out = createOutput('hooks');
10
12
  const getJobs = (argv) => {
11
13
  const parsed = Number(getArgValue(argv, '--jobs'));
12
14
  if (Number.isFinite(parsed) && parsed >= 1) {
@@ -17,7 +19,7 @@ const getJobs = (argv) => {
17
19
  export const hooksCommand = async (argv) => {
18
20
  const [hook] = argv.filter((a) => !a.startsWith('--'));
19
21
  if (!hook) {
20
- console.error('Usage: qpq hooks <name> [--jobs=N] (runs qpq:<name>, or plain <name>, in every app/package that defines it)');
22
+ out.error('Usage: qpq hooks <name> [--jobs=N] (runs qpq:<name>, or plain <name>, in every app/package that defines it)');
21
23
  process.exit(1);
22
24
  }
23
25
  const failures = await runHookForAllPackages(hook, getJobs(argv));