@rehearsal-db/core 0.1.0-beta.14 → 0.1.0-beta.16

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/CHANGELOG.md +51 -1
  2. package/README.md +1 -0
  3. package/dist/package.json +101 -0
  4. package/dist/scripts/install/create_root_config.d.mts +3 -0
  5. package/dist/scripts/install/create_root_config.mjs +13 -0
  6. package/dist/scripts/runtime/manage_database.d.mts +6 -0
  7. package/{scripts → dist/scripts}/runtime/manage_database.mjs +6 -8
  8. package/dist/src/application/session.d.mts +96 -0
  9. package/dist/src/application/session.mjs +380 -0
  10. package/dist/src/baseline/artifact.d.mts +119 -0
  11. package/dist/src/baseline/artifact.mjs +522 -0
  12. package/dist/src/baseline/builder.d.mts +19 -0
  13. package/dist/src/baseline/builder.mjs +142 -0
  14. package/dist/src/baseline/input_discovery.d.mts +13 -0
  15. package/dist/src/baseline/input_discovery.mjs +149 -0
  16. package/dist/src/baseline/policy_review.d.mts +56 -0
  17. package/dist/src/baseline/policy_review.mjs +73 -0
  18. package/dist/src/baseline/preparation.d.mts +63 -0
  19. package/dist/src/baseline/preparation.mjs +295 -0
  20. package/dist/src/baseline/privacy_contract.d.mts +147 -0
  21. package/dist/src/baseline/privacy_contract.mjs +2 -0
  22. package/dist/src/baseline/privacy_dependency_graph.d.mts +7 -0
  23. package/dist/src/baseline/privacy_dependency_graph.mjs +110 -0
  24. package/dist/src/baseline/privacy_engine.d.mts +5 -0
  25. package/dist/src/baseline/privacy_engine.mjs +4 -0
  26. package/dist/src/baseline/privacy_key.d.mts +7 -0
  27. package/dist/src/baseline/privacy_key.mjs +42 -0
  28. package/dist/src/baseline/privacy_pipeline.d.mts +7 -0
  29. package/dist/src/baseline/privacy_pipeline.mjs +127 -0
  30. package/dist/src/baseline/privacy_policy.d.mts +6 -0
  31. package/dist/src/baseline/privacy_policy.mjs +237 -0
  32. package/dist/src/baseline/privacy_recipe_validation.d.mts +5 -0
  33. package/dist/src/baseline/privacy_recipe_validation.mjs +289 -0
  34. package/dist/src/baseline/privacy_rule_registry.d.mts +18 -0
  35. package/dist/src/baseline/privacy_rule_registry.mjs +143 -0
  36. package/dist/src/baseline/privacy_structured_json.d.mts +66 -0
  37. package/dist/src/baseline/privacy_structured_json.mjs +464 -0
  38. package/dist/src/baseline/privacy_transforms.d.mts +18 -0
  39. package/dist/src/baseline/privacy_transforms.mjs +142 -0
  40. package/dist/src/baseline/privacy_validation_shared.d.mts +31 -0
  41. package/dist/src/baseline/privacy_validation_shared.mjs +127 -0
  42. package/dist/src/baseline/sanitization_policy.d.mts +69 -0
  43. package/dist/src/baseline/sanitization_policy.mjs +227 -0
  44. package/dist/src/baseline/schema_snapshot.d.mts +19 -0
  45. package/dist/src/baseline/schema_snapshot.mjs +79 -0
  46. package/dist/src/cli/application_command_handlers.d.mts +8 -0
  47. package/dist/src/cli/application_command_handlers.mjs +52 -0
  48. package/dist/src/cli/arguments.d.mts +38 -0
  49. package/dist/src/cli/arguments.mjs +128 -0
  50. package/dist/src/cli/basic_command_handlers.d.mts +4 -0
  51. package/dist/src/cli/basic_command_handlers.mjs +56 -0
  52. package/dist/src/cli/cli_commands.d.mts +14 -0
  53. package/dist/src/cli/cli_commands.mjs +32 -0
  54. package/dist/src/cli/command_contract.d.mts +57 -0
  55. package/dist/src/cli/command_contract.mjs +39 -0
  56. package/dist/src/cli/command_output.d.mts +12 -0
  57. package/dist/src/cli/command_output.mjs +20 -0
  58. package/dist/src/cli/command_registry.d.mts +7 -0
  59. package/dist/src/cli/command_registry.mjs +14 -0
  60. package/dist/src/cli/guided.d.mts +53 -0
  61. package/dist/src/cli/guided.mjs +719 -0
  62. package/dist/src/cli/identity_command_handlers.d.mts +8 -0
  63. package/dist/src/cli/identity_command_handlers.mjs +43 -0
  64. package/dist/src/cli/init_command.d.mts +21 -0
  65. package/dist/src/cli/init_command.mjs +90 -0
  66. package/dist/src/cli/inspection_command_handlers.d.mts +3 -0
  67. package/dist/src/cli/inspection_command_handlers.mjs +79 -0
  68. package/dist/src/cli/project_command_handlers.d.mts +11 -0
  69. package/dist/src/cli/project_command_handlers.mjs +92 -0
  70. package/dist/src/cli/project_commands.d.mts +159 -0
  71. package/dist/src/cli/project_commands.mjs +183 -0
  72. package/dist/src/cli/rehearsal.d.mts +7 -0
  73. package/dist/src/cli/rehearsal.mjs +190 -0
  74. package/dist/src/cli/renderers.d.mts +299 -0
  75. package/dist/src/cli/renderers.mjs +554 -0
  76. package/dist/src/cli/runtime_action_handlers.d.mts +12 -0
  77. package/dist/src/cli/runtime_action_handlers.mjs +201 -0
  78. package/dist/src/cli/runtime_commands.d.mts +269 -0
  79. package/dist/src/cli/runtime_commands.mjs +601 -0
  80. package/dist/src/cli/source_command_handlers.d.mts +8 -0
  81. package/dist/src/cli/source_command_handlers.mjs +62 -0
  82. package/dist/src/cli/source_commands.d.mts +436 -0
  83. package/dist/src/cli/source_commands.mjs +301 -0
  84. package/dist/src/cli/terminal.d.mts +59 -0
  85. package/dist/src/cli/terminal.mjs +230 -0
  86. package/dist/src/identity/claim.d.mts +5 -0
  87. package/dist/src/identity/claim.mjs +4 -0
  88. package/dist/src/identity/claim_contract.d.mts +135 -0
  89. package/dist/src/identity/claim_contract.mjs +6 -0
  90. package/dist/src/identity/claim_executor.d.mts +10 -0
  91. package/dist/src/identity/claim_executor.mjs +358 -0
  92. package/dist/src/identity/claim_identity_lookup.d.mts +17 -0
  93. package/dist/src/identity/claim_identity_lookup.mjs +125 -0
  94. package/dist/src/identity/claim_plan.d.mts +8 -0
  95. package/dist/src/identity/claim_plan.mjs +61 -0
  96. package/dist/src/identity/claim_policy.d.mts +3 -0
  97. package/dist/src/identity/claim_policy.mjs +377 -0
  98. package/dist/src/identity/claim_sql.d.mts +10 -0
  99. package/dist/src/identity/claim_sql.mjs +46 -0
  100. package/dist/src/identity/claim_verification.d.mts +13 -0
  101. package/dist/src/identity/claim_verification.mjs +35 -0
  102. package/dist/src/identity/provider_configuration.d.mts +37 -0
  103. package/dist/src/identity/provider_configuration.mjs +132 -0
  104. package/dist/src/identity/storage.d.mts +21 -0
  105. package/dist/src/identity/storage.mjs +122 -0
  106. package/dist/src/index.d.mts +4 -0
  107. package/dist/src/index.mjs +3 -0
  108. package/dist/src/project/configuration.d.mts +13 -0
  109. package/dist/src/project/configuration.mjs +9 -0
  110. package/dist/src/project/configuration_contract.d.mts +125 -0
  111. package/dist/src/project/configuration_contract.mjs +27 -0
  112. package/dist/src/project/configuration_discovery.d.mts +7 -0
  113. package/dist/src/project/configuration_discovery.mjs +37 -0
  114. package/dist/src/project/configuration_normalization.d.mts +107 -0
  115. package/dist/src/project/configuration_normalization.mjs +302 -0
  116. package/dist/src/project/configuration_rendering.d.mts +14 -0
  117. package/dist/src/project/configuration_rendering.mjs +224 -0
  118. package/dist/src/project/configuration_resolution.d.mts +125 -0
  119. package/dist/src/project/configuration_resolution.mjs +81 -0
  120. package/dist/src/project/configuration_schema.d.mts +22 -0
  121. package/dist/src/project/configuration_schema.mjs +160 -0
  122. package/dist/src/project/configuration_validation.d.mts +22 -0
  123. package/dist/src/project/configuration_validation.mjs +136 -0
  124. package/dist/src/project/install_scaffold.d.mts +42 -0
  125. package/dist/src/project/install_scaffold.mjs +263 -0
  126. package/dist/src/project/project_detection.d.mts +14 -0
  127. package/dist/src/project/project_detection.mjs +47 -0
  128. package/dist/src/project/setup.d.mts +87 -0
  129. package/dist/src/project/setup.mjs +414 -0
  130. package/dist/src/project/support_report.d.mts +88 -0
  131. package/dist/src/project/support_report.mjs +83 -0
  132. package/dist/src/runtime/cleanup.d.mts +85 -0
  133. package/dist/src/runtime/cleanup.mjs +311 -0
  134. package/dist/src/runtime/lifecycle_engine.d.mts +63 -0
  135. package/dist/src/runtime/lifecycle_engine.mjs +114 -0
  136. package/dist/src/runtime/migration_history.d.mts +51 -0
  137. package/dist/src/runtime/migration_history.mjs +170 -0
  138. package/dist/src/runtime/plan.d.mts +134 -0
  139. package/dist/src/runtime/plan.mjs +637 -0
  140. package/dist/src/runtime/policy.d.mts +66 -0
  141. package/dist/src/runtime/policy.mjs +369 -0
  142. package/dist/src/runtime/restore.d.mts +22 -0
  143. package/dist/src/runtime/restore.mjs +276 -0
  144. package/dist/src/runtime/service_environment.d.mts +11 -0
  145. package/dist/src/runtime/service_environment.mjs +58 -0
  146. package/dist/src/runtime/topology.d.mts +51 -0
  147. package/dist/src/runtime/topology.mjs +128 -0
  148. package/dist/src/shared/diagnostics.d.mts +97 -0
  149. package/dist/src/shared/diagnostics.mjs +170 -0
  150. package/dist/src/shared/human_output.d.mts +2 -0
  151. package/{src → dist/src}/shared/human_output.mjs +1 -3
  152. package/dist/src/shared/node_runtime.d.mts +14 -0
  153. package/dist/src/shared/node_runtime.mjs +25 -0
  154. package/dist/src/shared/operation_guard.d.mts +22 -0
  155. package/dist/src/shared/operation_guard.mjs +150 -0
  156. package/dist/src/shared/process_environment.d.mts +15 -0
  157. package/dist/src/shared/process_environment.mjs +50 -0
  158. package/dist/src/source/access.d.mts +165 -0
  159. package/dist/src/source/access.mjs +602 -0
  160. package/dist/src/source/asset_transfer.d.mts +27 -0
  161. package/dist/src/source/asset_transfer.mjs +202 -0
  162. package/dist/src/source/baseline.d.mts +66 -0
  163. package/dist/src/source/baseline.mjs +372 -0
  164. package/dist/src/source/external_reader.d.mts +42 -0
  165. package/dist/src/source/external_reader.mjs +278 -0
  166. package/dist/src/source/postgresql_access.d.mts +86 -0
  167. package/dist/src/source/postgresql_access.mjs +454 -0
  168. package/dist/src/source/privacy_paths.d.mts +10 -0
  169. package/dist/src/source/privacy_paths.mjs +27 -0
  170. package/dist/src/targets/driver.d.mts +2 -0
  171. package/dist/src/targets/driver.mjs +13 -0
  172. package/dist/src/targets/postgresql.d.mts +5 -0
  173. package/dist/src/targets/postgresql.mjs +620 -0
  174. package/dist/src/targets/supabase.d.mts +8 -0
  175. package/dist/src/targets/supabase.mjs +627 -0
  176. package/dist/src/targets/supabase_environment.d.mts +49 -0
  177. package/dist/src/targets/supabase_environment.mjs +162 -0
  178. package/dist/src/targets/target.d.mts +33 -0
  179. package/dist/src/targets/target.mjs +39 -0
  180. package/docs/README.md +1 -0
  181. package/docs/architecture.md +133 -10
  182. package/docs/configuration.md +9 -3
  183. package/docs/index.md +1 -0
  184. package/docs/releasing.md +8 -3
  185. package/docs/typescript.md +134 -0
  186. package/package.json +36 -29
  187. package/types/configuration.d.mts +5 -0
  188. package/scripts/install/create_root_config.mjs +0 -19
  189. package/src/README.md +0 -17
  190. package/src/application/session.mjs +0 -435
  191. package/src/baseline/artifact.mjs +0 -684
  192. package/src/baseline/builder.mjs +0 -164
  193. package/src/baseline/input_discovery.mjs +0 -155
  194. package/src/baseline/policy_review.mjs +0 -92
  195. package/src/baseline/preparation.mjs +0 -323
  196. package/src/baseline/privacy_engine.mjs +0 -1399
  197. package/src/baseline/privacy_structured_json.mjs +0 -554
  198. package/src/baseline/sanitization_policy.mjs +0 -299
  199. package/src/baseline/schema_snapshot.mjs +0 -113
  200. package/src/cli/arguments.mjs +0 -126
  201. package/src/cli/guided.mjs +0 -814
  202. package/src/cli/init_command.mjs +0 -94
  203. package/src/cli/rehearsal.mjs +0 -972
  204. package/src/cli/renderers.mjs +0 -638
  205. package/src/cli/runtime_commands.mjs +0 -707
  206. package/src/cli/source_commands.mjs +0 -355
  207. package/src/cli/terminal.mjs +0 -275
  208. package/src/identity/claim.mjs +0 -1165
  209. package/src/identity/provider_configuration.mjs +0 -177
  210. package/src/identity/storage.mjs +0 -165
  211. package/src/project/configuration.d.mts +0 -164
  212. package/src/project/configuration.mjs +0 -1337
  213. package/src/project/install_scaffold.mjs +0 -325
  214. package/src/project/setup.mjs +0 -474
  215. package/src/project/support_report.mjs +0 -105
  216. package/src/runtime/cleanup.mjs +0 -381
  217. package/src/runtime/migration_history.mjs +0 -220
  218. package/src/runtime/plan.mjs +0 -722
  219. package/src/runtime/policy.mjs +0 -438
  220. package/src/runtime/restore.mjs +0 -337
  221. package/src/runtime/service_environment.mjs +0 -82
  222. package/src/runtime/topology.mjs +0 -177
  223. package/src/shared/diagnostics.mjs +0 -207
  224. package/src/shared/node_runtime.mjs +0 -31
  225. package/src/shared/operation_guard.mjs +0 -162
  226. package/src/shared/process_environment.mjs +0 -68
  227. package/src/source/access.mjs +0 -798
  228. package/src/source/asset_transfer.mjs +0 -259
  229. package/src/source/baseline.mjs +0 -482
  230. package/src/source/external_reader.mjs +0 -368
  231. package/src/source/postgresql_access.mjs +0 -638
  232. package/src/source/privacy_paths.mjs +0 -38
  233. package/src/targets/postgresql.mjs +0 -808
  234. package/src/targets/supabase.mjs +0 -840
  235. package/src/targets/supabase_environment.mjs +0 -229
  236. 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,128 @@
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 === "run")
117
+ return !flags.dryRun;
118
+ return [
119
+ "baseline create",
120
+ "baseline refresh",
121
+ "open",
122
+ "start",
123
+ "migrate",
124
+ "reset",
125
+ "stop",
126
+ "discard",
127
+ ].includes(command);
128
+ };
@@ -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,56 @@
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
+ doctor Check whether Rehearsal is safe and ready
22
+ support Print a safe, copy-ready support report
23
+ explain Show the immutable execution plan
24
+ run --dry-run Alias the exact explain plan without mutations
25
+ run --confirm-candidates= Execute reset, migration, and verification locally
26
+ open Start the runtime and keep the application open
27
+ candidates Show the exact pending migration digest
28
+ inspect baseline Show verified baseline provenance
29
+ inspect migrations Classify represented, applied, and candidate migrations
30
+ start Start an existing verified local runtime
31
+ migrate --confirm-candidates= Apply the exact candidate suffix without resetting
32
+ reset Restore and verify the immutable local baseline
33
+ status Report the disposable local runtime state
34
+ stop Stop only this project's local runtime
35
+ discard Remove only this project's disposable runtime
36
+ cleanup [--include-runtime] [--include-images] [--write] [--confirm-cleanup=]
37
+ Preview or apply conservative disk cleanup
38
+ verify Verify the current local Rehearsal runtime
39
+
40
+ Options: --help, -h --version, -V --json --verbose --debug --plain
41
+ --config=<path> --target=supabase|postgresql
42
+ --confirm-source-access=<digest> --confirm-source-retirement=<digest>
43
+ --confirm-refresh=<digest>`;
44
+ export const createBasicCommandHandlers = () => [
45
+ {
46
+ id: "version",
47
+ matches: ({ command, flags }) => command === "version" || flags.version,
48
+ handle: async ({ flags }) => textCommand(flags.json
49
+ ? JSON.stringify({ name: "@rehearsal-db/core", version: REHEARSAL_VERSION }, null, 2)
50
+ : REHEARSAL_VERSION),
51
+ },
52
+ {
53
+ ...exactCommands("help", ["help"], async () => textCommand(usage())),
54
+ matches: ({ command, flags }) => command === "help" || flags.help,
55
+ },
56
+ ];
@@ -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,32 @@
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
+ }),
22
+ ...createInspectionCommandHandlers(),
23
+ ...createApplicationCommandHandlers({
24
+ openRuntimeApplication: runtimeCommands.openRuntimeApplication,
25
+ }),
26
+ ...createRuntimeActionHandlers({
27
+ prepareCandidateConfirmation: runtimeCommands.prepareCandidateConfirmation,
28
+ prepareDependentTargets: runtimeCommands.prepareDependentTargets,
29
+ proveRuntimeStack: runtimeCommands.proveRuntimeStack,
30
+ runRuntimeStack: runtimeCommands.runRuntimeStack,
31
+ }),
32
+ ]);
@@ -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 {};