@ultimat3/cli 21.0.0 → 22.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 (236) hide show
  1. package/CLAUDE.md +84 -1650
  2. package/README.md +40 -2
  3. package/package.json +30 -30
  4. package/src/api-registration.ts +124 -0
  5. package/src/app-artifacts.ts +39 -0
  6. package/src/app-boundaries.ts +5 -10
  7. package/src/app-load.ts +37 -5
  8. package/src/app-openapi.ts +27 -0
  9. package/src/app-permissions.ts +0 -0
  10. package/src/app-root.ts +1 -1
  11. package/src/async-pages.ts +32 -0
  12. package/src/bin.ts +7 -1
  13. package/src/boundary-findings.ts +36 -0
  14. package/src/browser-launcher-fake-html.ts +80 -0
  15. package/src/browser-launcher-fake.ts +165 -0
  16. package/src/browser-launcher-port.ts +159 -0
  17. package/src/browser-launcher.ts +26 -133
  18. package/src/budgets.ts +11 -1
  19. package/src/cdp-shot-a11y.ts +77 -0
  20. package/src/cdp-shot-clock.ts +14 -0
  21. package/src/cdp-shot-driver.ts +150 -0
  22. package/src/cdp-shot-element.ts +147 -0
  23. package/src/cdp-shot-errors.ts +62 -0
  24. package/src/cdp-shot-keys.ts +152 -0
  25. package/src/cdp-shot-page.ts +230 -0
  26. package/src/cdp-shot-watch.ts +241 -0
  27. package/src/cmd-affected-spec.ts +24 -0
  28. package/src/cmd-affected.ts +3 -19
  29. package/src/cmd-build-spec.ts +16 -0
  30. package/src/cmd-build.ts +46 -20
  31. package/src/cmd-ci-spec.ts +24 -0
  32. package/src/cmd-ci.ts +17 -21
  33. package/src/cmd-db-branch.ts +2 -2
  34. package/src/cmd-db-spec.ts +99 -0
  35. package/src/cmd-db.ts +15 -94
  36. package/src/cmd-deploy-helm.ts +136 -0
  37. package/src/cmd-deploy-spec.ts +40 -0
  38. package/src/cmd-deploy.ts +111 -43
  39. package/src/cmd-dev-spec.ts +25 -0
  40. package/src/cmd-dev.ts +55 -36
  41. package/src/cmd-docs-spec.ts +16 -0
  42. package/src/cmd-docs.ts +2 -11
  43. package/src/cmd-doctor-spec.ts +21 -0
  44. package/src/cmd-doctor.ts +4 -18
  45. package/src/cmd-env-spec.ts +18 -0
  46. package/src/cmd-env.ts +4 -13
  47. package/src/cmd-errors-spec.ts +23 -0
  48. package/src/cmd-errors.ts +3 -17
  49. package/src/cmd-fix-spec.ts +18 -0
  50. package/src/cmd-fix.ts +4 -13
  51. package/src/cmd-generate-spec.ts +31 -0
  52. package/src/cmd-generate.ts +46 -42
  53. package/src/cmd-i18n-spec.ts +16 -0
  54. package/src/cmd-i18n.ts +7 -14
  55. package/src/cmd-jobs-spec.ts +56 -0
  56. package/src/cmd-jobs.ts +3 -50
  57. package/src/cmd-manifest-spec.ts +15 -0
  58. package/src/cmd-manifest.ts +19 -20
  59. package/src/cmd-mcp-spec.ts +21 -0
  60. package/src/cmd-mcp.ts +2 -15
  61. package/src/cmd-new-spec.ts +33 -0
  62. package/src/cmd-new.ts +38 -33
  63. package/src/cmd-policy-spec.ts +13 -0
  64. package/src/cmd-policy.ts +2 -9
  65. package/src/cmd-pr-spec.ts +39 -0
  66. package/src/cmd-pr.ts +5 -65
  67. package/src/cmd-registries-spec.ts +32 -0
  68. package/src/cmd-registries.ts +4 -25
  69. package/src/cmd-routes-spec.ts +12 -0
  70. package/src/cmd-routes.ts +2 -7
  71. package/src/cmd-secrets-spec.ts +19 -0
  72. package/src/cmd-secrets.ts +22 -34
  73. package/src/cmd-shot-island.ts +12 -13
  74. package/src/cmd-shot-spec.ts +53 -0
  75. package/src/cmd-shot.ts +11 -60
  76. package/src/cmd-tasks-spec.ts +21 -0
  77. package/src/cmd-tasks.ts +2 -16
  78. package/src/cmd-test-spec.ts +54 -0
  79. package/src/cmd-test.ts +4 -49
  80. package/src/cmd-verify-spec.ts +28 -0
  81. package/src/cmd-verify.ts +3 -23
  82. package/src/db-seed.ts +4 -2
  83. package/src/dev-dashboard.ts +4 -4
  84. package/src/dev-lock.ts +18 -2
  85. package/src/dev-port.ts +21 -0
  86. package/src/dev-route-table.ts +3 -3
  87. package/src/dispatch.ts +12 -5
  88. package/src/document-styles.ts +1 -1
  89. package/src/drift.ts +4 -18
  90. package/src/error-catalog.ts +16 -9
  91. package/src/error-codes.ts +28 -30
  92. package/src/error-pages.ts +19 -7
  93. package/src/errors.ts +14 -0
  94. package/src/favicon.ts +2 -2
  95. package/src/fix-imports.ts +1 -1
  96. package/src/fix-scan.ts +2 -9
  97. package/src/flag-reads.ts +1 -2
  98. package/src/foreign-text.ts +36 -0
  99. package/src/framework-schema.ts +5 -6
  100. package/src/generate-feature.ts +42 -0
  101. package/src/generate-files.ts +7 -3
  102. package/src/generate-grants.ts +83 -0
  103. package/src/generate-kinds.ts +56 -4
  104. package/src/i18n-index.ts +59 -10
  105. package/src/icon-assets.ts +1 -1
  106. package/src/image-prepare.ts +14 -0
  107. package/src/import-scan.ts +63 -0
  108. package/src/index.ts +67 -348
  109. package/src/invocation-flags.ts +26 -0
  110. package/src/island-bundle.ts +6 -1
  111. package/src/island-capture.ts +6 -6
  112. package/src/island-harness-script.ts +6 -2
  113. package/src/island-realtime.ts +15 -8
  114. package/src/island-shot.ts +5 -0
  115. package/src/island-store.ts +131 -0
  116. package/src/island-verdict.ts +1 -1
  117. package/src/job-registration.ts +42 -0
  118. package/src/jobs-driver.ts +2 -2
  119. package/src/load-findings.ts +51 -0
  120. package/src/mcp-db-target.ts +1 -1
  121. package/src/mcp-errors.ts +28 -27
  122. package/src/mcp-host.ts +27 -12
  123. package/src/mcp-ui-diff.ts +27 -0
  124. package/src/mcp-ui-inspect.ts +4 -4
  125. package/src/mcp-ui-interact.ts +21 -15
  126. package/src/mcp-ui.ts +23 -17
  127. package/src/measure-database.ts +73 -0
  128. package/src/measure-paths.ts +74 -0
  129. package/src/measure-scope.ts +74 -0
  130. package/src/messages.ts +1 -3
  131. package/src/metrics-endpoint.ts +1 -1
  132. package/src/otlp-export.ts +1 -1
  133. package/src/output.ts +6 -0
  134. package/src/permission-grants.ts +86 -0
  135. package/src/prerender-out.ts +25 -0
  136. package/src/prerender.ts +121 -102
  137. package/src/pwa-artifacts.ts +3 -3
  138. package/src/reexport-manifest.ts +2 -1
  139. package/src/registry.ts +80 -56
  140. package/src/role-realtime.ts +36 -0
  141. package/src/{dev-replicator.ts → role-replicator.ts} +1 -1
  142. package/src/{dev-roles-fixture.ts → role-start-fixture.ts} +9 -5
  143. package/src/role-start-types.ts +112 -0
  144. package/src/{dev-roles.ts → role-start.ts} +42 -115
  145. package/src/{dev-sync.ts → role-sync.ts} +22 -8
  146. package/src/root-env.ts +67 -0
  147. package/src/{dev-assets.ts → runtime-assets.ts} +7 -7
  148. package/src/{dev-services.ts → runtime-bindings.ts} +39 -16
  149. package/src/{dev-cache.ts → runtime-cache.ts} +2 -2
  150. package/src/runtime-jobs.ts +87 -0
  151. package/src/{dev-live-feed.ts → runtime-live-feed.ts} +18 -5
  152. package/src/{dev-notify-retention.ts → runtime-notify-retention.ts} +1 -1
  153. package/src/{dev-purge.ts → runtime-purge.ts} +2 -2
  154. package/src/{dev-queue.ts → runtime-queue.ts} +4 -4
  155. package/src/runtime-realtime.ts +55 -0
  156. package/src/{dev-replica.ts → runtime-replica.ts} +2 -2
  157. package/src/{dev-runtime.ts → runtime-services.ts} +41 -17
  158. package/src/{dev-storage.ts → runtime-storage.ts} +4 -4
  159. package/src/scaffold-fixture.ts +28 -6
  160. package/src/scaffold-typecheck.ts +6 -3
  161. package/src/schema-drift.ts +7 -1
  162. package/src/script-csp.ts +5 -2
  163. package/src/secrets-rotation.ts +59 -0
  164. package/src/serve-boot.ts +192 -0
  165. package/src/serve-drain.ts +24 -0
  166. package/src/serve-entry.ts +6 -0
  167. package/src/serve-env.ts +116 -0
  168. package/src/serve-types.ts +55 -0
  169. package/src/serve.ts +44 -347
  170. package/src/shot-server.ts +2 -2
  171. package/src/shot-settle.ts +10 -1
  172. package/src/shot-theme.ts +3 -3
  173. package/src/shot-verdict.ts +16 -7
  174. package/src/signal-shred.ts +27 -0
  175. package/src/solid-loader.ts +26 -2
  176. package/src/static-report.ts +8 -1
  177. package/src/sync-url.ts +21 -1
  178. package/src/templates/action.ts +30 -16
  179. package/src/templates/entity.ts +12 -7
  180. package/src/templates/index.ts +1 -1
  181. package/src/templates/job.ts +10 -7
  182. package/src/templates/policy.ts +20 -2
  183. package/src/templates/resource-create.ts +127 -0
  184. package/src/templates/resource-form-island.ts +49 -12
  185. package/src/templates/resource.ts +10 -4
  186. package/src/templates/scaffold-app.ts +4 -1
  187. package/src/templates/scaffold-auth.ts +3 -1
  188. package/src/templates/scaffold-container-compose.ts +184 -0
  189. package/src/templates/scaffold-container.ts +24 -159
  190. package/src/templates/scaffold-dashboard-example.ts +2 -2
  191. package/src/templates/scaffold-db-package.ts +16 -3
  192. package/src/templates/scaffold-demo-org.ts +41 -0
  193. package/src/templates/scaffold-entries.ts +1 -1
  194. package/src/templates/scaffold-env.ts +6 -0
  195. package/src/templates/scaffold-helm-templates.ts +66 -7
  196. package/src/templates/scaffold-helm.ts +27 -5
  197. package/src/templates/scaffold-i18n.ts +15 -10
  198. package/src/templates/scaffold-repo.ts +13 -10
  199. package/src/templates/scaffold-roles.ts +38 -10
  200. package/src/templates/slice-foundation.ts +1 -1
  201. package/src/templates/wrap.ts +4 -1
  202. package/src/test-passes.ts +2 -1
  203. package/src/test-workers.ts +26 -0
  204. package/src/ts-scan.ts +3 -6
  205. package/src/tsconfig-references.ts +1 -2
  206. package/src/verify-checks.ts +41 -39
  207. package/src/verify-e2e.ts +10 -7
  208. package/src/verify-run.ts +11 -1
  209. package/src/verify-step.ts +3 -3
  210. package/src/verify-tests.ts +1 -26
  211. package/src/verify-typecheck.ts +28 -0
  212. package/src/web-binding.ts +2 -2
  213. package/src/workspace-graph.ts +10 -33
  214. package/src/cdp-browser.ts +0 -94
  215. package/src/cdp-connection.ts +0 -247
  216. package/src/cdp-e2e-page.ts +0 -180
  217. package/src/cdp-e2e-session.ts +0 -199
  218. package/src/cdp-errors.ts +0 -56
  219. package/src/cdp-launch.ts +0 -193
  220. package/src/cdp-offline-script.ts +0 -73
  221. package/src/cdp-pipe.ts +0 -77
  222. package/src/e2e-app.ts +0 -103
  223. package/src/e2e-browser-handle.ts +0 -55
  224. package/src/e2e-dom-fixture.ts +0 -117
  225. package/src/e2e-driver.ts +0 -117
  226. package/src/e2e-errors.ts +0 -117
  227. package/src/e2e-evaluate.ts +0 -156
  228. package/src/e2e-locator.ts +0 -86
  229. package/src/e2e-page.ts +0 -153
  230. package/src/e2e-preload.ts +0 -64
  231. package/src/e2e-probe.ts +0 -23
  232. package/src/e2e-selection.ts +0 -182
  233. package/src/e2e-spawn.ts +0 -169
  234. package/src/measurement-actor.ts +0 -26
  235. /package/src/{dev-hooks.ts → runtime-hooks.ts} +0 -0
  236. /package/src/{dev-render.ts → runtime-render.ts} +0 -0
package/src/index.ts CHANGED
@@ -2,226 +2,66 @@
2
2
  // on these, and a barrel that re-exports everything would make every internal a compatibility
3
3
  // promise.
4
4
 
5
+ // The CLI's own codes and titles, registered for every process that imports this barrel — the
6
+ // gate's registry check (`scripts/verify.ts` → `registeredErrorCodes`) reads the registry, and the
7
+ // command modules that used to import `error-codes.ts` on the way load lazily since 22.0.0.
8
+ import './error-codes';
9
+
5
10
  /** The app's own API over HTTP — the one table `x dev` and a container both mount. */
6
11
  export { apiRoutes } from './api-routes';
7
- export type { BoundaryCode, SourceFile } from './app-boundaries';
12
+ export type { SourceFile } from './app-boundaries';
8
13
  export {
9
14
  appImportGraph,
10
- BOUNDARY_CODES,
11
15
  checkAppBoundaries,
12
- checkImportRules,
13
16
  readAppSources,
14
17
  resolveSpecifier,
15
18
  scanRuntimeImports,
16
19
  } from './app-boundaries';
17
- export type { LoadedApp } from './app-load';
18
- export { loadApp, resetAppLoad } from './app-load';
19
- export type { AppManifest } from './app-manifest';
20
- export { appManifest, policyFacts, readAppManifest, writeAppManifest } from './app-manifest';
21
- export { OPENAPI_FILE, openApiJson } from './app-openapi';
22
- export type { AppRoot } from './app-root';
23
- export { findAppRoot, requireAppRoot, requireBunVersion, versionAtLeast } from './app-root';
24
- export type { BoundaryCut, BoundarySplit } from './boundary-cuts';
25
- export { planBoundaryCuts } from './boundary-cuts';
26
- export type { BuildStats, RouteStats } from './budgets';
27
- export {
28
- BUILD_STATS_FILE,
29
- checkBudgets,
30
- FRAMEWORK_INLINE_SCRIPTS,
31
- FRAMEWORK_SCRIPTS,
32
- readBuildStats,
33
- } from './budgets';
34
- // The raw-CDP browser the driver above runs on. `openE2eBrowserIfAvailable()` is what an app's
35
- // test preload calls: it answers `undefined` on a machine with no Chrome, so the browser-backed
36
- // suite SKIPS rather than turning a gate red for a reason unrelated to the change.
37
- export type { E2eBrowser, OpenE2eBrowserOptions } from './cdp-browser';
38
- export {
39
- DEFAULT_CDP_TIMEOUT_MS,
40
- openE2eBrowser,
41
- openE2eBrowserIfAvailable,
42
- } from './cdp-browser';
43
- export type { CdpConnection, CdpConnectionOptions, CdpResult } from './cdp-connection';
44
- export { cdpConnect } from './cdp-connection';
45
- export type { CdpE2eTabOptions, E2eTab } from './cdp-e2e-page';
46
- export { cdpE2eTab } from './cdp-e2e-page';
47
- export type { CdpE2eSessionOptions, E2eSession } from './cdp-e2e-session';
48
- export { cdpE2eSession } from './cdp-e2e-session';
49
- export {
50
- CdpBrowserMissingError,
51
- CdpCallFailedError,
52
- CdpLaunchFailedError,
53
- CdpTimeoutError,
54
- } from './cdp-errors';
55
- export type { LaunchedBrowser, LaunchOptions } from './cdp-launch';
56
- export {
57
- CHROME_CANDIDATES,
58
- CHROME_PATH_ENV,
59
- findChrome,
60
- launchChrome,
61
- launchFoundChrome,
62
- } from './cdp-launch';
63
- export type { BuildTarget } from './cmd-build';
64
- export {
65
- argsFor,
66
- BUILD_ENTRY,
67
- BUILD_TARGETS,
68
- buildCommand,
69
- readTarget,
70
- requireEntry,
71
- } from './cmd-build';
20
+ export { loadApp } from './app-load';
21
+ export { appManifest, writeAppManifest } from './app-manifest';
22
+ export { requireAppRoot } from './app-root';
23
+ export type { RouteStats } from './budgets';
24
+ export { checkBudgets, FRAMEWORK_INLINE_SCRIPTS, FRAMEWORK_SCRIPTS } from './budgets';
25
+ export { BUILD_ENTRY, BUILD_TARGETS, readTarget } from './cmd-build';
72
26
  export { dbCommand } from './cmd-db';
73
- export { runBranchCommand } from './cmd-db-branch';
74
- export type { DeployPlan } from './cmd-deploy';
75
- export { deployCommand, planDeploy } from './cmd-deploy';
76
- export type { DevServer, StartDevOptions } from './cmd-dev';
77
- export { devCommand, startDev } from './cmd-dev';
78
- export type { DoctorProbe, EmbeddedDatabase } from './cmd-doctor';
79
- export {
80
- doctorCommand,
81
- ENV_DEVELOPMENT,
82
- embeddedDatabaseFinding,
83
- probeFor,
84
- runDoctor,
85
- } from './cmd-doctor';
86
- export { ERRORS_SUBCOMMANDS, errorsCommand } from './cmd-errors';
87
- export { FIX_SUBCOMMANDS, fixCommand } from './cmd-fix';
27
+ export { planDeploy } from './cmd-deploy';
28
+ export { startDev } from './cmd-dev';
29
+ export type { DoctorProbe } from './cmd-doctor';
88
30
  export type { GenerateOptions, Generator } from './cmd-generate';
89
- export { GENERATORS, generate, generateCommand, writeFiles } from './cmd-generate';
90
- export { createHelpCommand, createVersionCommand, renderHelp } from './cmd-help';
91
- export { buildDrainTarget, JOBS_SUBCOMMANDS, jobsCommand } from './cmd-jobs';
92
- export { manifestCommand } from './cmd-manifest';
93
- export type { McpHttpServer } from './cmd-mcp';
94
- export { mcpCommand, startMcpHttp } from './cmd-mcp';
95
- export type { NewAppOptions, WrittenApp } from './cmd-new';
31
+ export { GENERATORS, generate, writeFiles } from './cmd-generate';
32
+ export { JOBS_SUBCOMMANDS } from './cmd-jobs';
96
33
  export { newCommand, planNewApp, writeNewApp } from './cmd-new';
97
- export type { PlannedCommand, PlannedSubcommand } from './cmd-planned';
98
- export {
99
- PLANNED_COMMANDS,
100
- PLANNED_SUBCOMMANDS,
101
- plannedCommands,
102
- plannedSubcommand,
103
- } from './cmd-planned';
34
+ export { PLANNED_COMMANDS, PLANNED_SUBCOMMANDS, plannedSubcommand } from './cmd-planned';
104
35
  // `shotCommand`, `prCommand` and `ciCommand` are deliberately NOT re-exported here. They reach
105
36
  // `x` through `registry.ts`, which is the only thing that makes a command exist — and the barrel
106
- // is the surface an APP imports. Exporting them puts `cmd-shot.ts` in the module graph of every
107
- // app that imports `@ultimat3/cli`, which then has to resolve `@ultimat3/scraping` — a browser
108
- // driver it never uses. Measured: it reds `tsc -b` on `dummy/social-media-clone` with five
109
- // TS2307s in files that app never calls. The app path does not pay for the tool path.
110
- export { actionsCommand, entitiesCommand, queriesCommand } from './cmd-registries';
111
- export { renderRouteTable, routesCommand } from './cmd-routes';
112
- export { testCommand } from './cmd-test';
37
+ // is the surface an APP imports. Exporting them would put the browser driver and the GitHub client
38
+ // in the module graph of every app that imports `@ultimat3/cli`, for tools it never calls. The app
39
+ // path does not pay for the tool path.
40
+ export { renderRouteTable } from './cmd-routes';
113
41
  export { runVerify, VERIFY_STEPS, verifyCommand, verifyStepNames } from './cmd-verify';
114
- export type { CliCommand, CommandContext } from './command';
42
+ export type { CliCommand } from './command';
115
43
  export { failed, ok } from './command';
116
- export { acceptCreatedTables, createdTables } from './db-accept-created';
117
- export type { BranchRow, BranchSubcommand } from './db-branch';
118
- export {
119
- BRANCH_SUBCOMMANDS,
120
- branchDatabaseName,
121
- branchNameOf,
122
- isBranchSubcommand,
123
- pgliteBranchName,
124
- previewUrl,
125
- } from './db-branch';
126
- export type { GeneratedFiles, GenerateMigrationOptions, GenerateOutcome } from './db-generate';
127
- export { generateAppMigration, migrationSql } from './db-generate';
128
- export type { SubscribingQuery } from './db-subscribes';
44
+ export { acceptCreatedTables } from './db-accept-created';
45
+ export type { BranchRow } from './db-branch';
46
+ export { BRANCH_SUBCOMMANDS, branchDatabaseName, branchNameOf } from './db-branch';
47
+ export type { GeneratedFiles } from './db-generate';
48
+ export { generateAppMigration } from './db-generate';
129
49
  export { QuerySubscribesUnknownError, replicaIdentityTables } from './db-subscribes';
130
- export type { AssetRoutesOptions } from './dev-assets';
131
- export {
132
- assetRoutes,
133
- MEDIA_BASE_PATH,
134
- } from './dev-assets';
135
- export type { DevDashboardInput, DevStatus } from './dev-dashboard';
136
- export { devDashboardRoutes, devPanels, devSources } from './dev-dashboard';
137
- export { devHooks } from './dev-hooks';
138
- export type { DevDbClient, RunningQueue } from './dev-queue';
139
- export { startQueue } from './dev-queue';
140
- export type { DevRenderOptions, DevRouteData } from './dev-render';
141
- export { appRoutes, routeDocument } from './dev-render';
142
- export type { RunningRoles, StartRolesOptions, WebBinding } from './dev-roles';
143
- export { DEV_BINDING, DEV_ROLES, selectRoles, startRoles } from './dev-roles';
144
- export type { RunningServices } from './dev-runtime';
145
- export { startServices } from './dev-runtime';
146
- export type { DevServices, ServiceBinding } from './dev-services';
147
- export { describeServices, resolveServices } from './dev-services';
148
- export type { DispatchOptions } from './dispatch';
149
50
  export { dispatch } from './dispatch';
150
- export type { DeclaredEntityCount, HashReconciliation } from './drift';
151
- export {
152
- checkSourceDrift,
153
- reconcileSchemaHash,
154
- recordedHashes,
155
- schemaHash,
156
- writeSchemaHash,
157
- } from './drift';
158
- // The browser-backed e2e driver. `installE2eDriver` is the ONE entry point an app's test preload
159
- // calls; everything below it is exported because the adapter's own pieces are what a driver author
160
- // re-uses, and a deep import into `src/` would make each of them a compatibility promise anyway.
161
- export type { E2eApp, E2eAppMode, StartE2eAppOptions } from './e2e-app';
162
- export { startE2eApp } from './e2e-app';
163
- export { e2eApp, e2eBaseUrl, e2eBrowser } from './e2e-browser-handle';
164
- export type { E2eDriverOptions } from './e2e-driver';
165
- export { e2eFixtures, installE2eDriver } from './e2e-driver';
166
- export {
167
- E2eAppFailedError,
168
- E2eEvaluateCapturedError,
169
- E2eEvaluateThrewError,
170
- E2eEvaluateUnsupportedError,
171
- E2eLocatorAmbiguousError,
172
- E2eLocatorEmptyError,
173
- E2eServiceWorkerAbsentError,
174
- } from './e2e-errors';
175
- export type { EvaluablePage } from './e2e-evaluate';
176
- export { closureSource, evaluateClosure, evaluateExpression } from './e2e-evaluate';
177
- export type { LocatablePage } from './e2e-locator';
178
- export { e2eLocator, resetLocatorMarks } from './e2e-locator';
179
- export type { E2eBrowserPage, E2ePageOptions } from './e2e-page';
180
- export { DEFAULT_E2E_TIMEOUT_MS, DEFAULT_SERVICE_WORKER_TIMEOUT_MS, e2ePage } from './e2e-page';
181
- export type { E2eResolution, E2eSelection } from './e2e-selection';
182
- export {
183
- MARK_ATTRIBUTE,
184
- markSelector,
185
- selectionCall,
186
- selectionExpression,
187
- unmarkExpression,
188
- } from './e2e-selection';
189
- export type { ErrorCatalog } from './error-catalog';
190
- export {
191
- buildErrorCatalog,
192
- CATALOG_OPTIONAL_HOSTS,
193
- CATALOG_PACKAGES,
194
- loadErrorCatalog,
195
- registeredErrorCodes,
196
- resetErrorCatalog,
197
- } from './error-catalog';
51
+ export { checkSourceDrift, reconcileSchemaHash, writeSchemaHash } from './drift';
52
+ export { registeredErrorCodes } from './error-catalog';
198
53
  export type { CliErrorCode } from './error-codes';
199
- export { CLI_ERROR_CODES, CLI_ERROR_TITLES } from './error-codes';
200
- export type { ErrorFixReport } from './error-contract';
201
54
  export {
202
55
  BANNED_PHRASES,
203
56
  COMMAND_TOKENS,
204
57
  checkErrorCodeDocs,
205
58
  checkErrorCodeRegistry,
206
- checkErrorCodeResolution,
207
59
  checkErrorFixes,
208
- checkErrorFixReport,
209
60
  collectDeclaredCodes,
210
61
  documentedCodes,
211
62
  fixProblem,
212
- liveCodes,
213
- RESERVED_HEADING,
214
63
  staticFix,
215
64
  } from './error-contract';
216
- export type { CodeFixIndex, CodeFixScan } from './error-fixes';
217
- export {
218
- codeFixes,
219
- codeFixScan,
220
- loadCodeFixes,
221
- resetCodeFixes,
222
- scanScopeFixes,
223
- } from './error-fixes';
224
- export type { CodeUse } from './error-unthrown';
225
65
  export { checkErrorCodesThrown } from './error-unthrown';
226
66
  export {
227
67
  BadFlagError,
@@ -244,14 +84,7 @@ export {
244
84
  } from './errors';
245
85
  export type { ExecOptions, ExecResult, Runner } from './exec';
246
86
  export { exec, execOutput } from './exec';
247
- export {
248
- defaultFavicon,
249
- FAVICON_PATH,
250
- FAVICON_SOURCE,
251
- faviconResponse,
252
- faviconRoute,
253
- } from './favicon';
254
- export type { CitationFault, CitationRules, CommandCatalog, FixCitation } from './fix-command';
87
+ export type { CitationFault, CommandCatalog, FixCitation } from './fix-command';
255
88
  export {
256
89
  citationFault,
257
90
  citationProblem,
@@ -259,193 +92,79 @@ export {
259
92
  fixCitations,
260
93
  loadCommandCatalog,
261
94
  } from './fix-command';
262
- export type { HelperResolver } from './fix-imports';
263
- export { candidatePaths, createHelperResolver, scanImports } from './fix-imports';
264
- export {
265
- CITED_FILE_EXTENSIONS,
266
- citedPathProblem,
267
- FILE_TOKEN_PATTERN,
268
- pathCitations,
269
- } from './fix-path';
270
- export type { FixHelper, FixScan } from './fix-scan';
271
- export { scanFixes, scanFixHelpers, scanFixSites } from './fix-scan';
272
- export type { DeclaredFlag } from './flag-reads';
273
- export { checkFlagReads, declaredFlags, readsFlag } from './flag-reads';
274
- export type { FrameworkSchema, SchemaExecutor } from './framework-schema';
95
+ export { candidatePaths, scanImports } from './fix-imports';
96
+ export type { FixScan } from './fix-scan';
97
+ export { scanFixes } from './fix-scan';
98
+ export { checkFlagReads } from './flag-reads';
275
99
  // The framework's own tables, as data. Exported so `scripts/` can read the applier's list without
276
100
  // re-deriving it — the shape a ratchet over declared-but-never-applied DDL needs.
277
- export {
278
- applyFrameworkSchema,
279
- FRAMEWORK_SCHEMA,
280
- frameworkTableNames,
281
- schemaStatements,
282
- } from './framework-schema';
101
+ export { FRAMEWORK_SCHEMA } from './framework-schema';
283
102
  export type { Guard } from './guards';
284
- export { findingProblem, GUARD_DIR, guardFindings, guardPaths } from './guards';
285
- export {
286
- hasSourceIcon,
287
- ICON_BASE_PATH,
288
- ICON_SOURCE,
289
- iconPlan,
290
- iconRenderer,
291
- } from './icon-assets';
103
+ export { findingProblem, guardFindings, guardPaths } from './guards';
104
+ export { ICON_BASE_PATH, ICON_SOURCE } from './icon-assets';
292
105
  // The island bundler, and only its entry point. An island is the one module Ultimate ships to a
293
106
  // browser, so an app has to be able to build one to TEST one — `mountIsland` from
294
107
  // `@ultimat3/testing` takes this function as its `build` parameter (issue #260). `discoverIslands`,
295
108
  // `islandBundle`, `writeIslands`, `ISLAND_BASE_PATH` and `ISLAND_GLOB` stay internal: they are
296
109
  // `x build`'s and `x dev`'s wiring, and every name here is a semver promise forever.
297
- export type { IslandBundle, IslandChunk } from './island-bundle';
298
- export { buildIslands, clearIslandChunkCache } from './island-bundle';
299
- export type { DrainFailure, DrainOutcome, DrainSkip } from './jobs-drain';
300
- export { drainJobs } from './jobs-drain';
301
- export type { JobsListFilter, JobsListResult } from './jobs-report';
302
- export { JOB_STATES, listJobs, retryJob, showJob } from './jobs-report';
110
+ export type { IslandChunk } from './island-bundle';
111
+ export { buildIslands } from './island-bundle';
112
+ export { JOB_STATES } from './jobs-report';
303
113
  export { renderJobTable } from './jobs-table';
304
- export type { CliMcpServer, DevHostInput } from './mcp-host';
305
- export { createDevMcpServer, DEV_TOOL_SCOPES, localCaller } from './mcp-host';
306
- export { messageKeys, msg } from './messages';
307
- export type { MetricsEndpoint, MetricsEndpointOptions } from './metrics-endpoint';
114
+ export { msg } from './messages';
308
115
  export { DEFAULT_METRICS_PORT, startMetricsEndpoint } from './metrics-endpoint';
309
- export {
310
- hashFileName,
311
- MIGRATIONS_DIR,
312
- migrationName,
313
- parseMigrationSql,
314
- readMigrations,
315
- snapshotFileName,
316
- } from './migrations';
317
- export type { CommandResult, Finding, JsonValue, StepResult } from './output';
318
- export {
319
- exitCodeFor,
320
- findingFrom,
321
- isUltimateErrorShape,
322
- render,
323
- renderFinding,
324
- renderHuman,
325
- renderJson,
326
- renderUltimateError,
327
- } from './output';
116
+ export { parseMigrationSql, readMigrations } from './migrations';
117
+ export type { CommandResult, Finding, JsonValue } from './output';
118
+ export { exitCodeFor, findingFrom, render, renderFinding, renderHuman } from './output';
328
119
  export type { CommandSpec, FlagSpec, ParsedArgs } from './parse';
329
120
  export { flagBool, flagList, flagString, GLOBAL_FLAGS, nearest, parseArgs } from './parse';
330
- export type { PrerenderedPage, PrerenderOptions, PrerenderReport } from './prerender';
121
+ export type { PrerenderedPage, PrerenderReport } from './prerender';
331
122
  export { DEFAULT_ORIGIN, isPrerenderable, prerenderSite } from './prerender';
332
123
  export type { PwaArtifacts } from './pwa-artifacts';
333
- export {
334
- loadPwaArtifacts,
335
- pwaManifestRoute,
336
- WEB_MANIFEST_PATH,
337
- writePwaIcons,
338
- } from './pwa-artifacts';
339
- export { COMMANDS, cliVersion, commandFor, SPECS } from './registry';
340
- export type { SchemaDifference, SchemaDirection, SchemaPart } from './schema-diff';
341
- export { diffDeclaredSchema } from './schema-diff';
124
+ export { loadPwaArtifacts } from './pwa-artifacts';
125
+ export { COMMANDS, cliVersion, SPECS } from './registry';
126
+ export type { RunningRoles, WebBinding } from './role-start';
127
+ export { DEV_BINDING, DEV_ROLES, startRoles } from './role-start';
128
+ export { assetRoutes, MEDIA_BASE_PATH } from './runtime-assets';
129
+ export { resolveServices } from './runtime-bindings';
130
+ export { devHooks } from './runtime-hooks';
131
+ export { startQueue } from './runtime-queue';
132
+ export { appRoutes, routeDocument } from './runtime-render';
133
+ export type { RunningServices } from './runtime-services';
134
+ export { startServices } from './runtime-services';
342
135
  // The drift a hash cannot see, and the composition both the gate step and `x doctor` read.
343
- export type { DeclaredEntities } from './schema-drift';
344
136
  export { checkMigrationDrift, checkSnapshotDrift } from './schema-drift';
345
137
  export { FrameworkSchemaFailedError } from './schema-errors';
346
- export type { MigratedApp, ServedApp, ServeOptions, StartedApp } from './serve';
138
+ export type { MigratedApp, ServeOptions } from './serve';
347
139
  export {
348
140
  CONTAINER_BINDING,
349
141
  DEFAULT_PORT,
350
- metricsPortFromEnv,
351
- portFromEnv,
352
142
  roleFromEnv,
353
143
  runMigrations,
354
144
  runRole,
355
145
  serveApp,
356
146
  } from './serve';
357
147
  export { quoteArg } from './shell-quote';
358
- export {
359
- eachSourceFile,
360
- isGenerated,
361
- isTest,
362
- isVendored,
363
- SOURCE_GLOBS,
364
- } from './source-files';
365
- export type {
366
- EmittedPage,
367
- RouteFacts,
368
- SkippedRoute,
369
- SkipReason,
370
- StaticReport,
371
- UnmeasuredRoute,
372
- } from './static-report';
373
- export {
374
- parseStaticReport,
375
- readStaticReport,
376
- removeStaticReport,
377
- renderStaticReport,
378
- SKIP_REASONS,
379
- STATIC_REPORT_FILE,
380
- skippedRoute,
381
- skipReasonFor,
382
- writeStaticReport,
383
- } from './static-report';
384
- export type { StyleBundle, StyleChunk } from './style-bundle';
385
- export { STYLE_BASE_PATH, styleBundle } from './style-bundle';
386
- export type { TestCounts } from './test-counts';
387
- export { countsOf } from './test-counts';
388
- export type { TestFile } from './test-select';
389
- export { belongsToType, discoverTests, sampleFiles } from './test-select';
390
- export type { ReproduceOptions, RunShardsOptions } from './test-shards';
391
- export { filesIn, reproduceFor, runShards, testArgs } from './test-shards';
392
- export { availableCpus, defaultWorkers, WORKER_CEILING } from './test-workers';
393
- export type {
394
- CodeFixSite,
395
- CodeScan,
396
- CodeSite,
397
- FixSite,
398
- SourceSite,
399
- UnresolvedCodeSite,
400
- } from './ts-scan';
401
- export {
402
- isCodeRegistry,
403
- maskLiterals,
404
- scanBorrowedCodes,
405
- scanCodeDeclarations,
406
- scanCodeFixSites,
407
- scanCodes,
408
- stripComments,
409
- } from './ts-scan';
148
+ export { eachSourceFile, isGenerated, isTest, SOURCE_GLOBS } from './source-files';
149
+ export type { SkippedRoute, StaticReport } from './static-report';
150
+ export { parseStaticReport } from './static-report';
151
+ export { filesIn, testArgs } from './test-shards';
152
+ export { defaultWorkers } from './test-workers';
153
+ export { scanCodeDeclarations, scanCodeFixSites, scanCodes } from './ts-scan';
410
154
  // The one spelling rule for a `references` entry. Exported because the two gate scripts ask the
411
155
  // same question this package's `package-shape` step does, and three answers is a duplicate entry.
412
156
  export { normalizeReferencePath } from './tsconfig-references';
413
- export type { VerifyFloor } from './verify-floor';
414
- export {
415
- floorProblemFindings,
416
- floorRequires,
417
- parseVerifyFloor,
418
- readVerifyFloor,
419
- skippedSuiteFinding,
420
- VERIFY_FLOOR_FILE,
421
- vanishedSuiteFinding,
422
- } from './verify-floor';
423
- export type {
424
- HostCheck,
425
- StepOutcome,
426
- VerifyContext,
427
- VerifyStep,
428
- VerifyStepName,
429
- } from './verify-step';
157
+ export { readVerifyFloor, skippedSuiteFinding, VERIFY_FLOOR_FILE } from './verify-floor';
158
+ export type { HostCheck, StepOutcome, VerifyStep, VerifyStepName } from './verify-step';
430
159
  export { VERIFY_STEP_NAMES } from './verify-step';
431
160
  export type { TestType } from './verify-tests';
432
- export { TEST_STEPS, TEST_TYPES, testStepCommand, typeFiltersOf } from './verify-tests';
433
- export type { ManifestFacts, PackageShapeOptions } from './workspace-checks';
161
+ export { TEST_TYPES } from './verify-tests';
434
162
  export {
435
163
  checkFileSizes,
436
164
  checkLockstep,
437
165
  checkPackageShape,
438
- frameworkDepsOf,
439
- hasWorkspacePackages,
440
166
  LINE_CEILING,
441
167
  PACKAGE_FILES,
442
168
  SEMVER,
443
- workspacePackages,
444
169
  } from './workspace-checks';
445
- export type { WorkspaceNode, WorkspaceScan } from './workspace-graph';
446
- // The graph itself, not just the gate's verdict on it: issue #239's complaint is that a
447
- // scaffolded repo's dependency graph exists only inside `tsc`, so an app's own tooling has
448
- // nothing to read. `checkWorkspaceDependencies` stays internal — it is reached through
449
- // `x verify`, which is the one way a rule is enforced here.
450
- export { readWorkspaceGraph, scanWorkspaces } from './workspace-graph';
451
170
  export { writeErrorLine, writeLine } from './write-line';
@@ -0,0 +1,26 @@
1
+ // The flags a caller set, spelled so pasting them reproduces the same run. A `fix:` that re-runs a
2
+ // command with `--force` and loses `--feature` or `--dir` writes somewhere the caller never asked
3
+ // for — `x g`'s conflict fix wrote a second slice, `x new`'s a second app in the cwd.
4
+
5
+ import type { CommandSpec, ParsedArgs } from './parse';
6
+ import { quoteArg } from './shell-quote';
7
+
8
+ /** Never reproduced: the fix adds its own `--force`, and output flags do not change what runs. */
9
+ const NOT_REPRODUCED = new Set(['force', 'dry-run', 'json', 'help', 'verbose', 'cwd']);
10
+
11
+ /**
12
+ * Every declared flag whose value differs from its default, in the spec's order: a string as
13
+ * `--name <quoted>`, a boolean as `--name` or `--no-name`. A default is nobody's request, so it is
14
+ * left for the default to supply again.
15
+ */
16
+ export function reproducedFlags(spec: CommandSpec, args: ParsedArgs): readonly string[] {
17
+ const out: string[] = [];
18
+ for (const flag of spec.flags ?? []) {
19
+ if (NOT_REPRODUCED.has(flag.name)) continue;
20
+ const value = args.flags.get(flag.name);
21
+ if (value === undefined || value === flag.default) continue;
22
+ if (typeof value === 'string') out.push(`--${flag.name}`, quoteArg(value));
23
+ else out.push(value ? `--${flag.name}` : `--no-${flag.name}`);
24
+ }
25
+ return out;
26
+ }
@@ -85,7 +85,12 @@ async function buildOne(root: string, file: string): Promise<IslandChunk> {
85
85
  // the real path here and the `success` test below is the belt for a future default.
86
86
  // Only an island whose own graph reaches `@ultimat3/realtime` is wrapped (`island-realtime.ts`);
87
87
  // every other one is built from its own file, byte for byte what it was.
88
- const realtime = await reachesRealtime(root, file);
88
+ // Inside the refusal too: the realtime probe PARSES the island's graph, and a file that will not
89
+ // parse rejected with a raw `AggregateError: Failed to scan imports` — out of the web boot, with
90
+ // no code, no file and no fix — before `Bun.build` ever ran to raise the one below.
91
+ const realtime = await reachesRealtime(root, file).catch((error: unknown) => {
92
+ throw new IslandBuildFailedError({ file, logs: describeBuildError(error) });
93
+ });
89
94
  let built: Awaited<ReturnType<typeof Bun.build>>;
90
95
  try {
91
96
  built = await Bun.build({
@@ -5,10 +5,10 @@
5
5
  // why: no Bun native joins a path; `Bun.write` takes one already joined.
6
6
  import { join } from 'node:path';
7
7
  import { finiteCount } from '@ultimat3/core';
8
- import type { CaptureClip, ScrapeDriver, ScrapeSession } from '@ultimat3/scraping';
9
- import { systemScrapeClock } from '@ultimat3/scraping';
10
8
  import type { IslandShotTarget, IslandViewport } from '@ultimat3/testing';
11
9
  import { islandStatesFile } from '@ultimat3/testing';
10
+ import type { CaptureClip, ShotDriver, ShotSession } from './browser-launcher-port';
11
+ import { systemShotClock } from './cdp-shot-clock';
12
12
  import { ISLAND_HARNESS_PATH } from './island-harness';
13
13
  import { readinessProbe } from './island-harness-script';
14
14
  import { IslandRequestUnstubbedError, IslandUnphotographableError } from './island-shot-errors';
@@ -43,7 +43,7 @@ export const ISLAND_CROP_MARGIN_PX = 8;
43
43
  * takes the viewport as a LAUNCH option (`LocalBrowserOptions.options`) and a state declares its
44
44
  * own — so "photograph this state at 480x320" is a different browser, not a different call.
45
45
  */
46
- export type IslandBrowser = (viewport: IslandViewport) => Promise<ScrapeDriver>;
46
+ export type IslandBrowser = (viewport: IslandViewport) => Promise<ShotDriver>;
47
47
 
48
48
  interface Refusal {
49
49
  readonly reason: string;
@@ -181,13 +181,13 @@ export async function captureIslandState(
181
181
  floor: number,
182
182
  ): Promise<IslandStateShot> {
183
183
  const url = new URL(`${ISLAND_HARNESS_PATH}${target.query}`, server.url).toString();
184
- let session: ScrapeSession | undefined;
184
+ let session: ShotSession | undefined;
185
185
  try {
186
186
  const driver = await options.driver(target.viewport);
187
187
  session = await driver.open({
188
188
  name: 'x shot --island',
189
189
  rules: { allowHosts: allowHostsFrom(server.url, options.extraHosts) },
190
- clock: systemScrapeClock,
190
+ clock: systemShotClock,
191
191
  timeoutMs: options.timeoutMs,
192
192
  });
193
193
  const page = session.page;
@@ -237,7 +237,7 @@ export async function captureIslandState(
237
237
  // around, and which nothing passed until 2026-08-26 (issue #338).
238
238
  //
239
239
  // The clip ALONE. `fullPage: false` beside it is accepted — `assertCaptureFraming` refuses only
240
- // `=== true`, and `cdp-target.ts` sends `{ clip }` and nothing else either way — but it is a
240
+ // `=== true`, and `cdp-shot-page.ts` sends `{ clip }` and nothing else either way — but it is a
241
241
  // field that says nothing: the two are exclusive, and spelling out the default of the one you
242
242
  // did not ask for reads as a choice.
243
243
  // `??` screens null and undefined and NOTHING else, so `cropMarginPx: NaN` reached `clipFor`,
@@ -147,12 +147,16 @@ Intl.DateTimeFormat=ShotDTF;
147
147
 
148
148
  /**
149
149
  * Ready is quiet, not idle. Fonts first — a picture taken mid-swap photographs the fallback face —
150
- * then `QUIET_FRAMES` consecutive frames in which nothing started and nothing settled.
150
+ * then `QUIET_FRAMES` consecutive frames in which nothing started and nothing settled, counted only
151
+ * once the island has MOUNTED or FAILED (#474): an `idle` island mounts in idle time, after frames
152
+ * that were quiet only because nothing had started yet. A page with no island host is not waited on.
151
153
  */
152
154
  const readyScript = (): string => `
153
155
  var last=-1;var still=0;
156
+ function answered(){var h=document.querySelector("[data-x-island]");
157
+ return !h||h.hasAttribute("data-x-mounted")||h.hasAttribute("data-x-failed")}
154
158
  function tick(){var seen=W.activity;
155
- if(seen===last)still+=1;else{still=0;last=seen}
159
+ if(!answered()){still=0;last=seen}else if(seen===last)still+=1;else{still=0;last=seen}
156
160
  if(still>=${QUIET_FRAMES}){W.ready=true;return}
157
161
  requestAnimationFrame(tick)}
158
162
  (document.fonts?document.fonts.ready:Promise.resolve()).then(function(){requestAnimationFrame(tick)});
@@ -56,12 +56,15 @@ export function realtimeIslandFiles(): ReadonlySet<string> {
56
56
  const ENTRY_SOURCE = `import '${INSTALL}';\nexport * from '${MODULE}';\n`;
57
57
 
58
58
  /**
59
- * The install resolves `@ultimat3/realtime` from the ISLAND's own directory — the resolution the
60
- * island itself gets — so the bundle holds one copy and the signal lands where the hooks read it.
59
+ * The install names `@ultimat3/realtime` BARE, and `islandRealtimePlugin` resolves it from the
60
+ * ISLAND's own directory — the resolution the island itself gets — so the bundle holds one copy
61
+ * and the signal lands where the hooks read it. Never the resolved absolute path spliced in: this
62
+ * source is part of the chunk's `sourcesContent`, which is what `graphHash` names the URL from, so
63
+ * a path in it gave the same island a different URL in every checkout and every image build.
61
64
  * `solid-js` goes through `island-solid-dedupe.ts` like every other import in the graph.
62
65
  */
63
- const INSTALL_SOURCE = (realtime: string): string =>
64
- `import { installRealtime } from ${JSON.stringify(realtime)};\n` +
66
+ const INSTALL_SOURCE =
67
+ `import { installRealtime } from '${REALTIME}';\n` +
65
68
  `import { createSignal } from 'solid-js';\n` +
66
69
  `installRealtime({ signal: createSignal });\n`;
67
70
 
@@ -79,11 +82,15 @@ export function islandRealtimePlugin(root: string, file: string): BunPlugin {
79
82
  namespace: NAMESPACE,
80
83
  }));
81
84
  build.onResolve({ filter: /^ultimate:island-module$/ }, () => ({ path: island }));
85
+ // Every bare `@ultimat3/realtime` in this build, the virtual install's included — a virtual
86
+ // module has no directory to resolve from. The island's directory for all of them, which is
87
+ // what the island itself would get, and one copy in the bundle is the requirement anyway:
88
+ // the signal the install sets is only read by hooks from the same module instance.
89
+ build.onResolve({ filter: /^@ultimat3\/realtime$/ }, () => ({
90
+ path: Bun.resolveSync(REALTIME, dirname(island)),
91
+ }));
82
92
  build.onLoad({ filter: /.*/, namespace: NAMESPACE }, (args) => ({
83
- contents:
84
- args.path === 'entry'
85
- ? ENTRY_SOURCE
86
- : INSTALL_SOURCE(Bun.resolveSync(REALTIME, dirname(island))),
93
+ contents: args.path === 'entry' ? ENTRY_SOURCE : INSTALL_SOURCE,
87
94
  loader: 'js',
88
95
  }));
89
96
  },