@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
@@ -17,9 +17,9 @@ exports.promptCommandFromMenu = void 0;
17
17
  // continues until the user picks a runnable leaf. Rows are deliberately left
18
18
  // unstyled so inquirer's active-item highlight colours the whole row.
19
19
  const prompts_1 = require("../lib/prompts");
20
- const lastSegment = (name) => name.split(':').slice(-1)[0];
20
+ const lastSegment = (name) => { var _a; return (_a = name.split(':').slice(-1)[0]) !== null && _a !== void 0 ? _a : name; };
21
21
  // The first path segment of `name` below `prefix` ('' means the tree root).
22
- const childSegment = (name, prefix) => name.slice(prefix ? prefix.length + 1 : 0).split(':')[0];
22
+ const childSegment = (name, prefix) => { var _a; return (_a = name.slice(prefix ? prefix.length + 1 : 0).split(':')[0]) !== null && _a !== void 0 ? _a : ''; };
23
23
  const runRow = (command) => ({
24
24
  label: `qpq ${command.name}`,
25
25
  summary: command.summary,
@@ -35,8 +35,9 @@ const buildRows = (commands, prefix) => {
35
35
  for (const segment of segments) {
36
36
  const segmentPrefix = prefix ? `${prefix}:${segment}` : segment;
37
37
  const subtree = deeper.filter((command) => command.name === segmentPrefix || command.name.startsWith(`${segmentPrefix}:`));
38
- if (subtree.length === 1 && subtree[0].name === segmentPrefix) {
39
- leafRows.push(runRow(subtree[0]));
38
+ const [only] = subtree;
39
+ if (subtree.length === 1 && only && only.name === segmentPrefix) {
40
+ leafRows.push(runRow(only));
40
41
  }
41
42
  else {
42
43
  // A group's summary is its own runnable command's summary when it has
@@ -1 +1 @@
1
- {"version":3,"file":"commandMenu.js","sourceRoot":"","sources":["../../../src/cli/commandMenu.ts"],"names":[],"mappings":"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","sourcesContent":["// Interactive drill-down for a bare `qpq`: the colon-separated command names\n// form a tree (go, go:dev, go:dev:api, ...). Each menu level renders its\n// options as the full command line they resolve to (`qpq go:dev:api`) with\n// the command's summary alongside, groups shown as `qpq go:??`, and drilling\n// continues until the user picks a runnable leaf. Rows are deliberately left\n// unstyled so inquirer's active-item highlight colours the whole row.\nimport { promptSelectDetailed } from '../lib/prompts';\nimport { CliCommand } from './commandRegistry';\n\ntype MenuChoice = { kind: 'run'; command: CliCommand } | { kind: 'drill'; prefix: string } | { kind: 'back' };\n\ntype MenuRow = { label: string; summary?: string; value: MenuChoice };\n\nconst lastSegment = (name: string): string => name.split(':').slice(-1)[0];\n\n// The first path segment of `name` below `prefix` ('' means the tree root).\nconst childSegment = (name: string, prefix: string): string => name.slice(prefix ? prefix.length + 1 : 0).split(':')[0];\n\nconst runRow = (command: CliCommand): MenuRow => ({\n label: `qpq ${command.name}`,\n summary: command.summary,\n value: { kind: 'run', command },\n});\n\nconst buildRows = (commands: CliCommand[], prefix: string): MenuRow[] => {\n const exact = prefix ? commands.find((command) => command.name === prefix) : undefined;\n const deeper = commands.filter((command) => command.name !== prefix && (!prefix || command.name.startsWith(`${prefix}:`)));\n const segments = [...new Set(deeper.map((command) => childSegment(command.name, prefix)))];\n\n const groupRows: MenuRow[] = [];\n const leafRows: MenuRow[] = [];\n\n for (const segment of segments) {\n const segmentPrefix = prefix ? `${prefix}:${segment}` : segment;\n const subtree = deeper.filter((command) => command.name === segmentPrefix || command.name.startsWith(`${segmentPrefix}:`));\n\n if (subtree.length === 1 && subtree[0].name === segmentPrefix) {\n leafRows.push(runRow(subtree[0]));\n } else {\n // A group's summary is its own runnable command's summary when it has\n // one, otherwise a listing of what's inside.\n const groupSummary = subtree.find((command) => command.name === segmentPrefix)?.summary;\n groupRows.push({\n label: `qpq ${segmentPrefix}:??`,\n summary: groupSummary ?? subtree.map((command) => lastSegment(command.name)).join(', '),\n value: { kind: 'drill', prefix: segmentPrefix },\n });\n }\n }\n\n // The current prefix's own command (run what this menu is named after)\n // leads, then groups, then the remaining runnable commands.\n const rows = [...(exact ? [runRow(exact)] : []), ...groupRows, ...leafRows];\n\n if (prefix) {\n rows.push({ label: '(back)', value: { kind: 'back' } });\n }\n\n return rows;\n};\n\n// Align the rows into two columns: the command line, then its summary.\nconst toChoices = (rows: MenuRow[]): { name: string; value: MenuChoice; short?: string }[] => {\n const columnWidth = Math.max(...rows.map((row) => row.label.length)) + 2;\n\n return rows.map((row) => ({\n name: row.summary ? `${row.label.padEnd(columnWidth)}${row.summary}` : row.label,\n value: row.value,\n short: row.label,\n }));\n};\n\n// Walk the menu until a runnable command is picked.\nexport const promptCommandFromMenu = async (commands: CliCommand[]): Promise<CliCommand> => {\n let prefix = '';\n\n for (;;) {\n const picked = await promptSelectDetailed<MenuChoice>('Run:', toChoices(buildRows(commands, prefix)));\n\n if (picked.kind === 'run') {\n return picked.command;\n }\n\n prefix = picked.kind === 'drill' ? picked.prefix : prefix.split(':').slice(0, -1).join(':');\n }\n};\n"]}
1
+ {"version":3,"file":"commandMenu.js","sourceRoot":"","sources":["../../../src/cli/commandMenu.ts"],"names":[],"mappings":"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","sourcesContent":["// Interactive drill-down for a bare `qpq`: the colon-separated command names\n// form a tree (go, go:dev, go:dev:api, ...). Each menu level renders its\n// options as the full command line they resolve to (`qpq go:dev:api`) with\n// the command's summary alongside, groups shown as `qpq go:??`, and drilling\n// continues until the user picks a runnable leaf. Rows are deliberately left\n// unstyled so inquirer's active-item highlight colours the whole row.\nimport { promptSelectDetailed } from '../lib/prompts';\nimport { CliCommand } from './commandRegistry';\n\ntype MenuChoice = { kind: 'run'; command: CliCommand } | { kind: 'drill'; prefix: string } | { kind: 'back' };\n\ntype MenuRow = { label: string; summary?: string; value: MenuChoice };\n\nconst lastSegment = (name: string): string => name.split(':').slice(-1)[0] ?? name;\n\n// The first path segment of `name` below `prefix` ('' means the tree root).\nconst childSegment = (name: string, prefix: string): string => name.slice(prefix ? prefix.length + 1 : 0).split(':')[0] ?? '';\n\nconst runRow = (command: CliCommand): MenuRow => ({\n label: `qpq ${command.name}`,\n summary: command.summary,\n value: { kind: 'run', command },\n});\n\nconst buildRows = (commands: CliCommand[], prefix: string): MenuRow[] => {\n const exact = prefix ? commands.find((command) => command.name === prefix) : undefined;\n const deeper = commands.filter((command) => command.name !== prefix && (!prefix || command.name.startsWith(`${prefix}:`)));\n const segments = [...new Set(deeper.map((command) => childSegment(command.name, prefix)))];\n\n const groupRows: MenuRow[] = [];\n const leafRows: MenuRow[] = [];\n\n for (const segment of segments) {\n const segmentPrefix = prefix ? `${prefix}:${segment}` : segment;\n const subtree = deeper.filter((command) => command.name === segmentPrefix || command.name.startsWith(`${segmentPrefix}:`));\n\n const [only] = subtree;\n if (subtree.length === 1 && only && only.name === segmentPrefix) {\n leafRows.push(runRow(only));\n } else {\n // A group's summary is its own runnable command's summary when it has\n // one, otherwise a listing of what's inside.\n const groupSummary = subtree.find((command) => command.name === segmentPrefix)?.summary;\n groupRows.push({\n label: `qpq ${segmentPrefix}:??`,\n summary: groupSummary ?? subtree.map((command) => lastSegment(command.name)).join(', '),\n value: { kind: 'drill', prefix: segmentPrefix },\n });\n }\n }\n\n // The current prefix's own command (run what this menu is named after)\n // leads, then groups, then the remaining runnable commands.\n const rows = [...(exact ? [runRow(exact)] : []), ...groupRows, ...leafRows];\n\n if (prefix) {\n rows.push({ label: '(back)', value: { kind: 'back' } });\n }\n\n return rows;\n};\n\n// Align the rows into two columns: the command line, then its summary.\nconst toChoices = (rows: MenuRow[]): { name: string; value: MenuChoice; short?: string }[] => {\n const columnWidth = Math.max(...rows.map((row) => row.label.length)) + 2;\n\n return rows.map((row) => ({\n name: row.summary ? `${row.label.padEnd(columnWidth)}${row.summary}` : row.label,\n value: row.value,\n short: row.label,\n }));\n};\n\n// Walk the menu until a runnable command is picked.\nexport const promptCommandFromMenu = async (commands: CliCommand[]): Promise<CliCommand> => {\n let prefix = '';\n\n for (;;) {\n const picked = await promptSelectDetailed<MenuChoice>('Run:', toChoices(buildRows(commands, prefix)));\n\n if (picked.kind === 'run') {\n return picked.command;\n }\n\n prefix = picked.kind === 'drill' ? picked.prefix : prefix.split(':').slice(0, -1).join(':');\n }\n};\n"]}
@@ -10,14 +10,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.runCli = void 0;
13
+ const CliError_1 = require("../lib/CliError");
14
+ const out_1 = require("../lib/out");
13
15
  const commandMenu_1 = require("./commandMenu");
14
16
  const commandRegistry_1 = require("./commandRegistry");
15
- // Service infrastructure.ts files (and app config fragments) are TypeScript —
17
+ const out = (0, out_1.createOutput)('cli');
18
+ // Service infrastructure.ts files (and app config fragments) are TypeScript, so
16
19
  // register ts-node's transpile-only require hook so the CLI can require them
17
20
  // directly, using the consumer root's tsconfig.json ts-node settings.
18
21
  //
19
22
  // CONTRACT: JavaScript apps (create-qpq-app --language javascript) also lean
20
- // on this hook — their tsconfig.json ts-node block sets allowJs (so their
23
+ // on this hook, their tsconfig.json ts-node block sets allowJs (so their
21
24
  // ESM-syntax infrastructure.js compiles at require time) and scope/scopeDir
22
25
  // (so the hook never touches quidproquo libs outside the app). Any
23
26
  // replacement for ts-node here must honour those consumer tsconfig options.
@@ -46,7 +49,7 @@ const resolveCommandInteractively = () => __awaiter(void 0, void 0, void 0, func
46
49
  const runCli = (argv) => __awaiter(void 0, void 0, void 0, function* () {
47
50
  const [commandName, ...argvRest] = argv;
48
51
  if (commandName === 'help' || commandName === '--help') {
49
- console.log((0, commandRegistry_1.buildUsage)());
52
+ out.log((0, commandRegistry_1.buildUsage)());
50
53
  return;
51
54
  }
52
55
  let command;
@@ -54,7 +57,7 @@ const runCli = (argv) => __awaiter(void 0, void 0, void 0, function* () {
54
57
  if (!commandName) {
55
58
  // Only prompt on a real terminal; piped/CI invocations get the usage text.
56
59
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
57
- console.log((0, commandRegistry_1.buildUsage)());
60
+ out.log((0, commandRegistry_1.buildUsage)());
58
61
  return;
59
62
  }
60
63
  const resolved = yield resolveCommandInteractively();
@@ -67,8 +70,8 @@ const runCli = (argv) => __awaiter(void 0, void 0, void 0, function* () {
67
70
  command = commandRegistry_1.cliCommands.find((c) => c.name === commandName);
68
71
  commandArgv = argvRest;
69
72
  if (!command) {
70
- console.error(`Unknown command: ${commandName}`);
71
- console.log((0, commandRegistry_1.buildUsage)());
73
+ out.error(`Unknown command: ${commandName}`);
74
+ out.log((0, commandRegistry_1.buildUsage)());
72
75
  process.exitCode = 1;
73
76
  return;
74
77
  }
@@ -78,7 +81,12 @@ const runCli = (argv) => __awaiter(void 0, void 0, void 0, function* () {
78
81
  yield command.run(commandArgv);
79
82
  }
80
83
  catch (error) {
81
- console.error(`qpq ${command.name} failed:`, error);
84
+ if (error instanceof CliError_1.CliError) {
85
+ out.error(error.message);
86
+ process.exitCode = error.exitCode;
87
+ return;
88
+ }
89
+ out.error(`qpq ${command.name} failed:`, error);
82
90
  process.exitCode = 1;
83
91
  }
84
92
  });
@@ -1 +1 @@
1
- {"version":3,"file":"runCli.js","sourceRoot":"","sources":["../../../src/cli/runCli.ts"],"names":[],"mappings":"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","sourcesContent":["import { promptCommandFromMenu } from './commandMenu';\nimport { buildUsage, CliCommand, cliCommands } from './commandRegistry';\n\n// Service infrastructure.ts files (and app config fragments) are TypeScript —\n// register ts-node's transpile-only require hook so the CLI can require them\n// directly, using the consumer root's tsconfig.json ts-node settings.\n//\n// CONTRACT: JavaScript apps (create-qpq-app --language javascript) also lean\n// on this hook — their tsconfig.json ts-node block sets allowJs (so their\n// ESM-syntax infrastructure.js compiles at require time) and scope/scopeDir\n// (so the hook never touches quidproquo libs outside the app). Any\n// replacement for ts-node here must honour those consumer tsconfig options.\nconst registerTsNode = (): void => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n require('ts-node').register({ transpileOnly: true });\n};\n\n// Inquirer throws ExitPromptError on ctrl-c; treat that as a quiet exit\n// rather than a command failure.\nconst isPromptExit = (error: unknown): boolean => error instanceof Error && error.name === 'ExitPromptError';\n\n// Bare `qpq` on a terminal: drill through the command menu, gathering any\n// arguments the picked command needs. Returns null when the user bails out.\nconst resolveCommandInteractively = async (): Promise<{ command: CliCommand; commandArgv: string[] } | null> => {\n try {\n const command = await promptCommandFromMenu(cliCommands);\n const commandArgv = command.promptArgs ? await command.promptArgs() : [];\n\n return { command, commandArgv };\n } catch (error) {\n if (isPromptExit(error)) {\n return null;\n }\n\n throw error;\n }\n};\n\nexport const runCli = async (argv: string[]): Promise<void> => {\n const [commandName, ...argvRest] = argv;\n\n if (commandName === 'help' || commandName === '--help') {\n console.log(buildUsage());\n return;\n }\n\n let command: CliCommand | undefined;\n let commandArgv: string[] = [];\n\n if (!commandName) {\n // Only prompt on a real terminal; piped/CI invocations get the usage text.\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n console.log(buildUsage());\n return;\n }\n\n const resolved = await resolveCommandInteractively();\n\n if (!resolved) {\n return;\n }\n\n ({ command, commandArgv } = resolved);\n } else {\n command = cliCommands.find((c) => c.name === commandName);\n commandArgv = argvRest;\n\n if (!command) {\n console.error(`Unknown command: ${commandName}`);\n console.log(buildUsage());\n process.exitCode = 1;\n return;\n }\n }\n\n registerTsNode();\n\n try {\n await command.run(commandArgv);\n } catch (error) {\n console.error(`qpq ${command.name} failed:`, error);\n process.exitCode = 1;\n }\n};\n"]}
1
+ {"version":3,"file":"runCli.js","sourceRoot":"","sources":["../../../src/cli/runCli.ts"],"names":[],"mappings":"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","sourcesContent":["import { Nullable } from '@qpqjs/core';\n\nimport { CliError } from '../lib/CliError';\nimport { createOutput } from '../lib/out';\nimport { promptCommandFromMenu } from './commandMenu';\nimport { buildUsage, CliCommand, cliCommands } from './commandRegistry';\n\nconst out = createOutput('cli');\n\n// Service infrastructure.ts files (and app config fragments) are TypeScript, so\n// register ts-node's transpile-only require hook so the CLI can require them\n// directly, using the consumer root's tsconfig.json ts-node settings.\n//\n// CONTRACT: JavaScript apps (create-qpq-app --language javascript) also lean\n// on this hook, their tsconfig.json ts-node block sets allowJs (so their\n// ESM-syntax infrastructure.js compiles at require time) and scope/scopeDir\n// (so the hook never touches quidproquo libs outside the app). Any\n// replacement for ts-node here must honour those consumer tsconfig options.\nconst registerTsNode = (): void => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n require('ts-node').register({ transpileOnly: true });\n};\n\n// Inquirer throws ExitPromptError on ctrl-c; treat that as a quiet exit\n// rather than a command failure.\nconst isPromptExit = (error: unknown): boolean => error instanceof Error && error.name === 'ExitPromptError';\n\n// Bare `qpq` on a terminal: drill through the command menu, gathering any\n// arguments the picked command needs. Returns null when the user bails out.\nconst resolveCommandInteractively = async (): Promise<Nullable<{ command: CliCommand; commandArgv: string[] }>> => {\n try {\n const command = await promptCommandFromMenu(cliCommands);\n const commandArgv = command.promptArgs ? await command.promptArgs() : [];\n\n return { command, commandArgv };\n } catch (error) {\n if (isPromptExit(error)) {\n return null;\n }\n\n throw error;\n }\n};\n\nexport const runCli = async (argv: string[]): Promise<void> => {\n const [commandName, ...argvRest] = argv;\n\n if (commandName === 'help' || commandName === '--help') {\n out.log(buildUsage());\n return;\n }\n\n let command: CliCommand | undefined;\n let commandArgv: string[] = [];\n\n if (!commandName) {\n // Only prompt on a real terminal; piped/CI invocations get the usage text.\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n out.log(buildUsage());\n return;\n }\n\n const resolved = await resolveCommandInteractively();\n\n if (!resolved) {\n return;\n }\n\n ({ command, commandArgv } = resolved);\n } else {\n command = cliCommands.find((c) => c.name === commandName);\n commandArgv = argvRest;\n\n if (!command) {\n out.error(`Unknown command: ${commandName}`);\n out.log(buildUsage());\n process.exitCode = 1;\n return;\n }\n }\n\n registerTsNode();\n\n try {\n await command.run(commandArgv);\n } catch (error) {\n if (error instanceof CliError) {\n out.error(error.message);\n process.exitCode = error.exitCode;\n return;\n }\n\n out.error(`qpq ${command.name} failed:`, error);\n process.exitCode = 1;\n }\n};\n"]}
@@ -10,13 +10,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.checkCircularCommand = void 0;
13
- // `qpq check:circular` — scan every workspace's src for circular imports (the
13
+ // `qpq check:circular`, scan every workspace's src for circular imports (the
14
14
  // class of bug that TDZ-crashes ESM bundles and silently drops exports under
15
- // CJS). Cycles fail the command (exit 1) — they are never acceptable; --warn or
15
+ // CJS). Cycles fail the command (exit 1), they are never acceptable; --warn or
16
16
  // QPQ_CIRCULAR_DEPS_WARN=1 is a temporary escape hatch that reports without
17
17
  // failing while fixing.
18
18
  const circularImports_1 = require("../lib/circularImports");
19
19
  const discovery_1 = require("../lib/discovery");
20
+ const out_1 = require("../lib/out");
21
+ const out = (0, out_1.createOutput)('check:circular');
20
22
  // madge reports every distinct loop path; one tangled module can produce dozens
21
23
  // of chains through the same files. Merge chains that share any file into one
22
24
  // group so the report shows each tangle once, with its full blast radius.
@@ -34,13 +36,19 @@ const groupCycles = (cycles) => {
34
36
  return rootFile;
35
37
  };
36
38
  for (const cycle of cycles) {
39
+ const [first] = cycle;
40
+ if (first === undefined)
41
+ continue;
37
42
  for (const file of cycle) {
38
- parent.set(find(file), find(cycle[0]));
43
+ parent.set(find(file), find(first));
39
44
  }
40
45
  }
41
46
  const groups = new Map();
42
47
  for (const cycle of cycles) {
43
- const key = find(cycle[0]);
48
+ const [first] = cycle;
49
+ if (first === undefined)
50
+ continue;
51
+ const key = find(first);
44
52
  const group = (_a = groups.get(key)) !== null && _a !== void 0 ? _a : { files: [], chainCount: 0 };
45
53
  group.chainCount += 1;
46
54
  group.files = [...new Set([...group.files, ...cycle])];
@@ -52,16 +60,16 @@ const checkCircularCommand = (argv) => __awaiter(void 0, void 0, void 0, functio
52
60
  const warnOnly = argv.includes('--warn') || !!process.env.QPQ_CIRCULAR_DEPS_WARN;
53
61
  const cycles = yield (0, circularImports_1.findWorkspaceImportCycles)((0, discovery_1.getRoot)());
54
62
  if (cycles.length === 0) {
55
- console.log('check:circular: no circular imports found');
63
+ out.log('check:circular: no circular imports found');
56
64
  return;
57
65
  }
58
66
  const groups = groupCycles(cycles);
59
67
  const colour = warnOnly ? '\x1b[33m' : '\x1b[31m';
60
68
  for (const group of groups) {
61
69
  const chainNote = group.chainCount > 1 ? `, ${group.chainCount} distinct loops` : '';
62
- console.warn(`${colour}Circular imports (${group.files.length} files${chainNote}):\n ${group.files.join('\n ')}\x1b[0m`);
70
+ out.warn(`${colour}Circular imports (${group.files.length} files${chainNote}):\n ${group.files.join('\n ')}\x1b[0m`);
63
71
  }
64
- console.warn(`${colour}check:circular: ${groups.length} circular import group(s) found (${cycles.length} loops)\x1b[0m`);
72
+ out.warn(`${colour}check:circular: ${groups.length} circular import group(s) found (${cycles.length} loops)\x1b[0m`);
65
73
  if (!warnOnly) {
66
74
  process.exitCode = 1;
67
75
  }
@@ -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":";;;;;;;;;;;;AAAA,6EAA6E;AAC7E,6EAA6E;AAC7E,+EAA+E;AAC/E,4EAA4E;AAC5E,wBAAwB;AACxB,4DAAgF;AAChF,gDAA2C;AAC3C,oCAA0C;AAE1C,MAAM,GAAG,GAAG,IAAA,kBAAY,EAAC,gBAAgB,CAAC,CAAC;AAI3C,gFAAgF;AAChF,8EAA8E;AAC9E,0EAA0E;AAC1E,MAAM,WAAW,GAAG,CAAC,MAAqB,EAAgB,EAAE;;IAC1D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEzC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAU,EAAE;;QACpC,MAAM,KAAK,GAAG,MAAA,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,mCAAI,IAAI,CAAC;QACvC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC3B,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;QACtB,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC7C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;QACtB,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,MAAM,KAAK,GAAG,MAAA,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,mCAAI,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;QAC9D,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC;QACtB,KAAK,CAAC,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC,CAAC;AAEK,MAAM,oBAAoB,GAAG,CAAO,IAAc,EAAiB,EAAE;IAC1E,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;IAEjF,MAAM,MAAM,GAAG,MAAM,IAAA,2CAAyB,EAAC,IAAA,mBAAO,GAAE,CAAC,CAAC;IAE1D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,GAAG,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;QACrD,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAEnC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;IAClD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,UAAU,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;QACrF,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,qBAAqB,KAAK,CAAC,KAAK,CAAC,MAAM,SAAS,SAAS,WAAW,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC7H,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,mBAAmB,MAAM,CAAC,MAAM,oCAAoC,MAAM,CAAC,MAAM,gBAAgB,CAAC,CAAC;IAErH,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC,CAAA,CAAC;AAtBW,QAAA,oBAAoB,wBAsB/B","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"]}
@@ -10,27 +10,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.clearResourcesCommand = void 0;
13
- // `qpq clear-resources` — interactively EMPTY selected data resources (storage
13
+ // `qpq clear-resources`, interactively EMPTY selected data resources (storage
14
14
  // drive buckets, key value store tables) without touching the stacks: the
15
15
  // "reset my data" counterpart to `qpq teardown`. Resolves the app +
16
16
  // deployment the same way as go/teardown, enumerates the app's owned
17
17
  // resources from its live qpq configs, multi-selects what to empty (with a
18
- // typed confirmation — this deletes stored data), then hands off to the
18
+ // typed confirmation, this deletes stored data), then hands off to the
19
19
  // platform driver.
20
20
  const clearResourcesPlan_1 = require("../lib/clearResourcesPlan");
21
- const resolveAppSelection_1 = require("../lib/resolveAppSelection");
22
- const resolveDeployment_1 = require("../lib/resolveDeployment");
23
- const platforms_1 = require("../platforms");
21
+ const requireDriverCapability_1 = require("../lib/requireDriverCapability");
22
+ const resolveCommandContext_1 = require("../lib/resolveCommandContext");
24
23
  const clearResourcesCommand = (argv) => __awaiter(void 0, void 0, void 0, function* () {
25
- const appName = yield (0, resolveAppSelection_1.resolveAppSelection)({ argv, envVar: 'DEPLOY_APP_NAME' });
26
- const { deployment } = yield (0, resolveDeployment_1.resolveDeployment)(argv, appName);
27
- const driver = (0, platforms_1.getPlatformDriver)(deployment.platform);
28
- if (!driver.clearResources) {
29
- console.error(`The '${deployment.platform}' platform has no clear-resources strategy.`);
30
- process.exit(1);
31
- }
32
- const plan = yield (0, clearResourcesPlan_1.promptClearResourcesPlan)(appName);
33
- yield driver.clearResources(appName, plan);
24
+ const context = yield (0, resolveCommandContext_1.resolveCommandContext)(argv);
25
+ const clearResources = (0, requireDriverCapability_1.requireDriverCapability)(context, 'clearResources');
26
+ const plan = yield (0, clearResourcesPlan_1.promptClearResourcesPlan)(context.appName);
27
+ yield clearResources(context.appName, plan);
34
28
  });
35
29
  exports.clearResourcesCommand = clearResourcesCommand;
36
30
  //# 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,kEAAqE;AACrE,oEAAiE;AACjE,gEAA6D;AAC7D,4CAAiD;AAE1C,MAAM,qBAAqB,GAAG,CAAO,IAAc,EAAiB,EAAE;IAC3E,MAAM,OAAO,GAAG,MAAM,IAAA,yCAAmB,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC/E,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,IAAA,qCAAiB,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,IAAA,6BAAiB,EAAC,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,IAAA,6CAAwB,EAAC,OAAO,CAAC,CAAC;IAErD,MAAM,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC,CAAA,CAAC;AAbW,QAAA,qBAAqB,yBAahC","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,kEAAqE;AACrE,4EAAyE;AACzE,wEAAqE;AAE9D,MAAM,qBAAqB,GAAG,CAAO,IAAc,EAAiB,EAAE;IAC3E,MAAM,OAAO,GAAG,MAAM,IAAA,6CAAqB,EAAC,IAAI,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,IAAA,iDAAuB,EAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAE1E,MAAM,IAAI,GAAG,MAAM,IAAA,6CAAwB,EAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAE7D,MAAM,cAAc,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC,CAAA,CAAC;AAPW,QAAA,qBAAqB,yBAOhC","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"]}
@@ -10,18 +10,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.goCommand = void 0;
13
- // `qpq go` — interactive deploy. Resolves the app + deployment (whose entry in
13
+ // `qpq go`, interactive deploy. Resolves the app + deployment (whose entry in
14
14
  // apps/<app>/deploy.config.json names the platform), asks the deploy plan, then
15
15
  // hands off to the platform driver.
16
16
  const deployPrompts_1 = require("../lib/deployPrompts");
17
- const resolveAppSelection_1 = require("../lib/resolveAppSelection");
18
- const resolveDeployment_1 = require("../lib/resolveDeployment");
19
- const platforms_1 = require("../platforms");
17
+ const resolveCommandContext_1 = require("../lib/resolveCommandContext");
20
18
  const goCommand = (argv) => __awaiter(void 0, void 0, void 0, function* () {
21
19
  var _a;
22
- const appName = yield (0, resolveAppSelection_1.resolveAppSelection)({ argv, envVar: 'DEPLOY_APP_NAME' });
23
- const { deployment } = yield (0, resolveDeployment_1.resolveDeployment)(argv, appName);
24
- const driver = (0, platforms_1.getPlatformDriver)(deployment.platform);
20
+ const { appName, driver } = yield (0, resolveCommandContext_1.resolveCommandContext)(argv);
25
21
  // Positional args (`qpq go all all`) run prompt-free; otherwise ask.
26
22
  const plan = (_a = (0, deployPrompts_1.buildDeployPlanFromArgs)(appName, argv)) !== null && _a !== void 0 ? _a : (yield (0, deployPrompts_1.promptDeployPlan)(appName));
27
23
  yield 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,wDAAiF;AACjF,oEAAiE;AACjE,gEAA6D;AAC7D,4CAAiD;AAE1C,MAAM,SAAS,GAAG,CAAO,IAAc,EAAiB,EAAE;;IAC/D,MAAM,OAAO,GAAG,MAAM,IAAA,yCAAmB,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC/E,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,IAAA,qCAAiB,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,IAAA,6BAAiB,EAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEtD,qEAAqE;IACrE,MAAM,IAAI,GAAG,MAAA,IAAA,uCAAuB,EAAC,OAAO,EAAE,IAAI,CAAC,mCAAI,CAAC,MAAM,IAAA,gCAAgB,EAAC,OAAO,CAAC,CAAC,CAAC;IAEzF,MAAM,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC,CAAA,CAAC;AATW,QAAA,SAAS,aASpB","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,wDAAiF;AACjF,wEAAqE;AAE9D,MAAM,SAAS,GAAG,CAAO,IAAc,EAAiB,EAAE;;IAC/D,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,IAAA,6CAAqB,EAAC,IAAI,CAAC,CAAC;IAE9D,qEAAqE;IACrE,MAAM,IAAI,GAAG,MAAA,IAAA,uCAAuB,EAAC,OAAO,EAAE,IAAI,CAAC,mCAAI,CAAC,MAAM,IAAA,gCAAgB,EAAC,OAAO,CAAC,CAAC,CAAC;IAEzF,MAAM,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC,CAAA,CAAC;AAPW,QAAA,SAAS,aAOpB","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"]}
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.goDevCommand = void 0;
13
- // `qpq go:dev` — the whole local dev stack in one process: the API dev server
13
+ // `qpq go:dev`, the whole local dev stack in one process: the API dev server
14
14
  // (go:dev:api) plus every views dev server (go:dev:web), so a single ctrl+c
15
15
  // tears it all down. A background tsc watcher keeps workspace declaration
16
16
  // output fresh for the editor (--no-types to skip it). The app is resolved
@@ -18,11 +18,13 @@ exports.goDevCommand = void 0;
18
18
  // likewise via DEPLOY_NAME, so neither asks again; their output shares the terminal.
19
19
  const deploy_rspack_1 = require("@qpqjs/deploy-rspack");
20
20
  const discovery_1 = require("../lib/discovery");
21
+ const out_1 = require("../lib/out");
21
22
  const resolveAppSelection_1 = require("../lib/resolveAppSelection");
22
23
  const resolveDeployment_1 = require("../lib/resolveDeployment");
23
24
  const typeWatcher_1 = require("../lib/typeWatcher");
24
25
  const goDevApi_1 = require("./goDevApi");
25
26
  const goDevWeb_1 = require("./goDevWeb");
27
+ const out = (0, out_1.createOutput)('go:dev');
26
28
  const goDevCommand = (argv) => __awaiter(void 0, void 0, void 0, function* () {
27
29
  const appName = yield (0, resolveAppSelection_1.resolveAppSelection)({ argv, envVar: 'QPQ_DEV_APP' });
28
30
  process.env.QPQ_DEV_APP = appName;
@@ -37,7 +39,7 @@ const goDevCommand = (argv) => __awaiter(void 0, void 0, void 0, function* () {
37
39
  // the background of this process.
38
40
  yield (0, goDevApi_1.goDevApiCommand)(argv);
39
41
  if ((0, deploy_rspack_1.getAllViews)((0, discovery_1.getRoot)(), appName).length === 0) {
40
- console.log('No views projects found. Running the API dev server only.');
42
+ out.log('No views projects found. Running the API dev server only.');
41
43
  return;
42
44
  }
43
45
  yield (0, goDevWeb_1.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,wDAAmD;AAEnD,gDAA2C;AAC3C,oEAAiE;AACjE,gEAA6D;AAC7D,oDAAsD;AACtD,yCAA6C;AAC7C,yCAA6C;AAEtC,MAAM,YAAY,GAAG,CAAO,IAAc,EAAiB,EAAE;IAClE,MAAM,OAAO,GAAG,MAAM,IAAA,yCAAmB,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,OAAO,CAAC;IAClC,MAAM,IAAA,qCAAiB,EAAC,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,IAAA,8BAAgB,EAAC,IAAA,mBAAO,GAAE,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,IAAA,0BAAe,EAAC,IAAI,CAAC,CAAC;IAE5B,IAAI,IAAA,2BAAW,EAAC,IAAA,mBAAO,GAAE,EAAE,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;QACzE,OAAO;IACT,CAAC;IAED,MAAM,IAAA,0BAAe,EAAC,IAAI,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3D,CAAC,CAAA,CAAC;AAtBW,QAAA,YAAY,gBAsBvB","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,wDAAmD;AAEnD,gDAA2C;AAC3C,oCAA0C;AAC1C,oEAAiE;AACjE,gEAA6D;AAC7D,oDAAsD;AACtD,yCAA6C;AAC7C,yCAA6C;AAE7C,MAAM,GAAG,GAAG,IAAA,kBAAY,EAAC,QAAQ,CAAC,CAAC;AAE5B,MAAM,YAAY,GAAG,CAAO,IAAc,EAAiB,EAAE;IAClE,MAAM,OAAO,GAAG,MAAM,IAAA,yCAAmB,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,OAAO,CAAC;IAClC,MAAM,IAAA,qCAAiB,EAAC,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,IAAA,8BAAgB,EAAC,IAAA,mBAAO,GAAE,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,IAAA,0BAAe,EAAC,IAAI,CAAC,CAAC;IAE5B,IAAI,IAAA,2BAAW,EAAC,IAAA,mBAAO,GAAE,EAAE,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjD,GAAG,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;QACrE,OAAO;IACT,CAAC;IAED,MAAM,IAAA,0BAAe,EAAC,IAAI,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3D,CAAC,CAAA,CAAC;AAtBW,QAAA,YAAY,gBAsBvB","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"]}
@@ -13,7 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.goDevApiCommand = void 0;
16
- // `qpq go:dev:api` — boots the QPQ local dev server. Resolves the app,
16
+ // `qpq go:dev:api`, boots the QPQ local dev server. Resolves the app,
17
17
  // generates the dev-server entry, builds the rspack config, then runs rspack
18
18
  // in watch mode, restarting the server process on every successful rebuild.
19
19
  //
@@ -23,12 +23,12 @@ exports.goDevApiCommand = void 0;
23
23
  //
24
24
  // The one thing NOT hot-reloaded is the qpq configs themselves: each service's
25
25
  // infrastructure.ts is evaluated once at launch and baked into the
26
- // `quidproquo-dynamic-loader` virtual module — config changes need a full
26
+ // `quidproquo-dynamic-loader` virtual module, config changes need a full
27
27
  // `go:dev:api` restart.
28
+ const core_1 = require("@qpqjs/core");
28
29
  const deploy_rspack_1 = require("@qpqjs/deploy-rspack");
29
- const child_process_1 = require("child_process");
30
30
  const path_1 = __importDefault(require("path"));
31
- const core_1 = require("@rspack/core");
31
+ const core_2 = require("@rspack/core");
32
32
  const args_1 = require("../lib/args");
33
33
  const devServerEntry_1 = require("../lib/devServerEntry");
34
34
  const devServerPorts_1 = require("../lib/devServerPorts");
@@ -36,51 +36,54 @@ const discovery_1 = require("../lib/discovery");
36
36
  const keepOtherDevServersFlag_1 = require("../lib/keepOtherDevServersFlag");
37
37
  const killChildWithEscalation_1 = require("../lib/killChildWithEscalation");
38
38
  const killStaleListeners_1 = require("../lib/killStaleListeners");
39
+ const out_1 = require("../lib/out");
39
40
  const resolveAppSelection_1 = require("../lib/resolveAppSelection");
40
41
  const resolveDeployment_1 = require("../lib/resolveDeployment");
42
+ const runCommand_1 = require("../lib/runCommand");
43
+ const out = (0, out_1.createOutput)('go:dev:api');
41
44
  // 8080/8888 are set in the generated entry; 3001 is the @qpqjs/dev-server
42
45
  // file-storage (secure URL) default port.
43
46
  const getDevServerPortList = (appName) => Object.values((0, devServerPorts_1.readDevServerPorts)(appName));
44
- const DEV_SERVER_BUNDLE_PATH = path_1.default.join('dist', 'qpq', 'dev-server', 'main.js');
47
+ const getDevServerBundlePath = (root) => path_1.default.join((0, core_1.getDevServerDistPath)(root), 'main.js');
45
48
  const goDevApiCommand = (argv) => __awaiter(void 0, void 0, void 0, function* () {
46
49
  const root = (0, discovery_1.getRoot)();
47
50
  const appName = yield (0, resolveAppSelection_1.resolveAppSelection)({ argv, envVar: 'QPQ_DEV_APP' });
48
51
  process.env.QPQ_DEV_APP = appName;
49
52
  yield (0, resolveDeployment_1.resolveDeployment)(argv, appName);
50
- console.log(`Dev server for app [${appName}]`);
53
+ out.log(`Dev server for app [${appName}]`);
51
54
  // The sweep matches on a RELATIVE bundle path, so every checkout's dev
52
55
  // server looks like ours and a sibling worktree gets taken down with it.
53
56
  // Opting out spares it, at the cost of this one not starting: the ports are
54
57
  // the same either way, so what you get instead is EADDRINUSE. Report who
55
58
  // holds them, or that failure says nothing about the cause.
56
59
  if ((0, args_1.hasArgFlag)(argv, keepOtherDevServersFlag_1.KEEP_OTHER_DEV_SERVERS_FLAG)) {
57
- console.log(`${keepOtherDevServersFlag_1.KEEP_OTHER_DEV_SERVERS_FLAG}: leaving other dev servers alone.`);
60
+ out.log(`${keepOtherDevServersFlag_1.KEEP_OTHER_DEV_SERVERS_FLAG}: leaving other dev servers alone.`);
58
61
  (0, killStaleListeners_1.reportPortHolders)(getDevServerPortList(appName));
59
62
  }
60
63
  else {
61
64
  // Catches a lingering watcher from a previous run even if its spawned
62
- // child already exited (see killOtherQpqDevProcesses) — then the usual
65
+ // child already exited (see killOtherQpqDevProcesses), then the usual
63
66
  // port-based sweep for anything else still bound to our ports.
64
67
  (0, killStaleListeners_1.killOtherQpqDevProcesses)(root);
65
- (0, killStaleListeners_1.killStaleListeners)(getDevServerPortList(appName), (command) => command.includes(DEV_SERVER_BUNDLE_PATH));
68
+ (0, killStaleListeners_1.killStaleListeners)(getDevServerPortList(appName), (command) => command.includes(getDevServerBundlePath(root)));
66
69
  }
67
70
  const qpqConfigs = (0, deploy_rspack_1.getAppServiceQpqConfigs)(root, appName);
68
71
  const entry = (0, devServerEntry_1.writeDevServerEntry)(root, appName);
69
72
  const userScriptChildEntry = (0, devServerEntry_1.writeUserScriptChildEntry)(root);
70
73
  const rspackConfig = (0, deploy_rspack_1.getDevServerRspackConfig)({ root, entry, userScriptChildEntry, qpqConfigs });
71
- const bundlePath = path_1.default.join(root, DEV_SERVER_BUNDLE_PATH);
72
- const env = Object.assign(Object.assign({}, process.env), { QPQ_DEV_APP: appName });
74
+ const bundlePath = getDevServerBundlePath(root);
75
+ const env = { QPQ_DEV_APP: appName };
73
76
  // The long-lived server process (HTTP 8080 / WS 8888), restarted per rebuild.
74
77
  let child = null;
75
78
  let restartQueued = false;
76
79
  const startServer = () => {
77
- child = (0, child_process_1.spawn)('node', [bundlePath], { stdio: 'inherit', env });
80
+ child = (0, runCommand_1.spawnCommand)('node', [bundlePath], { env });
78
81
  child.on('exit', (code) => {
79
82
  child = null;
80
83
  if (!restartQueued) {
81
- // Crashed (or exited) on its own — leave it down; the next successful
84
+ // Crashed (or exited) on its own, leave it down; the next successful
82
85
  // rebuild (i.e. the next file save) brings it back up.
83
- console.log(`Dev server exited with code ${code}. Save a file to restart it.`);
86
+ out.log(`Dev server exited with code ${code}. Save a file to restart it.`);
84
87
  }
85
88
  });
86
89
  };
@@ -101,17 +104,17 @@ const goDevApiCommand = (argv) => __awaiter(void 0, void 0, void 0, function* ()
101
104
  // the exit is what keeps the ports free for the replacement.
102
105
  void (0, killChildWithEscalation_1.killChildWithEscalation)(child);
103
106
  };
104
- console.log('Bundling dev server (watch mode)...');
107
+ out.log('Bundling dev server (watch mode)...');
105
108
  let lastHash;
106
- const compiler = (0, core_1.rspack)(rspackConfig);
109
+ const compiler = (0, core_2.rspack)(rspackConfig);
107
110
  compiler.watch({ aggregateTimeout: 200 }, (err, stats) => {
108
111
  if (err) {
109
- console.error(err);
112
+ out.error(err);
110
113
  return;
111
114
  }
112
115
  if (stats === null || stats === void 0 ? void 0 : stats.hasErrors()) {
113
- console.error(stats.toString({ colors: true, chunks: false, modules: false }));
114
- console.log('Build failed — dev server not restarted. Fix the error and save again.');
116
+ out.error(stats.toString({ colors: true, chunks: false, modules: false }));
117
+ out.log('Build failed — dev server not restarted. Fix the error and save again.');
115
118
  return;
116
119
  }
117
120
  // Skip no-op rebuilds (e.g. the virtual-module-triggered second compile at
@@ -120,7 +123,7 @@ const goDevApiCommand = (argv) => __awaiter(void 0, void 0, void 0, function* ()
120
123
  return;
121
124
  }
122
125
  lastHash = stats === null || stats === void 0 ? void 0 : stats.hash;
123
- console.log(child ? 'Rebuilt. Restarting dev server...' : 'Dev server bundled. Starting...');
126
+ out.log(child ? 'Rebuilt. Restarting dev server...' : 'Dev server bundled. Starting...');
124
127
  restartServer();
125
128
  });
126
129
  // 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"]}