@ultimat3/cli 29.4.0 → 30.1.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 (448) hide show
  1. package/CLAUDE.md +64 -40
  2. package/README.md +61 -11
  3. package/package.json +42 -28
  4. package/src/affected-tests.ts +97 -0
  5. package/src/affected-unowned.ts +43 -0
  6. package/src/affected.ts +25 -6
  7. package/src/app-boundaries.ts +29 -1
  8. package/src/app-evals.ts +12 -4
  9. package/src/app-load-unresolved.ts +62 -0
  10. package/src/app-load.ts +30 -37
  11. package/src/app-mcp.ts +14 -2
  12. package/src/app-module-graph.ts +232 -0
  13. package/src/app-reload-graph.ts +2 -2
  14. package/src/app-root.ts +37 -1
  15. package/src/bin.ts +1 -0
  16. package/src/boundary-findings.ts +6 -0
  17. package/src/budgets-freshness.ts +32 -0
  18. package/src/budgets.ts +20 -1
  19. package/src/build-capture-env.ts +9 -0
  20. package/src/cdp-shot-a11y.ts +2 -39
  21. package/src/ci-tested.ts +243 -0
  22. package/src/client-emit-customer-runtime.ts +139 -0
  23. package/src/client-emit-customer.ts +108 -0
  24. package/src/client-emit-drift.ts +72 -0
  25. package/src/client-emit-header.ts +67 -0
  26. package/src/client-emit-schemas.ts +175 -0
  27. package/src/client-emit-types.ts +121 -0
  28. package/src/client-emit-vendor.ts +146 -0
  29. package/src/client-errors-routes.ts +229 -0
  30. package/src/client-errors-script.ts +74 -0
  31. package/src/client-vitals-route.ts +197 -0
  32. package/src/client-vitals-script.ts +56 -0
  33. package/src/cmd-affected.ts +23 -0
  34. package/src/cmd-build-spec.ts +7 -1
  35. package/src/cmd-build.ts +35 -9
  36. package/src/cmd-ci-spec.ts +42 -6
  37. package/src/cmd-ci.ts +99 -2
  38. package/src/cmd-client-customer.ts +134 -0
  39. package/src/cmd-client-source.ts +81 -0
  40. package/src/cmd-client-spec.ts +48 -0
  41. package/src/cmd-client-write.ts +41 -0
  42. package/src/cmd-client.ts +111 -0
  43. package/src/cmd-db-recount.ts +120 -0
  44. package/src/cmd-db-spec.ts +36 -6
  45. package/src/cmd-db.ts +11 -3
  46. package/src/cmd-deploy-compose.ts +61 -3
  47. package/src/cmd-deploy-drain.ts +10 -2
  48. package/src/cmd-deploy-helm.ts +11 -0
  49. package/src/cmd-deploy-preflight.ts +118 -0
  50. package/src/cmd-deploy-spec.ts +58 -6
  51. package/src/cmd-deploy-verify.ts +380 -0
  52. package/src/cmd-deploy.ts +42 -9
  53. package/src/cmd-docs.ts +34 -4
  54. package/src/cmd-doctor.ts +66 -9
  55. package/src/cmd-drill-spec.ts +25 -0
  56. package/src/cmd-drill.ts +176 -0
  57. package/src/cmd-env-init.ts +102 -0
  58. package/src/cmd-env-spec.ts +10 -3
  59. package/src/cmd-env.ts +15 -10
  60. package/src/cmd-errors-recent.ts +60 -0
  61. package/src/cmd-errors-spec.ts +9 -1
  62. package/src/cmd-errors.ts +4 -0
  63. package/src/cmd-exercise-spec.ts +19 -0
  64. package/src/cmd-exercise.ts +129 -0
  65. package/src/cmd-generate-spec.ts +9 -1
  66. package/src/cmd-generate.ts +32 -27
  67. package/src/cmd-graph-load.ts +97 -0
  68. package/src/cmd-graph-spec.ts +16 -0
  69. package/src/cmd-graph.ts +73 -0
  70. package/src/cmd-i18n.ts +4 -1
  71. package/src/cmd-impact-spec.ts +13 -0
  72. package/src/cmd-impact.ts +64 -0
  73. package/src/cmd-jobs-resolve.ts +76 -0
  74. package/src/cmd-jobs-spec.ts +21 -2
  75. package/src/cmd-jobs.ts +10 -6
  76. package/src/cmd-mail-spec.ts +28 -0
  77. package/src/cmd-mail.ts +70 -0
  78. package/src/cmd-mcp-lock.ts +69 -0
  79. package/src/cmd-mcp-spec.ts +23 -4
  80. package/src/cmd-mcp.ts +17 -3
  81. package/src/cmd-new-spec.ts +8 -1
  82. package/src/cmd-new.ts +61 -9
  83. package/src/cmd-planned.ts +0 -6
  84. package/src/cmd-repro-spec.ts +31 -0
  85. package/src/cmd-repro.ts +174 -0
  86. package/src/cmd-stop-spec.ts +21 -0
  87. package/src/cmd-stop.ts +166 -0
  88. package/src/cmd-test-spec.ts +17 -4
  89. package/src/cmd-test.ts +70 -14
  90. package/src/cmd-upgrade-spec.ts +26 -0
  91. package/src/cmd-upgrade.ts +274 -0
  92. package/src/cmd-verify-spec.ts +3 -3
  93. package/src/db-backfill.ts +6 -0
  94. package/src/db-diagnostics.ts +106 -0
  95. package/src/db-generate.ts +9 -0
  96. package/src/db-reset-template.ts +1 -1
  97. package/src/db-rolling.ts +45 -0
  98. package/src/db-seed-generate.ts +188 -0
  99. package/src/deploy-verify-findings.ts +98 -0
  100. package/src/deploy-verify-flags.ts +109 -0
  101. package/src/deploy-verify-grade.ts +185 -0
  102. package/src/deploy-verify-queues.ts +53 -0
  103. package/src/dev-boot.ts +35 -15
  104. package/src/dev-child-watch.ts +16 -4
  105. package/src/dev-dashboard-guard.ts +8 -1
  106. package/src/dev-dashboard.ts +7 -0
  107. package/src/dev-lock-identity.ts +61 -0
  108. package/src/dev-lock-port-holder.ts +80 -0
  109. package/src/dev-lock-steal.ts +124 -0
  110. package/src/dev-lock.ts +92 -120
  111. package/src/dev-mail-templates.ts +51 -0
  112. package/src/dev-rebuild.ts +26 -2
  113. package/src/dev-route-table.ts +17 -0
  114. package/src/dev-supervisor.ts +5 -2
  115. package/src/dev-watch-tree.ts +11 -10
  116. package/src/dev-watch.ts +1 -1
  117. package/src/dispatch.ts +29 -6
  118. package/src/docs-section.ts +69 -0
  119. package/src/docs-sources.ts +100 -0
  120. package/src/doctor-auth.ts +11 -2
  121. package/src/doctor-chart-alerts.ts +55 -0
  122. package/src/doctor-pooler.ts +107 -0
  123. package/src/doctor-rolling.ts +35 -0
  124. package/src/doctor-row-security.ts +40 -0
  125. package/src/document-options.ts +13 -0
  126. package/src/drill-sync-lane.ts +25 -0
  127. package/src/drill-targets.ts +39 -0
  128. package/src/duplicate-packages.ts +1 -1
  129. package/src/env-production.ts +93 -0
  130. package/src/error-codes-shot.ts +59 -0
  131. package/src/error-codes-tooling.ts +29 -0
  132. package/src/error-codes.ts +100 -54
  133. package/src/error-contract.ts +2 -2
  134. package/src/errors.ts +22 -3
  135. package/src/exercise-database.ts +99 -0
  136. package/src/exercise-findings.ts +159 -0
  137. package/src/exercise-overrides.ts +42 -0
  138. package/src/exercise-registration.ts +58 -0
  139. package/src/exercise-static.ts +88 -0
  140. package/src/exercise-subject.ts +69 -0
  141. package/src/failure-capture-boot.ts +30 -0
  142. package/src/framework-env.ts +7 -1
  143. package/src/framework-schema.ts +72 -5
  144. package/src/generate-catalog-locales.ts +19 -0
  145. package/src/generate-chart-alerts.ts +156 -0
  146. package/src/generate-feature-required.ts +65 -0
  147. package/src/generate-feature.ts +83 -6
  148. package/src/generate-files.ts +24 -0
  149. package/src/generate-format-written.ts +32 -0
  150. package/src/generate-kinds.ts +6 -0
  151. package/src/generate-sign-in-config.ts +100 -0
  152. package/src/generate-sign-in-manifest.ts +28 -0
  153. package/src/generate-sign-in-mode.ts +101 -0
  154. package/src/generate-sign-in.ts +250 -0
  155. package/src/generate-write.ts +44 -7
  156. package/src/hand-rolled-socket.ts +72 -0
  157. package/src/i18n-app-key-shapes.ts +29 -0
  158. package/src/i18n-audit.ts +10 -3
  159. package/src/i18n-registration.ts +18 -3
  160. package/src/index.ts +2 -0
  161. package/src/island-bundle.ts +4 -3
  162. package/src/island-disposer.ts +116 -0
  163. package/src/island-realtime-state.ts +34 -6
  164. package/src/island-realtime.ts +6 -2
  165. package/src/island-routes.ts +3 -2
  166. package/src/isr-query-advice.ts +6 -11
  167. package/src/isr-query-guard.ts +4 -3
  168. package/src/job-budget.ts +95 -0
  169. package/src/jobs-json.ts +11 -0
  170. package/src/lint-findings.ts +104 -0
  171. package/src/local-cli.ts +34 -4
  172. package/src/loopback-host.ts +2 -2
  173. package/src/mail-preview-findings.ts +24 -0
  174. package/src/mcp-errors.ts +82 -2
  175. package/src/mcp-host.ts +11 -1
  176. package/src/mcp-lock-findings.ts +57 -0
  177. package/src/measure-paths.ts +12 -4
  178. package/src/measure-scope.ts +27 -13
  179. package/src/messages-client.ts +23 -0
  180. package/src/messages-db.ts +56 -0
  181. package/src/messages-gate.ts +107 -0
  182. package/src/messages-repro.ts +11 -0
  183. package/src/messages-shot.ts +51 -0
  184. package/src/messages-upgrade.ts +45 -0
  185. package/src/messages.ts +53 -178
  186. package/src/metrics-endpoint.ts +23 -5
  187. package/src/new-shapes-generate.ts +71 -0
  188. package/src/new-shapes.ts +63 -0
  189. package/src/openapi-compile-ir.ts +68 -0
  190. package/src/openapi-compile-schema.ts +284 -0
  191. package/src/openapi-compile.ts +273 -0
  192. package/src/openapi-refuse.ts +45 -0
  193. package/src/otlp-export.ts +2 -1
  194. package/src/output-findings.ts +123 -0
  195. package/src/output.ts +32 -8
  196. package/src/package-boundaries.ts +110 -0
  197. package/src/page-pins.ts +23 -0
  198. package/src/plain-routes.ts +13 -0
  199. package/src/prerender-entries.ts +59 -0
  200. package/src/prerender-heaviest.ts +27 -0
  201. package/src/prerender-preload.ts +6 -0
  202. package/src/prerender-report.ts +12 -0
  203. package/src/prerender-seo-reads.ts +38 -0
  204. package/src/prerender-served.ts +22 -7
  205. package/src/prerender-vitals.ts +42 -0
  206. package/src/prerender.ts +61 -32
  207. package/src/pwa-artifacts.ts +4 -3
  208. package/src/pwa-manifest-locales.ts +1 -1
  209. package/src/registry.ts +18 -0
  210. package/src/repro-bundle.ts +65 -0
  211. package/src/repro-errors.ts +47 -0
  212. package/src/repro-job.ts +72 -0
  213. package/src/repro-literal.ts +41 -0
  214. package/src/repro-request.ts +48 -0
  215. package/src/repro-write.ts +100 -0
  216. package/src/retain-sweep.ts +27 -0
  217. package/src/retained-assets-boot.ts +113 -0
  218. package/src/retained-assets-layout.ts +110 -0
  219. package/src/retained-assets-read.ts +142 -0
  220. package/src/retained-assets-sweep.ts +70 -0
  221. package/src/retained-assets.ts +171 -0
  222. package/src/revalidated-response.ts +8 -5
  223. package/src/role-replicator.ts +7 -1
  224. package/src/role-start-devices.ts +119 -0
  225. package/src/role-start-types.ts +6 -0
  226. package/src/role-start.ts +22 -5
  227. package/src/role-sync.ts +7 -1
  228. package/src/route-islands.ts +42 -0
  229. package/src/route-table.ts +2 -1
  230. package/src/row-security-boot.ts +58 -0
  231. package/src/row-security-wanted.ts +32 -0
  232. package/src/runtime-admin.ts +0 -1
  233. package/src/runtime-assets-site-cache.ts +55 -0
  234. package/src/runtime-assets-site.ts +136 -0
  235. package/src/runtime-assets.ts +99 -55
  236. package/src/runtime-bindings.ts +19 -3
  237. package/src/runtime-cache.ts +23 -14
  238. package/src/runtime-isr-outcome.ts +114 -60
  239. package/src/runtime-purge.ts +14 -2
  240. package/src/runtime-queue.ts +31 -4
  241. package/src/runtime-render-document.ts +204 -0
  242. package/src/runtime-render.ts +48 -198
  243. package/src/runtime-replica-position.ts +62 -0
  244. package/src/runtime-replica.ts +18 -3
  245. package/src/runtime-s3-path-style.ts +17 -0
  246. package/src/runtime-services.ts +19 -6
  247. package/src/runtime-statement-bound.ts +22 -0
  248. package/src/runtime-storage-upload.ts +9 -0
  249. package/src/runtime-storage.ts +41 -81
  250. package/src/schema-diff-views.ts +54 -0
  251. package/src/schema-diff.ts +21 -3
  252. package/src/schema-drift.ts +28 -9
  253. package/src/schema-dump-drift.ts +91 -7
  254. package/src/script-csp.ts +1 -1
  255. package/src/seo-cards.ts +26 -0
  256. package/src/seo-routes.ts +22 -8
  257. package/src/serve-boot.ts +54 -21
  258. package/src/serve-drain.ts +1 -0
  259. package/src/serve-env.ts +26 -8
  260. package/src/serve-retire.ts +12 -6
  261. package/src/serve-web.ts +42 -4
  262. package/src/serve.ts +9 -7
  263. package/src/site-asset-routes.ts +7 -1
  264. package/src/site-config.ts +4 -0
  265. package/src/site-llms-pages.ts +106 -0
  266. package/src/site-llms.ts +64 -0
  267. package/src/site-seo-write.ts +4 -2
  268. package/src/site-seo.ts +55 -6
  269. package/src/source-mtime.ts +50 -0
  270. package/src/static-capture-errors.ts +41 -0
  271. package/src/static-capture.ts +56 -0
  272. package/src/static-cards-serve.ts +39 -0
  273. package/src/static-cards.ts +93 -0
  274. package/src/static-document.ts +14 -13
  275. package/src/static-images.ts +115 -0
  276. package/src/stream-hole-scope.ts +55 -0
  277. package/src/style-bundle.ts +1 -1
  278. package/src/style-routes.ts +3 -2
  279. package/src/sw-precache-plan.ts +2 -2
  280. package/src/sw-routes.ts +2 -2
  281. package/src/templates/action-tests.ts +306 -0
  282. package/src/templates/action.ts +81 -269
  283. package/src/templates/backfill.ts +1 -1
  284. package/src/templates/entity.ts +21 -5
  285. package/src/templates/github/ci.yml.ts +8 -9
  286. package/src/templates/guard-bare-error.ts +2 -2
  287. package/src/templates/guard-error-declared.ts +263 -0
  288. package/src/templates/guard-native-confirm.ts +132 -0
  289. package/src/templates/guard-raw-fetch.ts +151 -0
  290. package/src/templates/guard-raw-interval.ts +121 -0
  291. package/src/templates/guard-repo-raw-sql.ts +71 -2
  292. package/src/templates/job.ts +1 -1
  293. package/src/templates/naming.ts +5 -0
  294. package/src/templates/pinned/docker-compose.yml +6 -0
  295. package/src/templates/pinned-images.ts +8 -0
  296. package/src/templates/policy.ts +85 -2
  297. package/src/templates/query.ts +70 -13
  298. package/src/templates/resource-create.ts +3 -1
  299. package/src/templates/resource-form-island.ts +15 -4
  300. package/src/templates/resource-page-db.ts +83 -0
  301. package/src/templates/resource-page.ts +161 -52
  302. package/src/templates/route.ts +4 -6
  303. package/src/templates/scaffold-app.ts +3 -0
  304. package/src/templates/scaffold-auth.ts +2 -1
  305. package/src/templates/scaffold-bin.ts +5 -52
  306. package/src/templates/scaffold-claude-agents.ts +19 -19
  307. package/src/templates/scaffold-claude-commands.ts +28 -31
  308. package/src/templates/scaffold-claude.ts +26 -23
  309. package/src/templates/scaffold-container-compose.ts +6 -1
  310. package/src/templates/scaffold-container.ts +24 -4
  311. package/src/templates/scaffold-dashboard-bare.ts +3 -3
  312. package/src/templates/scaffold-dashboard-example-tests.ts +49 -9
  313. package/src/templates/scaffold-dashboard-example-view.ts +156 -0
  314. package/src/templates/scaffold-dashboard-example.ts +43 -131
  315. package/src/templates/scaffold-dashboard-shared.ts +3 -7
  316. package/src/templates/scaffold-db-client.ts +20 -6
  317. package/src/templates/scaffold-db-package.ts +5 -14
  318. package/src/templates/scaffold-docs.ts +73 -57
  319. package/src/templates/scaffold-domain-package.ts +18 -14
  320. package/src/templates/scaffold-entries.ts +7 -2
  321. package/src/templates/scaffold-exercise.ts +37 -0
  322. package/src/templates/scaffold-guards.ts +13 -1
  323. package/src/templates/scaffold-helm-alerts.ts +234 -0
  324. package/src/templates/scaffold-helm-templates.ts +7 -5
  325. package/src/templates/scaffold-helm.ts +46 -12
  326. package/src/templates/scaffold-i18n.ts +6 -2
  327. package/src/templates/scaffold-mcp-endpoint.ts +182 -0
  328. package/src/templates/scaffold-mcp-json.ts +31 -0
  329. package/src/templates/scaffold-mcp-package.ts +59 -56
  330. package/src/templates/scaffold-repo.ts +7 -2
  331. package/src/templates/scaffold-shell.ts +45 -79
  332. package/src/templates/scaffold-test-services.ts +13 -5
  333. package/src/templates/shapes/api-keys.ts +170 -0
  334. package/src/templates/shapes/api.ts +101 -0
  335. package/src/templates/shapes/blog-site.ts +340 -0
  336. package/src/templates/shapes/blog-slice.ts +265 -0
  337. package/src/templates/shapes/blog.ts +114 -0
  338. package/src/templates/shapes/dashboard-detail.ts +242 -0
  339. package/src/templates/shapes/dashboard.ts +53 -0
  340. package/src/templates/shapes/index.ts +17 -0
  341. package/src/templates/shapes/overlay.ts +99 -0
  342. package/src/templates/shapes/shared-edits.ts +46 -0
  343. package/src/templates/sign-in-action-tests.ts +237 -0
  344. package/src/templates/sign-in-authenticator.ts +112 -0
  345. package/src/templates/sign-in-oidc.ts +189 -0
  346. package/src/templates/sign-in-pages.ts +148 -0
  347. package/src/templates/sign-in-password.ts +216 -0
  348. package/src/templates/sign-in-shared.ts +268 -0
  349. package/src/templates/slice-foundation.ts +70 -15
  350. package/src/test-batches.ts +1 -1
  351. package/src/test-database.ts +1 -1
  352. package/src/test-shards.ts +7 -1
  353. package/src/test-workers.ts +18 -12
  354. package/src/tool-gate-names.ts +34 -0
  355. package/src/upgrade-agents-link.ts +49 -0
  356. package/src/upgrade-bun-floor.ts +225 -0
  357. package/src/upgrade-gate.ts +228 -0
  358. package/src/upgrade-pins.ts +63 -0
  359. package/src/upgrade-plan.ts +214 -0
  360. package/src/upgrade-registry.ts +53 -0
  361. package/src/upgrade-report.ts +139 -0
  362. package/src/upgrade-root.ts +74 -0
  363. package/src/verify-budgets-build.ts +118 -0
  364. package/src/verify-checks.ts +67 -24
  365. package/src/verify-coverage-run.ts +1 -1
  366. package/src/verify-e2e-lane.ts +41 -0
  367. package/src/verify-exercise.ts +64 -0
  368. package/src/verify-floor.ts +41 -0
  369. package/src/verify-merge.ts +19 -4
  370. package/src/verify-role-load.ts +2 -0
  371. package/src/verify-run.ts +28 -8
  372. package/src/verify-shard.ts +12 -2
  373. package/src/verify-skip-ceiling.ts +87 -0
  374. package/src/verify-step.ts +5 -0
  375. package/src/verify-tests.ts +25 -5
  376. package/src/view-drift.ts +55 -0
  377. package/src/worker-bundle.ts +3 -2
  378. package/src/workspace-graph.ts +38 -19
  379. package/src/write-generated.ts +43 -0
  380. package/src/zone-boot.ts +20 -0
  381. package/wiki/Actions.md +342 -0
  382. package/wiki/Admin-Dashboard.md +432 -0
  383. package/wiki/Agents.md +958 -0
  384. package/wiki/Auth.md +195 -0
  385. package/wiki/Bare-VM.md +111 -0
  386. package/wiki/Batching-And-Preloading.md +136 -0
  387. package/wiki/Building-Your-Own-Base.md +203 -0
  388. package/wiki/CI-Parallel-Gate.md +220 -0
  389. package/wiki/CLI-Reference.md +1894 -0
  390. package/wiki/Caching-And-Invalidation.md +255 -0
  391. package/wiki/Client-Data.md +194 -0
  392. package/wiki/Client-Navigation.md +513 -0
  393. package/wiki/Compared.md +93 -0
  394. package/wiki/Configuration.md +868 -0
  395. package/wiki/Contributing.md +12 -0
  396. package/wiki/Deploy-Recipes.md +122 -0
  397. package/wiki/Deployment.md +508 -0
  398. package/wiki/Entities-And-Migrations.md +1116 -0
  399. package/wiki/FAQ.md +175 -0
  400. package/wiki/Feature-Flags.md +65 -0
  401. package/wiki/Getting-Started.md +221 -0
  402. package/wiki/Home.md +160 -0
  403. package/wiki/I18n.md +239 -0
  404. package/wiki/Installation.md +206 -0
  405. package/wiki/Interface-Rules.md +339 -0
  406. package/wiki/Jobs-And-Workflows.md +783 -0
  407. package/wiki/Known-Gaps.md +185 -0
  408. package/wiki/MCP-And-AI.md +753 -0
  409. package/wiki/Mail.md +138 -0
  410. package/wiki/Migrating-An-Existing-App.md +594 -0
  411. package/wiki/Migrating-From-Django.md +54 -0
  412. package/wiki/Migrating-From-Laravel.md +53 -0
  413. package/wiki/Migrating-From-Node-Drizzle.md +53 -0
  414. package/wiki/Migrating-From-Rails.md +53 -0
  415. package/wiki/Migrations-And-Backfills.md +552 -0
  416. package/wiki/Money.md +338 -0
  417. package/wiki/N-Plus-One-Detection.md +197 -0
  418. package/wiki/Notify.md +208 -0
  419. package/wiki/Observability.md +245 -0
  420. package/wiki/Outbound-HTTP.md +109 -0
  421. package/wiki/PWA-And-Offline.md +343 -0
  422. package/wiki/Policies-And-Authz.md +251 -0
  423. package/wiki/Project-Layout.md +150 -0
  424. package/wiki/Queries-And-Live-Queries.md +429 -0
  425. package/wiki/Realtime.md +734 -0
  426. package/wiki/Resource-Management.md +121 -0
  427. package/wiki/Routes-And-Render-Modes.md +521 -0
  428. package/wiki/SEO.md +288 -0
  429. package/wiki/Scheduled-Tasks.md +175 -0
  430. package/wiki/Scraping.md +493 -0
  431. package/wiki/Shapes.md +63 -0
  432. package/wiki/Stability.md +97 -0
  433. package/wiki/Static-Assets.md +166 -0
  434. package/wiki/Storage-And-Uploads.md +404 -0
  435. package/wiki/Testing.md +1314 -0
  436. package/wiki/The-Eight-Primitives.md +247 -0
  437. package/wiki/Theming.md +362 -0
  438. package/wiki/Timezones-And-Dates.md +194 -0
  439. package/wiki/Troubleshooting.md +163 -0
  440. package/wiki/Tutorial-01-First-App.md +289 -0
  441. package/wiki/Tutorial-02-First-Feature.md +339 -0
  442. package/wiki/Tutorial-03-Auth-And-Admin.md +379 -0
  443. package/wiki/Tutorial-04-Jobs-And-Realtime.md +263 -0
  444. package/wiki/Tutorial-05-Deploy-Free.md +231 -0
  445. package/wiki/Tutorial-06-Growing-Up.md +158 -0
  446. package/wiki/UI-Components.md +156 -0
  447. package/wiki/Upgrading.md +3667 -0
  448. package/src/stored-object-headers.ts +0 -43
@@ -0,0 +1,87 @@
1
+ // `skipCeiling` in `x.verify.json`: how many tests a step may skip before the gate stops calling it
2
+ // a run. The floor refuses a step that ran NOTHING; a step that ran 8 of 17 behind
3
+ // `skipIf(!process.env.TYPO)` was green. Judged where the verdict is (CI, and `x verify merge`),
4
+ // never on a laptop without services, which stays a dev loop.
5
+
6
+ import { ERROR_DOCS_URL, renderFixShellArg } from '@ultimat3/core';
7
+ import type { Finding } from './output';
8
+ import type { TestCounts } from './test-counts';
9
+
10
+ /** The floor's skip-ceiling key. Named once: the problem quotes it and the fix repairs it. */
11
+ export const SKIP_CEILING_FIELD = 'skipCeiling';
12
+
13
+ /** Step name → the most tests it may skip. */
14
+ export type SkipCeiling = Readonly<Record<string, number>>;
15
+
16
+ /** `{ "<step>": n }`, a whole number at or above zero per step the gate runs, or the problems. */
17
+ export function readSkipCeiling(
18
+ payload: Record<string, unknown> | undefined,
19
+ declared: readonly string[],
20
+ ): { ceiling?: SkipCeiling; problems: readonly string[] } {
21
+ const raw = payload?.[SKIP_CEILING_FIELD];
22
+ if (raw === undefined) return { problems: [] };
23
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
24
+ return { problems: [`"${SKIP_CEILING_FIELD}" is not an object of { "<step>": tests }`] };
25
+ }
26
+ const problems: string[] = [];
27
+ const ceiling = new Map<string, number>();
28
+ for (const [step, n] of Object.entries(raw)) {
29
+ if (!declared.includes(step)) {
30
+ problems.push(`"${SKIP_CEILING_FIELD}" names ${step}, which x verify does not run`);
31
+ } else if (typeof n !== 'number' || !Number.isSafeInteger(n) || n < 0) {
32
+ problems.push(
33
+ `"${SKIP_CEILING_FIELD}" gives ${step} ${JSON.stringify(n)}, which is not a whole number of tests`,
34
+ );
35
+ } else ceiling.set(step, n);
36
+ }
37
+ return {
38
+ ...(ceiling.size === 0 ? {} : { ceiling: Object.fromEntries(ceiling) }),
39
+ problems,
40
+ };
41
+ }
42
+
43
+ /** `CI` as GitHub, GitLab and most runners set it; `false`/`0`/empty is a laptop that said so. */
44
+ export const inCi = (env: Readonly<Record<string, string | undefined>>): boolean => {
45
+ const value = env['CI'];
46
+ return value !== undefined && value !== '' && value !== 'false' && value !== '0';
47
+ };
48
+
49
+ const ceilingOf = (ceiling: SkipCeiling | undefined, step: string): number | undefined =>
50
+ ceiling !== undefined && Object.hasOwn(ceiling, step) ? ceiling[step] : undefined;
51
+
52
+ /**
53
+ * The verdict on one step's counts — the whole run's, or the merged shards'. Over the ceiling is a
54
+ * finding; under it nothing; no ceiling and something skipped is a WARNING naming the number to
55
+ * write, since a new app holds nothing yet and a gate must not invent the bar.
56
+ */
57
+ export function judgeSkips(
58
+ step: string,
59
+ tests: TestCounts | undefined,
60
+ ceiling: SkipCeiling | undefined,
61
+ ): { readonly findings: readonly Finding[]; readonly warnings: readonly string[] } {
62
+ if (tests === undefined || tests.ran === 0) return { findings: [], warnings: [] };
63
+ const allowed = ceilingOf(ceiling, step);
64
+ if (allowed === undefined) {
65
+ return tests.skipped === 0
66
+ ? { findings: [], warnings: [] }
67
+ : {
68
+ findings: [],
69
+ warnings: [
70
+ `${step} skipped ${String(tests.skipped)} of ${String(tests.ran + tests.skipped)} test(s): hold it with "${SKIP_CEILING_FIELD}": { "${step}": ${String(tests.skipped)} } in x.verify.json`,
71
+ ],
72
+ };
73
+ }
74
+ if (tests.skipped <= allowed) return { findings: [], warnings: [] };
75
+ return {
76
+ findings: [
77
+ {
78
+ code: 'X_VERIFY_SKIPS_OVER_CEILING',
79
+ cause: `the ${step} step skipped ${String(tests.skipped)} test(s) and ran ${String(tests.ran)}; x.verify.json "${SKIP_CEILING_FIELD}" allows ${String(allowed)}`,
80
+ fix: `x test ${renderFixShellArg(step, '<step>')} --json # then set what the skipped tests need, or raise "${SKIP_CEILING_FIELD}" for ${step} in x.verify.json with the reason in the diff`,
81
+ docs: ERROR_DOCS_URL,
82
+ at: 'x.verify.json',
83
+ },
84
+ ],
85
+ warnings: [],
86
+ };
87
+ }
@@ -27,6 +27,11 @@ export const VERIFY_STEP_NAMES = [
27
27
  'contract',
28
28
  'live',
29
29
  'job',
30
+ // Its own step, not a rider on `job` or `contract`: those ask whether the tests someone WROTE
31
+ // pass, and this asks what every primitive does when it actually runs with no test written — a
32
+ // different question with a different fix (an override in `apps/web/exercise.ts`). After `job`,
33
+ // the last suite it can stand beside without a browser; before `e2e`, the costliest.
34
+ 'exercise',
30
35
  'e2e',
31
36
  'eval',
32
37
  'drift',
@@ -185,7 +185,8 @@ export const testStepCommand = (type: TestType, pace?: MachinePace): readonly st
185
185
  * "no test files matched", a red gate reporting a suite that by its own rule is not here.
186
186
  *
187
187
  * Memoized because `runVerify` asks `applies` and then `run`, and a repeated walk of the whole
188
- * tree per type is the cost this change exists to remove.
188
+ * tree per type is the cost this change exists to remove. For one run only: `runVerify` clears it
189
+ * first, since the dev MCP host's `verify` tool runs the gate again in the same process.
189
190
  */
190
191
  const discovered = new Map<string, readonly TestFile[]>();
191
192
 
@@ -198,11 +199,27 @@ const filesFor = async (root: string, type: TestType): Promise<readonly TestFile
198
199
  return files;
199
200
  };
200
201
 
201
- /** Test seam: a fixture that writes new test files under a root this process already scanned. */
202
+ /** `runVerify` starts every run here; a test that calls a step outside `runVerify` does too. */
202
203
  export const resetTestDiscovery = (): void => discovered.clear();
203
204
 
204
- const runSerial = async (ctx: VerifyContext, type: TestType): Promise<StepOutcome> => {
205
- const command = testStepCommand(type, ctx.pace);
205
+ /**
206
+ * `files`, when given, is a `--shard` slice: the same one process and the same per-test deadline,
207
+ * over an explicit list instead of the type's own globs — `runParallel` hands `bun test` its files
208
+ * the same way. Serial is a fact about ONE machine (one replication slot, one browser); each CI
209
+ * runner starts its own services, so a slice per runner shares nothing with another runner's.
210
+ */
211
+ const runSerial = async (
212
+ ctx: VerifyContext,
213
+ type: TestType,
214
+ files?: readonly string[],
215
+ ): Promise<StepOutcome> => {
216
+ const whole = testStepCommand(type, ctx.pace);
217
+ const command =
218
+ files === undefined
219
+ ? whole
220
+ : // Its flags kept — the deadline and the ignore list — and its type filters replaced by
221
+ // the slice: `bun test` reads a positional as a path filter either way.
222
+ [...whole.filter((arg, at) => at < 2 || arg.startsWith('--')), ...[...files].sort()];
206
223
  const envOverrides = { ...testEnvOverrides(ctx.root, ctx.env ?? Bun.env), ...paceEnv(ctx.pace) };
207
224
  const exec = (e2e: { command: readonly string[]; env: typeof envOverrides }) =>
208
225
  ctx.runner(e2e.command, {
@@ -229,7 +246,7 @@ const runSerial = async (ctx: VerifyContext, type: TestType): Promise<StepOutcom
229
246
  };
230
247
 
231
248
  const runType = async (ctx: VerifyContext, type: TestType): Promise<StepOutcome> => {
232
- if (isSerial(type)) return runSerial(ctx, type);
249
+ if (isSerial(type) && ctx.shard === undefined) return runSerial(ctx, type);
233
250
  const discoveredFiles = await filesFor(ctx.root, type);
234
251
  // Under `--shard`, this job runs its slice and says which — `x verify merge` checks the slices.
235
252
  // An EMPTY slice is a pass with zero tests, never the serial fallback below (which would run
@@ -245,6 +262,9 @@ const runType = async (ctx: VerifyContext, type: TestType): Promise<StepOutcome>
245
262
  if (shard !== undefined && shard.files.length === 0) {
246
263
  return { ok: true, findings: [], workers: 0, tests: { ran: 0, skipped: 0 }, shard };
247
264
  }
265
+ if (isSerial(type) && shard !== undefined) {
266
+ return { ...(await runSerial(ctx, type, shard.files)), shard };
267
+ }
248
268
  const files =
249
269
  shard === undefined
250
270
  ? discoveredFiles
@@ -0,0 +1,55 @@
1
+ // Single responsibility: `X_ENTITY_VIEW_DRIFT` — a view entity's declared `columns` against the
2
+ // output columns of the view the migrations created. Only a database can say what a query
3
+ // outputs, so this reads the `drift` step's scratch replay (`schema-dump-drift.ts`), never source.
4
+
5
+ import { ERROR_DOCS_URL } from '@ultimat3/core';
6
+ import type { EntityDescriptionLike } from '@ultimat3/db';
7
+ import type { CatalogDescription } from '@ultimat3/db/schema-dump';
8
+ import { MIGRATIONS_DIR } from './migrations';
9
+ import type { Finding } from './output';
10
+ import { quoteArg } from './shell-quote';
11
+
12
+ const named = (names: readonly string[]): string => names.map((name) => `"${name}"`).join(', ');
13
+
14
+ /**
15
+ * One finding per view, naming both directions: a declared column the view does not output is a
16
+ * `42703` on every read; an output no column names is data the entity can never reach. A view the
17
+ * replay did not create is `X_DB_SCHEMA_UNMIGRATED`'s (`schema-diff-views.ts`), and a catalog that
18
+ * carries no columns — one built by hand — states nothing to hold the entity to.
19
+ */
20
+ export function viewColumnFindings(
21
+ entities: readonly EntityDescriptionLike[],
22
+ catalog: CatalogDescription,
23
+ ): readonly Finding[] {
24
+ const created = new Map(catalog.views.map((view) => [view.name, view.columns]));
25
+ return entities.flatMap((entity): readonly Finding[] => {
26
+ if (entity.view === undefined) return [];
27
+ const output = created.get(entity.table);
28
+ if (output === undefined) return [];
29
+ const declared = entity.columns.map((column) => column.column);
30
+ const unproduced = declared.filter((name) => !output.includes(name));
31
+ const unnamed = output.filter((name) => !declared.includes(name));
32
+ if (unproduced.length === 0 && unnamed.length === 0) return [];
33
+ const said = [
34
+ ...(unproduced.length === 0
35
+ ? []
36
+ : [
37
+ `view entity ${entity.name} declares ${named(unproduced)}, which view "${entity.table}" does not output`,
38
+ ]),
39
+ ...(unnamed.length === 0
40
+ ? []
41
+ : [
42
+ `view "${entity.table}" outputs ${named(unnamed)}, which no column of view entity ${entity.name} names`,
43
+ ]),
44
+ ].join('; ');
45
+ return [
46
+ {
47
+ code: 'X_ENTITY_VIEW_DRIFT',
48
+ cause: `${said} — its columns are ${output.join(', ')}`,
49
+ fix: `x entities show ${quoteArg(entity.name)} --json # then make columns name exactly the view's output, or change view.sql, and run x db gen "record ${entity.table}"`,
50
+ docs: ERROR_DOCS_URL,
51
+ at: MIGRATIONS_DIR,
52
+ },
53
+ ];
54
+ });
55
+ }
@@ -7,7 +7,7 @@
7
7
  // why: Bun ships no path API; the entry is resolved to a file and named in the cause.
8
8
  import { dirname, join, relative } from 'node:path';
9
9
  import type { Route, UltimateRequest } from '@ultimat3/http';
10
- import { applyCacheHeaders, jsonResponse, NO_STORE } from '@ultimat3/http';
10
+ import { applyCacheHeaders, jsonResponse, NO_STORE, textResponse } from '@ultimat3/http';
11
11
  import { FrameworkScriptBuildFailedError, type FrameworkScriptKind } from './errors';
12
12
  import { describeBuildError, graphHash, stripDebugId } from './island-identity';
13
13
 
@@ -224,7 +224,8 @@ function scriptRoute(
224
224
  return applyCacheHeaders(missing, NO_STORE);
225
225
  }
226
226
  return applyCacheHeaders(
227
- new Response(script.code, { headers: { 'content-type': 'text/javascript' } }),
227
+ // `textResponse` for the length it declares: `compress` reads nothing undeclared.
228
+ textResponse(script.code, { headers: { 'content-type': 'text/javascript' } }),
228
229
  { mode: 'immutable' },
229
230
  );
230
231
  },
@@ -67,6 +67,31 @@ export function workspaceGlobs(manifest: unknown): readonly string[] {
67
67
  return Array.isArray(field) ? stringsOf(field) : stringsOf(asRecord(field)?.['packages']);
68
68
  }
69
69
 
70
+ /**
71
+ * The one walker over `workspaces`: every manifest the globs claim, root-relative, POSIX and sorted,
72
+ * never a vendored one. A `!` entry subtracts, as npm reads it. Handed to `Bun.Glob` it is a glob of
73
+ * its own, matching every file in the tree that is not that manifest.
74
+ */
75
+ export async function workspaceManifestPaths(
76
+ root: string,
77
+ globs: readonly string[],
78
+ ): Promise<readonly string[]> {
79
+ const excluded = globs
80
+ .filter((glob) => glob.startsWith('!'))
81
+ .map((glob) => new Bun.Glob(glob.slice(1).replace(/\/+$/, '')));
82
+ const found = new Set<string>();
83
+ for (const glob of globs.filter((candidate) => !candidate.startsWith('!'))) {
84
+ const manifests = new Bun.Glob(`${glob.replace(/\/+$/, '')}/package.json`);
85
+ for await (const path of manifests.scan({ cwd: root, absolute: false })) {
86
+ const manifest = path.replaceAll('\\', '/');
87
+ const dir = manifest.slice(0, -'/package.json'.length);
88
+ if (isVendored(manifest) || excluded.some((negated) => negated.match(dir))) continue;
89
+ found.add(manifest);
90
+ }
91
+ }
92
+ return [...found].sort();
93
+ }
94
+
70
95
  const declaredDepsOf = (manifest: Record<string, unknown>): readonly string[] =>
71
96
  DEPENDENCY_FIELDS.flatMap((field) => Object.keys(asRecord(manifest[field]) ?? {}));
72
97
 
@@ -89,26 +114,20 @@ export async function scanWorkspaces(root: string): Promise<WorkspaceScan> {
89
114
  const rootManifest = await readManifest(join(root, 'package.json'));
90
115
  const found: { dir: string; name: string; version: string; declared: readonly string[] }[] = [];
91
116
  const unreadable: string[] = [];
92
- for (const pattern of workspaceGlobs(rootManifest)) {
93
- for await (const relative of new Bun.Glob(`${pattern}/package.json`).scan({
94
- cwd: root,
95
- absolute: false,
96
- })) {
97
- if (isVendored(relative)) continue;
98
- const manifest = await readManifest(join(root, relative));
99
- const name = manifest?.['name'];
100
- if (manifest === undefined || typeof name !== 'string' || name === '') {
101
- unreadable.push(relative.replaceAll('\\', '/'));
102
- continue;
103
- }
104
- const version = manifest['version'];
105
- found.push({
106
- dir: relative.replaceAll('\\', '/').slice(0, -'/package.json'.length),
107
- name,
108
- version: typeof version === 'string' ? version : '0.0.0',
109
- declared: declaredDepsOf(manifest),
110
- });
117
+ for (const relative of await workspaceManifestPaths(root, workspaceGlobs(rootManifest))) {
118
+ const manifest = await readManifest(join(root, relative));
119
+ const name = manifest?.['name'];
120
+ if (manifest === undefined || typeof name !== 'string' || name === '') {
121
+ unreadable.push(relative);
122
+ continue;
111
123
  }
124
+ const version = manifest['version'];
125
+ found.push({
126
+ dir: relative.slice(0, -'/package.json'.length),
127
+ name,
128
+ version: typeof version === 'string' ? version : '0.0.0',
129
+ declared: declaredDepsOf(manifest),
130
+ });
112
131
  }
113
132
  found.sort((left, right) => left.dir.localeCompare(right.dir));
114
133
  const names = new Set<string>();
@@ -0,0 +1,43 @@
1
+ // Write one planned file to disk: bytes through `Bun.write`, a `link` entry as a relative symlink.
2
+ // The copy fallback is Windows-only, where creating a symlink needs Developer Mode or an elevated
3
+ // token and `symlink` fails with EPERM; anywhere else a failed link is a real error and surfaces.
4
+
5
+ // why: Bun ships no symlink or mkdir API, nor a path API to find the link's parent directory.
6
+ import { mkdir, rm, symlink } from 'node:fs/promises';
7
+ import { dirname, join } from 'node:path';
8
+ import { stringField } from '@ultimat3/core';
9
+ import type { GeneratedFile } from './templates';
10
+
11
+ /** The OS refusing the privilege, not the call being wrong: only these fall back to a copy. */
12
+ const PRIVILEGE_CODES: ReadonlySet<string> = new Set(['EPERM', 'EACCES', 'ENOTSUP', 'ENOSYS']);
13
+
14
+ export interface WriteGeneratedSeams {
15
+ readonly link?: (target: string, path: string) => Promise<void>;
16
+ readonly platform?: NodeJS.Platform;
17
+ }
18
+
19
+ /** `'link'` when a symlink landed, `'copy'` when Windows refused one and the text was written. */
20
+ export async function writeGenerated(
21
+ root: string,
22
+ file: GeneratedFile,
23
+ seams: WriteGeneratedSeams = {},
24
+ ): Promise<'file' | 'link' | 'copy'> {
25
+ const path = join(root, file.path);
26
+ if (file.merge !== undefined || file.link === undefined) {
27
+ await Bun.write(path, file.contents);
28
+ return 'file';
29
+ }
30
+ // `'file'`: Windows cannot infer the kind of a target written after its link.
31
+ const link = seams.link ?? ((target: string, at: string) => symlink(target, at, 'file'));
32
+ await mkdir(dirname(path), { recursive: true });
33
+ await rm(path, { force: true });
34
+ try {
35
+ await link(file.link, path);
36
+ return 'link';
37
+ } catch (error) {
38
+ const windows = (seams.platform ?? process.platform) === 'win32';
39
+ if (!windows || !PRIVILEGE_CODES.has(stringField(error, 'code') ?? '')) throw error;
40
+ await Bun.write(path, file.contents);
41
+ return 'copy';
42
+ }
43
+ }
@@ -0,0 +1,20 @@
1
+ // `time.detect`'s boot fact: the zone script's tag and the CSP source that admits exactly it, or
2
+ // nothing for an app that left detection off. Composed into `app/` documents only, by the one
3
+ // head both boots spread (`clientScriptHeads`), so `site/` never pays for it (axiom 6).
4
+
5
+ import type { AppTimeConfig } from '@ultimat3/core';
6
+ import { cspHashSource } from '@ultimat3/http';
7
+ import { renderHead, zoneScript, zoneScriptBody } from '@ultimat3/render';
8
+
9
+ export interface ZoneBoot {
10
+ /** The rendered `<script>`, for the `app/` document head. */
11
+ readonly head: string;
12
+ /** The `script-src` source that admits exactly that tag's body. */
13
+ readonly cspSource: string;
14
+ }
15
+
16
+ /** Tag and hash from ONE body, as `themeBoot` does. `undefined` unless the app said `detect`. */
17
+ export function zoneBoot(time: AppTimeConfig | undefined): ZoneBoot | undefined {
18
+ if (time?.detect !== true) return undefined;
19
+ return { head: renderHead([zoneScript()]), cspSource: cspHashSource(zoneScriptBody()) };
20
+ }