@rehearsal-db/core 0.1.0-beta.9 → 0.1.0-rc.2

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 (247) hide show
  1. package/CHANGELOG.md +319 -1
  2. package/COMPATIBILITY.md +15 -0
  3. package/README.md +73 -16
  4. package/dist/package.json +100 -0
  5. package/dist/scripts/install/create_root_config.d.mts +3 -0
  6. package/dist/scripts/install/create_root_config.mjs +13 -0
  7. package/dist/scripts/runtime/manage_database.d.mts +6 -0
  8. package/{scripts → dist/scripts}/runtime/manage_database.mjs +6 -8
  9. package/dist/src/application/interactive_task.d.mts +30 -0
  10. package/dist/src/application/interactive_task.mjs +83 -0
  11. package/dist/src/application/session.d.mts +97 -0
  12. package/dist/src/application/session.mjs +380 -0
  13. package/dist/src/baseline/artifact.d.mts +119 -0
  14. package/dist/src/baseline/artifact.mjs +522 -0
  15. package/dist/src/baseline/builder.d.mts +19 -0
  16. package/dist/src/baseline/builder.mjs +142 -0
  17. package/dist/src/baseline/input_discovery.d.mts +13 -0
  18. package/dist/src/baseline/input_discovery.mjs +149 -0
  19. package/dist/src/baseline/policy_review.d.mts +56 -0
  20. package/dist/src/baseline/policy_review.mjs +73 -0
  21. package/dist/src/baseline/preparation.d.mts +63 -0
  22. package/dist/src/baseline/preparation.mjs +295 -0
  23. package/dist/src/baseline/privacy_contract.d.mts +147 -0
  24. package/dist/src/baseline/privacy_contract.mjs +2 -0
  25. package/dist/src/baseline/privacy_dependency_graph.d.mts +7 -0
  26. package/dist/src/baseline/privacy_dependency_graph.mjs +110 -0
  27. package/dist/src/baseline/privacy_engine.d.mts +5 -0
  28. package/dist/src/baseline/privacy_engine.mjs +4 -0
  29. package/dist/src/baseline/privacy_key.d.mts +7 -0
  30. package/dist/src/baseline/privacy_key.mjs +42 -0
  31. package/dist/src/baseline/privacy_pipeline.d.mts +7 -0
  32. package/dist/src/baseline/privacy_pipeline.mjs +127 -0
  33. package/dist/src/baseline/privacy_policy.d.mts +6 -0
  34. package/dist/src/baseline/privacy_policy.mjs +237 -0
  35. package/dist/src/baseline/privacy_recipe_validation.d.mts +5 -0
  36. package/dist/src/baseline/privacy_recipe_validation.mjs +289 -0
  37. package/dist/src/baseline/privacy_rule_registry.d.mts +18 -0
  38. package/dist/src/baseline/privacy_rule_registry.mjs +143 -0
  39. package/dist/src/baseline/privacy_structured_json.d.mts +66 -0
  40. package/dist/src/baseline/privacy_structured_json.mjs +464 -0
  41. package/dist/src/baseline/privacy_transforms.d.mts +18 -0
  42. package/dist/src/baseline/privacy_transforms.mjs +142 -0
  43. package/dist/src/baseline/privacy_validation_shared.d.mts +31 -0
  44. package/dist/src/baseline/privacy_validation_shared.mjs +127 -0
  45. package/dist/src/baseline/sanitization_policy.d.mts +69 -0
  46. package/dist/src/baseline/sanitization_policy.mjs +227 -0
  47. package/dist/src/baseline/schema_snapshot.d.mts +19 -0
  48. package/dist/src/baseline/schema_snapshot.mjs +79 -0
  49. package/dist/src/cli/application_command_handlers.d.mts +8 -0
  50. package/dist/src/cli/application_command_handlers.mjs +52 -0
  51. package/dist/src/cli/arguments.d.mts +38 -0
  52. package/dist/src/cli/arguments.mjs +130 -0
  53. package/dist/src/cli/basic_command_handlers.d.mts +4 -0
  54. package/dist/src/cli/basic_command_handlers.mjs +57 -0
  55. package/dist/src/cli/cli_commands.d.mts +14 -0
  56. package/dist/src/cli/cli_commands.mjs +34 -0
  57. package/dist/src/cli/command_contract.d.mts +57 -0
  58. package/dist/src/cli/command_contract.mjs +39 -0
  59. package/dist/src/cli/command_output.d.mts +12 -0
  60. package/dist/src/cli/command_output.mjs +20 -0
  61. package/dist/src/cli/command_registry.d.mts +7 -0
  62. package/dist/src/cli/command_registry.mjs +14 -0
  63. package/dist/src/cli/guided.d.mts +53 -0
  64. package/dist/src/cli/guided.mjs +727 -0
  65. package/dist/src/cli/identity_command_handlers.d.mts +12 -0
  66. package/dist/src/cli/identity_command_handlers.mjs +239 -0
  67. package/dist/src/cli/identity_renderer.d.mts +8 -0
  68. package/dist/src/cli/identity_renderer.mjs +33 -0
  69. package/dist/src/cli/init_command.d.mts +21 -0
  70. package/dist/src/cli/init_command.mjs +90 -0
  71. package/dist/src/cli/inspection_command_handlers.d.mts +3 -0
  72. package/dist/src/cli/inspection_command_handlers.mjs +79 -0
  73. package/dist/src/cli/project_command_handlers.d.mts +11 -0
  74. package/dist/src/cli/project_command_handlers.mjs +92 -0
  75. package/dist/src/cli/project_commands.d.mts +283 -0
  76. package/dist/src/cli/project_commands.mjs +192 -0
  77. package/dist/src/cli/rehearsal.d.mts +7 -0
  78. package/dist/src/cli/rehearsal.mjs +190 -0
  79. package/dist/src/cli/renderers.d.mts +299 -0
  80. package/dist/src/cli/renderers.mjs +554 -0
  81. package/dist/src/cli/runtime_action_handlers.d.mts +12 -0
  82. package/dist/src/cli/runtime_action_handlers.mjs +201 -0
  83. package/dist/src/cli/runtime_commands.d.mts +294 -0
  84. package/dist/src/cli/runtime_commands.mjs +619 -0
  85. package/dist/src/cli/source_command_handlers.d.mts +8 -0
  86. package/dist/src/cli/source_command_handlers.mjs +62 -0
  87. package/dist/src/cli/source_commands.d.mts +436 -0
  88. package/dist/src/cli/source_commands.mjs +301 -0
  89. package/dist/src/cli/terminal.d.mts +59 -0
  90. package/dist/src/cli/terminal.mjs +230 -0
  91. package/dist/src/identity/claim.d.mts +5 -0
  92. package/dist/src/identity/claim.mjs +4 -0
  93. package/dist/src/identity/claim_contract.d.mts +135 -0
  94. package/dist/src/identity/claim_contract.mjs +6 -0
  95. package/dist/src/identity/claim_executor.d.mts +10 -0
  96. package/dist/src/identity/claim_executor.mjs +358 -0
  97. package/dist/src/identity/claim_identity_lookup.d.mts +23 -0
  98. package/dist/src/identity/claim_identity_lookup.mjs +134 -0
  99. package/dist/src/identity/claim_plan.d.mts +8 -0
  100. package/dist/src/identity/claim_plan.mjs +61 -0
  101. package/dist/src/identity/claim_policy.d.mts +3 -0
  102. package/dist/src/identity/claim_policy.mjs +377 -0
  103. package/dist/src/identity/claim_sql.d.mts +10 -0
  104. package/dist/src/identity/claim_sql.mjs +46 -0
  105. package/dist/src/identity/claim_verification.d.mts +13 -0
  106. package/dist/src/identity/claim_verification.mjs +35 -0
  107. package/dist/src/identity/connect.d.mts +30 -0
  108. package/dist/src/identity/connect.mjs +111 -0
  109. package/dist/src/identity/provider_configuration.d.mts +37 -0
  110. package/dist/src/identity/provider_configuration.mjs +132 -0
  111. package/dist/src/identity/storage.d.mts +21 -0
  112. package/dist/src/identity/storage.mjs +122 -0
  113. package/dist/src/index.d.mts +4 -0
  114. package/dist/src/index.mjs +3 -0
  115. package/dist/src/project/configuration.d.mts +13 -0
  116. package/dist/src/project/configuration.mjs +9 -0
  117. package/dist/src/project/configuration_contract.d.mts +125 -0
  118. package/dist/src/project/configuration_contract.mjs +27 -0
  119. package/dist/src/project/configuration_discovery.d.mts +7 -0
  120. package/dist/src/project/configuration_discovery.mjs +37 -0
  121. package/dist/src/project/configuration_normalization.d.mts +107 -0
  122. package/dist/src/project/configuration_normalization.mjs +302 -0
  123. package/dist/src/project/configuration_rendering.d.mts +14 -0
  124. package/dist/src/project/configuration_rendering.mjs +228 -0
  125. package/dist/src/project/configuration_resolution.d.mts +125 -0
  126. package/dist/src/project/configuration_resolution.mjs +81 -0
  127. package/dist/src/project/configuration_schema.d.mts +22 -0
  128. package/dist/src/project/configuration_schema.mjs +160 -0
  129. package/dist/src/project/configuration_validation.d.mts +22 -0
  130. package/dist/src/project/configuration_validation.mjs +136 -0
  131. package/dist/src/project/install_scaffold.d.mts +42 -0
  132. package/dist/src/project/install_scaffold.mjs +263 -0
  133. package/dist/src/project/project_detection.d.mts +14 -0
  134. package/dist/src/project/project_detection.mjs +47 -0
  135. package/dist/src/project/setup.d.mts +87 -0
  136. package/dist/src/project/setup.mjs +414 -0
  137. package/dist/src/project/support_report.d.mts +88 -0
  138. package/dist/src/project/support_report.mjs +83 -0
  139. package/dist/src/runtime/cleanup.d.mts +85 -0
  140. package/dist/src/runtime/cleanup.mjs +311 -0
  141. package/dist/src/runtime/lifecycle_engine.d.mts +63 -0
  142. package/dist/src/runtime/lifecycle_engine.mjs +114 -0
  143. package/dist/src/runtime/migration_history.d.mts +51 -0
  144. package/dist/src/runtime/migration_history.mjs +170 -0
  145. package/dist/src/runtime/plan.d.mts +134 -0
  146. package/dist/src/runtime/plan.mjs +640 -0
  147. package/dist/src/runtime/policy.d.mts +66 -0
  148. package/dist/src/runtime/policy.mjs +369 -0
  149. package/dist/src/runtime/restore.d.mts +22 -0
  150. package/dist/src/runtime/restore.mjs +276 -0
  151. package/dist/src/runtime/service_environment.d.mts +11 -0
  152. package/dist/src/runtime/service_environment.mjs +58 -0
  153. package/dist/src/runtime/topology.d.mts +51 -0
  154. package/dist/src/runtime/topology.mjs +128 -0
  155. package/dist/src/shared/diagnostics.d.mts +97 -0
  156. package/dist/src/shared/diagnostics.mjs +170 -0
  157. package/dist/src/shared/human_output.d.mts +2 -0
  158. package/{src → dist/src}/shared/human_output.mjs +1 -3
  159. package/dist/src/shared/node_runtime.d.mts +14 -0
  160. package/dist/src/shared/node_runtime.mjs +25 -0
  161. package/dist/src/shared/operation_guard.d.mts +22 -0
  162. package/dist/src/shared/operation_guard.mjs +150 -0
  163. package/dist/src/shared/process_environment.d.mts +15 -0
  164. package/dist/src/shared/process_environment.mjs +50 -0
  165. package/dist/src/source/access.d.mts +165 -0
  166. package/dist/src/source/access.mjs +602 -0
  167. package/dist/src/source/asset_transfer.d.mts +27 -0
  168. package/dist/src/source/asset_transfer.mjs +202 -0
  169. package/dist/src/source/baseline.d.mts +66 -0
  170. package/dist/src/source/baseline.mjs +372 -0
  171. package/dist/src/source/external_reader.d.mts +42 -0
  172. package/dist/src/source/external_reader.mjs +278 -0
  173. package/dist/src/source/postgresql_access.d.mts +86 -0
  174. package/dist/src/source/postgresql_access.mjs +454 -0
  175. package/dist/src/source/privacy_paths.d.mts +10 -0
  176. package/dist/src/source/privacy_paths.mjs +27 -0
  177. package/dist/src/targets/driver.d.mts +2 -0
  178. package/dist/src/targets/driver.mjs +13 -0
  179. package/dist/src/targets/postgresql.d.mts +5 -0
  180. package/dist/src/targets/postgresql.mjs +620 -0
  181. package/dist/src/targets/supabase.d.mts +8 -0
  182. package/dist/src/targets/supabase.mjs +629 -0
  183. package/dist/src/targets/supabase_environment.d.mts +54 -0
  184. package/dist/src/targets/supabase_environment.mjs +184 -0
  185. package/dist/src/targets/target.d.mts +33 -0
  186. package/dist/src/targets/target.mjs +39 -0
  187. package/docs/README.md +35 -16
  188. package/docs/architecture.md +135 -10
  189. package/docs/commands.md +53 -15
  190. package/docs/configuration.md +186 -31
  191. package/docs/getting-started.md +66 -9
  192. package/docs/index.md +67 -0
  193. package/docs/production-source.md +175 -17
  194. package/docs/releasing.md +24 -12
  195. package/docs/roadmap.md +3 -2
  196. package/docs/runtime-lifecycle.md +99 -0
  197. package/docs/runtime-policies.md +80 -7
  198. package/docs/sanitization.md +572 -4
  199. package/docs/security-model.md +8 -0
  200. package/docs/stability.md +70 -0
  201. package/docs/standalone-workflow.md +36 -13
  202. package/docs/troubleshooting.md +82 -10
  203. package/docs/tutorial.md +7 -1
  204. package/docs/typescript.md +134 -0
  205. package/package.json +44 -29
  206. package/types/configuration.d.mts +5 -0
  207. package/src/README.md +0 -17
  208. package/src/application/session.mjs +0 -313
  209. package/src/baseline/artifact.mjs +0 -661
  210. package/src/baseline/builder.mjs +0 -164
  211. package/src/baseline/input_discovery.mjs +0 -155
  212. package/src/baseline/policy_review.mjs +0 -92
  213. package/src/baseline/preparation.mjs +0 -323
  214. package/src/baseline/privacy_engine.mjs +0 -413
  215. package/src/baseline/sanitization_policy.mjs +0 -299
  216. package/src/baseline/schema_snapshot.mjs +0 -113
  217. package/src/cli/arguments.mjs +0 -120
  218. package/src/cli/guided.mjs +0 -807
  219. package/src/cli/rehearsal.mjs +0 -933
  220. package/src/cli/renderers.mjs +0 -584
  221. package/src/cli/runtime_commands.mjs +0 -553
  222. package/src/cli/source_commands.mjs +0 -326
  223. package/src/cli/terminal.mjs +0 -275
  224. package/src/identity/claim.mjs +0 -975
  225. package/src/identity/storage.mjs +0 -165
  226. package/src/project/configuration.d.mts +0 -153
  227. package/src/project/configuration.mjs +0 -1197
  228. package/src/project/setup.mjs +0 -379
  229. package/src/project/support_report.mjs +0 -105
  230. package/src/runtime/cleanup.mjs +0 -381
  231. package/src/runtime/migration_history.mjs +0 -220
  232. package/src/runtime/plan.mjs +0 -685
  233. package/src/runtime/policy.mjs +0 -438
  234. package/src/runtime/restore.mjs +0 -329
  235. package/src/runtime/service_environment.mjs +0 -82
  236. package/src/runtime/topology.mjs +0 -177
  237. package/src/shared/diagnostics.mjs +0 -199
  238. package/src/shared/operation_guard.mjs +0 -162
  239. package/src/shared/process_environment.mjs +0 -68
  240. package/src/source/access.mjs +0 -578
  241. package/src/source/asset_transfer.mjs +0 -177
  242. package/src/source/baseline.mjs +0 -446
  243. package/src/source/postgresql_access.mjs +0 -480
  244. package/src/targets/postgresql.mjs +0 -808
  245. package/src/targets/supabase.mjs +0 -830
  246. package/src/targets/supabase_environment.mjs +0 -229
  247. package/src/targets/target.mjs +0 -66
@@ -0,0 +1,283 @@
1
+ /** Project-scoped CLI orchestration that is shared by direct and guided commands. */
2
+ import { summarizeBaselinePreparation } from "../baseline/preparation.mjs";
3
+ import type { RehearsalConfigPathOptions } from "../project/configuration.mjs";
4
+ import type { RehearsalCleanupPlan } from "../runtime/cleanup.mjs";
5
+ import type { RehearsalCliFlags } from "./arguments.mjs";
6
+ import type { CliSessionState } from "./command_contract.mjs";
7
+ type CleanupStackPlan = Readonly<{
8
+ digest: string;
9
+ targets: readonly Readonly<{
10
+ name: string;
11
+ configPath: string;
12
+ plan: RehearsalCleanupPlan;
13
+ }>[];
14
+ }>;
15
+ type RunManager = (input: {
16
+ action: "discard";
17
+ flags: RehearsalCliFlags;
18
+ configPath?: string;
19
+ targetName?: string;
20
+ }) => unknown;
21
+ interface ProjectCommandInput {
22
+ readonly flags: RehearsalCliFlags;
23
+ readonly planOptions: RehearsalConfigPathOptions;
24
+ readonly session?: CliSessionState;
25
+ }
26
+ export declare const createProjectCommands: ({ projectRoot, runManager, }: {
27
+ projectRoot: string;
28
+ runManager: RunManager;
29
+ }) => Readonly<{
30
+ loadIdentityClaimPlan: ({ flags, planOptions, session, }: ProjectCommandInput) => Promise<{
31
+ loaded: Readonly<{
32
+ config: Readonly<{
33
+ schemaVersion: 1;
34
+ project: Readonly<{
35
+ name: string;
36
+ }>;
37
+ supabase: Readonly<{
38
+ workdir: string;
39
+ migrationDirectory: string;
40
+ rehearsalConfig: string;
41
+ runtimeWorkdir: string;
42
+ authentication: Readonly<{
43
+ enableLocalSignup: true;
44
+ environmentFile: string;
45
+ providers: readonly Readonly<{
46
+ name: "github" | "google";
47
+ clientIdEnvironmentVariable: string;
48
+ clientSecretEnvironmentVariable: string;
49
+ skipNonceCheck: boolean;
50
+ emailOptional: boolean;
51
+ }>[];
52
+ }> | null;
53
+ serviceEnvironmentFile: string | null;
54
+ serviceEnvironmentVariables: readonly string[];
55
+ }> | null;
56
+ postgresql: Readonly<{
57
+ migrationDirectory: string;
58
+ runtimeWorkdir: string;
59
+ image: string;
60
+ database: string;
61
+ user: string;
62
+ }> | null;
63
+ baseline: Readonly<{
64
+ artifactDirectory: string;
65
+ sanitizationPolicy: string;
66
+ }>;
67
+ containerRuntime: Readonly<{
68
+ autoStartColima: boolean;
69
+ }>;
70
+ cleanup: Readonly<{
71
+ retainBaselineGenerations: number;
72
+ }>;
73
+ preparation: Readonly<{
74
+ sourcePolicy: string;
75
+ privacyKey: string;
76
+ batchRows: number;
77
+ maximumRows: number;
78
+ maximumBytes: number;
79
+ diskHeadroomBytes: number;
80
+ }> | null;
81
+ runtimePolicy: string | null;
82
+ identityPolicy: string | null;
83
+ dependentTargets: readonly Readonly<{
84
+ name: string;
85
+ configPath: string;
86
+ prepareCommand: string | null;
87
+ }>[];
88
+ application: Readonly<{
89
+ startCommand: string;
90
+ proofCommand: string;
91
+ environmentFile: string;
92
+ environmentVariables: Readonly<Record<string, string>>;
93
+ readiness: Readonly<{
94
+ url: string;
95
+ expectedStatus: number;
96
+ timeoutSeconds: number;
97
+ }> | null;
98
+ httpProofs: readonly Readonly<{
99
+ name: string;
100
+ kind: "positive" | "negative";
101
+ url: string;
102
+ method: string;
103
+ expectedStatus: number;
104
+ json: Readonly<{
105
+ path: readonly string[];
106
+ equals?: unknown;
107
+ notEquals?: unknown;
108
+ minimumItems?: number;
109
+ }> | null;
110
+ }>[];
111
+ runtimeAdapter: string | null;
112
+ }>;
113
+ runtime: Readonly<{
114
+ target: "postgresql" | "supabase";
115
+ applicationUrl: string;
116
+ projectId: string;
117
+ ports: Readonly<{
118
+ api?: number;
119
+ database: number;
120
+ studio?: number;
121
+ }>;
122
+ }>;
123
+ safety: Readonly<{
124
+ allowedHosts: readonly string[];
125
+ blockedEnvironmentVariables: readonly string[];
126
+ authenticationProviders: readonly string[];
127
+ hostedAccess: "disabled";
128
+ outboundNetwork: "deny";
129
+ }>;
130
+ verification: Readonly<{
131
+ commands: readonly string[];
132
+ }>;
133
+ }>;
134
+ configPath: string;
135
+ projectRoot: string;
136
+ paths: Readonly<{
137
+ artifactDirectory: string;
138
+ applicationEnvironment: string;
139
+ migrationDirectory: string;
140
+ rehearsalConfig: string | null;
141
+ runtimeWorkdir: string;
142
+ serviceEnvironment: string | null;
143
+ sanitizationPolicy: string;
144
+ sourcePolicy: string | null;
145
+ privacyKey: string | null;
146
+ runtimePolicy: string | null;
147
+ identityPolicy: string | null;
148
+ supabaseWorkdir: string | null;
149
+ runtimeAdapter: string | null;
150
+ }>;
151
+ }>;
152
+ plan: import("../identity/claim_contract.mjs").IdentityClaimPlan;
153
+ }>;
154
+ loadIdentityPolicy: ({ planOptions }: ProjectCommandInput) => Promise<{
155
+ loaded: Readonly<{
156
+ config: Readonly<{
157
+ schemaVersion: 1;
158
+ project: Readonly<{
159
+ name: string;
160
+ }>;
161
+ supabase: Readonly<{
162
+ workdir: string;
163
+ migrationDirectory: string;
164
+ rehearsalConfig: string;
165
+ runtimeWorkdir: string;
166
+ authentication: Readonly<{
167
+ enableLocalSignup: true;
168
+ environmentFile: string;
169
+ providers: readonly Readonly<{
170
+ name: "github" | "google";
171
+ clientIdEnvironmentVariable: string;
172
+ clientSecretEnvironmentVariable: string;
173
+ skipNonceCheck: boolean;
174
+ emailOptional: boolean;
175
+ }>[];
176
+ }> | null;
177
+ serviceEnvironmentFile: string | null;
178
+ serviceEnvironmentVariables: readonly string[];
179
+ }> | null;
180
+ postgresql: Readonly<{
181
+ migrationDirectory: string;
182
+ runtimeWorkdir: string;
183
+ image: string;
184
+ database: string;
185
+ user: string;
186
+ }> | null;
187
+ baseline: Readonly<{
188
+ artifactDirectory: string;
189
+ sanitizationPolicy: string;
190
+ }>;
191
+ containerRuntime: Readonly<{
192
+ autoStartColima: boolean;
193
+ }>;
194
+ cleanup: Readonly<{
195
+ retainBaselineGenerations: number;
196
+ }>;
197
+ preparation: Readonly<{
198
+ sourcePolicy: string;
199
+ privacyKey: string;
200
+ batchRows: number;
201
+ maximumRows: number;
202
+ maximumBytes: number;
203
+ diskHeadroomBytes: number;
204
+ }> | null;
205
+ runtimePolicy: string | null;
206
+ identityPolicy: string | null;
207
+ dependentTargets: readonly Readonly<{
208
+ name: string;
209
+ configPath: string;
210
+ prepareCommand: string | null;
211
+ }>[];
212
+ application: Readonly<{
213
+ startCommand: string;
214
+ proofCommand: string;
215
+ environmentFile: string;
216
+ environmentVariables: Readonly<Record<string, string>>;
217
+ readiness: Readonly<{
218
+ url: string;
219
+ expectedStatus: number;
220
+ timeoutSeconds: number;
221
+ }> | null;
222
+ httpProofs: readonly Readonly<{
223
+ name: string;
224
+ kind: "positive" | "negative";
225
+ url: string;
226
+ method: string;
227
+ expectedStatus: number;
228
+ json: Readonly<{
229
+ path: readonly string[];
230
+ equals?: unknown;
231
+ notEquals?: unknown;
232
+ minimumItems?: number;
233
+ }> | null;
234
+ }>[];
235
+ runtimeAdapter: string | null;
236
+ }>;
237
+ runtime: Readonly<{
238
+ target: "postgresql" | "supabase";
239
+ applicationUrl: string;
240
+ projectId: string;
241
+ ports: Readonly<{
242
+ api?: number;
243
+ database: number;
244
+ studio?: number;
245
+ }>;
246
+ }>;
247
+ safety: Readonly<{
248
+ allowedHosts: readonly string[];
249
+ blockedEnvironmentVariables: readonly string[];
250
+ authenticationProviders: readonly string[];
251
+ hostedAccess: "disabled";
252
+ outboundNetwork: "deny";
253
+ }>;
254
+ verification: Readonly<{
255
+ commands: readonly string[];
256
+ }>;
257
+ }>;
258
+ configPath: string;
259
+ projectRoot: string;
260
+ paths: Readonly<{
261
+ artifactDirectory: string;
262
+ applicationEnvironment: string;
263
+ migrationDirectory: string;
264
+ rehearsalConfig: string | null;
265
+ runtimeWorkdir: string;
266
+ serviceEnvironment: string | null;
267
+ sanitizationPolicy: string;
268
+ sourcePolicy: string | null;
269
+ privacyKey: string | null;
270
+ runtimePolicy: string | null;
271
+ identityPolicy: string | null;
272
+ supabaseWorkdir: string | null;
273
+ runtimeAdapter: string | null;
274
+ }>;
275
+ }>;
276
+ policy: import("../identity/claim_contract.mjs").IdentityPolicy;
277
+ }>;
278
+ planRuntimeStackCleanup: ({ flags, planOptions, }: ProjectCommandInput) => Promise<RehearsalCleanupPlan | CleanupStackPlan>;
279
+ runBaselinePreparation: ({ flags, planOptions, session, }: ProjectCommandInput) => Promise<ReturnType<typeof summarizeBaselinePreparation>>;
280
+ runCleanup: ({ flags, planOptions, session, }: ProjectCommandInput) => Promise<unknown>;
281
+ runSetup: ({ flags, planOptions, session, }: ProjectCommandInput) => Promise<unknown>;
282
+ }>;
283
+ export {};
@@ -0,0 +1,192 @@
1
+ /** Project-scoped CLI orchestration that is shared by direct and guided commands. */
2
+ import { createHash } from "node:crypto";
3
+ import { readFile } from "node:fs/promises";
4
+ import { applyBaselinePreparation, planBaselinePreparation, summarizeBaselinePreparation, } from "../baseline/preparation.mjs";
5
+ import { createIdentityClaimPlan, validateIdentityPolicy, } from "../identity/claim.mjs";
6
+ import { loadRehearsalConfig } from "../project/configuration.mjs";
7
+ import { applyRehearsalSetup, planRehearsalSetup, summarizeRehearsalSetup, } from "../project/setup.mjs";
8
+ import { applyRehearsalCleanup, planRehearsalCleanup, } from "../runtime/cleanup.mjs";
9
+ import { runRehearsalDoctor } from "../runtime/plan.mjs";
10
+ import { loadRuntimeTopology } from "../runtime/topology.mjs";
11
+ const isCleanupStackPlan = (plan) => "targets" in plan;
12
+ export const createProjectCommands = ({ projectRoot, runManager, }) => {
13
+ const runSetup = async ({ flags, planOptions, session, }) => {
14
+ const setupTarget = flags.target === "supabase" || flags.target === "postgresql"
15
+ ? flags.target
16
+ : undefined;
17
+ if (flags.target !== undefined && setupTarget === undefined) {
18
+ throw new Error("--target must be supabase or postgresql.");
19
+ }
20
+ const plan = session?.setupPlan ??
21
+ (await planRehearsalSetup({
22
+ projectRoot,
23
+ ...(planOptions.configPath === undefined
24
+ ? {}
25
+ : { configPath: planOptions.configPath }),
26
+ ...(setupTarget === undefined ? {} : { target: setupTarget }),
27
+ }));
28
+ if (flags.write)
29
+ await applyRehearsalSetup(plan);
30
+ const result = summarizeRehearsalSetup(plan, {
31
+ mode: flags.write ? "written" : "preview",
32
+ });
33
+ if (!flags.write)
34
+ return result;
35
+ const readiness = await runRehearsalDoctor(planOptions);
36
+ const needsBaselinePolicy = readiness.checks.some((check) => check.id === "sanitization-policy" && check.status === "fail");
37
+ return {
38
+ ...result,
39
+ readiness,
40
+ nextAction: [
41
+ `Review ${result.configurationPath}.`,
42
+ readiness.state === "READY"
43
+ ? "Next: run rehearsal explain to review the migration plan."
44
+ : needsBaselinePolicy
45
+ ? flags.guided
46
+ ? "Next: choose Prepare the script to create a reviewable policy draft."
47
+ : "Next: run rehearsal again and choose Prepare a reviewable baseline policy draft."
48
+ : "Next: complete the remaining readiness items shown above.",
49
+ ].join("\n"),
50
+ };
51
+ };
52
+ const runBaselinePreparation = async ({ flags, planOptions, session, }) => {
53
+ if (!flags.recordsPath || !flags.ledgerPath) {
54
+ throw new Error("baseline prepare requires --records and --ledger input paths.");
55
+ }
56
+ const plan = session?.preparationPlan ??
57
+ (await planBaselinePreparation({
58
+ ...planOptions,
59
+ recordsPath: flags.recordsPath,
60
+ ledgerPath: flags.ledgerPath,
61
+ }));
62
+ if (flags.write)
63
+ await applyBaselinePreparation(plan);
64
+ const result = summarizeBaselinePreparation(plan, {
65
+ mode: flags.write ? "written" : "preview",
66
+ });
67
+ return flags.guided && flags.write
68
+ ? {
69
+ ...result,
70
+ nextAction: "Next: choose Review the script to classify every column interactively.",
71
+ }
72
+ : result;
73
+ };
74
+ const planRuntimeStackCleanup = async ({ flags, planOptions, }) => {
75
+ const topology = await loadRuntimeTopology(planOptions);
76
+ const targets = [];
77
+ for (const target of topology.targets) {
78
+ targets.push({
79
+ name: target.name,
80
+ configPath: target.configPath,
81
+ plan: await planRehearsalCleanup({
82
+ projectRoot: topology.projectRoot,
83
+ configPath: target.configPath,
84
+ includeRuntime: flags.includeRuntime,
85
+ includeImages: flags.includeImages && target.primary,
86
+ }),
87
+ });
88
+ }
89
+ if (targets.length === 1)
90
+ return targets[0].plan;
91
+ return {
92
+ digest: createHash("sha256")
93
+ .update(JSON.stringify(targets.map((target) => ({
94
+ name: target.name,
95
+ digest: target.plan.digest,
96
+ }))))
97
+ .digest("hex"),
98
+ targets,
99
+ };
100
+ };
101
+ const runCleanup = async ({ flags, planOptions, session, }) => {
102
+ const plan = session?.cleanupPlan ??
103
+ (await planRuntimeStackCleanup({ flags, planOptions }));
104
+ if (!flags.write)
105
+ return { mode: "preview", plan };
106
+ if (isCleanupStackPlan(plan)) {
107
+ if (flags.cleanupConfirmation !== plan.digest) {
108
+ throw new Error("Cleanup requires the exact --confirm-cleanup digest from a fresh preview. Nothing was removed.");
109
+ }
110
+ for (const target of plan.targets) {
111
+ const refreshed = await planRehearsalCleanup({
112
+ projectRoot,
113
+ configPath: target.configPath,
114
+ includeRuntime: target.plan.runtime.included,
115
+ includeImages: target.plan.images.requested,
116
+ });
117
+ if (refreshed.digest !== target.plan.digest) {
118
+ throw new Error(`Cleanup targets changed for ${target.name} after the preview. Nothing was removed; preview the cleanup again.`);
119
+ }
120
+ }
121
+ const appliedTargets = [];
122
+ for (const target of plan.targets) {
123
+ appliedTargets.push({
124
+ name: target.name,
125
+ applied: await applyRehearsalCleanup({
126
+ plan: target.plan,
127
+ confirmation: target.plan.digest,
128
+ projectRoot,
129
+ configPath: target.configPath,
130
+ removeRuntime: async () => {
131
+ runManager({
132
+ action: "discard",
133
+ flags,
134
+ configPath: target.configPath,
135
+ targetName: target.name,
136
+ });
137
+ },
138
+ }),
139
+ });
140
+ }
141
+ return {
142
+ mode: "written",
143
+ plan,
144
+ applied: { targets: appliedTargets },
145
+ };
146
+ }
147
+ const applied = await applyRehearsalCleanup({
148
+ plan,
149
+ ...(flags.cleanupConfirmation === undefined
150
+ ? {}
151
+ : { confirmation: flags.cleanupConfirmation }),
152
+ ...planOptions,
153
+ removeRuntime: async () => {
154
+ runManager({ action: "discard", flags });
155
+ },
156
+ });
157
+ return { mode: "written", plan, applied };
158
+ };
159
+ const loadIdentityPolicy = async ({ planOptions }) => {
160
+ const loaded = await loadRehearsalConfig(planOptions);
161
+ if (!loaded.paths.identityPolicy) {
162
+ throw new Error("No config.identityPolicy is configured.");
163
+ }
164
+ const policy = validateIdentityPolicy(JSON.parse(await readFile(loaded.paths.identityPolicy, "utf8")));
165
+ return { loaded, policy };
166
+ };
167
+ const loadIdentityClaimPlan = async ({ flags, planOptions, session, }) => {
168
+ const { loaded, policy } = await loadIdentityPolicy({
169
+ flags,
170
+ planOptions,
171
+ ...(session === undefined ? {} : { session }),
172
+ });
173
+ if (!flags.identityName) {
174
+ throw new Error("Choose a declared identity with --identity=<name>.");
175
+ }
176
+ return {
177
+ loaded,
178
+ plan: createIdentityClaimPlan({
179
+ policy,
180
+ name: flags.identityName,
181
+ }),
182
+ };
183
+ };
184
+ return Object.freeze({
185
+ loadIdentityClaimPlan,
186
+ loadIdentityPolicy,
187
+ planRuntimeStackCleanup,
188
+ runBaselinePreparation,
189
+ runCleanup,
190
+ runSetup,
191
+ });
192
+ };
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Purpose: Parse one CLI request, protect project mutations, and delegate to
4
+ * the typed command registry shared by scripted and guided flows.
5
+ * Run: `npm run rehearsal -- doctor` or `npm run rehearsal -- explain`.
6
+ */
7
+ export {};
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Purpose: Parse one CLI request, protect project mutations, and delegate to
4
+ * the typed command registry shared by scripted and guided flows.
5
+ * Run: `npm run rehearsal -- doctor` or `npm run rehearsal -- explain`.
6
+ */
7
+ import { join } from "node:path";
8
+ import { performance } from "node:perf_hooks";
9
+ import { fileURLToPath } from "node:url";
10
+ import * as prompts from "@clack/prompts";
11
+ import { normalizeRehearsalError, renderHumanError, serializeRehearsalError, } from "../shared/diagnostics.mjs";
12
+ import { acquireProjectOperation, assertInstalledPackageFingerprint, createInstalledPackageFingerprint, } from "../shared/operation_guard.mjs";
13
+ import { commandMutatesProject, parseArguments, resetGuidedFlags, } from "./arguments.mjs";
14
+ import { usage } from "./basic_command_handlers.mjs";
15
+ import { createCliCommandRegistry } from "./cli_commands.mjs";
16
+ import { createCliSessionState, resetCommandSessionState, } from "./command_contract.mjs";
17
+ import { createCommandEmitter } from "./command_output.mjs";
18
+ import { createGuidedHome } from "./guided.mjs";
19
+ import { createProjectCommands } from "./project_commands.mjs";
20
+ import { buildRuntimeStackPlan, createRuntimeCommands, runRuntimeStackDoctor, topologyCandidateSummary, topologyCommandEnvironment, } from "./runtime_commands.mjs";
21
+ import { buildRefreshWorkflowPlan, createRefreshWorkflow, } from "./source_commands.mjs";
22
+ import { installGuidedExitShortcut, useStyledPrompts } from "./terminal.mjs";
23
+ const packageRoot = fileURLToPath(new URL("../../..", import.meta.url));
24
+ const projectRoot = process.cwd();
25
+ const managerPath = join(packageRoot, "dist/scripts/runtime/manage_database.mjs");
26
+ const state = createCliSessionState();
27
+ let activePackageFingerprint = null;
28
+ const runtimeCommands = createRuntimeCommands({
29
+ packageRoot,
30
+ projectRoot,
31
+ managerPath,
32
+ getActivePackageFingerprint: () => activePackageFingerprint ?? undefined,
33
+ });
34
+ const projectCommands = createProjectCommands({
35
+ projectRoot,
36
+ runManager: runtimeCommands.runManager,
37
+ });
38
+ const runRefreshWorkflow = createRefreshWorkflow({
39
+ runRuntimeStack: runtimeCommands.runRuntimeStack,
40
+ prepareDependentTargets: runtimeCommands.prepareDependentTargets,
41
+ topologyCommandEnvironment,
42
+ });
43
+ const commandRegistry = createCliCommandRegistry({
44
+ projectRoot,
45
+ projectCommands,
46
+ runtimeCommands,
47
+ runRefreshWorkflow,
48
+ });
49
+ const emitCommand = createCommandEmitter({
50
+ startedAt: new Date(),
51
+ startedMs: performance.now(),
52
+ });
53
+ const runGuidedHome = createGuidedHome({
54
+ projectRoot,
55
+ topologyCandidateSummary,
56
+ buildRefreshWorkflowPlan,
57
+ planRuntimeStackCleanup: projectCommands.planRuntimeStackCleanup,
58
+ getLastGuidedDetails: () => state.lastGuidedDetails,
59
+ session: state,
60
+ });
61
+ const errorMessage = (error) => error instanceof Error ? error.message : String(error);
62
+ const executeCommand = async ({ command, flags, planOptions, guided, }) => {
63
+ const result = await commandRegistry.execute({
64
+ command,
65
+ flags,
66
+ planOptions,
67
+ guided,
68
+ state,
69
+ });
70
+ if (!result) {
71
+ throw new Error(`Unknown Rehearsal command: ${command}.\n\n${usage()}`);
72
+ }
73
+ const exitCode = emitCommand({ command, flags, result });
74
+ if (exitCode !== undefined)
75
+ process.exitCode = exitCode;
76
+ };
77
+ const main = async () => {
78
+ const { flags, positionals } = parseArguments(process.argv.slice(2));
79
+ const command = positionals.join(" ") || "help";
80
+ const planOptions = {
81
+ projectRoot,
82
+ ...(flags.configPath === undefined ? {} : { configPath: flags.configPath }),
83
+ };
84
+ const wantsAutomaticGuide = positionals.length === 0 &&
85
+ !flags.help &&
86
+ !flags.json &&
87
+ process.stdin.isTTY &&
88
+ process.stdout.isTTY;
89
+ const guided = command === "guide" || wantsAutomaticGuide;
90
+ const mutating = commandMutatesProject({ command, flags, guided });
91
+ const operation = mutating
92
+ ? await acquireProjectOperation({ projectRoot, command })
93
+ : null;
94
+ if (operation) {
95
+ activePackageFingerprint = createInstalledPackageFingerprint({
96
+ packageRoot,
97
+ });
98
+ }
99
+ try {
100
+ if (!guided) {
101
+ await executeCommand({ command, flags, planOptions, guided: false });
102
+ return;
103
+ }
104
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
105
+ throw new Error("The guided home screen requires an interactive terminal. Run rehearsal --help to list scriptable commands.");
106
+ }
107
+ flags.guided = true;
108
+ const installExitShortcut = () => installGuidedExitShortcut(flags, {
109
+ beforeExit: () => operation?.releaseSync(),
110
+ });
111
+ let removeGuidedExitShortcut = installExitShortcut();
112
+ if (useStyledPrompts(flags)) {
113
+ prompts.intro("REHEARSAL · Safe local migration testing");
114
+ }
115
+ try {
116
+ while (true) {
117
+ resetGuidedFlags(flags);
118
+ resetCommandSessionState(state);
119
+ const selected = await runGuidedHome({ flags, planOptions });
120
+ if (!selected)
121
+ break;
122
+ if (selected === "home")
123
+ continue;
124
+ const opensApplication = selected === "open";
125
+ if (opensApplication) {
126
+ removeGuidedExitShortcut?.();
127
+ removeGuidedExitShortcut = null;
128
+ }
129
+ try {
130
+ await executeCommand({
131
+ command: selected,
132
+ flags,
133
+ planOptions,
134
+ guided: true,
135
+ });
136
+ }
137
+ finally {
138
+ if (opensApplication) {
139
+ removeGuidedExitShortcut = installExitShortcut();
140
+ }
141
+ }
142
+ if (flags.exitGuidedSession)
143
+ break;
144
+ }
145
+ }
146
+ finally {
147
+ removeGuidedExitShortcut?.();
148
+ }
149
+ if (useStyledPrompts(flags)) {
150
+ prompts.outro("See you at the next rehearsal.");
151
+ }
152
+ else {
153
+ console.log("See you at the next rehearsal.");
154
+ }
155
+ }
156
+ finally {
157
+ if (operation) {
158
+ try {
159
+ assertInstalledPackageFingerprint({
160
+ packageRoot,
161
+ expected: activePackageFingerprint,
162
+ });
163
+ }
164
+ finally {
165
+ activePackageFingerprint = null;
166
+ await operation.release();
167
+ }
168
+ }
169
+ }
170
+ };
171
+ try {
172
+ await main();
173
+ }
174
+ catch (error) {
175
+ const failure = normalizeRehearsalError(error, {
176
+ expected: "a safe, versioned, local-only Rehearsal operation",
177
+ actual: errorMessage(error),
178
+ refused: "No further Rehearsal action was performed.",
179
+ suggestions: ["Run rehearsal doctor for actionable readiness checks."],
180
+ });
181
+ const wantsJson = process.argv.includes("--json");
182
+ const debug = process.argv.includes("--debug");
183
+ if (wantsJson) {
184
+ console.log(JSON.stringify(serializeRehearsalError(failure, { debug }), null, 2));
185
+ }
186
+ else {
187
+ console.error(renderHumanError(failure, { debug }));
188
+ }
189
+ process.exitCode = failure.exitCode;
190
+ }