@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,79 @@
1
+ /**
2
+ * Purpose: Capture and compare bounded, data-free PostgreSQL public-schema
3
+ * snapshots for a local Rehearsal runtime. Do not run directly.
4
+ */
5
+ import { spawnSync } from "node:child_process";
6
+ import { createHash } from "node:crypto";
7
+ import { chmod, mkdir, mkdtemp, readFile, rm } from "node:fs/promises";
8
+ import { basename, join, resolve, sep } from "node:path";
9
+ import { createCleanProcessEnvironment } from "../shared/process_environment.mjs";
10
+ const maximumSchemaBytes = 64 * 1024 * 1024;
11
+ const assertArtifactRoot = (artifactRoot) => {
12
+ const resolved = resolve(artifactRoot);
13
+ if (basename(resolved) !== ".rehearsal" || resolved === sep) {
14
+ throw new Error(`Refusing an unsafe Rehearsal artifact root: ${artifactRoot}`);
15
+ }
16
+ return resolved;
17
+ };
18
+ export const assertProductionSchemaDump = (schemaSql) => {
19
+ if (typeof schemaSql !== "string" || schemaSql.length === 0) {
20
+ throw new Error("The Rehearsal production schema snapshot is empty.");
21
+ }
22
+ if (Buffer.byteLength(schemaSql) > maximumSchemaBytes) {
23
+ throw new Error("The Rehearsal production schema snapshot is too large.");
24
+ }
25
+ if (!schemaSql.includes('CREATE SCHEMA IF NOT EXISTS "public";')) {
26
+ throw new Error("The Rehearsal production schema snapshot does not define public.");
27
+ }
28
+ if (/^COPY\s|^\\connect\s|^CREATE DATABASE\s/mu.test(schemaSql)) {
29
+ throw new Error("The Rehearsal production schema snapshot contains data or database switching commands.");
30
+ }
31
+ return schemaSql;
32
+ };
33
+ const comparableSchemaDump = (schemaSql) => assertProductionSchemaDump(schemaSql)
34
+ .split("\n")
35
+ .map((line) => line.trimEnd())
36
+ .filter(Boolean)
37
+ .map((line) => {
38
+ const checkConstraint = line.match(/^(\s*CONSTRAINT "[^"]+" CHECK ).*(,?)$/u);
39
+ return checkConstraint
40
+ ? `${checkConstraint[1]}<database-normalized-expression>${checkConstraint[2]}`
41
+ : line;
42
+ })
43
+ .join("\n");
44
+ export const compareProductionSchemaDumps = ({ expected, actual, }) => {
45
+ const expectedComparable = comparableSchemaDump(expected);
46
+ const actualComparable = comparableSchemaDump(actual);
47
+ if (expectedComparable !== actualComparable) {
48
+ throw new Error("The local Rehearsal public schema does not structurally match the production snapshot.");
49
+ }
50
+ return createHash("sha256").update(actualComparable).digest("hex");
51
+ };
52
+ export const captureSupabasePublicSchema = async ({ repositoryRoot, artifactRoot, arguments_, }) => {
53
+ const root = assertArtifactRoot(artifactRoot);
54
+ await mkdir(root, { recursive: true, mode: 0o700 });
55
+ const temporaryDirectory = await mkdtemp(join(root, ".schema-capture-"));
56
+ const destination = join(temporaryDirectory, "production-schema.sql");
57
+ try {
58
+ const result = spawnSync("supabase", [...arguments_, "--schema", "public", "--file", destination], {
59
+ cwd: repositoryRoot,
60
+ env: createCleanProcessEnvironment(),
61
+ encoding: "utf8",
62
+ stdio: ["ignore", "pipe", "pipe"],
63
+ maxBuffer: 4 * 1024 * 1024,
64
+ });
65
+ if (result.error || result.status !== 0) {
66
+ throw new Error("The exact Rehearsal schema snapshot could not be captured.", { cause: result.error });
67
+ }
68
+ await chmod(destination, 0o600);
69
+ return assertProductionSchemaDump(await readFile(destination, "utf8"));
70
+ }
71
+ finally {
72
+ await rm(temporaryDirectory, { recursive: true, force: true });
73
+ }
74
+ };
75
+ export const captureLocalPublicSchema = ({ repositoryRoot, artifactRoot, workdir, }) => captureSupabasePublicSchema({
76
+ repositoryRoot,
77
+ artifactRoot,
78
+ arguments_: ["db", "dump", "--local", "--workdir", workdir],
79
+ });
@@ -0,0 +1,8 @@
1
+ /** Persistent application-session command handler. */
2
+ import type { CommandDefinition } from "./command_contract.mjs";
3
+ import type { createRuntimeCommands } from "./runtime_commands.mjs";
4
+ type RuntimeCommands = ReturnType<typeof createRuntimeCommands>;
5
+ export declare const createApplicationCommandHandlers: ({ openRuntimeApplication, }: {
6
+ openRuntimeApplication: RuntimeCommands["openRuntimeApplication"];
7
+ }) => readonly CommandDefinition[];
8
+ export {};
@@ -0,0 +1,52 @@
1
+ /** Persistent application-session command handler. */
2
+ import * as prompts from "@clack/prompts";
3
+ import { exactCommands, renderedCommand } from "./command_contract.mjs";
4
+ import { useStyledPrompts } from "./terminal.mjs";
5
+ export const createApplicationCommandHandlers = ({ openRuntimeApplication, }) => [
6
+ exactCommands("open", ["open"], async ({ flags, planOptions, guided, state }) => {
7
+ if (flags.dryRun) {
8
+ throw new Error("--dry-run is supported only by rehearsal run.");
9
+ }
10
+ const data = await openRuntimeApplication({
11
+ flags,
12
+ planOptions,
13
+ session: state,
14
+ onReady: (ready) => {
15
+ const lines = [
16
+ `Application: ${ready.url}`,
17
+ "The verified database runtime stays running and keeps your local changes.",
18
+ guided
19
+ ? "Press Ctrl+C to close the app and return here, or Ctrl+Z to exit Rehearsal."
20
+ : "Press Ctrl+C or Ctrl+Z to close the app. Rehearsal will leave the database runtime running.",
21
+ ];
22
+ if (useStyledPrompts(flags)) {
23
+ prompts.note(lines.join("\n"), "SANDBOX READY");
24
+ }
25
+ else if (!flags.json) {
26
+ console.log(["", "SANDBOX READY", ...lines, ""].join("\n"));
27
+ }
28
+ },
29
+ });
30
+ if (guided && data.application.stoppedBy === "SIGTSTP") {
31
+ flags.exitGuidedSession = true;
32
+ }
33
+ if (guided) {
34
+ state.lastGuidedDetails = [
35
+ data.started.output,
36
+ data.verified.output,
37
+ ...data.preparations.map((preparation) => preparation.output),
38
+ ]
39
+ .filter(Boolean)
40
+ .join("\n");
41
+ }
42
+ return renderedCommand({
43
+ data,
44
+ render: (result) => [
45
+ "SANDBOX APP CLOSED",
46
+ `Application stopped after ${result.application.stoppedBy}.`,
47
+ "The database runtime and its local database and Storage changes were preserved.",
48
+ "Run rehearsal open to return, rehearsal verify to check it, or rehearsal stop to stop the databases.",
49
+ ].join("\n"),
50
+ });
51
+ }),
52
+ ];
@@ -0,0 +1,38 @@
1
+ /** Parse and classify the stable Rehearsal command-line contract. */
2
+ export type RehearsalVerbosity = "normal" | "verbose" | "debug";
3
+ export interface RehearsalCliFlags {
4
+ json: boolean;
5
+ help: boolean;
6
+ version: boolean;
7
+ verbosity: RehearsalVerbosity;
8
+ dryRun: boolean;
9
+ write: boolean;
10
+ plain: boolean;
11
+ configPath: string | undefined;
12
+ confirmation: string | undefined;
13
+ recordsPath: string | undefined;
14
+ ledgerPath: string | undefined;
15
+ assetsPath: string | undefined;
16
+ target: string | undefined;
17
+ includeRuntime: boolean;
18
+ includeImages: boolean;
19
+ cleanupConfirmation: string | undefined;
20
+ sourceAccessConfirmation: string | undefined;
21
+ sourceRetirementConfirmation: string | undefined;
22
+ refreshConfirmation: string | undefined;
23
+ identityConfirmation: string | undefined;
24
+ identityName: string | undefined;
25
+ exitGuidedSession: boolean;
26
+ guided: boolean;
27
+ }
28
+ export interface ParsedArguments {
29
+ flags: RehearsalCliFlags;
30
+ positionals: string[];
31
+ }
32
+ export declare const parseArguments: (arguments_: readonly string[]) => ParsedArguments;
33
+ export declare const resetGuidedFlags: (flags: RehearsalCliFlags) => void;
34
+ export declare const commandMutatesProject: ({ command, flags, guided, }: {
35
+ command: string;
36
+ flags: RehearsalCliFlags;
37
+ guided: boolean;
38
+ }) => boolean;
@@ -0,0 +1,130 @@
1
+ /** Parse and classify the stable Rehearsal command-line contract. */
2
+ export const parseArguments = (arguments_) => {
3
+ const flags = {
4
+ json: false,
5
+ help: false,
6
+ version: false,
7
+ verbosity: "normal",
8
+ dryRun: false,
9
+ write: false,
10
+ plain: false,
11
+ configPath: undefined,
12
+ confirmation: undefined,
13
+ recordsPath: undefined,
14
+ ledgerPath: undefined,
15
+ assetsPath: undefined,
16
+ target: undefined,
17
+ includeRuntime: false,
18
+ includeImages: false,
19
+ cleanupConfirmation: undefined,
20
+ sourceAccessConfirmation: undefined,
21
+ sourceRetirementConfirmation: undefined,
22
+ refreshConfirmation: undefined,
23
+ identityConfirmation: undefined,
24
+ identityName: undefined,
25
+ exitGuidedSession: false,
26
+ guided: false,
27
+ };
28
+ const positionals = [];
29
+ for (const argument of arguments_) {
30
+ if (argument === "--json")
31
+ flags.json = true;
32
+ else if (argument === "--help" || argument === "-h")
33
+ flags.help = true;
34
+ else if (argument === "--version" || argument === "-V")
35
+ flags.version = true;
36
+ else if (argument === "--verbose")
37
+ flags.verbosity = "verbose";
38
+ else if (argument === "--debug")
39
+ flags.verbosity = "debug";
40
+ else if (argument === "--dry-run")
41
+ flags.dryRun = true;
42
+ else if (argument === "--write")
43
+ flags.write = true;
44
+ else if (argument === "--plain")
45
+ flags.plain = true;
46
+ else if (argument.startsWith("--config="))
47
+ flags.configPath = argument.slice("--config=".length);
48
+ else if (argument.startsWith("--confirm-candidates="))
49
+ flags.confirmation = argument.slice("--confirm-candidates=".length);
50
+ else if (argument.startsWith("--confirm-cleanup="))
51
+ flags.cleanupConfirmation = argument.slice("--confirm-cleanup=".length);
52
+ else if (argument.startsWith("--confirm-source-access="))
53
+ flags.sourceAccessConfirmation = argument.slice("--confirm-source-access=".length);
54
+ else if (argument.startsWith("--confirm-source-retirement="))
55
+ flags.sourceRetirementConfirmation = argument.slice("--confirm-source-retirement=".length);
56
+ else if (argument.startsWith("--confirm-refresh="))
57
+ flags.refreshConfirmation = argument.slice("--confirm-refresh=".length);
58
+ else if (argument.startsWith("--confirm-identity="))
59
+ flags.identityConfirmation = argument.slice("--confirm-identity=".length);
60
+ else if (argument.startsWith("--identity="))
61
+ flags.identityName = argument.slice("--identity=".length);
62
+ else if (argument.startsWith("--records="))
63
+ flags.recordsPath = argument.slice("--records=".length);
64
+ else if (argument.startsWith("--ledger="))
65
+ flags.ledgerPath = argument.slice("--ledger=".length);
66
+ else if (argument.startsWith("--assets="))
67
+ flags.assetsPath = argument.slice("--assets=".length);
68
+ else if (argument.startsWith("--target="))
69
+ flags.target = argument.slice("--target=".length);
70
+ else if (argument === "--include-runtime")
71
+ flags.includeRuntime = true;
72
+ else if (argument === "--include-images")
73
+ flags.includeImages = true;
74
+ else if (argument.startsWith("--"))
75
+ throw new Error(`Unknown Rehearsal option: ${argument}.`);
76
+ else
77
+ positionals.push(argument);
78
+ }
79
+ return { flags, positionals };
80
+ };
81
+ export const resetGuidedFlags = (flags) => {
82
+ Object.assign(flags, {
83
+ dryRun: false,
84
+ write: false,
85
+ confirmation: undefined,
86
+ recordsPath: undefined,
87
+ ledgerPath: undefined,
88
+ assetsPath: undefined,
89
+ target: undefined,
90
+ includeRuntime: false,
91
+ includeImages: false,
92
+ cleanupConfirmation: undefined,
93
+ sourceAccessConfirmation: undefined,
94
+ sourceRetirementConfirmation: undefined,
95
+ refreshConfirmation: undefined,
96
+ identityConfirmation: undefined,
97
+ identityName: undefined,
98
+ exitGuidedSession: false,
99
+ });
100
+ };
101
+ export const commandMutatesProject = ({ command, flags, guided, }) => {
102
+ if (guided)
103
+ return true;
104
+ if (["setup", "init", "baseline prepare", "privacy key"].includes(command))
105
+ return flags.write;
106
+ if (command === "cleanup")
107
+ return flags.write;
108
+ if (command === "source apply")
109
+ return Boolean(flags.sourceAccessConfirmation);
110
+ if (command === "source retire")
111
+ return Boolean(flags.sourceRetirementConfirmation);
112
+ if (command === "refresh")
113
+ return Boolean(flags.refreshConfirmation);
114
+ if (command === "identity claim")
115
+ return Boolean(flags.identityConfirmation);
116
+ if (command === "identity connect")
117
+ return true;
118
+ if (command === "run")
119
+ return !flags.dryRun;
120
+ return [
121
+ "baseline create",
122
+ "baseline refresh",
123
+ "open",
124
+ "start",
125
+ "migrate",
126
+ "reset",
127
+ "stop",
128
+ "discard",
129
+ ].includes(command);
130
+ };
@@ -0,0 +1,4 @@
1
+ /** Stable version and help handlers with no project-side effects. */
2
+ import type { CommandDefinition } from "./command_contract.mjs";
3
+ export declare const usage: () => string;
4
+ export declare const createBasicCommandHandlers: () => readonly CommandDefinition[];
@@ -0,0 +1,57 @@
1
+ /** Stable version and help handlers with no project-side effects. */
2
+ import { REHEARSAL_VERSION } from "../shared/diagnostics.mjs";
3
+ import { exactCommands, textCommand } from "./command_contract.mjs";
4
+ export const usage = () => `Usage: rehearsal <command> [options]
5
+
6
+ Commands:
7
+ version Print the installed Rehearsal version
8
+ guide Open the interactive, state-aware home screen
9
+ setup [--target=] [--write] Preview or create safe first-run scaffolding
10
+ init [--write] Preview or explicitly write safe starter config
11
+ baseline prepare --records= --ledger= [--write] Create a fail-closed policy draft
12
+ baseline create --records= --ledger= [--assets=] Create a baseline from safe local inputs
13
+ privacy key [--write] Preview or create the owner-only pseudonym key
14
+ source plan Preview exact, temporary source access
15
+ source apply --confirm-source-access= Apply the reviewed source-access plan
16
+ source retire [--confirm-source-retirement=] Preview or retire exact source access
17
+ baseline refresh Replace only the baseline from a reviewed source
18
+ refresh [--confirm-refresh=] Replace the database copy, reset locally, and remove old copies
19
+ identity plan --identity= Preview an approved local identity association
20
+ identity claim --identity= --confirm-identity= Apply the exact local association
21
+ identity connect [--identity=] Keep the app open, detect sign-in, and connect once
22
+ doctor Check whether Rehearsal is safe and ready
23
+ support Print a safe, copy-ready support report
24
+ explain Show the immutable execution plan
25
+ run --dry-run Alias the exact explain plan without mutations
26
+ run --confirm-candidates= Execute reset, migration, and verification locally
27
+ open Start the runtime and keep the application open
28
+ candidates Show the exact pending migration digest
29
+ inspect baseline Show verified baseline provenance
30
+ inspect migrations Classify represented, applied, and candidate migrations
31
+ start Start an existing verified local runtime
32
+ migrate --confirm-candidates= Apply the exact candidate suffix without resetting
33
+ reset Restore and verify the immutable local baseline
34
+ status Report the disposable local runtime state
35
+ stop Stop only this project's local runtime
36
+ discard Remove only this project's disposable runtime
37
+ cleanup [--include-runtime] [--include-images] [--write] [--confirm-cleanup=]
38
+ Preview or apply conservative disk cleanup
39
+ verify Verify the current local Rehearsal runtime
40
+
41
+ Options: --help, -h --version, -V --json --verbose --debug --plain
42
+ --config=<path> --target=supabase|postgresql
43
+ --confirm-source-access=<digest> --confirm-source-retirement=<digest>
44
+ --confirm-refresh=<digest>`;
45
+ export const createBasicCommandHandlers = () => [
46
+ {
47
+ id: "version",
48
+ matches: ({ command, flags }) => command === "version" || flags.version,
49
+ handle: async ({ flags }) => textCommand(flags.json
50
+ ? JSON.stringify({ name: "@rehearsal-db/core", version: REHEARSAL_VERSION }, null, 2)
51
+ : REHEARSAL_VERSION),
52
+ },
53
+ {
54
+ ...exactCommands("help", ["help"], async () => textCommand(usage())),
55
+ matches: ({ command, flags }) => command === "help" || flags.help,
56
+ },
57
+ ];
@@ -0,0 +1,14 @@
1
+ /** Assemble the CLI command families into one ordered typed registry. */
2
+ import type { createProjectCommands } from "./project_commands.mjs";
3
+ import type { createRuntimeCommands } from "./runtime_commands.mjs";
4
+ import type { createRefreshWorkflow } from "./source_commands.mjs";
5
+ type ProjectCommands = ReturnType<typeof createProjectCommands>;
6
+ type RuntimeCommands = ReturnType<typeof createRuntimeCommands>;
7
+ type RefreshWorkflow = ReturnType<typeof createRefreshWorkflow>;
8
+ export declare const createCliCommandRegistry: ({ projectRoot, projectCommands, runtimeCommands, runRefreshWorkflow, }: {
9
+ projectRoot: string;
10
+ projectCommands: ProjectCommands;
11
+ runtimeCommands: RuntimeCommands;
12
+ runRefreshWorkflow: RefreshWorkflow;
13
+ }) => import("./command_registry.mjs").CommandRegistry;
14
+ export {};
@@ -0,0 +1,34 @@
1
+ /** Assemble the CLI command families into one ordered typed registry. */
2
+ import { createApplicationCommandHandlers } from "./application_command_handlers.mjs";
3
+ import { createBasicCommandHandlers } from "./basic_command_handlers.mjs";
4
+ import { createCommandRegistry } from "./command_registry.mjs";
5
+ import { createIdentityCommandHandlers } from "./identity_command_handlers.mjs";
6
+ import { createInspectionCommandHandlers } from "./inspection_command_handlers.mjs";
7
+ import { createProjectCommandHandlers } from "./project_command_handlers.mjs";
8
+ import { createRuntimeActionHandlers } from "./runtime_action_handlers.mjs";
9
+ import { createSourceCommandHandlers } from "./source_command_handlers.mjs";
10
+ export const createCliCommandRegistry = ({ projectRoot, projectCommands, runtimeCommands, runRefreshWorkflow, }) => createCommandRegistry([
11
+ ...createBasicCommandHandlers(),
12
+ ...createProjectCommandHandlers({
13
+ projectRoot,
14
+ runSetup: projectCommands.runSetup,
15
+ runBaselinePreparation: projectCommands.runBaselinePreparation,
16
+ runCleanup: projectCommands.runCleanup,
17
+ }),
18
+ ...createSourceCommandHandlers({ runRefreshWorkflow }),
19
+ ...createIdentityCommandHandlers({
20
+ loadIdentityClaimPlan: projectCommands.loadIdentityClaimPlan,
21
+ loadIdentityPolicy: projectCommands.loadIdentityPolicy,
22
+ startRuntimeApplication: runtimeCommands.startRuntimeApplication,
23
+ }),
24
+ ...createInspectionCommandHandlers(),
25
+ ...createApplicationCommandHandlers({
26
+ openRuntimeApplication: runtimeCommands.openRuntimeApplication,
27
+ }),
28
+ ...createRuntimeActionHandlers({
29
+ prepareCandidateConfirmation: runtimeCommands.prepareCandidateConfirmation,
30
+ prepareDependentTargets: runtimeCommands.prepareDependentTargets,
31
+ proveRuntimeStack: runtimeCommands.proveRuntimeStack,
32
+ runRuntimeStack: runtimeCommands.runRuntimeStack,
33
+ }),
34
+ ]);
@@ -0,0 +1,57 @@
1
+ /** Typed contracts shared by CLI command handlers and the process entry point. */
2
+ import type { RehearsalConfigPathOptions } from "../project/configuration.mjs";
3
+ import type { RehearsalStatus } from "../shared/diagnostics.mjs";
4
+ import type { RehearsalCliFlags, RehearsalVerbosity } from "./arguments.mjs";
5
+ export interface CliSessionState {
6
+ lastGuidedDetails: string | undefined;
7
+ runtimeTopology: unknown | undefined;
8
+ targetConfirmations: unknown | undefined;
9
+ setupPlan: unknown | undefined;
10
+ preparationPlan: unknown | undefined;
11
+ cleanupPlan: unknown | undefined;
12
+ }
13
+ export declare const createCliSessionState: () => CliSessionState;
14
+ export declare const resetCommandSessionState: (state: CliSessionState) => void;
15
+ export interface CommandContext {
16
+ readonly command: string;
17
+ readonly flags: RehearsalCliFlags;
18
+ readonly planOptions: RehearsalConfigPathOptions;
19
+ readonly guided: boolean;
20
+ readonly state: CliSessionState;
21
+ }
22
+ export interface RenderedCommandResult {
23
+ readonly kind: "rendered";
24
+ readonly data: unknown;
25
+ readonly status: RehearsalStatus;
26
+ readonly render: (verbosity: RehearsalVerbosity) => string;
27
+ readonly exitCode?: number;
28
+ }
29
+ export interface TextCommandResult {
30
+ readonly kind: "text";
31
+ readonly output: string;
32
+ readonly exitCode?: number;
33
+ }
34
+ export interface SilentCommandResult {
35
+ readonly kind: "silent";
36
+ readonly exitCode?: number;
37
+ }
38
+ export type CommandResult = RenderedCommandResult | TextCommandResult | SilentCommandResult;
39
+ export type CommandHandler = (context: CommandContext) => Promise<CommandResult>;
40
+ export interface CommandDefinition {
41
+ readonly id: string;
42
+ readonly matches: (context: CommandContext) => boolean;
43
+ readonly handle: CommandHandler;
44
+ }
45
+ export declare const renderedCommand: <Data>({ data, render, status, exitCode, }: {
46
+ data: Data;
47
+ render: (data: Data, verbosity: RehearsalVerbosity) => string;
48
+ status?: RehearsalStatus;
49
+ exitCode?: number;
50
+ }) => RenderedCommandResult;
51
+ export declare const textCommand: (output: string, options?: {
52
+ exitCode?: number;
53
+ }) => TextCommandResult;
54
+ export declare const silentCommand: (options?: {
55
+ exitCode?: number;
56
+ }) => SilentCommandResult;
57
+ export declare const exactCommands: (id: string, commands: readonly string[], handle: CommandHandler) => CommandDefinition;
@@ -0,0 +1,39 @@
1
+ /** Typed contracts shared by CLI command handlers and the process entry point. */
2
+ export const createCliSessionState = () => ({
3
+ lastGuidedDetails: undefined,
4
+ runtimeTopology: undefined,
5
+ targetConfirmations: undefined,
6
+ setupPlan: undefined,
7
+ preparationPlan: undefined,
8
+ cleanupPlan: undefined,
9
+ });
10
+ export const resetCommandSessionState = (state) => {
11
+ Object.assign(state, {
12
+ runtimeTopology: undefined,
13
+ targetConfirmations: undefined,
14
+ setupPlan: undefined,
15
+ preparationPlan: undefined,
16
+ cleanupPlan: undefined,
17
+ });
18
+ };
19
+ export const renderedCommand = ({ data, render, status = "success", exitCode, }) => ({
20
+ kind: "rendered",
21
+ data,
22
+ status,
23
+ render: (verbosity) => render(data, verbosity),
24
+ ...(exitCode === undefined ? {} : { exitCode }),
25
+ });
26
+ export const textCommand = (output, options = {}) => ({
27
+ kind: "text",
28
+ output,
29
+ ...(options.exitCode === undefined ? {} : { exitCode: options.exitCode }),
30
+ });
31
+ export const silentCommand = (options = {}) => ({
32
+ kind: "silent",
33
+ ...(options.exitCode === undefined ? {} : { exitCode: options.exitCode }),
34
+ });
35
+ export const exactCommands = (id, commands, handle) => ({
36
+ id,
37
+ matches: ({ command }) => commands.includes(command),
38
+ handle,
39
+ });
@@ -0,0 +1,12 @@
1
+ /** Emit the stable JSON envelope or human result for a typed command result. */
2
+ import type { RehearsalCliFlags } from "./arguments.mjs";
3
+ import type { CommandResult } from "./command_contract.mjs";
4
+ export declare const createCommandEmitter: ({ startedAt, startedMs, write, }: {
5
+ startedAt: Date;
6
+ startedMs: number;
7
+ write?: (output: string) => void;
8
+ }) => ({ command, flags, result, }: {
9
+ command: string;
10
+ flags: RehearsalCliFlags;
11
+ result: CommandResult;
12
+ }) => number | undefined;
@@ -0,0 +1,20 @@
1
+ /** Emit the stable JSON envelope or human result for a typed command result. */
2
+ import { performance } from "node:perf_hooks";
3
+ import { createRehearsalResult } from "../shared/diagnostics.mjs";
4
+ export const createCommandEmitter = ({ startedAt, startedMs, write = console.log, }) => ({ command, flags, result, }) => {
5
+ if (result.kind === "text")
6
+ write(result.output);
7
+ if (result.kind === "rendered") {
8
+ const envelope = createRehearsalResult({
9
+ command,
10
+ status: result.status,
11
+ data: result.data,
12
+ startedAt,
13
+ durationMs: Math.round((performance.now() - startedMs) * 100) / 100,
14
+ });
15
+ write(flags.json
16
+ ? JSON.stringify(envelope, null, 2)
17
+ : result.render(flags.verbosity));
18
+ }
19
+ return result.exitCode;
20
+ };
@@ -0,0 +1,7 @@
1
+ /** Resolve one CLI request to exactly one typed command handler. */
2
+ import type { CommandContext, CommandDefinition, CommandResult } from "./command_contract.mjs";
3
+ export interface CommandRegistry {
4
+ readonly ids: readonly string[];
5
+ execute(context: CommandContext): Promise<CommandResult | null>;
6
+ }
7
+ export declare const createCommandRegistry: (definitions: readonly CommandDefinition[]) => CommandRegistry;
@@ -0,0 +1,14 @@
1
+ /** Resolve one CLI request to exactly one typed command handler. */
2
+ export const createCommandRegistry = (definitions) => {
3
+ const ids = definitions.map(({ id }) => id);
4
+ if (new Set(ids).size !== ids.length) {
5
+ throw new Error("CLI command registry IDs must be unique.");
6
+ }
7
+ return Object.freeze({
8
+ ids: Object.freeze(ids),
9
+ async execute(context) {
10
+ const definition = definitions.find((candidate) => candidate.matches(context));
11
+ return definition ? definition.handle(context) : null;
12
+ },
13
+ });
14
+ };
@@ -0,0 +1,53 @@
1
+ /**
2
+ * State-aware interactive home screen and first-run flows.
3
+ */
4
+ import type { RehearsalConfigPathOptions } from "../project/configuration.mjs";
5
+ import type { RehearsalCliFlags } from "./arguments.mjs";
6
+ import type { CliSessionState } from "./command_contract.mjs";
7
+ import type { RuntimeTopologyTarget } from "../runtime/topology.mjs";
8
+ import type { RehearsalCleanupPlan } from "../runtime/cleanup.mjs";
9
+ interface TopologySummary {
10
+ readonly topology: {
11
+ readonly dependents: readonly unknown[];
12
+ readonly targets: readonly RuntimeTopologyTarget[];
13
+ };
14
+ }
15
+ type GuidedCleanupPlan = RehearsalCleanupPlan | Readonly<{
16
+ digest: string;
17
+ targets: readonly Readonly<{
18
+ name: string;
19
+ plan: RehearsalCleanupPlan;
20
+ }>[];
21
+ }>;
22
+ interface GuidedRefreshPlan {
23
+ readonly digest: string;
24
+ readonly review: {
25
+ readonly currentBaseline: string;
26
+ readonly source: {
27
+ readonly readerExpiresAt: string;
28
+ };
29
+ readonly runtimeTargets: readonly string[];
30
+ readonly retention: {
31
+ readonly generations: number;
32
+ readonly removeAfterReplacement: readonly string[];
33
+ };
34
+ readonly steps: readonly string[];
35
+ };
36
+ }
37
+ export declare const createGuidedHome: ({ projectRoot, topologyCandidateSummary, buildRefreshWorkflowPlan, planRuntimeStackCleanup, getLastGuidedDetails, session, }: {
38
+ projectRoot: string;
39
+ topologyCandidateSummary: (options: RehearsalConfigPathOptions) => Promise<TopologySummary>;
40
+ buildRefreshWorkflowPlan: (options: RehearsalConfigPathOptions) => Promise<{
41
+ plan: GuidedRefreshPlan;
42
+ }>;
43
+ planRuntimeStackCleanup: (input: {
44
+ flags: RehearsalCliFlags;
45
+ planOptions: RehearsalConfigPathOptions;
46
+ }) => Promise<GuidedCleanupPlan>;
47
+ getLastGuidedDetails: () => string | undefined;
48
+ session: CliSessionState;
49
+ }) => ({ flags, planOptions, }: {
50
+ flags: RehearsalCliFlags;
51
+ planOptions: RehearsalConfigPathOptions;
52
+ }) => Promise<string | null>;
53
+ export {};