@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.
- package/CHANGELOG.md +319 -1
- package/COMPATIBILITY.md +15 -0
- package/README.md +73 -16
- package/dist/package.json +100 -0
- package/dist/scripts/install/create_root_config.d.mts +3 -0
- package/dist/scripts/install/create_root_config.mjs +13 -0
- package/dist/scripts/runtime/manage_database.d.mts +6 -0
- package/{scripts → dist/scripts}/runtime/manage_database.mjs +6 -8
- package/dist/src/application/interactive_task.d.mts +30 -0
- package/dist/src/application/interactive_task.mjs +83 -0
- package/dist/src/application/session.d.mts +97 -0
- package/dist/src/application/session.mjs +380 -0
- package/dist/src/baseline/artifact.d.mts +119 -0
- package/dist/src/baseline/artifact.mjs +522 -0
- package/dist/src/baseline/builder.d.mts +19 -0
- package/dist/src/baseline/builder.mjs +142 -0
- package/dist/src/baseline/input_discovery.d.mts +13 -0
- package/dist/src/baseline/input_discovery.mjs +149 -0
- package/dist/src/baseline/policy_review.d.mts +56 -0
- package/dist/src/baseline/policy_review.mjs +73 -0
- package/dist/src/baseline/preparation.d.mts +63 -0
- package/dist/src/baseline/preparation.mjs +295 -0
- package/dist/src/baseline/privacy_contract.d.mts +147 -0
- package/dist/src/baseline/privacy_contract.mjs +2 -0
- package/dist/src/baseline/privacy_dependency_graph.d.mts +7 -0
- package/dist/src/baseline/privacy_dependency_graph.mjs +110 -0
- package/dist/src/baseline/privacy_engine.d.mts +5 -0
- package/dist/src/baseline/privacy_engine.mjs +4 -0
- package/dist/src/baseline/privacy_key.d.mts +7 -0
- package/dist/src/baseline/privacy_key.mjs +42 -0
- package/dist/src/baseline/privacy_pipeline.d.mts +7 -0
- package/dist/src/baseline/privacy_pipeline.mjs +127 -0
- package/dist/src/baseline/privacy_policy.d.mts +6 -0
- package/dist/src/baseline/privacy_policy.mjs +237 -0
- package/dist/src/baseline/privacy_recipe_validation.d.mts +5 -0
- package/dist/src/baseline/privacy_recipe_validation.mjs +289 -0
- package/dist/src/baseline/privacy_rule_registry.d.mts +18 -0
- package/dist/src/baseline/privacy_rule_registry.mjs +143 -0
- package/dist/src/baseline/privacy_structured_json.d.mts +66 -0
- package/dist/src/baseline/privacy_structured_json.mjs +464 -0
- package/dist/src/baseline/privacy_transforms.d.mts +18 -0
- package/dist/src/baseline/privacy_transforms.mjs +142 -0
- package/dist/src/baseline/privacy_validation_shared.d.mts +31 -0
- package/dist/src/baseline/privacy_validation_shared.mjs +127 -0
- package/dist/src/baseline/sanitization_policy.d.mts +69 -0
- package/dist/src/baseline/sanitization_policy.mjs +227 -0
- package/dist/src/baseline/schema_snapshot.d.mts +19 -0
- package/dist/src/baseline/schema_snapshot.mjs +79 -0
- package/dist/src/cli/application_command_handlers.d.mts +8 -0
- package/dist/src/cli/application_command_handlers.mjs +52 -0
- package/dist/src/cli/arguments.d.mts +38 -0
- package/dist/src/cli/arguments.mjs +130 -0
- package/dist/src/cli/basic_command_handlers.d.mts +4 -0
- package/dist/src/cli/basic_command_handlers.mjs +57 -0
- package/dist/src/cli/cli_commands.d.mts +14 -0
- package/dist/src/cli/cli_commands.mjs +34 -0
- package/dist/src/cli/command_contract.d.mts +57 -0
- package/dist/src/cli/command_contract.mjs +39 -0
- package/dist/src/cli/command_output.d.mts +12 -0
- package/dist/src/cli/command_output.mjs +20 -0
- package/dist/src/cli/command_registry.d.mts +7 -0
- package/dist/src/cli/command_registry.mjs +14 -0
- package/dist/src/cli/guided.d.mts +53 -0
- package/dist/src/cli/guided.mjs +727 -0
- package/dist/src/cli/identity_command_handlers.d.mts +12 -0
- package/dist/src/cli/identity_command_handlers.mjs +239 -0
- package/dist/src/cli/identity_renderer.d.mts +8 -0
- package/dist/src/cli/identity_renderer.mjs +33 -0
- package/dist/src/cli/init_command.d.mts +21 -0
- package/dist/src/cli/init_command.mjs +90 -0
- package/dist/src/cli/inspection_command_handlers.d.mts +3 -0
- package/dist/src/cli/inspection_command_handlers.mjs +79 -0
- package/dist/src/cli/project_command_handlers.d.mts +11 -0
- package/dist/src/cli/project_command_handlers.mjs +92 -0
- package/dist/src/cli/project_commands.d.mts +283 -0
- package/dist/src/cli/project_commands.mjs +192 -0
- package/dist/src/cli/rehearsal.d.mts +7 -0
- package/dist/src/cli/rehearsal.mjs +190 -0
- package/dist/src/cli/renderers.d.mts +299 -0
- package/dist/src/cli/renderers.mjs +554 -0
- package/dist/src/cli/runtime_action_handlers.d.mts +12 -0
- package/dist/src/cli/runtime_action_handlers.mjs +201 -0
- package/dist/src/cli/runtime_commands.d.mts +294 -0
- package/dist/src/cli/runtime_commands.mjs +619 -0
- package/dist/src/cli/source_command_handlers.d.mts +8 -0
- package/dist/src/cli/source_command_handlers.mjs +62 -0
- package/dist/src/cli/source_commands.d.mts +436 -0
- package/dist/src/cli/source_commands.mjs +301 -0
- package/dist/src/cli/terminal.d.mts +59 -0
- package/dist/src/cli/terminal.mjs +230 -0
- package/dist/src/identity/claim.d.mts +5 -0
- package/dist/src/identity/claim.mjs +4 -0
- package/dist/src/identity/claim_contract.d.mts +135 -0
- package/dist/src/identity/claim_contract.mjs +6 -0
- package/dist/src/identity/claim_executor.d.mts +10 -0
- package/dist/src/identity/claim_executor.mjs +358 -0
- package/dist/src/identity/claim_identity_lookup.d.mts +23 -0
- package/dist/src/identity/claim_identity_lookup.mjs +134 -0
- package/dist/src/identity/claim_plan.d.mts +8 -0
- package/dist/src/identity/claim_plan.mjs +61 -0
- package/dist/src/identity/claim_policy.d.mts +3 -0
- package/dist/src/identity/claim_policy.mjs +377 -0
- package/dist/src/identity/claim_sql.d.mts +10 -0
- package/dist/src/identity/claim_sql.mjs +46 -0
- package/dist/src/identity/claim_verification.d.mts +13 -0
- package/dist/src/identity/claim_verification.mjs +35 -0
- package/dist/src/identity/connect.d.mts +30 -0
- package/dist/src/identity/connect.mjs +111 -0
- package/dist/src/identity/provider_configuration.d.mts +37 -0
- package/dist/src/identity/provider_configuration.mjs +132 -0
- package/dist/src/identity/storage.d.mts +21 -0
- package/dist/src/identity/storage.mjs +122 -0
- package/dist/src/index.d.mts +4 -0
- package/dist/src/index.mjs +3 -0
- package/dist/src/project/configuration.d.mts +13 -0
- package/dist/src/project/configuration.mjs +9 -0
- package/dist/src/project/configuration_contract.d.mts +125 -0
- package/dist/src/project/configuration_contract.mjs +27 -0
- package/dist/src/project/configuration_discovery.d.mts +7 -0
- package/dist/src/project/configuration_discovery.mjs +37 -0
- package/dist/src/project/configuration_normalization.d.mts +107 -0
- package/dist/src/project/configuration_normalization.mjs +302 -0
- package/dist/src/project/configuration_rendering.d.mts +14 -0
- package/dist/src/project/configuration_rendering.mjs +228 -0
- package/dist/src/project/configuration_resolution.d.mts +125 -0
- package/dist/src/project/configuration_resolution.mjs +81 -0
- package/dist/src/project/configuration_schema.d.mts +22 -0
- package/dist/src/project/configuration_schema.mjs +160 -0
- package/dist/src/project/configuration_validation.d.mts +22 -0
- package/dist/src/project/configuration_validation.mjs +136 -0
- package/dist/src/project/install_scaffold.d.mts +42 -0
- package/dist/src/project/install_scaffold.mjs +263 -0
- package/dist/src/project/project_detection.d.mts +14 -0
- package/dist/src/project/project_detection.mjs +47 -0
- package/dist/src/project/setup.d.mts +87 -0
- package/dist/src/project/setup.mjs +414 -0
- package/dist/src/project/support_report.d.mts +88 -0
- package/dist/src/project/support_report.mjs +83 -0
- package/dist/src/runtime/cleanup.d.mts +85 -0
- package/dist/src/runtime/cleanup.mjs +311 -0
- package/dist/src/runtime/lifecycle_engine.d.mts +63 -0
- package/dist/src/runtime/lifecycle_engine.mjs +114 -0
- package/dist/src/runtime/migration_history.d.mts +51 -0
- package/dist/src/runtime/migration_history.mjs +170 -0
- package/dist/src/runtime/plan.d.mts +134 -0
- package/dist/src/runtime/plan.mjs +640 -0
- package/dist/src/runtime/policy.d.mts +66 -0
- package/dist/src/runtime/policy.mjs +369 -0
- package/dist/src/runtime/restore.d.mts +22 -0
- package/dist/src/runtime/restore.mjs +276 -0
- package/dist/src/runtime/service_environment.d.mts +11 -0
- package/dist/src/runtime/service_environment.mjs +58 -0
- package/dist/src/runtime/topology.d.mts +51 -0
- package/dist/src/runtime/topology.mjs +128 -0
- package/dist/src/shared/diagnostics.d.mts +97 -0
- package/dist/src/shared/diagnostics.mjs +170 -0
- package/dist/src/shared/human_output.d.mts +2 -0
- package/{src → dist/src}/shared/human_output.mjs +1 -3
- package/dist/src/shared/node_runtime.d.mts +14 -0
- package/dist/src/shared/node_runtime.mjs +25 -0
- package/dist/src/shared/operation_guard.d.mts +22 -0
- package/dist/src/shared/operation_guard.mjs +150 -0
- package/dist/src/shared/process_environment.d.mts +15 -0
- package/dist/src/shared/process_environment.mjs +50 -0
- package/dist/src/source/access.d.mts +165 -0
- package/dist/src/source/access.mjs +602 -0
- package/dist/src/source/asset_transfer.d.mts +27 -0
- package/dist/src/source/asset_transfer.mjs +202 -0
- package/dist/src/source/baseline.d.mts +66 -0
- package/dist/src/source/baseline.mjs +372 -0
- package/dist/src/source/external_reader.d.mts +42 -0
- package/dist/src/source/external_reader.mjs +278 -0
- package/dist/src/source/postgresql_access.d.mts +86 -0
- package/dist/src/source/postgresql_access.mjs +454 -0
- package/dist/src/source/privacy_paths.d.mts +10 -0
- package/dist/src/source/privacy_paths.mjs +27 -0
- package/dist/src/targets/driver.d.mts +2 -0
- package/dist/src/targets/driver.mjs +13 -0
- package/dist/src/targets/postgresql.d.mts +5 -0
- package/dist/src/targets/postgresql.mjs +620 -0
- package/dist/src/targets/supabase.d.mts +8 -0
- package/dist/src/targets/supabase.mjs +629 -0
- package/dist/src/targets/supabase_environment.d.mts +54 -0
- package/dist/src/targets/supabase_environment.mjs +184 -0
- package/dist/src/targets/target.d.mts +33 -0
- package/dist/src/targets/target.mjs +39 -0
- package/docs/README.md +35 -16
- package/docs/architecture.md +135 -10
- package/docs/commands.md +53 -15
- package/docs/configuration.md +186 -31
- package/docs/getting-started.md +66 -9
- package/docs/index.md +67 -0
- package/docs/production-source.md +175 -17
- package/docs/releasing.md +24 -12
- package/docs/roadmap.md +3 -2
- package/docs/runtime-lifecycle.md +99 -0
- package/docs/runtime-policies.md +80 -7
- package/docs/sanitization.md +572 -4
- package/docs/security-model.md +8 -0
- package/docs/stability.md +70 -0
- package/docs/standalone-workflow.md +36 -13
- package/docs/troubleshooting.md +82 -10
- package/docs/tutorial.md +7 -1
- package/docs/typescript.md +134 -0
- package/package.json +44 -29
- package/types/configuration.d.mts +5 -0
- package/src/README.md +0 -17
- package/src/application/session.mjs +0 -313
- package/src/baseline/artifact.mjs +0 -661
- package/src/baseline/builder.mjs +0 -164
- package/src/baseline/input_discovery.mjs +0 -155
- package/src/baseline/policy_review.mjs +0 -92
- package/src/baseline/preparation.mjs +0 -323
- package/src/baseline/privacy_engine.mjs +0 -413
- package/src/baseline/sanitization_policy.mjs +0 -299
- package/src/baseline/schema_snapshot.mjs +0 -113
- package/src/cli/arguments.mjs +0 -120
- package/src/cli/guided.mjs +0 -807
- package/src/cli/rehearsal.mjs +0 -933
- package/src/cli/renderers.mjs +0 -584
- package/src/cli/runtime_commands.mjs +0 -553
- package/src/cli/source_commands.mjs +0 -326
- package/src/cli/terminal.mjs +0 -275
- package/src/identity/claim.mjs +0 -975
- package/src/identity/storage.mjs +0 -165
- package/src/project/configuration.d.mts +0 -153
- package/src/project/configuration.mjs +0 -1197
- package/src/project/setup.mjs +0 -379
- package/src/project/support_report.mjs +0 -105
- package/src/runtime/cleanup.mjs +0 -381
- package/src/runtime/migration_history.mjs +0 -220
- package/src/runtime/plan.mjs +0 -685
- package/src/runtime/policy.mjs +0 -438
- package/src/runtime/restore.mjs +0 -329
- package/src/runtime/service_environment.mjs +0 -82
- package/src/runtime/topology.mjs +0 -177
- package/src/shared/diagnostics.mjs +0 -199
- package/src/shared/operation_guard.mjs +0 -162
- package/src/shared/process_environment.mjs +0 -68
- package/src/source/access.mjs +0 -578
- package/src/source/asset_transfer.mjs +0 -177
- package/src/source/baseline.mjs +0 -446
- package/src/source/postgresql_access.mjs +0 -480
- package/src/targets/postgresql.mjs +0 -808
- package/src/targets/supabase.mjs +0 -830
- package/src/targets/supabase_environment.mjs +0 -229
- 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,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 {};
|