@supatype/cli 0.1.1 → 0.1.3

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 (334) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +126 -99
  3. package/.turbo/turbo-typecheck.log +2 -2
  4. package/dist/binary-cache.d.ts +2 -0
  5. package/dist/binary-cache.d.ts.map +1 -1
  6. package/dist/binary-cache.js +36 -0
  7. package/dist/binary-cache.js.map +1 -1
  8. package/dist/binary-download-lock.d.ts +12 -0
  9. package/dist/binary-download-lock.d.ts.map +1 -0
  10. package/dist/binary-download-lock.js +106 -0
  11. package/dist/binary-download-lock.js.map +1 -0
  12. package/dist/cli-package-version.d.ts +3 -0
  13. package/dist/cli-package-version.d.ts.map +1 -0
  14. package/dist/cli-package-version.js +15 -0
  15. package/dist/cli-package-version.js.map +1 -0
  16. package/dist/cli.d.ts.map +1 -1
  17. package/dist/cli.js +5 -2
  18. package/dist/cli.js.map +1 -1
  19. package/dist/commands/add.js +25 -19
  20. package/dist/commands/add.js.map +1 -1
  21. package/dist/commands/admin.d.ts +12 -0
  22. package/dist/commands/admin.d.ts.map +1 -1
  23. package/dist/commands/admin.js +116 -26
  24. package/dist/commands/admin.js.map +1 -1
  25. package/dist/commands/cache.d.ts +1 -1
  26. package/dist/commands/cache.d.ts.map +1 -1
  27. package/dist/commands/cache.js +98 -5
  28. package/dist/commands/cache.js.map +1 -1
  29. package/dist/commands/dev.d.ts.map +1 -1
  30. package/dist/commands/dev.js +26 -22
  31. package/dist/commands/dev.js.map +1 -1
  32. package/dist/commands/init.d.ts +3 -4
  33. package/dist/commands/init.d.ts.map +1 -1
  34. package/dist/commands/init.js +296 -121
  35. package/dist/commands/init.js.map +1 -1
  36. package/dist/commands/link-helpers.d.ts.map +1 -1
  37. package/dist/commands/link-helpers.js +26 -25
  38. package/dist/commands/link-helpers.js.map +1 -1
  39. package/dist/compose-local-server-image.d.ts +13 -0
  40. package/dist/compose-local-server-image.d.ts.map +1 -0
  41. package/dist/compose-local-server-image.js +57 -0
  42. package/dist/compose-local-server-image.js.map +1 -0
  43. package/dist/compose-rename.d.ts.map +1 -1
  44. package/dist/compose-rename.js +5 -8
  45. package/dist/compose-rename.js.map +1 -1
  46. package/dist/config.d.ts.map +1 -1
  47. package/dist/config.js +12 -1
  48. package/dist/config.js.map +1 -1
  49. package/dist/dev-compose.d.ts.map +1 -1
  50. package/dist/dev-compose.js +113 -56
  51. package/dist/dev-compose.js.map +1 -1
  52. package/dist/dev-log-bus.d.ts +5 -0
  53. package/dist/dev-log-bus.d.ts.map +1 -1
  54. package/dist/dev-log-bus.js +16 -0
  55. package/dist/dev-log-bus.js.map +1 -1
  56. package/dist/dev-log-filter.d.ts +4 -0
  57. package/dist/dev-log-filter.d.ts.map +1 -1
  58. package/dist/dev-log-filter.js +52 -0
  59. package/dist/dev-log-filter.js.map +1 -1
  60. package/dist/dev-ports.d.ts.map +1 -1
  61. package/dist/dev-ports.js +19 -12
  62. package/dist/dev-ports.js.map +1 -1
  63. package/dist/dev-ready-panel.d.ts +21 -0
  64. package/dist/dev-ready-panel.d.ts.map +1 -0
  65. package/dist/dev-ready-panel.js +67 -0
  66. package/dist/dev-ready-panel.js.map +1 -0
  67. package/dist/dev-session-lock.d.ts.map +1 -1
  68. package/dist/dev-session-lock.js +5 -8
  69. package/dist/dev-session-lock.js.map +1 -1
  70. package/dist/dev-session.d.ts +18 -5
  71. package/dist/dev-session.d.ts.map +1 -1
  72. package/dist/dev-session.js +91 -18
  73. package/dist/dev-session.js.map +1 -1
  74. package/dist/dev-shutdown.d.ts +2 -0
  75. package/dist/dev-shutdown.d.ts.map +1 -1
  76. package/dist/dev-shutdown.js +29 -15
  77. package/dist/dev-shutdown.js.map +1 -1
  78. package/dist/dev-task-colors.d.ts +3 -1
  79. package/dist/dev-task-colors.d.ts.map +1 -1
  80. package/dist/dev-task-colors.js +23 -3
  81. package/dist/dev-task-colors.js.map +1 -1
  82. package/dist/docker-runtime.js +1 -1
  83. package/dist/docker-runtime.js.map +1 -1
  84. package/dist/engine-push-output.d.ts +1 -0
  85. package/dist/engine-push-output.d.ts.map +1 -1
  86. package/dist/engine-push-output.js +4 -1
  87. package/dist/engine-push-output.js.map +1 -1
  88. package/dist/ensure-binary.d.ts.map +1 -1
  89. package/dist/ensure-binary.js +14 -2
  90. package/dist/ensure-binary.js.map +1 -1
  91. package/dist/ensure-component-binaries.d.ts +17 -0
  92. package/dist/ensure-component-binaries.d.ts.map +1 -0
  93. package/dist/ensure-component-binaries.js +45 -0
  94. package/dist/ensure-component-binaries.js.map +1 -0
  95. package/dist/ensure-dev-api-config.d.ts +3 -0
  96. package/dist/ensure-dev-api-config.d.ts.map +1 -0
  97. package/dist/ensure-dev-api-config.js +17 -0
  98. package/dist/ensure-dev-api-config.js.map +1 -0
  99. package/dist/init-dependency-versions.d.ts +13 -0
  100. package/dist/init-dependency-versions.d.ts.map +1 -0
  101. package/dist/init-dependency-versions.js +53 -0
  102. package/dist/init-dependency-versions.js.map +1 -0
  103. package/dist/init-package-json.d.ts +21 -0
  104. package/dist/init-package-json.d.ts.map +1 -0
  105. package/dist/init-package-json.js +46 -0
  106. package/dist/init-package-json.js.map +1 -0
  107. package/dist/init-project-detect.d.ts +14 -0
  108. package/dist/init-project-detect.d.ts.map +1 -0
  109. package/dist/init-project-detect.js +89 -0
  110. package/dist/init-project-detect.js.map +1 -0
  111. package/dist/postgres-ctl.d.ts.map +1 -1
  112. package/dist/postgres-ctl.js +2 -1
  113. package/dist/postgres-ctl.js.map +1 -1
  114. package/dist/required-host-components.d.ts +11 -0
  115. package/dist/required-host-components.d.ts.map +1 -0
  116. package/dist/required-host-components.js +25 -0
  117. package/dist/required-host-components.js.map +1 -0
  118. package/dist/resolve-api-url.d.ts +6 -0
  119. package/dist/resolve-api-url.d.ts.map +1 -0
  120. package/dist/resolve-api-url.js +39 -0
  121. package/dist/resolve-api-url.js.map +1 -0
  122. package/dist/rest-cache-admin.d.ts +33 -0
  123. package/dist/rest-cache-admin.d.ts.map +1 -0
  124. package/dist/rest-cache-admin.js +96 -0
  125. package/dist/rest-cache-admin.js.map +1 -0
  126. package/dist/scripts/postinstall.d.ts +4 -6
  127. package/dist/scripts/postinstall.d.ts.map +1 -1
  128. package/dist/scripts/postinstall.js +8 -41
  129. package/dist/scripts/postinstall.js.map +1 -1
  130. package/dist/self-host-compose.d.ts.map +1 -1
  131. package/dist/self-host-compose.js +23 -13
  132. package/dist/self-host-compose.js.map +1 -1
  133. package/dist/studio-dev-server.d.ts +4 -2
  134. package/dist/studio-dev-server.d.ts.map +1 -1
  135. package/dist/studio-dev-server.js +3 -2
  136. package/dist/studio-dev-server.js.map +1 -1
  137. package/dist/ui/brand.d.ts +2 -5
  138. package/dist/ui/brand.d.ts.map +1 -1
  139. package/dist/ui/brand.js +2 -7
  140. package/dist/ui/brand.js.map +1 -1
  141. package/dist/ui/clack-api.d.ts +44 -0
  142. package/dist/ui/clack-api.d.ts.map +1 -0
  143. package/dist/ui/clack-api.js +76 -0
  144. package/dist/ui/clack-api.js.map +1 -0
  145. package/dist/ui/clack.d.ts +14 -0
  146. package/dist/ui/clack.d.ts.map +1 -0
  147. package/dist/ui/clack.js +147 -0
  148. package/dist/ui/clack.js.map +1 -0
  149. package/dist/ui/components/FlowSpinner.d.ts +5 -0
  150. package/dist/ui/components/FlowSpinner.d.ts.map +1 -0
  151. package/dist/ui/components/FlowSpinner.js +8 -0
  152. package/dist/ui/components/FlowSpinner.js.map +1 -0
  153. package/dist/ui/components/LogoWordmark.d.ts +9 -0
  154. package/dist/ui/components/LogoWordmark.d.ts.map +1 -0
  155. package/dist/ui/components/LogoWordmark.js +17 -0
  156. package/dist/ui/components/LogoWordmark.js.map +1 -0
  157. package/dist/ui/components/PromptPanel.d.ts +5 -0
  158. package/dist/ui/components/PromptPanel.d.ts.map +1 -0
  159. package/dist/ui/components/PromptPanel.js +7 -0
  160. package/dist/ui/components/PromptPanel.js.map +1 -0
  161. package/dist/ui/components/SelectField.d.ts +11 -0
  162. package/dist/ui/components/SelectField.d.ts.map +1 -0
  163. package/dist/ui/components/SelectField.js +19 -0
  164. package/dist/ui/components/SelectField.js.map +1 -0
  165. package/dist/ui/confirm.d.ts +2 -1
  166. package/dist/ui/confirm.d.ts.map +1 -1
  167. package/dist/ui/confirm.js +4 -4
  168. package/dist/ui/confirm.js.map +1 -1
  169. package/dist/ui/dev/DevDashboard.d.ts +8 -0
  170. package/dist/ui/dev/DevDashboard.d.ts.map +1 -0
  171. package/dist/ui/dev/DevDashboard.js +158 -0
  172. package/dist/ui/dev/DevDashboard.js.map +1 -0
  173. package/dist/ui/dev/DevReadyPanelView.d.ts +8 -0
  174. package/dist/ui/dev/DevReadyPanelView.d.ts.map +1 -0
  175. package/dist/ui/dev/DevReadyPanelView.js +48 -0
  176. package/dist/ui/dev/DevReadyPanelView.js.map +1 -0
  177. package/dist/ui/fatal.d.ts.map +1 -1
  178. package/dist/ui/fatal.js +5 -11
  179. package/dist/ui/fatal.js.map +1 -1
  180. package/dist/ui/flows/FlowApp.d.ts +8 -0
  181. package/dist/ui/flows/FlowApp.d.ts.map +1 -0
  182. package/dist/ui/flows/FlowApp.js +44 -0
  183. package/dist/ui/flows/FlowApp.js.map +1 -0
  184. package/dist/ui/flows/prompt-fields.d.ts +48 -0
  185. package/dist/ui/flows/prompt-fields.d.ts.map +1 -0
  186. package/dist/ui/flows/prompt-fields.js +92 -0
  187. package/dist/ui/flows/prompt-fields.js.map +1 -0
  188. package/dist/ui/flows/types.d.ts +41 -0
  189. package/dist/ui/flows/types.d.ts.map +1 -0
  190. package/dist/ui/flows/types.js +2 -0
  191. package/dist/ui/flows/types.js.map +1 -0
  192. package/dist/ui/index.d.ts +1 -1
  193. package/dist/ui/index.js +1 -1
  194. package/dist/ui/messages.d.ts +1 -0
  195. package/dist/ui/messages.d.ts.map +1 -1
  196. package/dist/ui/messages.js +48 -8
  197. package/dist/ui/messages.js.map +1 -1
  198. package/dist/ui/progress.d.ts +5 -1
  199. package/dist/ui/progress.d.ts.map +1 -1
  200. package/dist/ui/progress.js +12 -3
  201. package/dist/ui/progress.js.map +1 -1
  202. package/dist/ui/prompts.d.ts +7 -5
  203. package/dist/ui/prompts.d.ts.map +1 -1
  204. package/dist/ui/prompts.js +15 -8
  205. package/dist/ui/prompts.js.map +1 -1
  206. package/dist/ui/runtime/cancel.d.ts +4 -0
  207. package/dist/ui/runtime/cancel.d.ts.map +1 -0
  208. package/dist/ui/runtime/cancel.js +6 -0
  209. package/dist/ui/runtime/cancel.js.map +1 -0
  210. package/dist/ui/runtime/command-chrome.d.ts +17 -0
  211. package/dist/ui/runtime/command-chrome.d.ts.map +1 -0
  212. package/dist/ui/runtime/command-chrome.js +123 -0
  213. package/dist/ui/runtime/command-chrome.js.map +1 -0
  214. package/dist/ui/runtime/dev-prompt-queue.d.ts +30 -0
  215. package/dist/ui/runtime/dev-prompt-queue.d.ts.map +1 -0
  216. package/dist/ui/runtime/dev-prompt-queue.js +57 -0
  217. package/dist/ui/runtime/dev-prompt-queue.js.map +1 -0
  218. package/dist/ui/runtime/flow-session.d.ts +4 -0
  219. package/dist/ui/runtime/flow-session.d.ts.map +1 -0
  220. package/dist/ui/runtime/flow-session.js +8 -0
  221. package/dist/ui/runtime/flow-session.js.map +1 -0
  222. package/dist/ui/runtime/run-clack-flow.d.ts +5 -0
  223. package/dist/ui/runtime/run-clack-flow.d.ts.map +1 -0
  224. package/dist/ui/runtime/run-clack-flow.js +46 -0
  225. package/dist/ui/runtime/run-clack-flow.js.map +1 -0
  226. package/dist/ui/runtime/stdin-after-ink.d.ts +3 -0
  227. package/dist/ui/runtime/stdin-after-ink.d.ts.map +1 -0
  228. package/dist/ui/runtime/stdin-after-ink.js +16 -0
  229. package/dist/ui/runtime/stdin-after-ink.js.map +1 -0
  230. package/dist/ui/theme.d.ts +24 -0
  231. package/dist/ui/theme.d.ts.map +1 -0
  232. package/dist/ui/theme.js +34 -0
  233. package/dist/ui/theme.js.map +1 -0
  234. package/dist/valkey-sidecar.d.ts +17 -0
  235. package/dist/valkey-sidecar.d.ts.map +1 -0
  236. package/dist/valkey-sidecar.js +94 -0
  237. package/dist/valkey-sidecar.js.map +1 -0
  238. package/package.json +9 -3
  239. package/src/binary-cache.ts +61 -0
  240. package/src/binary-download-lock.ts +124 -0
  241. package/src/cli-package-version.ts +15 -0
  242. package/src/cli.ts +6 -2
  243. package/src/commands/add.ts +26 -19
  244. package/src/commands/admin.ts +156 -29
  245. package/src/commands/cache.ts +105 -5
  246. package/src/commands/dev.ts +26 -21
  247. package/src/commands/init.ts +473 -247
  248. package/src/commands/link-helpers.ts +30 -29
  249. package/src/compose-local-server-image.ts +68 -0
  250. package/src/compose-rename.ts +5 -8
  251. package/src/config.ts +13 -1
  252. package/src/dev-compose.ts +139 -54
  253. package/src/dev-log-bus.ts +20 -0
  254. package/src/dev-log-filter.ts +42 -0
  255. package/src/dev-ports.ts +22 -11
  256. package/src/dev-ready-panel.ts +80 -0
  257. package/src/dev-session-lock.ts +5 -8
  258. package/src/dev-session.ts +98 -18
  259. package/src/dev-shutdown.ts +29 -17
  260. package/src/dev-task-colors.ts +22 -3
  261. package/src/docker-runtime.ts +1 -1
  262. package/src/engine-push-output.ts +5 -1
  263. package/src/ensure-binary.ts +21 -1
  264. package/src/ensure-component-binaries.ts +71 -0
  265. package/src/ensure-dev-api-config.ts +18 -0
  266. package/src/init-dependency-versions.ts +69 -0
  267. package/src/init-package-json.ts +63 -0
  268. package/src/init-project-detect.ts +99 -0
  269. package/src/postgres-ctl.ts +2 -1
  270. package/src/required-host-components.ts +37 -0
  271. package/src/resolve-api-url.ts +43 -0
  272. package/src/rest-cache-admin.ts +135 -0
  273. package/src/scripts/postinstall.ts +9 -46
  274. package/src/self-host-compose.ts +22 -12
  275. package/src/studio-dev-server.ts +5 -4
  276. package/src/ui/README.md +13 -9
  277. package/src/ui/brand.ts +2 -8
  278. package/src/ui/clack-api.ts +123 -0
  279. package/src/ui/clack.ts +153 -0
  280. package/src/ui/components/FlowSpinner.tsx +15 -0
  281. package/src/ui/components/LogoWordmark.tsx +36 -0
  282. package/src/ui/components/PromptPanel.tsx +17 -0
  283. package/src/ui/components/SelectField.tsx +58 -0
  284. package/src/ui/confirm.ts +5 -4
  285. package/src/ui/dev/DevDashboard.tsx +223 -0
  286. package/src/ui/dev/DevReadyPanelView.tsx +134 -0
  287. package/src/ui/fatal.ts +5 -10
  288. package/src/ui/flows/FlowApp.tsx +69 -0
  289. package/src/ui/flows/prompt-fields.tsx +198 -0
  290. package/src/ui/flows/types.ts +50 -0
  291. package/src/ui/index.ts +1 -1
  292. package/src/ui/messages.ts +50 -8
  293. package/src/ui/progress.ts +14 -3
  294. package/src/ui/prompts.ts +17 -9
  295. package/src/ui/runtime/cancel.ts +6 -0
  296. package/src/ui/runtime/command-chrome.ts +147 -0
  297. package/src/ui/runtime/dev-prompt-queue.ts +84 -0
  298. package/src/ui/runtime/flow-session.ts +11 -0
  299. package/src/ui/runtime/run-clack-flow.tsx +65 -0
  300. package/src/ui/runtime/stdin-after-ink.ts +18 -0
  301. package/src/ui/theme.ts +41 -0
  302. package/src/valkey-sidecar.ts +126 -0
  303. package/tests/admin-ensure.test.ts +80 -0
  304. package/tests/binary-cache-cloud-overrides.test.ts +2 -2
  305. package/tests/binary-download-lock.test.ts +41 -0
  306. package/tests/cli-help.test.ts +7 -4
  307. package/tests/cli-package-version.test.ts +15 -0
  308. package/tests/command-chrome-coverage.test.ts +149 -0
  309. package/tests/command-chrome-wrap.test.ts +51 -0
  310. package/tests/config.test.ts +27 -4
  311. package/tests/dev-ready-panel.test.ts +37 -0
  312. package/tests/dev-ui.test.ts +42 -2
  313. package/tests/docker-runtime.test.ts +9 -20
  314. package/tests/ensure-dev-api-config.test.ts +22 -0
  315. package/tests/init-dependency-versions.test.ts +62 -0
  316. package/tests/init-package-json.test.ts +18 -0
  317. package/tests/init-project-detect.test.ts +53 -0
  318. package/tests/init.test.ts +30 -3
  319. package/tests/required-host-components.test.ts +51 -0
  320. package/tests/resolve-api-url.test.ts +23 -0
  321. package/tests/rest-cache-admin.test.ts +28 -0
  322. package/tests/runtime-contract.test.ts +12 -3
  323. package/tests/stdin-after-ink.test.ts +8 -0
  324. package/tests/tsconfig.json +8 -2
  325. package/tests/ui-confirm.test.ts +13 -9
  326. package/tests/ui-messages.test.ts +4 -18
  327. package/tsconfig.json +1 -0
  328. package/tsconfig.tsbuildinfo +1 -1
  329. package/vitest.config.ts +3 -0
  330. package/dist/dev-tui.d.ts +0 -24
  331. package/dist/dev-tui.d.ts.map +0 -1
  332. package/dist/dev-tui.js +0 -188
  333. package/dist/dev-tui.js.map +0 -1
  334. package/src/dev-tui.ts +0 -232
@@ -12,7 +12,7 @@ import { targetFetch } from "../target-client.js"
12
12
  import { error, info, plain } from "../ui/messages.js"
13
13
  import { nextSteps } from "../ui/next-steps.js"
14
14
  import { isInteractive } from "../ui/interactive.js"
15
- import { ensureNotCancelled, printLogo, clack as p } from "../ui/prompts.js"
15
+ import { ensureNotCancelled, p, runClackFlow } from "../ui/prompts.js"
16
16
 
17
17
  function resolveLinkToken(opts: {
18
18
  token?: string
@@ -145,35 +145,36 @@ export async function runLinkAction(opts: {
145
145
  let url = opts.url
146
146
 
147
147
  if (isInteractive() && !project && !url) {
148
- printLogo()
149
- p.intro("Link this project")
150
- const targetKind = ensureNotCancelled(
151
- await p.select<"cloud" | "self-host">({
152
- message: "Link target",
153
- options: [
154
- { value: "cloud", label: "Supatype Cloud", hint: "managed project on supatype.com" },
155
- { value: "self-host", label: "Self-host", hint: "your Kong gateway URL" },
156
- ],
157
- }),
158
- )
159
- if (targetKind === "cloud") {
160
- project = ensureNotCancelled(
161
- await p.text({
162
- message: "Cloud project slug",
163
- placeholder: projectRef,
164
- defaultValue: projectRef,
148
+ await runClackFlow(async () => {
149
+ p.intro("Link this project")
150
+ const targetKind = ensureNotCancelled(
151
+ await p.select<"cloud" | "self-host">({
152
+ message: "Link target",
153
+ options: [
154
+ { value: "cloud", label: "Supatype Cloud", hint: "managed project on supatype.com" },
155
+ { value: "self-host", label: "Self-host", hint: "your Kong gateway URL" },
156
+ ],
165
157
  }),
166
- ).trim()
167
- } else {
168
- url = ensureNotCancelled(
169
- await p.text({
170
- message: "Kong gateway URL",
171
- placeholder: "https://api.example.com",
172
- defaultValue: "http://localhost:18473",
173
- }),
174
- ).trim()
175
- }
176
- p.outro("Linking...")
158
+ )
159
+ if (targetKind === "cloud") {
160
+ project = ensureNotCancelled(
161
+ await p.text({
162
+ message: "Cloud project slug",
163
+ placeholder: projectRef,
164
+ defaultValue: projectRef,
165
+ }),
166
+ ).trim()
167
+ } else {
168
+ url = ensureNotCancelled(
169
+ await p.text({
170
+ message: "Kong gateway URL",
171
+ placeholder: "https://api.example.com",
172
+ defaultValue: "http://localhost:18473",
173
+ }),
174
+ ).trim()
175
+ }
176
+ p.outro("Linking...")
177
+ })
177
178
  }
178
179
 
179
180
  const token = resolveLinkToken(opts)
@@ -0,0 +1,68 @@
1
+ import { existsSync } from "node:fs"
2
+ import { dirname, isAbsolute, join, resolve } from "node:path"
3
+ import { spawnSync } from "node:child_process"
4
+ import { VERSION_PIN_LOCAL } from "./binary-cache.js"
5
+ import { appendStackOutput, getActiveDevSession } from "./dev-session.js"
6
+ import { requireDockerDaemon } from "./docker-runtime.js"
7
+ import type { SupatypeProjectConfig } from "./project-config.js"
8
+
9
+ /** Docker tag for compose dev when `versions.server` is `local`. */
10
+ export const LOCAL_SERVER_DOCKER_IMAGE = "supatype/server:local-dev"
11
+
12
+ /** Find the server repo root (directory containing `Dockerfile`) from an overrides.server binary path. */
13
+ export function resolveServerSourceRoot(serverOverride: string, cwd: string): string | null {
14
+ const binaryPath = isAbsolute(serverOverride) ? serverOverride : resolve(cwd, serverOverride)
15
+ let dir = dirname(binaryPath)
16
+ for (let depth = 0; depth < 5; depth++) {
17
+ if (existsSync(join(dir, "Dockerfile"))) return dir
18
+ const parent = dirname(dir)
19
+ if (parent === dir) break
20
+ dir = parent
21
+ }
22
+ return null
23
+ }
24
+
25
+ /**
26
+ * When `versions.server` is `local`, build a Linux server image from the source tree
27
+ * next to `overrides.server` so compose dev matches the contributor's binary.
28
+ */
29
+ export async function ensureLocalServerDockerImage(
30
+ cwd: string,
31
+ config: SupatypeProjectConfig,
32
+ brand?: { intro?: string },
33
+ ): Promise<string | undefined> {
34
+ if (config.versions?.server !== VERSION_PIN_LOCAL) return undefined
35
+
36
+ const override = config.overrides?.server?.trim()
37
+ if (!override) return undefined
38
+
39
+ const root = resolveServerSourceRoot(override, cwd)
40
+ if (!root) {
41
+ console.warn(
42
+ `[supatype] ⚠ versions.server is "local" but no Dockerfile found near ${override}. ` +
43
+ "Compose will use the default supatype/server:latest image.",
44
+ )
45
+ return undefined
46
+ }
47
+
48
+ requireDockerDaemon(brand?.intro ? { brand: { intro: brand.intro } } : undefined)
49
+ const dockerfile = join(root, "Dockerfile")
50
+ console.log(`[supatype] Building local server Docker image from ${root}…`)
51
+ const result = spawnSync(
52
+ "docker",
53
+ ["build", "--progress=plain", "-t", LOCAL_SERVER_DOCKER_IMAGE, "-f", dockerfile, root],
54
+ { encoding: "utf8", stdio: "pipe" },
55
+ )
56
+ const tui = getActiveDevSession()?.isTui() ?? false
57
+ if (!tui) {
58
+ appendStackOutput(result.stdout, "log")
59
+ appendStackOutput(result.stderr, result.status === 0 ? "log" : "error")
60
+ } else if (result.status !== 0) {
61
+ appendStackOutput(result.stderr || result.stdout || "docker build failed", "error")
62
+ }
63
+ if (result.status !== 0) {
64
+ throw new Error(`docker build failed for local server (exit ${result.status ?? "unknown"})`)
65
+ }
66
+ console.log(`[supatype] Local server image ready: ${LOCAL_SERVER_DOCKER_IMAGE}`)
67
+ return LOCAL_SERVER_DOCKER_IMAGE
68
+ }
@@ -4,12 +4,12 @@
4
4
 
5
5
  import { existsSync, readFileSync } from "node:fs"
6
6
  import { join } from "node:path"
7
- import * as p from "@clack/prompts"
8
7
  import { loadLocalEnvironment } from "./link.js"
9
8
  import { composeStackHasContainers } from "./dev-session-lock.js"
10
9
  import { composeProjectName, runDockerCompose, type SelfHostComposePaths } from "./self-host-compose.js"
10
+ import { confirm as uiConfirm } from "./ui/confirm.js"
11
11
  import { isInteractive } from "./ui/interactive.js"
12
- import { warn } from "./ui/messages.js"
12
+ import { success, warn } from "./ui/messages.js"
13
13
 
14
14
  /**
15
15
  * When `project.name` changes, the compose project slug changes too (`supatype-{name}`).
@@ -39,19 +39,16 @@ export async function handleComposeProjectRename(
39
39
  return
40
40
  }
41
41
 
42
- const stopOld = await p.confirm({
43
- message: `${message}\n\nStop the old Docker stack now?`,
44
- initialValue: true,
45
- })
42
+ const stopOld = await uiConfirm(`${message}\n\nStop the old Docker stack now?`, { default: true })
46
43
 
47
- if (p.isCancel(stopOld) || !stopOld) {
44
+ if (!stopOld) {
48
45
  warn(`Leaving "${previousCompose}" running. Stop it with: docker compose -p ${previousCompose} down`)
49
46
  return
50
47
  }
51
48
 
52
49
  const status = runDockerCompose(paths.composePath, ["down"], cwd, previousCompose, { quiet: true })
53
50
  if (status === 0) {
54
- p.log.success(`Stopped old stack "${previousCompose}".`)
51
+ success(`Stopped old stack "${previousCompose}".`)
55
52
  warnIfHardcodedComposeScripts(cwd, previousCompose)
56
53
  } else {
57
54
  warn(`Could not stop "${previousCompose}" (exit ${status}). Try: docker compose -p ${previousCompose} down`)
package/src/config.ts CHANGED
@@ -158,7 +158,7 @@ process.stdout.write(JSON.stringify(config))
158
158
  }
159
159
 
160
160
  const failure = result.stderr || result.stdout
161
- if (!failure.includes("ERR_PACKAGE_PATH_NOT_EXPORTED")) {
161
+ if (!shouldStripCliImportOnLoadFailure(failure)) {
162
162
  throw new Error(`Failed to load ${candidate}:\n${failure}`)
163
163
  }
164
164
 
@@ -169,6 +169,18 @@ process.stdout.write(JSON.stringify(config))
169
169
  return null
170
170
  }
171
171
 
172
+ /** When @supatype/cli is not installed yet (e.g. during `supatype init`), strip its import. */
173
+ function shouldStripCliImportOnLoadFailure(failure: string): boolean {
174
+ if (failure.includes("ERR_PACKAGE_PATH_NOT_EXPORTED")) return true
175
+ if (!failure.includes("@supatype/cli")) return false
176
+ return (
177
+ failure.includes("ERR_MODULE_NOT_FOUND") ||
178
+ failure.includes("MODULE_NOT_FOUND") ||
179
+ failure.includes("Cannot find module '@supatype/cli'") ||
180
+ failure.includes('Cannot find package \'@supatype/cli\'')
181
+ )
182
+ }
183
+
172
184
  function loadTsConfigWithoutCliImport(
173
185
  configPath: string,
174
186
  cwd: string,
@@ -6,7 +6,7 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs"
6
6
  import { homedir } from "node:os"
7
7
  import { dirname, join, resolve } from "node:path"
8
8
  import { spawnSync } from "node:child_process"
9
- import { startProxyDevApp } from "./app/proxy-dev-app.js"
9
+ import { startProxyDevApp, resolveProxyDevScript } from "./app/proxy-dev-app.js"
10
10
  import { loadSchemaAst } from "./config.js"
11
11
  import {
12
12
  COMPOSE_DEV_KONG_PORT,
@@ -20,7 +20,8 @@ import { signJwt } from "./jwt.js"
20
20
  import { ensureDevDbPort, ensureKongPort } from "./dev-ports.js"
21
21
  import { handleComposeProjectRename } from "./compose-rename.js"
22
22
  import { recoverStaleDevSession, writeDevSessionLock } from "./dev-session-lock.js"
23
- import { readEnvValue, upsertEnvFile } from "./env-file.js"
23
+ import { endDevSession, startDevSession } from "./dev-session.js"
24
+ import { ensureDevApiConfig } from "./ensure-dev-api-config.js"
24
25
  import {
25
26
  COMPOSE_PINNED_IMAGE_ENV_KEYS,
26
27
  composeDockerImageEnv,
@@ -33,10 +34,11 @@ import {
33
34
  } from "./self-host-compose.js"
34
35
  import type { DockerBrandOptions } from "./docker-runtime.js"
35
36
  import { hasEngineOverride } from "./binary-cache.js"
36
- import { startStudioViteDevServer } from "./studio-dev-server.js"
37
+ import { STUDIO_DEV_PORT, startStudioViteDevServer } from "./studio-dev-server.js"
38
+ import { ensureLocalServerDockerImage } from "./compose-local-server-image.js"
37
39
  import { ensureEngine, engineRequest, type DiffResult } from "./engine-client.js"
38
40
  import { writeSchemaSourcePushArtifacts, type SchemaSourcePushArtifacts } from "./schema-sources.js"
39
- import { endDevSession } from "./dev-session.js"
41
+ import { readEnvValue, upsertEnvFile } from "./env-file.js"
40
42
  import { writeLocalEnvironment } from "./link.js"
41
43
  import { registerDevShutdown } from "./dev-shutdown.js"
42
44
  import {
@@ -50,6 +52,7 @@ import { restoreSystemRelationTargets } from "./restore-system-relation-targets.
50
52
  import { provisionBucketsFromAst } from "./storage-provision.js"
51
53
  import type { ExtractedSchemaAstV2 } from "./schema-ast-v2.js"
52
54
  import { ensureFirstAdminUserForProject } from "./commands/admin.js"
55
+ import { publishDevReady } from "./dev-ready-panel.js"
53
56
 
54
57
  const LOCAL_JWT_SECRET = "super-secret-jwt-token-with-at-least-32-characters-long"
55
58
 
@@ -171,6 +174,7 @@ function upsertDevComposeEnv(
171
174
  serviceRoleKey: string,
172
175
  kongPort: number,
173
176
  devDbPort?: number,
177
+ localServerImage?: string,
174
178
  ): void {
175
179
  const apiUrl = `http://localhost:${kongPort}`
176
180
  const imagePins = composeDockerImageEnv(config)
@@ -189,6 +193,7 @@ function upsertDevComposeEnv(
189
193
  SITE_URL: apiUrl,
190
194
  GOTRUE_MAILER_AUTOCONFIRM: "true",
191
195
  ...imagePins,
196
+ ...(localServerImage !== undefined && { SUPATYPE_SERVER_IMAGE: localServerImage }),
192
197
  }
193
198
  if (devDbPort !== undefined) {
194
199
  updates.SUPATYPE_DEV_DB_PORT = String(devDbPort)
@@ -207,8 +212,9 @@ function ensureDevComposeEnv(
207
212
  serviceRoleKey: string,
208
213
  kongPort: number,
209
214
  devDbPort?: number,
215
+ localServerImage?: string,
210
216
  ): void {
211
- upsertDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort)
217
+ upsertDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort, localServerImage)
212
218
  }
213
219
 
214
220
  async function waitComposeHealthy(paths: SelfHostComposePaths, cwd: string, maxMs: number, composeProject: string): Promise<void> {
@@ -244,6 +250,34 @@ async function waitKongReady(kongPort: number, maxSec: number): Promise<void> {
244
250
  throw new Error(`Kong gateway at ${base} did not become ready within ${maxSec}s`)
245
251
  }
246
252
 
253
+ /** Kong may be up while server → storage is still starting (503 or upstream errors). */
254
+ async function waitStorageApiReady(
255
+ kongPort: number,
256
+ serviceRoleKey: string,
257
+ maxSec: number,
258
+ ): Promise<void> {
259
+ const url = `http://localhost:${kongPort}/storage/v1/bucket`
260
+ const headers = { Authorization: `Bearer ${serviceRoleKey}` }
261
+ for (let i = 0; i < maxSec; i++) {
262
+ try {
263
+ const res = await fetch(url, { headers })
264
+ if (res.ok) return
265
+ const body = await res.text()
266
+ const kongUpstreamDown = body.includes("invalid response was received from the upstream server")
267
+ if (!kongUpstreamDown && res.status !== 503) {
268
+ // Non-transient storage response (e.g. 401) — stop waiting.
269
+ return
270
+ }
271
+ } catch {
272
+ /* retry */
273
+ }
274
+ await new Promise((r) => setTimeout(r, 1000))
275
+ }
276
+ console.warn(
277
+ `[supatype] Storage API at ${url} did not become ready within ${maxSec}s — bucket provisioning may fail.`,
278
+ )
279
+ }
280
+
247
281
  async function provisionDockerStorageBuckets(
248
282
  ast: ExtractedSchemaAstV2,
249
283
  kongPort: number,
@@ -641,6 +675,7 @@ export async function pushSchemaDocker(cwd: string, config: SupatypeProjectConfi
641
675
  exitComposeFailed(upGateway, "Could not start the Compose gateway stack.", pushBrand)
642
676
  }
643
677
  await waitKongReady(kongPort, 120)
678
+ await waitStorageApiReady(kongPort, serviceRoleKey, 90)
644
679
  await provisionDockerStorageBuckets(ast, kongPort, serviceRoleKey)
645
680
 
646
681
  await ensureFirstAdminUserForProject(cwd, config, {
@@ -666,14 +701,56 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
666
701
  const anonKey = signJwt({ ...jwtBase, role: "anon" }, LOCAL_JWT_SECRET)
667
702
  const serviceRoleKey = signJwt({ ...jwtBase, role: "service_role" }, LOCAL_JWT_SECRET)
668
703
 
669
- ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort)
704
+ const devBrand = { intro: "Local development" }
705
+ const localServerImage = await ensureLocalServerDockerImage(cwd, config, devBrand)
706
+
707
+ ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort, localServerImage)
670
708
 
671
709
  console.log(`[supatype] provider: docker — starting self-host Compose stack (project ${project}, gateway :${kongPort})...`)
672
710
  const paths = writeSelfHostCompose(cwd, config, { devLocal: true })
711
+ if (ensureDevApiConfig(cwd)) {
712
+ console.log("[supatype] API config written to .supatype/api-config.json")
713
+ }
714
+
715
+ type StudioProc = Awaited<ReturnType<typeof startStudioViteDevServer>>
716
+ type AppProc = ReturnType<typeof startProxyDevApp>
717
+ const shutdownState: {
718
+ studioProc: StudioProc
719
+ appProc: AppProc
720
+ schemaWatcher: import("node:fs").FSWatcher | null
721
+ debounceTimer: ReturnType<typeof setTimeout> | null
722
+ } = {
723
+ studioProc: null,
724
+ appProc: null,
725
+ schemaWatcher: null,
726
+ debounceTimer: null,
727
+ }
728
+
729
+ registerDevShutdown(async () => {
730
+ shutdownState.schemaWatcher?.close()
731
+ shutdownState.schemaWatcher = null
732
+ if (shutdownState.debounceTimer) {
733
+ clearTimeout(shutdownState.debounceTimer)
734
+ shutdownState.debounceTimer = null
735
+ }
736
+ console.log("[supatype] Shutting down compose...")
737
+ await shutdownState.studioProc?.stop()
738
+ await shutdownState.appProc?.stop()
739
+ const downStatus = runDockerCompose(paths.composePath, ["down"], cwd, project, { quiet: true })
740
+ if (downStatus === 0) {
741
+ console.log("[supatype] Compose stack stopped.")
742
+ } else {
743
+ console.warn(`[supatype] Compose down exited with status ${downStatus}.`)
744
+ }
745
+ }, {
746
+ cwd,
747
+ compose: { cwd, composePath: paths.composePath, composeProject: project },
748
+ })
749
+
673
750
  await recoverStaleDevSession(cwd)
674
751
  await handleComposeProjectRename(cwd, config.project.name, paths)
675
- const devBrand = { intro: "Local development" }
676
752
 
753
+ console.log("[supatype] Bringing up Docker Compose services...")
677
754
  const upStatus = runDockerCompose(paths.composePath, ["up", "-d"], cwd, project, {
678
755
  quiet: true,
679
756
  brand: devBrand,
@@ -691,12 +768,29 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
691
768
  console.error("[supatype] Initial schema push failed:", (e as Error).message),
692
769
  )
693
770
 
694
- await ensureFirstAdminUserForProject(cwd, config, {
695
- compose: { project, composePath: paths.composePath },
696
- })
771
+ if (localServerImage !== undefined) {
772
+ console.log("[supatype] Recreating server with local image...")
773
+ const recreateStatus = runDockerCompose(
774
+ paths.composePath,
775
+ ["up", "-d", "--force-recreate", "--no-deps", "server"],
776
+ cwd,
777
+ project,
778
+ { quiet: true, brand: devBrand },
779
+ )
780
+ if (recreateStatus !== 0) {
781
+ endDevSession()
782
+ exitComposeFailed(recreateStatus, "Could not recreate the server container with the local image.", devBrand)
783
+ }
784
+ }
697
785
 
698
786
  console.log("[supatype] Waiting for API gateway...")
699
787
  await waitKongReady(kongPort, 120)
788
+ console.log("[supatype] Waiting for storage API...")
789
+ await waitStorageApiReady(kongPort, serviceRoleKey, 90)
790
+
791
+ await ensureFirstAdminUserForProject(cwd, config, {
792
+ compose: { project, composePath: paths.composePath },
793
+ })
700
794
 
701
795
  writeLocalEnvironment(cwd, {
702
796
  target: "local",
@@ -721,7 +815,9 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
721
815
  const pidDir = join(homedir(), ".supatype", "projects", config.project.name, "pid")
722
816
  mkdirSync(pidDir, { recursive: true })
723
817
 
724
- let studioProc: Awaited<ReturnType<typeof startStudioViteDevServer>> = null
818
+ startDevSession()
819
+
820
+ let studioProc: StudioProc = null
725
821
  const studioOverride = config.overrides?.studio
726
822
  if (studioOverride) {
727
823
  studioProc = startStudioViteDevServer({
@@ -730,66 +826,55 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
730
826
  pidDir,
731
827
  serviceRoleKey,
732
828
  proxyTarget: `http://localhost:${kongPort}`,
733
- viteSupatypeUrl: `http://localhost:${kongPort}`,
829
+ viteSupatypeUrl: `http://localhost:${STUDIO_DEV_PORT}`,
734
830
  basePath: "/studio/",
735
831
  })
736
832
  studioProc?.start()
833
+ shutdownState.studioProc = studioProc
737
834
  if (studioProc) {
738
- console.log("[supatype] Studio Vite dev server (overrides.studio) — live reload at /studio/")
835
+ console.log(
836
+ `[supatype] Studio (overrides.studio) — live reload proxied at http://localhost:${kongPort}/studio/`,
837
+ )
739
838
  }
740
839
  }
741
840
 
742
- console.log(`
743
- [supatype] Services running (Docker Compose · project ${project}):
744
- API (Kong) http://localhost:${kongPort}
745
- REST API http://localhost:${kongPort}/rest/v1/
746
- Auth http://localhost:${kongPort}/auth/v1/
747
- Storage http://localhost:${kongPort}/storage/v1/
748
- Realtime ws://localhost:${kongPort}/realtime/v1/
749
- Studio http://localhost:${kongPort}/studio/
841
+ const links = [
842
+ { label: "API", url: `http://localhost:${kongPort}` },
843
+ { label: "REST", url: `http://localhost:${kongPort}/rest/v1/` },
844
+ { label: "Auth", url: `http://localhost:${kongPort}/auth/v1/` },
845
+ { label: "Storage", url: `http://localhost:${kongPort}/storage/v1/` },
846
+ { label: "Realtime", url: `ws://localhost:${kongPort}/realtime/v1/` },
847
+ ]
848
+ if (resolveProxyDevScript(config) !== null) {
849
+ links.push({ label: "App", url: `http://localhost:${kongPort}/` })
850
+ }
851
+ links.push({ label: "Studio", url: `http://localhost:${kongPort}/studio/` })
750
852
 
751
- API keys (local dev only):
752
- anon key ${anonKey}
753
- service_role ${serviceRoleKey}
853
+ const hints: string[] = []
854
+ if (existsSync(join(cwd, "seed.ts"))) {
855
+ hints.push("Demo data: pnpm seed")
856
+ }
754
857
 
755
- Press Ctrl+C to stop.
756
- `)
858
+ publishDevReady({
859
+ title: `Services running (Docker · ${project})`,
860
+ links,
861
+ anonKey,
862
+ serviceRoleKey,
863
+ ...(hints.length > 0 ? { hints } : {}),
864
+ })
757
865
 
758
866
  const appProc = startProxyDevApp(cwd, config, pidDir)
759
-
760
- let schemaWatcher: import("node:fs").FSWatcher | null = null
761
- let debounceTimer: ReturnType<typeof setTimeout> | null = null
762
-
763
- registerDevShutdown(async () => {
764
- schemaWatcher?.close()
765
- schemaWatcher = null
766
- if (debounceTimer) {
767
- clearTimeout(debounceTimer)
768
- debounceTimer = null
769
- }
770
- console.log("[supatype] Shutting down compose...")
771
- await studioProc?.stop()
772
- await appProc?.stop()
773
- const downStatus = runDockerCompose(paths.composePath, ["down"], cwd, project, { quiet: true })
774
- if (downStatus === 0) {
775
- console.log("[supatype] Compose stack stopped.")
776
- } else {
777
- console.warn(`[supatype] Compose down exited with status ${downStatus}.`)
778
- }
779
- }, {
780
- cwd,
781
- compose: { cwd, composePath: paths.composePath, composeProject: project },
782
- })
867
+ shutdownState.appProc = appProc
783
868
 
784
869
  if (opts.watch) {
785
870
  const schemaDir = join(projectRootFromConfig(config, cwd), config.schema?.path ?? "schema/index.ts", "..")
786
871
  console.log(`[supatype] Watching ${schemaDir} for changes...`)
787
872
  const { watch } = await import("node:fs")
788
- schemaWatcher = watch(schemaDir, { recursive: true }, (_eventType, filename) => {
873
+ shutdownState.schemaWatcher = watch(schemaDir, { recursive: true }, (_eventType, filename) => {
789
874
  if (!filename?.endsWith(".ts")) return
790
- if (debounceTimer) clearTimeout(debounceTimer)
791
- debounceTimer = setTimeout(() => {
792
- debounceTimer = null
875
+ if (shutdownState.debounceTimer) clearTimeout(shutdownState.debounceTimer)
876
+ shutdownState.debounceTimer = setTimeout(() => {
877
+ shutdownState.debounceTimer = null
793
878
  console.log(`\n[supatype] Change detected in ${filename}, pushing schema...`)
794
879
  runComposeSchemaPushQueued(cwd, config, paths, schemaPath, project)
795
880
  .then(async () => {
@@ -2,6 +2,9 @@
2
2
  * Per-task log buffers for `supatype dev` TUI mode.
3
3
  */
4
4
 
5
+ import type { DevReadyPanel } from "./dev-ready-panel.js"
6
+ import { devReadyPanelCompactRowCount, devReadyPanelRowCount } from "./dev-ready-panel.js"
7
+
5
8
  export type DevLogLevel = "log" | "warn" | "error"
6
9
 
7
10
  export interface DevTask {
@@ -18,6 +21,7 @@ export class DevLogBus {
18
21
  private readonly order: string[] = []
19
22
  private readonly listeners = new Set<() => void>()
20
23
  private focusedTaskId = "stack"
24
+ private readyPanel: DevReadyPanel | null = null
21
25
 
22
26
  constructor(private readonly maxLines = DEFAULT_MAX_LINES) {
23
27
  this.registerTask("stack", "supatype")
@@ -66,6 +70,22 @@ export class DevLogBus {
66
70
  if (prev) this.setFocusedTaskId(prev)
67
71
  }
68
72
 
73
+ setReadyPanel(panel: DevReadyPanel): void {
74
+ this.readyPanel = panel
75
+ this.notify()
76
+ }
77
+
78
+ getReadyPanel(): DevReadyPanel | null {
79
+ return this.readyPanel
80
+ }
81
+
82
+ readyPanelRowCount(compact = false): number {
83
+ if (!this.readyPanel) return 0
84
+ return compact
85
+ ? devReadyPanelCompactRowCount(this.readyPanel)
86
+ : devReadyPanelRowCount(this.readyPanel)
87
+ }
88
+
69
89
  append(taskId: string, line: string, level: DevLogLevel = "log"): void {
70
90
  this.ensureTask(taskId, taskId)
71
91
  const task = this.tasks.get(taskId)
@@ -2,6 +2,8 @@
2
2
  * Line filters for subprocess output during `supatype dev`.
3
3
  */
4
4
 
5
+ import { isComposeProgressLine } from "./engine-push-output.js"
6
+
5
7
  /** Strip ANSI SGR sequences for TUI rendering. */
6
8
  export function stripAnsi(text: string): string {
7
9
  return text.replace(/\x1b\[[0-9;]*m/g, "")
@@ -17,6 +19,46 @@ export function filterDevSubprocessLine(taskId: string, line: string): boolean {
17
19
  return true
18
20
  }
19
21
 
22
+ const DOCKER_BUILD_NOISE =
23
+ /^#\d+\s|^#\d+ \[|^\s*=> \[|^\s*=>\s|^\s*--->\s|^\s*\d+\.\d+s\s|^\s*CACHED\s|^\s*DONE\s[\d.]+s?$|^Step \d+\/\d+|^Successfully (built|tagged)|^WARNING:|^DEPRECATED:|^View build details:|^What's next:|^The push refers to|^Using docker|^Sending build context|^Pulling fs layer|^Waiting$|^Verifying Checksum|^Download complete|^Pull complete|^Extracting \[|^Already exists$|^Building dependency tree|^Reading state information|^Get:\d+ |^Fetched \d+ |^Reading package lists|^Preparing to unpack|^Unpacking |^Setting up /i
24
+
25
+ /** Drop docker build / compose progress from the orchestrator (stack) pane. */
26
+ export function filterStackLogLine(line: string): boolean {
27
+ const t = stripAnsi(line).trim()
28
+ if (!t) return false
29
+
30
+ if (t.startsWith("✗ ") || t.startsWith("⚠ ")) return true
31
+ if (/https?:\/\//.test(t) || /^ws:\/\//.test(t)) return true
32
+ if (/\[supatype\]/.test(line)) return true
33
+ if (/^Services running/i.test(t)) return true
34
+ if (/^(anon key|service_role|API \(Kong\)|REST API|Auth|Storage|Realtime|Studio|App|Demo data|Postgres|supatype-server|Press Ctrl)/.test(t)) {
35
+ return true
36
+ }
37
+ if (/^Applied \d+ operation|^Schema up to date|^Schema pushed|^Watching .+ for changes|^Change detected|^Shutting down|^Compose stack stopped|^Local server image ready|^Building local server|^Waiting for |^Recreating server|^API config written|^provider: docker|^Bringing up Docker|^Schema push failed|^Initial schema push failed|^Storage bucket|^Storage API at|^Local binary overrides active|^Resolving component binaries|^Postgres |^Demo data:|^JWT secret:/.test(t)) {
38
+ return true
39
+ }
40
+ if (/^\S+\s+→\s/.test(t)) return true
41
+ if (isComposeProgressLine(t)) return false
42
+ if (DOCKER_BUILD_NOISE.test(t)) return false
43
+ if (/^Container\s+/i.test(t)) return false
44
+ if (/^Image\s+/i.test(t)) return false
45
+ if (/^network\s+\S+\s+(Creating|Created)/i.test(t)) return false
46
+ if (/^volume\s+\S+\s+(Creating|Created)/i.test(t)) return false
47
+
48
+ return false
49
+ }
50
+
51
+ /** Drop docker noise only — keep diff tables, push status, and command output. */
52
+ export function filterCommandLogLine(line: string): boolean {
53
+ const t = stripAnsi(line).trim()
54
+ if (!t) return false
55
+ if (isComposeProgressLine(t)) return false
56
+ if (DOCKER_BUILD_NOISE.test(t)) return false
57
+ if (/^Container\s+/i.test(t)) return false
58
+ if (/^Image\s+/i.test(t)) return false
59
+ return true
60
+ }
61
+
20
62
  /** Format console.* arguments the way Node does for a single log line. */
21
63
  export function formatConsoleArgs(args: unknown[]): string {
22
64
  return args