pgpm 5.18.0 → 5.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ import { CLIOptions, Inquirerer, ParsedArgs } from 'inquirerer';
2
+ declare const _default: (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => Promise<Partial<ParsedArgs>>;
3
+ export default _default;
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const core_1 = require("@pgpmjs/core");
37
+ const logger_1 = require("@pgpmjs/logger");
38
+ const transform_1 = require("@pgpmjs/transform");
39
+ const fs = __importStar(require("fs"));
40
+ const inquirerer_1 = require("inquirerer");
41
+ const path = __importStar(require("path"));
42
+ const log = new logger_1.Logger('regen');
43
+ const regenUsageText = `
44
+ Regen Command:
45
+
46
+ pgpm regen [change...] [OPTIONS]
47
+
48
+ Generate revert/verify scripts from deploy scripts. By default sweeps every
49
+ change in pgpm.plan and fills in scripts that are missing or empty stubs
50
+ (only comments and a BEGIN/COMMIT wrapper). Reverts are mechanical inverses
51
+ in reverse dependency order; verifies are existence checks per created
52
+ object. Statements with no derivable inverse become
53
+ '-- revert not derivable: <reason>' comments.
54
+
55
+ Arguments:
56
+ change Regenerate only the named change(s) (targeted mode)
57
+
58
+ Options:
59
+ --help, -h Show this help message
60
+ --revert-only Only generate revert scripts
61
+ --verify-only Only generate verify scripts
62
+ --dry-run Report what would be written without writing
63
+ --force Overwrite non-empty existing scripts
64
+ --cwd <directory> Working directory (default: current directory)
65
+
66
+ Examples:
67
+ pgpm regen Fill in all missing/stub revert+verify scripts
68
+ pgpm regen schemas/app/tables/users/table Regenerate one change
69
+ pgpm regen --verify-only --dry-run Preview verify generation
70
+ pgpm regen foo --force Overwrite foo's scripts even if non-empty
71
+ `;
72
+ const wrapScript = (type, change, body) => {
73
+ const header = type === 'revert' ? `-- Revert ${change} from pg` : `-- Verify ${change} on pg`;
74
+ const close = type === 'revert' ? 'COMMIT;' : 'ROLLBACK;';
75
+ const sql = body.trim();
76
+ return `${header}\n\nBEGIN;\n\n${sql ? `${sql}\n\n` : ''}${close}\n`;
77
+ };
78
+ exports.default = async (argv, prompter, _options) => {
79
+ if (argv.help || argv.h) {
80
+ console.log(regenUsageText);
81
+ process.exit(0);
82
+ }
83
+ const cwd = argv.cwd || process.cwd();
84
+ const revertOnly = Boolean(argv['revert-only'] ?? argv.revertOnly);
85
+ const verifyOnly = Boolean(argv['verify-only'] ?? argv.verifyOnly);
86
+ const dryRun = Boolean(argv['dry-run'] ?? argv.dryRun);
87
+ const force = Boolean(argv.force);
88
+ if (revertOnly && verifyOnly) {
89
+ await (0, inquirerer_1.cliExitWithError)('--revert-only and --verify-only are mutually exclusive');
90
+ }
91
+ const types = revertOnly
92
+ ? ['revert']
93
+ : verifyOnly
94
+ ? ['verify']
95
+ : ['revert', 'verify'];
96
+ const pkg = new core_1.PgpmPackage(path.resolve(cwd));
97
+ if (!pkg.isInModule()) {
98
+ await (0, inquirerer_1.cliExitWithError)('This command must be run inside a pgpm module (or pass --cwd <module>).');
99
+ }
100
+ const modulePath = pkg.modulePath;
101
+ const planResult = (0, core_1.parsePlanFile)(path.join(modulePath, 'pgpm.plan'));
102
+ if (!planResult.data) {
103
+ await (0, inquirerer_1.cliExitWithError)(`Failed to parse pgpm.plan: ${planResult.errors.map(e => e.message).join(', ')}`);
104
+ }
105
+ const planChanges = planResult.data.changes.map(c => c.name);
106
+ const requested = argv._?.filter(Boolean) ?? [];
107
+ let targets;
108
+ if (requested.length > 0) {
109
+ const missing = requested.filter(name => !planChanges.includes(name));
110
+ if (missing.length > 0) {
111
+ await (0, inquirerer_1.cliExitWithError)(`Change(s) not found in pgpm.plan: ${missing.join(', ')}`);
112
+ }
113
+ targets = requested;
114
+ }
115
+ else {
116
+ targets = planChanges;
117
+ }
118
+ const result = { generated: [], skipped: [], warnings: [] };
119
+ await (0, transform_1.loadModule)();
120
+ for (const change of targets) {
121
+ const deploySql = (0, core_1.readScript)(modulePath, 'deploy', change);
122
+ if (!deploySql) {
123
+ result.warnings.push(`${change}: no deploy script found, skipping`);
124
+ continue;
125
+ }
126
+ const needed = types.filter(type => {
127
+ const existing = (0, core_1.readScript)(modulePath, type, change);
128
+ return force || (0, transform_1.isStubScript)(existing);
129
+ });
130
+ const untouched = types.filter(type => !needed.includes(type));
131
+ for (const type of untouched) {
132
+ result.skipped.push(`${type}/${change}`);
133
+ }
134
+ if (needed.length === 0)
135
+ continue;
136
+ let scripts;
137
+ try {
138
+ scripts = (0, transform_1.regenerateScripts)(deploySql);
139
+ }
140
+ catch (err) {
141
+ result.warnings.push(`${change}: failed to parse deploy script (${err?.message ?? err})`);
142
+ continue;
143
+ }
144
+ for (const warning of scripts.revert.warnings) {
145
+ result.warnings.push(`${change}: ${warning}`);
146
+ }
147
+ for (const warning of scripts.verify.warnings) {
148
+ result.warnings.push(`${change}: ${warning}`);
149
+ }
150
+ for (const type of needed) {
151
+ const body = type === 'revert' ? scripts.revert.sql : scripts.verify.sql;
152
+ const content = wrapScript(type, change, body);
153
+ const target = `${type}/${change}`;
154
+ if (dryRun) {
155
+ log.info(`would write ${target}.sql`);
156
+ }
157
+ else {
158
+ const filePath = path.join(modulePath, type, `${change}.sql`);
159
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
160
+ fs.writeFileSync(filePath, content);
161
+ }
162
+ result.generated.push(target);
163
+ }
164
+ }
165
+ for (const warning of result.warnings) {
166
+ log.warn(warning);
167
+ }
168
+ const verb = dryRun ? 'would generate' : 'generated';
169
+ log.success(`regen: ${verb} ${result.generated.length} script(s), skipped ${result.skipped.length} existing, ${result.warnings.length} warning(s)`);
170
+ return argv;
171
+ };
package/commands.js CHANGED
@@ -26,6 +26,7 @@ const materialize_1 = __importDefault(require("./commands/materialize"));
26
26
  const migrate_1 = __importDefault(require("./commands/migrate"));
27
27
  const package_1 = __importDefault(require("./commands/package"));
28
28
  const plan_1 = __importDefault(require("./commands/plan"));
29
+ const regen_1 = __importDefault(require("./commands/regen"));
29
30
  const remove_1 = __importDefault(require("./commands/remove"));
30
31
  const rename_1 = __importDefault(require("./commands/rename"));
31
32
  const revert_1 = __importDefault(require("./commands/revert"));
@@ -57,6 +58,7 @@ const ENGINE_EXEMPT_COMMANDS = new Set([
57
58
  'package',
58
59
  'materialize',
59
60
  'plan',
61
+ 'regen',
60
62
  'remove',
61
63
  'rename',
62
64
  'slice',
@@ -93,6 +95,7 @@ const createPgpmCommandMap = (skipPgTeardown = false) => {
93
95
  init: pgt(init_1.default),
94
96
  extension: pgt(extension_1.default),
95
97
  plan: pgt(plan_1.default),
98
+ regen: regen_1.default,
96
99
  export: pgt(export_1.default),
97
100
  package: pgt(package_1.default),
98
101
  tag: pgt(tag_1.default),
@@ -0,0 +1,136 @@
1
+ import { parsePlanFile, PgpmPackage, readScript } from '@pgpmjs/core';
2
+ import { Logger } from '@pgpmjs/logger';
3
+ import { isStubScript, loadModule, regenerateScripts } from '@pgpmjs/transform';
4
+ import * as fs from 'fs';
5
+ import { cliExitWithError } from 'inquirerer';
6
+ import * as path from 'path';
7
+ const log = new Logger('regen');
8
+ const regenUsageText = `
9
+ Regen Command:
10
+
11
+ pgpm regen [change...] [OPTIONS]
12
+
13
+ Generate revert/verify scripts from deploy scripts. By default sweeps every
14
+ change in pgpm.plan and fills in scripts that are missing or empty stubs
15
+ (only comments and a BEGIN/COMMIT wrapper). Reverts are mechanical inverses
16
+ in reverse dependency order; verifies are existence checks per created
17
+ object. Statements with no derivable inverse become
18
+ '-- revert not derivable: <reason>' comments.
19
+
20
+ Arguments:
21
+ change Regenerate only the named change(s) (targeted mode)
22
+
23
+ Options:
24
+ --help, -h Show this help message
25
+ --revert-only Only generate revert scripts
26
+ --verify-only Only generate verify scripts
27
+ --dry-run Report what would be written without writing
28
+ --force Overwrite non-empty existing scripts
29
+ --cwd <directory> Working directory (default: current directory)
30
+
31
+ Examples:
32
+ pgpm regen Fill in all missing/stub revert+verify scripts
33
+ pgpm regen schemas/app/tables/users/table Regenerate one change
34
+ pgpm regen --verify-only --dry-run Preview verify generation
35
+ pgpm regen foo --force Overwrite foo's scripts even if non-empty
36
+ `;
37
+ const wrapScript = (type, change, body) => {
38
+ const header = type === 'revert' ? `-- Revert ${change} from pg` : `-- Verify ${change} on pg`;
39
+ const close = type === 'revert' ? 'COMMIT;' : 'ROLLBACK;';
40
+ const sql = body.trim();
41
+ return `${header}\n\nBEGIN;\n\n${sql ? `${sql}\n\n` : ''}${close}\n`;
42
+ };
43
+ export default async (argv, prompter, _options) => {
44
+ if (argv.help || argv.h) {
45
+ console.log(regenUsageText);
46
+ process.exit(0);
47
+ }
48
+ const cwd = argv.cwd || process.cwd();
49
+ const revertOnly = Boolean(argv['revert-only'] ?? argv.revertOnly);
50
+ const verifyOnly = Boolean(argv['verify-only'] ?? argv.verifyOnly);
51
+ const dryRun = Boolean(argv['dry-run'] ?? argv.dryRun);
52
+ const force = Boolean(argv.force);
53
+ if (revertOnly && verifyOnly) {
54
+ await cliExitWithError('--revert-only and --verify-only are mutually exclusive');
55
+ }
56
+ const types = revertOnly
57
+ ? ['revert']
58
+ : verifyOnly
59
+ ? ['verify']
60
+ : ['revert', 'verify'];
61
+ const pkg = new PgpmPackage(path.resolve(cwd));
62
+ if (!pkg.isInModule()) {
63
+ await cliExitWithError('This command must be run inside a pgpm module (or pass --cwd <module>).');
64
+ }
65
+ const modulePath = pkg.modulePath;
66
+ const planResult = parsePlanFile(path.join(modulePath, 'pgpm.plan'));
67
+ if (!planResult.data) {
68
+ await cliExitWithError(`Failed to parse pgpm.plan: ${planResult.errors.map(e => e.message).join(', ')}`);
69
+ }
70
+ const planChanges = planResult.data.changes.map(c => c.name);
71
+ const requested = argv._?.filter(Boolean) ?? [];
72
+ let targets;
73
+ if (requested.length > 0) {
74
+ const missing = requested.filter(name => !planChanges.includes(name));
75
+ if (missing.length > 0) {
76
+ await cliExitWithError(`Change(s) not found in pgpm.plan: ${missing.join(', ')}`);
77
+ }
78
+ targets = requested;
79
+ }
80
+ else {
81
+ targets = planChanges;
82
+ }
83
+ const result = { generated: [], skipped: [], warnings: [] };
84
+ await loadModule();
85
+ for (const change of targets) {
86
+ const deploySql = readScript(modulePath, 'deploy', change);
87
+ if (!deploySql) {
88
+ result.warnings.push(`${change}: no deploy script found, skipping`);
89
+ continue;
90
+ }
91
+ const needed = types.filter(type => {
92
+ const existing = readScript(modulePath, type, change);
93
+ return force || isStubScript(existing);
94
+ });
95
+ const untouched = types.filter(type => !needed.includes(type));
96
+ for (const type of untouched) {
97
+ result.skipped.push(`${type}/${change}`);
98
+ }
99
+ if (needed.length === 0)
100
+ continue;
101
+ let scripts;
102
+ try {
103
+ scripts = regenerateScripts(deploySql);
104
+ }
105
+ catch (err) {
106
+ result.warnings.push(`${change}: failed to parse deploy script (${err?.message ?? err})`);
107
+ continue;
108
+ }
109
+ for (const warning of scripts.revert.warnings) {
110
+ result.warnings.push(`${change}: ${warning}`);
111
+ }
112
+ for (const warning of scripts.verify.warnings) {
113
+ result.warnings.push(`${change}: ${warning}`);
114
+ }
115
+ for (const type of needed) {
116
+ const body = type === 'revert' ? scripts.revert.sql : scripts.verify.sql;
117
+ const content = wrapScript(type, change, body);
118
+ const target = `${type}/${change}`;
119
+ if (dryRun) {
120
+ log.info(`would write ${target}.sql`);
121
+ }
122
+ else {
123
+ const filePath = path.join(modulePath, type, `${change}.sql`);
124
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
125
+ fs.writeFileSync(filePath, content);
126
+ }
127
+ result.generated.push(target);
128
+ }
129
+ }
130
+ for (const warning of result.warnings) {
131
+ log.warn(warning);
132
+ }
133
+ const verb = dryRun ? 'would generate' : 'generated';
134
+ log.success(`regen: ${verb} ${result.generated.length} script(s), skipped ${result.skipped.length} existing, ${result.warnings.length} warning(s)`);
135
+ return argv;
136
+ };
package/esm/commands.js CHANGED
@@ -20,6 +20,7 @@ import materialize from './commands/materialize';
20
20
  import migrate from './commands/migrate';
21
21
  import _package from './commands/package';
22
22
  import plan from './commands/plan';
23
+ import regen from './commands/regen';
23
24
  import remove from './commands/remove';
24
25
  import renameCmd from './commands/rename';
25
26
  import revert from './commands/revert';
@@ -51,6 +52,7 @@ const ENGINE_EXEMPT_COMMANDS = new Set([
51
52
  'package',
52
53
  'materialize',
53
54
  'plan',
55
+ 'regen',
54
56
  'remove',
55
57
  'rename',
56
58
  'slice',
@@ -87,6 +89,7 @@ export const createPgpmCommandMap = (skipPgTeardown = false) => {
87
89
  init: pgt(init),
88
90
  extension: pgt(extension),
89
91
  plan: pgt(plan),
92
+ regen,
90
93
  export: pgt(_export),
91
94
  package: pgt(_package),
92
95
  tag: pgt(tag),
@@ -11,6 +11,7 @@ export const usageText = `
11
11
  init Initialize workspace or module
12
12
  extension Manage module dependencies
13
13
  plan Generate module deployment plans
14
+ regen Generate revert/verify scripts from deploy scripts
14
15
  package Package module for distribution
15
16
  materialize Transpile an apply proxy into a plain, committed module
16
17
  sync-versions Sync .control/Makefile/sql metadata to package.json versions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgpm",
3
- "version": "5.18.0",
3
+ "version": "5.19.0",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "PostgreSQL Package Manager - Database migration and package management CLI",
6
6
  "main": "index.js",
@@ -46,11 +46,12 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "@inquirerer/utils": "^3.3.9",
49
- "@pgpmjs/core": "^7.21.0",
49
+ "@pgpmjs/core": "^7.21.1",
50
50
  "@pgpmjs/env": "^2.40.2",
51
- "@pgpmjs/export": "^1.14.0",
51
+ "@pgpmjs/export": "^1.14.1",
52
52
  "@pgpmjs/logger": "^2.23.2",
53
- "@pgpmjs/slice": "^0.13.5",
53
+ "@pgpmjs/slice": "^0.13.6",
54
+ "@pgpmjs/transform": "^0.17.0",
54
55
  "@pgpmjs/types": "^2.49.2",
55
56
  "@pgsql/quotes": "^18.1.0",
56
57
  "appstash": "^0.7.0",
@@ -60,7 +61,7 @@
60
61
  "js-yaml": "^4.1.0",
61
62
  "pg-cache": "^3.24.2",
62
63
  "pg-env": "^1.27.2",
63
- "pgsql-deparser": "^18.1.1",
64
+ "pgsql-deparser": "^18.2.0",
64
65
  "semver": "^7.8.1",
65
66
  "shelljs": "^0.10.0",
66
67
  "yanse": "^0.2.1"
@@ -77,5 +78,5 @@
77
78
  "pg",
78
79
  "pgsql"
79
80
  ],
80
- "gitHead": "7a37da1f5655c36813343f09c6efa62ca0d7a855"
81
+ "gitHead": "45cd961cf956d2d28e4d09b20db4204982c33593"
81
82
  }
@@ -1 +1 @@
1
- export declare const usageText = "\n Usage: pgpm <command> [options]\n\n Core Database Operations:\n add Add database changes to plans and create SQL files\n deploy Deploy database changes and migrations\n verify Verify database state and migrations\n revert Revert database changes and migrations\n\n Project Management:\n init Initialize workspace or module\n extension Manage module dependencies\n plan Generate module deployment plans\n package Package module for distribution\n materialize Transpile an apply proxy into a plain, committed module\n sync-versions Sync .control/Makefile/sql metadata to package.json versions\n export Export database migrations from existing databases\n update Update pgpm to the latest version\n cache Manage cached templates (clean)\n upgrade Upgrade installed pgpm modules to latest versions (alias: up)\n\n Database Administration:\n dump Dump a database to a sql file\n kill Terminate database connections and optionally drop databases\n install Install database modules\n tag Add tags to changes for versioning\n clear Clear database state\n remove Remove database changes\n analyze Analyze database structure\n rename Rename database changes\n admin-users Manage admin users\n tune Tune PostgreSQL for throwaway environments (CI/test)\n\n Testing:\n test-packages Run integration tests on all workspace packages\n\n Migration Tools:\n migrate Migration management subcommands\n init Initialize migration tracking\n status Show migration status\n list List all changes\n deps Show change dependencies\n \n Development Tools:\n docker Manage Docker containers (start/stop/ls, --minio)\n doctor Check local dependencies (node, docker, psql) with install guidance\n env Manage environment variables (--supabase, --minio)\n test-packages Run integration tests on workspace packages\n \n Global Options:\n -h, --help Display this help information\n -v, --version Display version information\n --cwd <directory> Working directory (default: current directory)\n --engine <name> Migration backend: pg (default, Postgres server) or\n pglite (in-process WASM Postgres, no server). Also set by\n the \"engine\" key of pgpm.json or PGPM_ENGINE.\n --driver <pkg> Driver plugin package backing the engine (escape hatch)\n --pglite[=dataDir] Sugar for --engine pglite, persisted to <dataDir> if given\n\n Individual Command Help:\n pgpm <command> --help Display detailed help for specific command\n pgpm <command> -h Display detailed help for specific command\n\n Examples:\n pgpm deploy --help Show deploy command options\n pgpm init workspace Initialize new workspace\n pgpm install @pgpm/base32 Install a database module\n ";
1
+ export declare const usageText = "\n Usage: pgpm <command> [options]\n\n Core Database Operations:\n add Add database changes to plans and create SQL files\n deploy Deploy database changes and migrations\n verify Verify database state and migrations\n revert Revert database changes and migrations\n\n Project Management:\n init Initialize workspace or module\n extension Manage module dependencies\n plan Generate module deployment plans\n regen Generate revert/verify scripts from deploy scripts\n package Package module for distribution\n materialize Transpile an apply proxy into a plain, committed module\n sync-versions Sync .control/Makefile/sql metadata to package.json versions\n export Export database migrations from existing databases\n update Update pgpm to the latest version\n cache Manage cached templates (clean)\n upgrade Upgrade installed pgpm modules to latest versions (alias: up)\n\n Database Administration:\n dump Dump a database to a sql file\n kill Terminate database connections and optionally drop databases\n install Install database modules\n tag Add tags to changes for versioning\n clear Clear database state\n remove Remove database changes\n analyze Analyze database structure\n rename Rename database changes\n admin-users Manage admin users\n tune Tune PostgreSQL for throwaway environments (CI/test)\n\n Testing:\n test-packages Run integration tests on all workspace packages\n\n Migration Tools:\n migrate Migration management subcommands\n init Initialize migration tracking\n status Show migration status\n list List all changes\n deps Show change dependencies\n \n Development Tools:\n docker Manage Docker containers (start/stop/ls, --minio)\n doctor Check local dependencies (node, docker, psql) with install guidance\n env Manage environment variables (--supabase, --minio)\n test-packages Run integration tests on workspace packages\n \n Global Options:\n -h, --help Display this help information\n -v, --version Display version information\n --cwd <directory> Working directory (default: current directory)\n --engine <name> Migration backend: pg (default, Postgres server) or\n pglite (in-process WASM Postgres, no server). Also set by\n the \"engine\" key of pgpm.json or PGPM_ENGINE.\n --driver <pkg> Driver plugin package backing the engine (escape hatch)\n --pglite[=dataDir] Sugar for --engine pglite, persisted to <dataDir> if given\n\n Individual Command Help:\n pgpm <command> --help Display detailed help for specific command\n pgpm <command> -h Display detailed help for specific command\n\n Examples:\n pgpm deploy --help Show deploy command options\n pgpm init workspace Initialize new workspace\n pgpm install @pgpm/base32 Install a database module\n ";
package/utils/display.js CHANGED
@@ -14,6 +14,7 @@ exports.usageText = `
14
14
  init Initialize workspace or module
15
15
  extension Manage module dependencies
16
16
  plan Generate module deployment plans
17
+ regen Generate revert/verify scripts from deploy scripts
17
18
  package Package module for distribution
18
19
  materialize Transpile an apply proxy into a plain, committed module
19
20
  sync-versions Sync .control/Makefile/sql metadata to package.json versions