@ultimat3/cli 29.3.2 → 30.0.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.
- package/CLAUDE.md +64 -40
- package/README.md +61 -11
- package/package.json +42 -28
- package/src/affected-tests.ts +97 -0
- package/src/affected-unowned.ts +43 -0
- package/src/affected.ts +25 -6
- package/src/app-boundaries.ts +29 -1
- package/src/app-evals.ts +12 -4
- package/src/app-load-unresolved.ts +62 -0
- package/src/app-load.ts +30 -37
- package/src/app-mcp.ts +14 -2
- package/src/app-module-graph.ts +232 -0
- package/src/app-reload-graph.ts +2 -2
- package/src/app-root.ts +37 -1
- package/src/bin.ts +1 -0
- package/src/boundary-findings.ts +6 -0
- package/src/budgets-freshness.ts +32 -0
- package/src/budgets.ts +20 -1
- package/src/build-capture-env.ts +9 -0
- package/src/cdp-shot-a11y.ts +2 -39
- package/src/ci-tested.ts +243 -0
- package/src/client-emit-customer-runtime.ts +139 -0
- package/src/client-emit-customer.ts +108 -0
- package/src/client-emit-drift.ts +72 -0
- package/src/client-emit-header.ts +67 -0
- package/src/client-emit-schemas.ts +175 -0
- package/src/client-emit-types.ts +121 -0
- package/src/client-emit-vendor.ts +146 -0
- package/src/client-errors-routes.ts +229 -0
- package/src/client-errors-script.ts +74 -0
- package/src/client-vitals-route.ts +197 -0
- package/src/client-vitals-script.ts +56 -0
- package/src/cmd-affected.ts +23 -0
- package/src/cmd-build-spec.ts +7 -1
- package/src/cmd-build.ts +35 -9
- package/src/cmd-ci-spec.ts +42 -6
- package/src/cmd-ci.ts +99 -2
- package/src/cmd-client-customer.ts +134 -0
- package/src/cmd-client-source.ts +81 -0
- package/src/cmd-client-spec.ts +48 -0
- package/src/cmd-client-write.ts +41 -0
- package/src/cmd-client.ts +111 -0
- package/src/cmd-db-recount.ts +120 -0
- package/src/cmd-db-spec.ts +36 -6
- package/src/cmd-db.ts +13 -3
- package/src/cmd-deploy-compose.ts +61 -3
- package/src/cmd-deploy-drain.ts +10 -2
- package/src/cmd-deploy-helm.ts +11 -0
- package/src/cmd-deploy-preflight.ts +118 -0
- package/src/cmd-deploy-spec.ts +58 -6
- package/src/cmd-deploy-verify.ts +380 -0
- package/src/cmd-deploy.ts +42 -9
- package/src/cmd-docs.ts +34 -4
- package/src/cmd-doctor.ts +66 -9
- package/src/cmd-drill-spec.ts +25 -0
- package/src/cmd-drill.ts +176 -0
- package/src/cmd-env-init.ts +102 -0
- package/src/cmd-env-spec.ts +10 -3
- package/src/cmd-env.ts +15 -10
- package/src/cmd-errors-recent.ts +60 -0
- package/src/cmd-errors-spec.ts +9 -1
- package/src/cmd-errors.ts +4 -0
- package/src/cmd-exercise-spec.ts +19 -0
- package/src/cmd-exercise.ts +129 -0
- package/src/cmd-generate-spec.ts +9 -1
- package/src/cmd-generate.ts +32 -27
- package/src/cmd-graph-load.ts +97 -0
- package/src/cmd-graph-spec.ts +16 -0
- package/src/cmd-graph.ts +73 -0
- package/src/cmd-i18n.ts +4 -1
- package/src/cmd-impact-spec.ts +13 -0
- package/src/cmd-impact.ts +64 -0
- package/src/cmd-jobs-resolve.ts +76 -0
- package/src/cmd-jobs-spec.ts +21 -2
- package/src/cmd-jobs.ts +10 -6
- package/src/cmd-mail-spec.ts +28 -0
- package/src/cmd-mail.ts +70 -0
- package/src/cmd-mcp-lock.ts +69 -0
- package/src/cmd-mcp-spec.ts +23 -4
- package/src/cmd-mcp.ts +17 -3
- package/src/cmd-new-spec.ts +8 -1
- package/src/cmd-new.ts +61 -9
- package/src/cmd-planned.ts +0 -6
- package/src/cmd-repro-spec.ts +31 -0
- package/src/cmd-repro.ts +174 -0
- package/src/cmd-stop-spec.ts +21 -0
- package/src/cmd-stop.ts +166 -0
- package/src/cmd-test-spec.ts +17 -4
- package/src/cmd-test.ts +70 -14
- package/src/cmd-upgrade-spec.ts +26 -0
- package/src/cmd-upgrade.ts +274 -0
- package/src/cmd-verify-spec.ts +3 -3
- package/src/db-backfill.ts +6 -0
- package/src/db-diagnostics.ts +106 -0
- package/src/db-generate.ts +28 -8
- package/src/db-reset-template.ts +1 -1
- package/src/db-rolling.ts +45 -0
- package/src/db-seed-generate.ts +188 -0
- package/src/deploy-verify-findings.ts +98 -0
- package/src/deploy-verify-flags.ts +109 -0
- package/src/deploy-verify-grade.ts +185 -0
- package/src/deploy-verify-queues.ts +53 -0
- package/src/dev-boot.ts +35 -15
- package/src/dev-child-watch.ts +16 -4
- package/src/dev-dashboard-guard.ts +8 -1
- package/src/dev-dashboard.ts +7 -0
- package/src/dev-lock-identity.ts +61 -0
- package/src/dev-lock-port-holder.ts +80 -0
- package/src/dev-lock-steal.ts +124 -0
- package/src/dev-lock.ts +92 -120
- package/src/dev-mail-templates.ts +51 -0
- package/src/dev-rebuild.ts +26 -2
- package/src/dev-route-table.ts +17 -0
- package/src/dev-supervisor.ts +5 -2
- package/src/dev-watch-tree.ts +11 -10
- package/src/dev-watch.ts +1 -1
- package/src/dispatch.ts +29 -6
- package/src/docs-section.ts +69 -0
- package/src/docs-sources.ts +100 -0
- package/src/doctor-auth.ts +11 -2
- package/src/doctor-chart-alerts.ts +55 -0
- package/src/doctor-pooler.ts +107 -0
- package/src/doctor-rolling.ts +35 -0
- package/src/doctor-row-security.ts +40 -0
- package/src/document-options.ts +13 -0
- package/src/drill-sync-lane.ts +25 -0
- package/src/drill-targets.ts +39 -0
- package/src/duplicate-packages.ts +1 -1
- package/src/env-production.ts +93 -0
- package/src/error-codes-shot.ts +59 -0
- package/src/error-codes-tooling.ts +29 -0
- package/src/error-codes.ts +100 -54
- package/src/error-contract.ts +2 -2
- package/src/errors.ts +22 -3
- package/src/exercise-database.ts +99 -0
- package/src/exercise-findings.ts +159 -0
- package/src/exercise-overrides.ts +42 -0
- package/src/exercise-registration.ts +58 -0
- package/src/exercise-static.ts +88 -0
- package/src/exercise-subject.ts +69 -0
- package/src/failure-capture-boot.ts +30 -0
- package/src/framework-env.ts +7 -1
- package/src/framework-schema.ts +72 -5
- package/src/generate-catalog-locales.ts +19 -0
- package/src/generate-chart-alerts.ts +156 -0
- package/src/generate-feature-required.ts +65 -0
- package/src/generate-feature.ts +83 -6
- package/src/generate-files.ts +24 -0
- package/src/generate-format-written.ts +32 -0
- package/src/generate-kinds.ts +6 -0
- package/src/generate-sign-in-config.ts +100 -0
- package/src/generate-sign-in-manifest.ts +28 -0
- package/src/generate-sign-in-mode.ts +101 -0
- package/src/generate-sign-in.ts +250 -0
- package/src/generate-write.ts +44 -7
- package/src/hand-rolled-socket.ts +72 -0
- package/src/i18n-app-key-shapes.ts +29 -0
- package/src/i18n-audit.ts +10 -3
- package/src/i18n-registration.ts +18 -3
- package/src/index.ts +2 -0
- package/src/island-bundle.ts +4 -3
- package/src/island-disposer.ts +116 -0
- package/src/island-realtime-state.ts +34 -6
- package/src/island-realtime.ts +6 -2
- package/src/island-routes.ts +3 -2
- package/src/isr-query-advice.ts +6 -11
- package/src/isr-query-guard.ts +4 -3
- package/src/job-budget.ts +95 -0
- package/src/jobs-json.ts +11 -0
- package/src/lint-findings.ts +104 -0
- package/src/local-cli.ts +34 -4
- package/src/loopback-host.ts +2 -2
- package/src/mail-preview-findings.ts +24 -0
- package/src/mcp-errors.ts +82 -2
- package/src/mcp-host.ts +11 -1
- package/src/mcp-lock-findings.ts +57 -0
- package/src/measure-paths.ts +12 -4
- package/src/measure-scope.ts +27 -13
- package/src/messages-client.ts +23 -0
- package/src/messages-db.ts +56 -0
- package/src/messages-gate.ts +107 -0
- package/src/messages-repro.ts +11 -0
- package/src/messages-shot.ts +51 -0
- package/src/messages-upgrade.ts +45 -0
- package/src/messages.ts +53 -178
- package/src/metrics-endpoint.ts +23 -5
- package/src/new-shapes-generate.ts +71 -0
- package/src/new-shapes.ts +63 -0
- package/src/openapi-compile-ir.ts +68 -0
- package/src/openapi-compile-schema.ts +284 -0
- package/src/openapi-compile.ts +273 -0
- package/src/openapi-refuse.ts +45 -0
- package/src/otlp-export.ts +2 -1
- package/src/output-findings.ts +123 -0
- package/src/output.ts +32 -8
- package/src/package-boundaries.ts +110 -0
- package/src/page-pins.ts +23 -0
- package/src/plain-routes.ts +13 -0
- package/src/prerender-entries.ts +59 -0
- package/src/prerender-heaviest.ts +27 -0
- package/src/prerender-preload.ts +6 -0
- package/src/prerender-report.ts +12 -0
- package/src/prerender-seo-reads.ts +38 -0
- package/src/prerender-served.ts +22 -7
- package/src/prerender-vitals.ts +42 -0
- package/src/prerender.ts +61 -32
- package/src/pwa-artifacts.ts +4 -3
- package/src/pwa-manifest-locales.ts +1 -1
- package/src/registry.ts +18 -0
- package/src/repro-bundle.ts +65 -0
- package/src/repro-errors.ts +47 -0
- package/src/repro-job.ts +72 -0
- package/src/repro-literal.ts +41 -0
- package/src/repro-request.ts +48 -0
- package/src/repro-write.ts +100 -0
- package/src/retain-sweep.ts +27 -0
- package/src/retained-assets-boot.ts +113 -0
- package/src/retained-assets-layout.ts +110 -0
- package/src/retained-assets-read.ts +142 -0
- package/src/retained-assets-sweep.ts +70 -0
- package/src/retained-assets.ts +171 -0
- package/src/revalidated-response.ts +8 -5
- package/src/role-replicator.ts +7 -1
- package/src/role-start-devices.ts +119 -0
- package/src/role-start-types.ts +6 -0
- package/src/role-start.ts +22 -5
- package/src/role-sync.ts +7 -1
- package/src/route-islands.ts +42 -0
- package/src/route-table.ts +2 -1
- package/src/row-security-boot.ts +58 -0
- package/src/row-security-wanted.ts +32 -0
- package/src/runtime-admin.ts +0 -1
- package/src/runtime-assets-site-cache.ts +55 -0
- package/src/runtime-assets-site.ts +136 -0
- package/src/runtime-assets.ts +99 -55
- package/src/runtime-bindings.ts +19 -3
- package/src/runtime-cache.ts +23 -14
- package/src/runtime-isr-outcome.ts +114 -60
- package/src/runtime-purge.ts +14 -2
- package/src/runtime-queue.ts +31 -4
- package/src/runtime-render-document.ts +204 -0
- package/src/runtime-render.ts +48 -198
- package/src/runtime-replica-position.ts +62 -0
- package/src/runtime-replica.ts +18 -3
- package/src/runtime-s3-path-style.ts +17 -0
- package/src/runtime-services.ts +19 -6
- package/src/runtime-statement-bound.ts +22 -0
- package/src/runtime-storage-upload.ts +9 -0
- package/src/runtime-storage.ts +42 -138
- package/src/schema-diff-views.ts +54 -0
- package/src/schema-diff.ts +21 -3
- package/src/schema-drift.ts +28 -9
- package/src/schema-dump-drift.ts +91 -7
- package/src/script-csp.ts +1 -1
- package/src/seo-cards.ts +26 -0
- package/src/seo-routes.ts +22 -8
- package/src/serve-boot.ts +54 -21
- package/src/serve-drain.ts +1 -0
- package/src/serve-env.ts +26 -8
- package/src/serve-retire.ts +12 -6
- package/src/serve-web.ts +42 -4
- package/src/serve.ts +9 -7
- package/src/site-asset-routes.ts +17 -27
- package/src/site-config.ts +4 -0
- package/src/site-llms-pages.ts +106 -0
- package/src/site-llms.ts +64 -0
- package/src/site-seo-write.ts +4 -2
- package/src/site-seo.ts +55 -6
- package/src/source-mtime.ts +50 -0
- package/src/static-capture-errors.ts +41 -0
- package/src/static-capture.ts +56 -0
- package/src/static-cards-serve.ts +39 -0
- package/src/static-cards.ts +93 -0
- package/src/static-document.ts +14 -13
- package/src/static-images.ts +115 -0
- package/src/stream-hole-scope.ts +55 -0
- package/src/style-bundle.ts +1 -1
- package/src/style-routes.ts +3 -2
- package/src/sw-precache-plan.ts +2 -2
- package/src/sw-routes.ts +2 -2
- package/src/templates/action-tests.ts +306 -0
- package/src/templates/action.ts +81 -269
- package/src/templates/backfill.ts +1 -1
- package/src/templates/entity.ts +21 -5
- package/src/templates/github/ci.yml.ts +8 -9
- package/src/templates/guard-bare-error.ts +2 -2
- package/src/templates/guard-error-declared.ts +263 -0
- package/src/templates/guard-native-confirm.ts +132 -0
- package/src/templates/guard-raw-fetch.ts +151 -0
- package/src/templates/guard-raw-interval.ts +121 -0
- package/src/templates/guard-repo-raw-sql.ts +71 -2
- package/src/templates/job.ts +1 -1
- package/src/templates/naming.ts +5 -0
- package/src/templates/pinned/docker-compose.yml +6 -0
- package/src/templates/pinned-images.ts +8 -0
- package/src/templates/policy.ts +85 -2
- package/src/templates/query.ts +70 -13
- package/src/templates/resource-create.ts +3 -1
- package/src/templates/resource-form-island.ts +15 -4
- package/src/templates/resource-page-db.ts +83 -0
- package/src/templates/resource-page.ts +161 -52
- package/src/templates/route.ts +4 -6
- package/src/templates/scaffold-app.ts +3 -0
- package/src/templates/scaffold-auth.ts +2 -1
- package/src/templates/scaffold-bin.ts +5 -52
- package/src/templates/scaffold-claude-agents.ts +19 -19
- package/src/templates/scaffold-claude-commands.ts +28 -31
- package/src/templates/scaffold-claude.ts +26 -23
- package/src/templates/scaffold-container-compose.ts +6 -1
- package/src/templates/scaffold-container.ts +24 -4
- package/src/templates/scaffold-dashboard-bare.ts +3 -3
- package/src/templates/scaffold-dashboard-example-tests.ts +49 -9
- package/src/templates/scaffold-dashboard-example-view.ts +156 -0
- package/src/templates/scaffold-dashboard-example.ts +43 -131
- package/src/templates/scaffold-dashboard-shared.ts +3 -7
- package/src/templates/scaffold-db-client.ts +20 -6
- package/src/templates/scaffold-db-package.ts +5 -14
- package/src/templates/scaffold-docs.ts +73 -57
- package/src/templates/scaffold-domain-package.ts +18 -14
- package/src/templates/scaffold-entries.ts +7 -2
- package/src/templates/scaffold-exercise.ts +37 -0
- package/src/templates/scaffold-guards.ts +13 -1
- package/src/templates/scaffold-helm-alerts.ts +234 -0
- package/src/templates/scaffold-helm-templates.ts +7 -5
- package/src/templates/scaffold-helm.ts +46 -12
- package/src/templates/scaffold-i18n.ts +6 -2
- package/src/templates/scaffold-mcp-endpoint.ts +182 -0
- package/src/templates/scaffold-mcp-json.ts +31 -0
- package/src/templates/scaffold-mcp-package.ts +59 -56
- package/src/templates/scaffold-repo.ts +7 -2
- package/src/templates/scaffold-shell.ts +45 -79
- package/src/templates/scaffold-test-services.ts +13 -5
- package/src/templates/shapes/api-keys.ts +170 -0
- package/src/templates/shapes/api.ts +101 -0
- package/src/templates/shapes/blog-site.ts +340 -0
- package/src/templates/shapes/blog-slice.ts +265 -0
- package/src/templates/shapes/blog.ts +114 -0
- package/src/templates/shapes/dashboard-detail.ts +242 -0
- package/src/templates/shapes/dashboard.ts +53 -0
- package/src/templates/shapes/index.ts +17 -0
- package/src/templates/shapes/overlay.ts +99 -0
- package/src/templates/shapes/shared-edits.ts +46 -0
- package/src/templates/sign-in-action-tests.ts +237 -0
- package/src/templates/sign-in-authenticator.ts +112 -0
- package/src/templates/sign-in-oidc.ts +189 -0
- package/src/templates/sign-in-pages.ts +148 -0
- package/src/templates/sign-in-password.ts +216 -0
- package/src/templates/sign-in-shared.ts +268 -0
- package/src/templates/slice-foundation.ts +70 -15
- package/src/test-batches.ts +1 -1
- package/src/test-database.ts +1 -1
- package/src/test-shards.ts +7 -1
- package/src/test-workers.ts +18 -12
- package/src/tool-gate-names.ts +34 -0
- package/src/upgrade-agents-link.ts +49 -0
- package/src/upgrade-bun-floor.ts +225 -0
- package/src/upgrade-gate.ts +228 -0
- package/src/upgrade-pins.ts +63 -0
- package/src/upgrade-plan.ts +214 -0
- package/src/upgrade-registry.ts +53 -0
- package/src/upgrade-report.ts +139 -0
- package/src/upgrade-root.ts +74 -0
- package/src/verify-budgets-build.ts +118 -0
- package/src/verify-checks.ts +67 -24
- package/src/verify-coverage-run.ts +1 -1
- package/src/verify-e2e-lane.ts +41 -0
- package/src/verify-exercise.ts +64 -0
- package/src/verify-floor.ts +41 -0
- package/src/verify-merge.ts +19 -4
- package/src/verify-role-load.ts +2 -0
- package/src/verify-run.ts +28 -8
- package/src/verify-shard.ts +12 -2
- package/src/verify-skip-ceiling.ts +87 -0
- package/src/verify-step.ts +5 -0
- package/src/verify-tests.ts +25 -5
- package/src/view-drift.ts +55 -0
- package/src/worker-bundle.ts +3 -2
- package/src/workspace-graph.ts +38 -19
- package/src/write-generated.ts +43 -0
- package/src/zone-boot.ts +20 -0
- package/wiki/Actions.md +342 -0
- package/wiki/Admin-Dashboard.md +432 -0
- package/wiki/Agents.md +958 -0
- package/wiki/Auth.md +195 -0
- package/wiki/Bare-VM.md +111 -0
- package/wiki/Batching-And-Preloading.md +136 -0
- package/wiki/Building-Your-Own-Base.md +203 -0
- package/wiki/CI-Parallel-Gate.md +220 -0
- package/wiki/CLI-Reference.md +1894 -0
- package/wiki/Caching-And-Invalidation.md +255 -0
- package/wiki/Client-Data.md +194 -0
- package/wiki/Client-Navigation.md +513 -0
- package/wiki/Compared.md +93 -0
- package/wiki/Configuration.md +868 -0
- package/wiki/Contributing.md +12 -0
- package/wiki/Deploy-Recipes.md +122 -0
- package/wiki/Deployment.md +508 -0
- package/wiki/Entities-And-Migrations.md +1116 -0
- package/wiki/FAQ.md +175 -0
- package/wiki/Feature-Flags.md +65 -0
- package/wiki/Getting-Started.md +221 -0
- package/wiki/Home.md +160 -0
- package/wiki/I18n.md +239 -0
- package/wiki/Installation.md +206 -0
- package/wiki/Interface-Rules.md +339 -0
- package/wiki/Jobs-And-Workflows.md +783 -0
- package/wiki/Known-Gaps.md +185 -0
- package/wiki/MCP-And-AI.md +753 -0
- package/wiki/Mail.md +138 -0
- package/wiki/Migrating-An-Existing-App.md +594 -0
- package/wiki/Migrating-From-Django.md +54 -0
- package/wiki/Migrating-From-Laravel.md +53 -0
- package/wiki/Migrating-From-Node-Drizzle.md +53 -0
- package/wiki/Migrating-From-Rails.md +53 -0
- package/wiki/Migrations-And-Backfills.md +552 -0
- package/wiki/Money.md +338 -0
- package/wiki/N-Plus-One-Detection.md +197 -0
- package/wiki/Notify.md +208 -0
- package/wiki/Observability.md +245 -0
- package/wiki/Outbound-HTTP.md +109 -0
- package/wiki/PWA-And-Offline.md +343 -0
- package/wiki/Policies-And-Authz.md +251 -0
- package/wiki/Project-Layout.md +150 -0
- package/wiki/Queries-And-Live-Queries.md +429 -0
- package/wiki/Realtime.md +734 -0
- package/wiki/Resource-Management.md +121 -0
- package/wiki/Routes-And-Render-Modes.md +521 -0
- package/wiki/SEO.md +288 -0
- package/wiki/Scheduled-Tasks.md +175 -0
- package/wiki/Scraping.md +493 -0
- package/wiki/Shapes.md +63 -0
- package/wiki/Stability.md +97 -0
- package/wiki/Static-Assets.md +166 -0
- package/wiki/Storage-And-Uploads.md +404 -0
- package/wiki/Testing.md +1313 -0
- package/wiki/The-Eight-Primitives.md +247 -0
- package/wiki/Theming.md +362 -0
- package/wiki/Timezones-And-Dates.md +194 -0
- package/wiki/Troubleshooting.md +163 -0
- package/wiki/Tutorial-01-First-App.md +289 -0
- package/wiki/Tutorial-02-First-Feature.md +339 -0
- package/wiki/Tutorial-03-Auth-And-Admin.md +379 -0
- package/wiki/Tutorial-04-Jobs-And-Realtime.md +263 -0
- package/wiki/Tutorial-05-Deploy-Free.md +231 -0
- package/wiki/Tutorial-06-Growing-Up.md +158 -0
- package/wiki/UI-Components.md +156 -0
- package/wiki/Upgrading.md +3667 -0
- package/src/stored-object-headers.ts +0 -43
package/src/mcp-errors.ts
CHANGED
|
@@ -28,7 +28,8 @@ const CLI_FIXES: Readonly<Record<CliErrorCode, string>> = {
|
|
|
28
28
|
X_CLI_FLAG_UNREAD:
|
|
29
29
|
'bun test packages/cli/src/flag-reads.test.ts # the finding names the flag and the file to read it in',
|
|
30
30
|
X_VERIFY_FAILED: 'x verify --json',
|
|
31
|
-
|
|
31
|
+
// Outside an app `x` is on no PATH, and `bunx x` fetches an unrelated npm package named `x`.
|
|
32
|
+
X_NOT_IN_APP: 'bunx create-ultimate myapp --json && cd myapp',
|
|
32
33
|
X_BUN_VERSION: 'bun upgrade',
|
|
33
34
|
X_NOT_IMPLEMENTED: 'x doctor --json',
|
|
34
35
|
// Core's three env codes, answered by the command that covers each. `X_CONFIG_INVALID` gets
|
|
@@ -125,7 +126,7 @@ const CLI_FIXES: Readonly<Record<CliErrorCode, string>> = {
|
|
|
125
126
|
X_CLI_UNEXPECTED: 'x doctor --json',
|
|
126
127
|
// `-p .`: an app root has no `references`, so the gate's own step runs this form (#450).
|
|
127
128
|
X_TYPECHECK_FAILED: 'bunx tsc -p . --pretty false',
|
|
128
|
-
X_LINT_FAILED: 'bunx biome check
|
|
129
|
+
X_LINT_FAILED: 'bunx biome check .',
|
|
129
130
|
X_TEST_FAILED: 'x test --json # the finding carries the exact bun test invocation that failed',
|
|
130
131
|
// The same two edits `vanishedSuiteFinding` names, verbatim, so both surfaces of this code hand
|
|
131
132
|
// an agent one instruction. Neither edit is scripted here on purpose: a command that rewrites
|
|
@@ -312,6 +313,85 @@ const CLI_FIXES: Readonly<Record<CliErrorCode, string>> = {
|
|
|
312
313
|
'x i18n check --json # the finding names the locale and the key still carrying the reference value',
|
|
313
314
|
X_WORKER_QUEUE_UNKNOWN:
|
|
314
315
|
'x jobs list --json # set WORKER_QUEUES to queues it lists, or add the queue to jobs.queues in app.config.ts',
|
|
316
|
+
X_UPGRADE_DIRTY_TREE: 'git status --short # then commit or stash, and re-run: x upgrade --json',
|
|
317
|
+
X_UPGRADE_MIXED_PINS: 'x upgrade --dry-run --json # the refusal names the exact --to to paste',
|
|
318
|
+
X_UPGRADE_HOP_TOO_WIDE:
|
|
319
|
+
'x upgrade --dry-run --json # with no --to, it answers the one hop this app may take',
|
|
320
|
+
X_UPGRADE_REGISTRY_UNREACHABLE:
|
|
321
|
+
'bun pm view @ultimat3/cli version # once this answers, re-run: x upgrade --json',
|
|
322
|
+
X_UPGRADE_PIN_UNREADABLE:
|
|
323
|
+
'x upgrade --json # after editing the package.json the cause names, so every @ultimat3/* carries a version',
|
|
324
|
+
X_UPGRADE_VERSION_UNPUBLISHED:
|
|
325
|
+
'bun pm view @ultimat3/cli versions --json # then: x upgrade --to <one of them> --json',
|
|
326
|
+
X_UPGRADE_INSTALL_FAILED:
|
|
327
|
+
'git restore . # undoes the pins, since the tree was clean; then fix what the cause names and re-run: x upgrade --json',
|
|
328
|
+
X_UPGRADE_GATE_UNREADABLE: 'bun node_modules/@ultimat3/cli/src/bin.ts verify --json',
|
|
329
|
+
X_DEPLOY_BUILD_UNSTAMPED:
|
|
330
|
+
"x build --target docker --json # stamps BUILD_ID into the image; or set BUILD_ID in the image's environment",
|
|
331
|
+
X_DEPLOY_UNSTABLE:
|
|
332
|
+
'x deploy verify --url https://app.example.com --json # samples.byStatus and samples.byBuild name what interrupted it',
|
|
333
|
+
X_DEPLOY_QUEUE_UNSERVED:
|
|
334
|
+
'x jobs list --json # then WORKER_QUEUES=<queue> on a worker Deployment, or --idle-ok <queue> on x deploy verify for a scale-to-zero pool',
|
|
335
|
+
X_DEPLOY_BUILD_MISMATCH:
|
|
336
|
+
'x deploy verify --url https://app.example.com --build "$BUILD_ID" --json # the id CI stamped; meta.byBuild names what answered',
|
|
337
|
+
X_JOB_OUTLASTS_DRAIN:
|
|
338
|
+
"drain: { workerRetireMs: 7200000 }, // at least the job's timeout, in app.config.ts, then x verify --only manifest --json",
|
|
339
|
+
X_FEATURE_REQUIRED:
|
|
340
|
+
'x help g --json # then the query generator with --feature <slice>, or the resource generator for a new table',
|
|
341
|
+
X_BOUNDARY_PACKAGE_TO_APP:
|
|
342
|
+
'x verify --only boundaries --json # after moving the shared code into the package, or importing in the opposite direction',
|
|
343
|
+
X_APP_IMPORT_UNRESOLVED:
|
|
344
|
+
'x doctor --json # names the package to bun add, or the file whose import to edit',
|
|
345
|
+
X_STREAM_ALREADY_FLUSHED:
|
|
346
|
+
'load: async () => { setCookie(name, value); return data; }, // in defineRoute, never inside a Hole',
|
|
347
|
+
X_QUERY_SLICE_ENTITY:
|
|
348
|
+
'x queries list --json # then declare the read by hand over the entity the slice declares',
|
|
349
|
+
X_DEPLOY_ENV_MISSING: 'x env init --production --json',
|
|
350
|
+
X_ENV_FILE_EXISTS:
|
|
351
|
+
'NODE_ENV=production x env check --json # the file is kept: edit a value in it by hand',
|
|
352
|
+
X_DEV_STOP_TIMEOUT:
|
|
353
|
+
'x stop --timeout 2m --json # still running: kill -9 the pid its cause names, then x dev --json',
|
|
354
|
+
X_DEV_STOP_DENIED: 'cat .x/dev.lock # then, as the user who owns that pid: x stop --json',
|
|
355
|
+
X_ASSET_RETAIN_FAILED: 'x doctor --json',
|
|
356
|
+
X_APP_MODULE_LOAD_FAILED:
|
|
357
|
+
'x manifest --json # names each module that does not load and why; fix it, then restart the role',
|
|
358
|
+
X_CHART_MISSING: 'x g chart-alerts --print --json',
|
|
359
|
+
X_ENTITY_VIEW_DRIFT:
|
|
360
|
+
"x verify --only drift --json # the cause names the view entity and both column lists: make columns name exactly the view's output, or change view.sql and x db gen",
|
|
361
|
+
X_CLIENT_SPEC_UNSUPPORTED:
|
|
362
|
+
'x help client --json # then rerun with --only naming the tags around the pointer the cause names, or pin a corrected source.json',
|
|
363
|
+
X_CLIENT_STALE:
|
|
364
|
+
'x verify --only drift --json # each finding names the line that regenerates its client',
|
|
365
|
+
X_CLIENT_EDITED:
|
|
366
|
+
'x verify --only drift --json # regenerate with the command the finding names, and keep custom code in a file of your own that wraps the client',
|
|
367
|
+
X_GRAPH_NODE_UNKNOWN: 'x graph --json # every node id is in data.nodes',
|
|
368
|
+
X_CLIENT_SPEC_INVALID:
|
|
369
|
+
'x help client --json # then point --from at the OpenAPI 3.0 or 3.1 document itself',
|
|
370
|
+
X_REPRO_UNKNOWN: 'x repro --list --json',
|
|
371
|
+
X_REPRO_NOT_REPRODUCED:
|
|
372
|
+
'x repro --list --json # re-read the bundle (x repro ID --json), then set its listed masked fields and unread rows by hand in the written test',
|
|
373
|
+
X_REPRO_CAPTURE_OFF:
|
|
374
|
+
'x jobs list --json # a job id replays with capture off; for requests set failureCapture: { enabled: true } in app.config.ts',
|
|
375
|
+
X_ENTITY_RETAIN_UNSWEPT:
|
|
376
|
+
"add export const retention = purge({ entities: 'declared' }) to a jobs module named in jobs: [...] in apps/web/api/index.ts, then x verify",
|
|
377
|
+
X_NEW_SHAPE_UNKNOWN: 'bunx @ultimat3/cli help new',
|
|
378
|
+
X_NEW_SHAPE_CONFLICT: 'bunx @ultimat3/cli new myapp --shape blog',
|
|
379
|
+
X_SEO_CARD_ROUTE_UNKNOWN:
|
|
380
|
+
'x routes --json # list the site/ routes; add apps/web/site/<the capture path>/page.tsx at 1200 x 630 with robots: { index: false }, or correct the og.capture path',
|
|
381
|
+
X_SEO_CARD_BROWSER_MISSING:
|
|
382
|
+
'export CHROME_PATH=/usr/bin/google-chrome # any Chrome, Chromium or Edge binary; or drop og.capture from the route; the gate build passes --no-capture and needs none',
|
|
383
|
+
X_IMAGE_SOURCE_UNREADABLE:
|
|
384
|
+
"x build --target static --json # lists the export; put the file under apps/web/site/assets/ and pass asset('assets/<file>') as src, or give an absolute https:// URL",
|
|
385
|
+
X_VERIFY_SKIPS_OVER_CEILING:
|
|
386
|
+
'x test unit --json # then set what the skipped tests need, or raise skipCeiling in x.verify.json with the reason in the diff',
|
|
387
|
+
X_ASSET_VARIANT_UNDECLARED:
|
|
388
|
+
"responsiveImage({ src: asset('assets/hero.png'), width, height, alt }) # no widths/formats override for a site asset; an upload under /media answers any width",
|
|
389
|
+
X_NEW_SHAPE_GENERATE_FAILED:
|
|
390
|
+
'bunx x g sign-in --password --json # in the app x new wrote, reproduces it; then bun test packages/cli/src/templates/shapes',
|
|
391
|
+
X_ISLAND_DISPOSER_MISSING:
|
|
392
|
+
'x verify --only boundaries --json # names the file; end its mount() with return render(() => <Island {...props} />, el)',
|
|
393
|
+
X_SOCKET_HAND_ROLLED:
|
|
394
|
+
'x verify --only boundaries --json — names the file and line; delete the upgrade and declare the socket with deviceSocket({ path, resolveToken, onFrame }) from @ultimat3/realtime/server',
|
|
315
395
|
};
|
|
316
396
|
|
|
317
397
|
const isCliCode = (code: string): code is CliErrorCode =>
|
package/src/mcp-host.ts
CHANGED
|
@@ -25,9 +25,10 @@ import {
|
|
|
25
25
|
readOnlyQuery,
|
|
26
26
|
} from '@ultimat3/db';
|
|
27
27
|
import { inspectJobList, inspectQueues } from '@ultimat3/jobs';
|
|
28
|
-
import { MANIFEST_FILENAME } from '@ultimat3/manifest';
|
|
28
|
+
import { impactOf, MANIFEST_FILENAME, pathBetween } from '@ultimat3/manifest';
|
|
29
29
|
import type {
|
|
30
30
|
DevCapabilities,
|
|
31
|
+
DevGraphQuestion,
|
|
31
32
|
McpCaller,
|
|
32
33
|
McpServer,
|
|
33
34
|
QueryLimits,
|
|
@@ -38,6 +39,7 @@ import type {
|
|
|
38
39
|
import { DEV_SCOPES, devHost, devMcpServer, frameworkIntrospection } from '@ultimat3/mcp';
|
|
39
40
|
import { loadApp } from './app-load';
|
|
40
41
|
import { appManifest, policyFacts } from './app-manifest';
|
|
42
|
+
import { loadAppGraph, resolveNode } from './cmd-graph-load';
|
|
41
43
|
import { runVerify, VERIFY_STEPS } from './cmd-verify';
|
|
42
44
|
import { declareDevEnvironment } from './dev-environment';
|
|
43
45
|
import { loadCodeFixes } from './error-fixes';
|
|
@@ -312,6 +314,14 @@ function capabilities(
|
|
|
312
314
|
|
|
313
315
|
explainError: explainErrorCode,
|
|
314
316
|
|
|
317
|
+
// Loaded per question, as `x impact` loads it: an agent asks between edits, and a graph held
|
|
318
|
+
// for the session would answer for the code as it was when the host started.
|
|
319
|
+
async queryGraph(question: DevGraphQuestion) {
|
|
320
|
+
const { graph } = await loadAppGraph(root);
|
|
321
|
+
if (question.kind === 'impact') return impactOf(graph, resolveNode(graph, question.node));
|
|
322
|
+
return pathBetween(graph, resolveNode(graph, question.from), resolveNode(graph, question.to));
|
|
323
|
+
},
|
|
324
|
+
|
|
315
325
|
...ui,
|
|
316
326
|
|
|
317
327
|
async verify(fix: boolean): Promise<VerifyResult> {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// The `manifest` step's remote-MCP half: every `mcpTools()` the app declares, its live server
|
|
2
|
+
// compared with `tools.lock.json` — what `x mcp lock <name> --check` does, for every name at once.
|
|
3
|
+
// A drift is the convention's build error (`X_MCP_REMOTE_TOOL_CHANGED`); a server that cannot be
|
|
4
|
+
// reached is a warning, because a third party's outage must not block an unrelated change.
|
|
5
|
+
|
|
6
|
+
// why: Bun exposes no path-join primitive; the lock sits at the app root.
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { ERROR_DOCS_URL, isUltimateError, renderThrowable } from '@ultimat3/core';
|
|
9
|
+
import type { DeclaredMcpServer } from '@ultimat3/mcp';
|
|
10
|
+
import {
|
|
11
|
+
declaredMcpServers,
|
|
12
|
+
lockChanges,
|
|
13
|
+
McpRemoteToolChangedError,
|
|
14
|
+
readToolsLock,
|
|
15
|
+
TOOLS_LOCK_FILE,
|
|
16
|
+
} from '@ultimat3/mcp';
|
|
17
|
+
import { loadApp } from './app-load';
|
|
18
|
+
import type { AppLoader } from './app-permissions';
|
|
19
|
+
import type { Finding } from './output';
|
|
20
|
+
|
|
21
|
+
export interface McpLockReport {
|
|
22
|
+
readonly findings: readonly Finding[];
|
|
23
|
+
/** One line per server whose live list could not be read. */
|
|
24
|
+
readonly warnings: readonly string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Says nothing when the load failed: a missing lock is already the load's finding. */
|
|
28
|
+
export async function mcpLockFindings(
|
|
29
|
+
root: string,
|
|
30
|
+
load: AppLoader = loadApp,
|
|
31
|
+
servers: () => ReadonlyMap<string, DeclaredMcpServer> = declaredMcpServers,
|
|
32
|
+
): Promise<McpLockReport> {
|
|
33
|
+
if ((await load(root)).findings.length > 0) return { findings: [], warnings: [] };
|
|
34
|
+
const declared = [...servers().values()];
|
|
35
|
+
if (declared.length === 0) return { findings: [], warnings: [] };
|
|
36
|
+
const file = Bun.file(join(root, TOOLS_LOCK_FILE));
|
|
37
|
+
const lock = readToolsLock((await file.exists()) ? ((await file.json()) as unknown) : undefined);
|
|
38
|
+
const findings: Finding[] = [];
|
|
39
|
+
const warnings: string[] = [];
|
|
40
|
+
for (const server of declared) {
|
|
41
|
+
let live: Awaited<ReturnType<DeclaredMcpServer['client']['listTools']>>;
|
|
42
|
+
try {
|
|
43
|
+
live = await server.client.listTools();
|
|
44
|
+
} catch (error) {
|
|
45
|
+
const code = isUltimateError(error) ? error.code : 'unknown';
|
|
46
|
+
warnings.push(
|
|
47
|
+
`${TOOLS_LOCK_FILE}: "${server.name}" was not checked, its server did not list its tools (${code}: ${renderThrowable(error)})`,
|
|
48
|
+
);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const changes = lockChanges(lock.get(server.name), server.url, server.allow, live);
|
|
52
|
+
if (changes.length === 0) continue;
|
|
53
|
+
const drift = new McpRemoteToolChangedError({ server: server.name, changes });
|
|
54
|
+
findings.push({ code: drift.code, cause: drift.message, fix: drift.fix, docs: ERROR_DOCS_URL });
|
|
55
|
+
}
|
|
56
|
+
return { findings, warnings };
|
|
57
|
+
}
|
package/src/measure-paths.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
// `/blog/:slug` with an empty `slug` failed the page's own input schema (`X_INPUT_INVALID`), and
|
|
5
5
|
// that was filed as "could not be weighed", a failure of the app dressed as a gap in the build.
|
|
6
6
|
|
|
7
|
-
import type { RouteEntry } from '@ultimat3/render';
|
|
8
|
-
import {
|
|
7
|
+
import type { PrerenderEntry, RouteEntry } from '@ultimat3/render';
|
|
8
|
+
import { enumeratePrerenderEntries } from '@ultimat3/render/server';
|
|
9
9
|
import { quoteArg } from './shell-quote';
|
|
10
10
|
import type { UnmeasuredRoute } from './static-report';
|
|
11
11
|
|
|
@@ -62,11 +62,19 @@ export const perRequestParams = (entry: RouteEntry): UnmeasuredRoute => ({
|
|
|
62
62
|
weighable: false,
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
/**
|
|
66
|
+
* `enumerate` is where a dynamic route's pages come from: the build passes the one enumeration it
|
|
67
|
+
* shares with `siteSeo`'s entries, so a budgeted route's `prerender()` runs once per build, not once
|
|
68
|
+
* to weigh and again to list. Omitted, `prerender()` is asked here.
|
|
69
|
+
*/
|
|
70
|
+
export async function measurePaths(
|
|
71
|
+
entry: RouteEntry,
|
|
72
|
+
enumerate: (entry: RouteEntry) => Promise<readonly PrerenderEntry[]> = enumeratePrerenderEntries,
|
|
73
|
+
): Promise<MeasurePlan> {
|
|
66
74
|
if (entry.pattern.keys.length === 0) return { paths: [{ path: entry.path, params: {} }] };
|
|
67
75
|
if (entry.config.render === 'ssr') return { unmeasured: perRequestParams(entry) };
|
|
68
76
|
if (entry.config.prerender === undefined) return { unmeasured: paramsUndeclared(entry, false) };
|
|
69
|
-
const sets = await
|
|
77
|
+
const sets = (await enumerate(entry)).map((page) => page.params);
|
|
70
78
|
if (sets.length === 0) return { unmeasured: paramsUndeclared(entry, true) };
|
|
71
79
|
return {
|
|
72
80
|
paths: sets.map((params) => ({ path: fillPath(entry.pattern.source, params), params })),
|
package/src/measure-scope.ts
CHANGED
|
@@ -17,16 +17,13 @@ export interface MeasureScope {
|
|
|
17
17
|
run<T>(fn: () => T): T;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
* comes from its actions and queries, and a route the render reaches that is not one of them
|
|
23
|
-
* answers 404 — which the render reports, and the route is filed unmeasured with that reason.
|
|
24
|
-
*/
|
|
25
|
-
export async function measureScope(input: {
|
|
20
|
+
/** A scope's in-process API: the app's own table, as `actor` — or, `null`, as nobody. */
|
|
21
|
+
interface ScopeInput {
|
|
26
22
|
readonly origin: string;
|
|
27
23
|
readonly buildId: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function inProcessRunner(input: ScopeInput, actor: Actor | null): <T>(fn: () => T) => T {
|
|
30
27
|
// No rate limit: every request here is this build's own render, and a limiter would need a
|
|
31
28
|
// deployment scope a build does not have (`X_RATE_LIMIT_SCOPE_UNSET`).
|
|
32
29
|
const config = defineHttpConfig({ buildId: input.buildId, rateLimit: { enabled: false } });
|
|
@@ -36,7 +33,7 @@ export async function measureScope(input: {
|
|
|
36
33
|
role: 'web',
|
|
37
34
|
config,
|
|
38
35
|
});
|
|
39
|
-
ctx.actor = actor;
|
|
36
|
+
if (actor !== null) ctx.actor = actor;
|
|
40
37
|
const pipeline = httpPipeline({
|
|
41
38
|
table: httpRouter(apiRoutes()),
|
|
42
39
|
config,
|
|
@@ -45,10 +42,27 @@ export async function measureScope(input: {
|
|
|
45
42
|
const dispatch = (url: string, init: RequestInit): Promise<Response> =>
|
|
46
43
|
pipeline.handle(new Request(url, init), { role: 'web' });
|
|
47
44
|
const request: Ctx = ctx;
|
|
48
|
-
return
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
return <T>(fn: () => T): T => withInProcessFetch(dispatch, () => runWithContext(request, fn));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The scope for `origin`. The pipeline is the app's API table and nothing else: a page's data
|
|
50
|
+
* comes from its actions and queries, and a route the render reaches that is not one of them
|
|
51
|
+
* answers 404 — which the render reports, and the route is filed unmeasured with that reason.
|
|
52
|
+
* For a render that is WEIGHED and discarded only: its output is never published.
|
|
53
|
+
*/
|
|
54
|
+
export async function measureScope(input: ScopeInput): Promise<MeasureScope> {
|
|
55
|
+
const actor = await measurementActor();
|
|
56
|
+
return { actor, run: inProcessRunner(input, actor) };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The same in-process API, authenticating NOBODY: what a read whose answer is PUBLISHED runs in —
|
|
61
|
+
* a `site/` route's `prerender()` (sitemap.xml) and an llms.txt page's `load`. Run as the
|
|
62
|
+
* measurement actor, those listed rows only that actor may read (a demo owner's drafts).
|
|
63
|
+
*/
|
|
64
|
+
export function publicScope(input: ScopeInput): <T>(fn: () => T) => T {
|
|
65
|
+
return inProcessRunner(input, null);
|
|
52
66
|
}
|
|
53
67
|
|
|
54
68
|
/**
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// The `x client`, `x graph` and `x impact` rows of the CLI catalog (`messages.ts` composes them):
|
|
2
|
+
// what a generation wrote, what the app graph holds, what a change reaches. Data only.
|
|
3
|
+
|
|
4
|
+
export const CLIENT_MESSAGES = {
|
|
5
|
+
'cli.client.vendor.written':
|
|
6
|
+
'{name}: {operations} operation(s), {types} type(s) compiled from {source} into {dir}',
|
|
7
|
+
'cli.client.customer.written':
|
|
8
|
+
'{operations} operation(s), {types} type(s) compiled from {source} into {dir}',
|
|
9
|
+
'cli.client.file': ' wrote {path}',
|
|
10
|
+
'cli.graph.summary': '{nodes} node(s), {edges} edge(s) ({provenance}); {opaque} opaque file(s)',
|
|
11
|
+
'cli.graph.kind': ' {kind}: {count}',
|
|
12
|
+
'cli.graph.path': '{from} → {to} in {steps} step(s)',
|
|
13
|
+
'cli.graph.pathStep': ' {from} —{rel} ({provenance})→ {to}',
|
|
14
|
+
'cli.graph.noPath': 'no known path between {from} and {to} (searched: {searched})',
|
|
15
|
+
'cli.impact.summary':
|
|
16
|
+
'{node} reaches {routes} route(s), {actions} action(s), {queries} query(ies), {jobs} job(s), {tests} test(s)',
|
|
17
|
+
'cli.impact.published':
|
|
18
|
+
' published: {operations} — contract-diff will have an opinion about this change',
|
|
19
|
+
'cli.impact.section': ' {section}: {names}',
|
|
20
|
+
'cli.affected.tests': '{count} test file(s) in this app import a changed file, transitively',
|
|
21
|
+
'cli.affected.testsAll':
|
|
22
|
+
'every test file in this app: {files} changed and no import says who reads it',
|
|
23
|
+
} as const;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// The `x db` family's rows of the CLI catalog (`messages.ts` composes them): migrations, seeds,
|
|
2
|
+
// backfills, branches, diagnostics. Data only — `msg()` is the one lookup.
|
|
3
|
+
|
|
4
|
+
export const DB_MESSAGES = {
|
|
5
|
+
'cli.db.backfill.empty': 'no backfill has run against this database yet',
|
|
6
|
+
'cli.db.backfill.listed': '{count} backfill pass(es)',
|
|
7
|
+
/** The empty cell in a `x db backfill --list` column — a value, not a column key. */
|
|
8
|
+
'cli.db.backfill.none': '-',
|
|
9
|
+
'cli.db.backfill.pending': '{count} of {declared} declared backfill(s) never completed',
|
|
10
|
+
'cli.db.backfill.swept': 'every one of {declared} declared backfill(s) has completed',
|
|
11
|
+
// Every action counted, never derived: `count - enqueued` folded a deduped pass into "blocked",
|
|
12
|
+
// so the summary said blocked while `--json` said deduped for the same row — two renderers
|
|
13
|
+
// stating different facts about one run, which is the thing `--json` exists to make impossible.
|
|
14
|
+
'cli.db.backfill.planned':
|
|
15
|
+
'{count} backfill(s): {enqueued} enqueued, {deduped} already live, {blocked} blocked',
|
|
16
|
+
'cli.db.backfill.dryRun': '{count} backfill(s) would run — nothing written without --write',
|
|
17
|
+
'cli.db.branch.ready': 'branch {name} ready',
|
|
18
|
+
'cli.db.branch.dropped': 'branch {name} dropped',
|
|
19
|
+
'cli.db.branch.failed': 'branch command failed',
|
|
20
|
+
'cli.db.branch.listed': '{count} branch(es) of this database',
|
|
21
|
+
'cli.db.branch.none': 'this database has no branch',
|
|
22
|
+
/** The empty cell in an `x db branch list` column — a value, not a column key. */
|
|
23
|
+
'cli.db.branch.unknown': '-',
|
|
24
|
+
'cli.db.diagnostics.done': '{available} of {total} diagnostic section(s) answered',
|
|
25
|
+
'cli.db.recount.drift': '{target}: {count} row(s) drifted from the true count',
|
|
26
|
+
'cli.db.recount.repaired': '{target}: {count} row(s) set to the true count',
|
|
27
|
+
'cli.db.diagnostics.section': '{section}: {count} row(s)',
|
|
28
|
+
'cli.db.diagnostics.unavailable': '{section}: unavailable, {code} — {reason} fix: {fix}',
|
|
29
|
+
'cli.db.gen.failed': 'migration not generated',
|
|
30
|
+
'cli.db.gen.unchanged': 'entities and migrations agree — nothing to generate',
|
|
31
|
+
'cli.db.gen.blocked':
|
|
32
|
+
'nothing was compared — the app did not load ({count} finding(s)); fix them, then run x db gen again',
|
|
33
|
+
// A THIRD outcome, and it is neither of the other two: nothing to generate, but the sidecar the
|
|
34
|
+
// `drift` step reads did move — an edit under `packages/db/src` that implies no DDL. Rendering it
|
|
35
|
+
// as `written` would name a migration nobody can apply; as `unchanged`, it would hide a file this
|
|
36
|
+
// command wrote. `GeneratedFiles.outcome` is what `--json` carries the same distinction on.
|
|
37
|
+
'cli.db.gen.recorded': 'no migration needed — schema hash re-recorded in {file}',
|
|
38
|
+
// The fourth: no DDL and no sidecar moved, but `packages/db/schema/` did — a hand edit repaired,
|
|
39
|
+
// or a framework table that changed under an upgrade. `unchanged` would deny a write the lines
|
|
40
|
+
// below it list, and this command is `X_SCHEMA_DUMP_DRIFT`'s whole `fix:`.
|
|
41
|
+
'cli.db.gen.dumped': 'no migration needed — schema dump rewritten ({count} file(s))',
|
|
42
|
+
'cli.db.gen.written': 'migration {id} generated',
|
|
43
|
+
// Exit 1 and a migration on disk at once: the summary carries the half the exit code hides.
|
|
44
|
+
'cli.db.gen.writtenDumpFailed':
|
|
45
|
+
'migration {id} generated and written — the schema dump was not; do not generate it again',
|
|
46
|
+
'cli.db.migrate.applied': 'migrations applied',
|
|
47
|
+
'cli.db.migrate.failed': 'migration failed',
|
|
48
|
+
'cli.db.reset.done': 'database reset and migrated',
|
|
49
|
+
// Every seed counted per outcome, exactly as the backfill summary is: a replayed seed writes
|
|
50
|
+
// nothing and skips everything, and a total that hid that would make the second run look idle.
|
|
51
|
+
'cli.db.seed.done':
|
|
52
|
+
'{count} seed(s): {inserted} inserted, {updated} updated, {skipped} already stored',
|
|
53
|
+
'cli.db.seed.dryRun': '{count} seed(s) would run — nothing written while --dry-run is set',
|
|
54
|
+
'cli.db.seed.failed': '{failed} of {count} seed(s) failed',
|
|
55
|
+
'cli.db.seed.none': 'no seed matched — nothing to run',
|
|
56
|
+
} as const;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// The gate's rows of the CLI catalog (`messages.ts` composes them): `x verify`, `x ci`, `x pr`
|
|
2
|
+
// and `x affected`. Data only — `msg()` is the one lookup.
|
|
3
|
+
|
|
4
|
+
export const GATE_MESSAGES = {
|
|
5
|
+
'cli.affected.count':
|
|
6
|
+
'{count} workspace(s) affected by {base}...HEAD, from {changed} changed file(s)',
|
|
7
|
+
'cli.affected.dirty':
|
|
8
|
+
' including the working tree (--dirty): every uncommitted change in this checkout, whoever made it',
|
|
9
|
+
'cli.affected.none': 'no workspace is affected by {base}...HEAD, from {changed} changed file(s)',
|
|
10
|
+
'cli.affected.rootWide':
|
|
11
|
+
' every workspace: {files} belongs to none of them and changes what all of them compile',
|
|
12
|
+
'cli.ci.failed':
|
|
13
|
+
'{failed} of {runs} workflow run(s) on {branch} failed — {findings} finding(s) recovered from the log',
|
|
14
|
+
'cli.ci.green': 'every one of {runs} workflow run(s) on {branch} passed',
|
|
15
|
+
'cli.ci.job': ' {conclusion} {job} ({steps})',
|
|
16
|
+
'cli.ci.jobs.other': ' {count} other job(s) in this run',
|
|
17
|
+
'cli.ci.logs.empty': ' the failed step wrote no log — {url}',
|
|
18
|
+
/** The conclusion of a run GitHub has not finished — a value, not a column key. */
|
|
19
|
+
'cli.ci.pending': 'pending',
|
|
20
|
+
'cli.ci.run': '{conclusion} {workflow} {url}',
|
|
21
|
+
'cli.ci.running':
|
|
22
|
+
'{running} of {runs} workflow run(s) on {branch} has not finished — nothing has failed yet',
|
|
23
|
+
'cli.ci.tail': ' log tail, {job}:',
|
|
24
|
+
// `x ci tested`, one reason per condition (`TESTED_CONDITIONS`): what reused, or why it ran all.
|
|
25
|
+
'cli.ci.tested.tested':
|
|
26
|
+
'tested: PR #{pr} merged this tree, and {workflow} run {run} passed on its head — the jobs it ran are reused',
|
|
27
|
+
'cli.ci.tested.subject':
|
|
28
|
+
'not tested: the subject does not end (#N), so no pull request merged this commit — a full run',
|
|
29
|
+
'cli.ci.tested.merged': 'not tested: PR #{pr} was not merged as this commit — a full run',
|
|
30
|
+
'cli.ci.tested.fork':
|
|
31
|
+
"not tested: PR #{pr}'s head is not in {repo}, and a fork's run is never reused — a full run",
|
|
32
|
+
'cli.ci.tested.tree':
|
|
33
|
+
"not tested: this tree is not PR #{pr}'s head tree, so its base moved after the run — a full run",
|
|
34
|
+
'cli.ci.tested.run': "not tested: no green {workflow} run on PR #{pr}'s head — a full run",
|
|
35
|
+
'cli.ci.tested.stale':
|
|
36
|
+
'not tested: {workflow} run {run} for PR #{pr} is older than {maxAge} — a full run',
|
|
37
|
+
'cli.ci.tested.api': 'not tested: GitHub did not answer ({detail}) — a full run',
|
|
38
|
+
'cli.ci.tested.sha':
|
|
39
|
+
'not tested: no GITHUB_SHA, and git rev-parse HEAD named no commit — a full run',
|
|
40
|
+
'cli.pr.body.truncated': ' … {hidden} more line(s) — re-run with --full',
|
|
41
|
+
/** The line of a thread whose anchor GitHub answers null for — a value, not a column key. */
|
|
42
|
+
'cli.pr.line.unknown': '-',
|
|
43
|
+
'cli.pr.replied': 'replied on thread {id}: {url}',
|
|
44
|
+
// Resolving closes a CONVERSATION. Whether the finding is fixed is a fact about the code that
|
|
45
|
+
// no GitHub mutation observes, and a summary saying "addressed" would assert one from the other.
|
|
46
|
+
'cli.pr.resolved':
|
|
47
|
+
'thread {id} is marked resolved on GitHub — that records the conversation, not that the finding is fixed',
|
|
48
|
+
'cli.pr.review.count':
|
|
49
|
+
'{unresolved} unresolved and {resolved} resolved review thread(s) on {repo}#{pr}',
|
|
50
|
+
'cli.pr.review.current': ' submitted against the current head {head}',
|
|
51
|
+
'cli.pr.review.decision': ' review: {decision} by {author} at {submitted}',
|
|
52
|
+
'cli.pr.review.none': 'no review thread is anchored to a line on {repo}#{pr}',
|
|
53
|
+
'cli.pr.review.stale':
|
|
54
|
+
' submitted against {commit}; the head is now {head} ({committed}) — this decision predates the current code',
|
|
55
|
+
'cli.pr.review.truncated':
|
|
56
|
+
' more than {count} threads — this is the first page, not the whole review',
|
|
57
|
+
'cli.pr.review.undecided': ' GitHub reports no review decision yet',
|
|
58
|
+
'cli.pr.thread.closed': ' resolved {path}:{line} {id}',
|
|
59
|
+
'cli.pr.thread.comment': ' {author} at {createdAt}',
|
|
60
|
+
'cli.pr.thread.more': ' {hidden} more comment(s) on this thread',
|
|
61
|
+
'cli.pr.thread.open': ' unresolved {path}:{line} {id}',
|
|
62
|
+
'cli.pr.thread.outdated':
|
|
63
|
+
' the diff has moved under this thread — {line} is where the comment was written',
|
|
64
|
+
// The banner a `--only` run carries, in front of whichever summary above it renders. Rendered
|
|
65
|
+
// output, so it lives here — `data.notAGateRun` is the machine marker, and a reader testing for
|
|
66
|
+
// one narrowed run reads that boolean rather than substring-matching this line.
|
|
67
|
+
'cli.verify.notAGateRun': 'NOT A GATE RUN — {summary}',
|
|
68
|
+
'cli.verify.pass': 'all {count} steps passed in {ms}ms',
|
|
69
|
+
'cli.verify.fail': '{failed} of {count} steps failed',
|
|
70
|
+
// The budgets step built before it weighed (`verify-budgets-build.ts`): which stats state made it.
|
|
71
|
+
'cli.verify.budgets.built':
|
|
72
|
+
'built first: build stats were {state} — x build --target static --out {out} ({ms}ms)',
|
|
73
|
+
// A skipped step is not a passed one, so the two counts never share a sentence — and the skipped
|
|
74
|
+
// ones are named, because "which suite has nothing to run here?" is the question a green gate
|
|
75
|
+
// over a missing suite has to answer on its own line. Whole sentences per case rather than a
|
|
76
|
+
// clause the caller glues on: a catalog clause cannot know the sentence it lands in.
|
|
77
|
+
'cli.verify.passSkipped':
|
|
78
|
+
'{passed} of {count} steps passed in {ms}ms — {skipped} skipped: {names}',
|
|
79
|
+
'cli.verify.failSkipped': '{failed} of {count} steps failed — {skipped} skipped: {names}',
|
|
80
|
+
// The `errors` step's own coverage, in `output`: a scan without a parser reads most fix lines
|
|
81
|
+
// and not all of them, and a step that reports findings alone claims a completeness it lacks.
|
|
82
|
+
'cli.verify.fixCoverage': 'checked {checked} fix line(s), could not read {unreadable}',
|
|
83
|
+
// Why a skipped step is a dash when the step can say so: the suite exists and not one of its
|
|
84
|
+
// tests ran. Each test's own name carries the reason it skipped, and `bun test` prints only the
|
|
85
|
+
// counts — so the line says how many and `x test <type>` prints the names.
|
|
86
|
+
'cli.verify.allSkipped': 'found {skipped} test(s) and every one skipped itself',
|
|
87
|
+
'cli.verify.warnings': '{count} warning(s) — --verbose or --json lists them',
|
|
88
|
+
'cli.verify.slowest': 'slowest: {files}',
|
|
89
|
+
'cli.verify.isrQueryOmitted':
|
|
90
|
+
'{file}: reads the query parameter "{name}", which revalidate.query does not list — the page is stored under a key without it, so every visitor gets the document rendered for whichever value arrived first. Declare query: [{declared}], or stop reading it',
|
|
91
|
+
// The other shape the same counts can take: a suite that reported no test at all, skipped ones
|
|
92
|
+
// included. Its own line and not `allSkipped` with a zero, because the repair differs — there is
|
|
93
|
+
// no skipped test to read a reason off, so the files the step selected hold no test.
|
|
94
|
+
'cli.verify.ranNothing': 'found no test to run in the file(s) it selected',
|
|
95
|
+
'cli.verify.merged': 'merged {parts} part(s) — {summary}',
|
|
96
|
+
// The heartbeat `verify-progress.ts` writes while a step is still running: `{steps}` is
|
|
97
|
+
// `unit (12m 3s), live (4m 0s)`, each step with the time since it started.
|
|
98
|
+
'cli.verify.stillRunning': 'still running: {steps}',
|
|
99
|
+
// The `unit` step's own measurement, in `output`: what the suite covered of the app's whole
|
|
100
|
+
// source tree, beside the floor it was held to. A shard says it measured a slice instead.
|
|
101
|
+
'cli.verify.coverage':
|
|
102
|
+
'coverage: {lines}% of lines, {funcs}% of functions over {files} source file(s) — floor {floor}',
|
|
103
|
+
'cli.verify.coverageDeferred':
|
|
104
|
+
'coverage: this shard measured its own slice — x verify merge folds every shard and judges the floor',
|
|
105
|
+
'cli.verify.serial': 'serial',
|
|
106
|
+
'cli.verify.workers': '{workers} workers',
|
|
107
|
+
} as const;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// The `x repro` rows of the CLI catalog (`messages.ts` composes them). Data only — `msg()` is the
|
|
2
|
+
// one lookup.
|
|
3
|
+
|
|
4
|
+
export const REPRO_MESSAGES = {
|
|
5
|
+
'cli.repro.job': 'job {name} ({id}) died with {code} at step {step}',
|
|
6
|
+
'cli.repro.request': '{primitive} {name} answered {code} — fingerprint {fingerprint}',
|
|
7
|
+
'cli.repro.written': ' wrote {file}',
|
|
8
|
+
'cli.repro.reproduced': ' reproduced: {file} fails with {code}',
|
|
9
|
+
'cli.repro.notReproduced': ' not reproduced: {file} ended in {got}',
|
|
10
|
+
'cli.repro.listed': '{count} captured bundle(s)',
|
|
11
|
+
} as const;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// The `x shot` rows of the CLI catalog (`messages.ts` composes them): capture, compare and the
|
|
2
|
+
// verdict lines. Data only — `msg()` is the one lookup.
|
|
3
|
+
|
|
4
|
+
export const SHOT_MESSAGES = {
|
|
5
|
+
// `x shot` — the picture is the `lines`, the verdict is the artifact. The summary names the
|
|
6
|
+
// GATING fact, and a redirect comes first: a photograph of the sign-in page with every island
|
|
7
|
+
// missing reads as a bug in the app, and it is a bug in the capture.
|
|
8
|
+
'cli.shot.ok': '{route} clean — {islands} island(s) mounted, nothing logged and nothing threw',
|
|
9
|
+
'cli.shot.errors': '{route}: {errors} console error(s) — verdict.json names each one',
|
|
10
|
+
'cli.shot.redirected': '{route} redirected to {url} — the picture is not the route asked for',
|
|
11
|
+
// After the redirect and before everything else: a 404 page can be spotless, and a picture of
|
|
12
|
+
// "Not found" read as the route is the capture lying about its subject.
|
|
13
|
+
'cli.shot.status':
|
|
14
|
+
'{route} answered HTTP {status}, expected {expected} — the picture is that response, not the page',
|
|
15
|
+
'cli.shot.document': ' document HTTP {status}',
|
|
16
|
+
'cli.shot.documentUnknown': ' document status not seen — the driver recorded no response for it',
|
|
17
|
+
'cli.shot.server.booted': ' server booted for this shot on {url}',
|
|
18
|
+
'cli.shot.server.reused': ' server the x dev already running on {url}',
|
|
19
|
+
'cli.shot.canvas': ' canvas {width}x{height}',
|
|
20
|
+
'cli.shot.canvasUnreadable': ' canvas unreadable — {bytes} byte(s), not a decodable image',
|
|
21
|
+
'cli.shot.islands': ' islands {booted} of {declared} mounted ({strategies})',
|
|
22
|
+
'cli.shot.islandsUnknown': ' islands not counted — the page answered no probe',
|
|
23
|
+
// The failure a picture cannot show and a console count cannot see: a rejected mount promise
|
|
24
|
+
// calls no console method, so the FIRST one is named here rather than left to verdict.json.
|
|
25
|
+
'cli.shot.islandFailed': '{route}: {failed} island(s) failed to mount — {island}: {message}',
|
|
26
|
+
'cli.shot.network': ' network {requests} request(s), {refused} refused, {dropped} dropped',
|
|
27
|
+
'cli.shot.console': ' console {level}: {text}',
|
|
28
|
+
'cli.shot.threw': '{route}: {thrown} uncaught exception(s) — {first}',
|
|
29
|
+
'cli.shot.pageError': ' threw {message} {at}',
|
|
30
|
+
'cli.shot.picture': ' picture {path}',
|
|
31
|
+
'cli.shot.verdict': ' verdict {path}',
|
|
32
|
+
// `--viewport`: one route at several sizes. The summary is ONE size's verdict, so it says which
|
|
33
|
+
// size; each size line leads with its size and the per-size detail lines sit indented beneath.
|
|
34
|
+
'cli.shot.viewport.summary': '{size}: {summary}',
|
|
35
|
+
'cli.shot.viewport.line': '{size} {summary}',
|
|
36
|
+
// `--island`. A component capture reports per STATE, so the summary counts pictures and the
|
|
37
|
+
// lines name one state each; nothing here restates a fact `--json` does not carry.
|
|
38
|
+
'cli.shot.island.ok':
|
|
39
|
+
'{island} clean — {pictures} picture(s), every one mounted, nothing logged and nothing threw',
|
|
40
|
+
'cli.shot.island.failed':
|
|
41
|
+
'{island}: {taken} of {expected} declared picture(s) taken — verdict.json names each refusal',
|
|
42
|
+
'cli.shot.island.state': ' {state} {theme} {width}x{height} {file}',
|
|
43
|
+
'cli.shot.island.missing': ' missing {file} — no picture was taken for this declared state',
|
|
44
|
+
'cli.shot.island.picture': ' pictures {path}',
|
|
45
|
+
'cli.shot.island.verdict': ' verdict {path}',
|
|
46
|
+
'cli.shot.island.index': ' index {path}',
|
|
47
|
+
'cli.shot.island.blind.crop':
|
|
48
|
+
"the picture is the crop target and a thin margin around it — anything further out, including the space a component's own fault sits in, is outside the frame; content that overflows the box is recorded per state as overflow, never shown",
|
|
49
|
+
'cli.shot.island.blind.locale':
|
|
50
|
+
'toLocaleString() on a Date resolves its zone inside the engine — only an explicit timeZone is pinned by this harness',
|
|
51
|
+
} as const;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// The `x upgrade` rows of the CLI catalog (`messages.ts` composes them): the hop walk, its stages
|
|
2
|
+
// and its `then:` lines. Data only — `msg()` is the one lookup.
|
|
3
|
+
|
|
4
|
+
export const UPGRADE_MESSAGES = {
|
|
5
|
+
'cli.upgrade.atLatest': 'already at {version}, the newest release',
|
|
6
|
+
'cli.upgrade.atTarget': 'already at {version}; {next} is the next release',
|
|
7
|
+
'cli.upgrade.noApp.done':
|
|
8
|
+
'{from} -> {to}: no app.config.ts, so no x verify ran; {count} script(s) passed',
|
|
9
|
+
'cli.upgrade.noApp.none':
|
|
10
|
+
'{from} -> {to}: nothing checked: no app.config.ts, and no typecheck or test script',
|
|
11
|
+
'cli.upgrade.noApp.red': '{from} -> {to}: no app.config.ts, and a script failed: {names}',
|
|
12
|
+
'cli.upgrade.scriptRed': 'failed, re-run it: bun run {name}',
|
|
13
|
+
'cli.upgrade.then.atTarget':
|
|
14
|
+
'nothing to do at {version}; a bare x upgrade --json takes the next release, {next}',
|
|
15
|
+
'cli.upgrade.then.dryRunNoApp':
|
|
16
|
+
'no app.config.ts, so on a clean tree x upgrade --json moves the pins and runs {scripts} in place of x verify',
|
|
17
|
+
'cli.upgrade.then.noProof':
|
|
18
|
+
'nothing checked this hop: confirm {to} works by hand, commit it, then re-run x upgrade --json for the next one',
|
|
19
|
+
'cli.upgrade.then.scriptsGreen':
|
|
20
|
+
'the scripts passed, which is less than x verify would say: review the diff, commit this hop to {to}, then re-run x upgrade --json for the next one',
|
|
21
|
+
'cli.upgrade.then.scriptsRed':
|
|
22
|
+
'read the section, make each failed script pass, commit this hop to {to}, then re-run x upgrade --json for the next one',
|
|
23
|
+
'cli.upgrade.agentsMd.link':
|
|
24
|
+
'AGENTS.md: byte-identical to CLAUDE.md, so this hop makes it a symlink to it',
|
|
25
|
+
'cli.upgrade.agentsMd.differs':
|
|
26
|
+
'AGENTS.md: differs from CLAUDE.md, left alone. Merge what only AGENTS.md says into CLAUDE.md, then: ln -sf CLAUDE.md AGENTS.md',
|
|
27
|
+
'cli.upgrade.bunEdited': 'bun floor: {path} {from} -> {to}',
|
|
28
|
+
'cli.upgrade.bunManual': 'bun floor, by hand: {path}:{line} — {why}',
|
|
29
|
+
'cli.upgrade.done': '{from} -> {to}: the gate is green',
|
|
30
|
+
'cli.upgrade.dryRun': '{from} -> {to}: nothing written, no gate run',
|
|
31
|
+
'cli.upgrade.guard': 'guard, yours to take or leave: {fix}',
|
|
32
|
+
'cli.upgrade.read': 'read: {title} — {url}',
|
|
33
|
+
'cli.upgrade.red': '{from} -> {to}: not done, the gate says: {summary}',
|
|
34
|
+
'cli.upgrade.stillRunning': 'x upgrade: still in {stage} ({elapsed})',
|
|
35
|
+
'cli.upgrade.then': 'then: {then}',
|
|
36
|
+
'cli.upgrade.then.atLatest':
|
|
37
|
+
'nothing to do: this app is on {version}, and no newer release is published',
|
|
38
|
+
'cli.upgrade.then.dryRun': 'on a clean tree, run the hop: x upgrade --json',
|
|
39
|
+
'cli.upgrade.then.last':
|
|
40
|
+
'review the diff and commit this hop to {to}: it is the newest release, so the walk is over',
|
|
41
|
+
'cli.upgrade.then.red':
|
|
42
|
+
'read the section, close each finding by its fix, re-check with x verify --json, commit this hop to {to}, then re-run x upgrade --json for the next one',
|
|
43
|
+
'cli.upgrade.then.walk':
|
|
44
|
+
'review the diff and commit this hop to {to}, then re-run x upgrade --json to take the next one, {next}',
|
|
45
|
+
} as const;
|