pgpm 0.0.1

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 (121) hide show
  1. package/README.md +416 -0
  2. package/commands/add.d.ts +7 -0
  3. package/commands/add.js +86 -0
  4. package/commands/admin-users/add.d.ts +4 -0
  5. package/commands/admin-users/add.js +89 -0
  6. package/commands/admin-users/bootstrap.d.ts +4 -0
  7. package/commands/admin-users/bootstrap.js +50 -0
  8. package/commands/admin-users/remove.d.ts +4 -0
  9. package/commands/admin-users/remove.js +82 -0
  10. package/commands/admin-users.d.ts +4 -0
  11. package/commands/admin-users.js +68 -0
  12. package/commands/analyze.d.ts +4 -0
  13. package/commands/analyze.js +21 -0
  14. package/commands/clear.d.ts +3 -0
  15. package/commands/clear.js +59 -0
  16. package/commands/deploy.d.ts +4 -0
  17. package/commands/deploy.js +146 -0
  18. package/commands/explorer.d.ts +3 -0
  19. package/commands/explorer.js +94 -0
  20. package/commands/export.d.ts +3 -0
  21. package/commands/export.js +129 -0
  22. package/commands/extension.d.ts +4 -0
  23. package/commands/extension.js +48 -0
  24. package/commands/init/index.d.ts +7 -0
  25. package/commands/init/index.js +47 -0
  26. package/commands/init/module.d.ts +4 -0
  27. package/commands/init/module.js +71 -0
  28. package/commands/init/workspace.d.ts +4 -0
  29. package/commands/init/workspace.js +52 -0
  30. package/commands/install.d.ts +4 -0
  31. package/commands/install.js +37 -0
  32. package/commands/kill.d.ts +3 -0
  33. package/commands/kill.js +107 -0
  34. package/commands/migrate/deps.d.ts +4 -0
  35. package/commands/migrate/deps.js +186 -0
  36. package/commands/migrate/init.d.ts +4 -0
  37. package/commands/migrate/init.js +65 -0
  38. package/commands/migrate/list.d.ts +4 -0
  39. package/commands/migrate/list.js +85 -0
  40. package/commands/migrate/status.d.ts +4 -0
  41. package/commands/migrate/status.js +94 -0
  42. package/commands/migrate.d.ts +4 -0
  43. package/commands/migrate.js +69 -0
  44. package/commands/package.d.ts +3 -0
  45. package/commands/package.js +65 -0
  46. package/commands/plan.d.ts +3 -0
  47. package/commands/plan.js +62 -0
  48. package/commands/remove.d.ts +3 -0
  49. package/commands/remove.js +42 -0
  50. package/commands/rename.d.ts +4 -0
  51. package/commands/rename.js +35 -0
  52. package/commands/revert.d.ts +3 -0
  53. package/commands/revert.js +107 -0
  54. package/commands/server.d.ts +3 -0
  55. package/commands/server.js +187 -0
  56. package/commands/tag.d.ts +6 -0
  57. package/commands/tag.js +168 -0
  58. package/commands/verify.d.ts +3 -0
  59. package/commands/verify.js +85 -0
  60. package/commands.d.ts +5 -0
  61. package/commands.js +118 -0
  62. package/dist/README.md +416 -0
  63. package/dist/package.json +77 -0
  64. package/esm/commands/add.js +51 -0
  65. package/esm/commands/admin-users/add.js +87 -0
  66. package/esm/commands/admin-users/bootstrap.js +48 -0
  67. package/esm/commands/admin-users/remove.js +80 -0
  68. package/esm/commands/admin-users.js +63 -0
  69. package/esm/commands/analyze.js +16 -0
  70. package/esm/commands/clear.js +54 -0
  71. package/esm/commands/deploy.js +144 -0
  72. package/esm/commands/explorer.js +92 -0
  73. package/esm/commands/export.js +127 -0
  74. package/esm/commands/extension.js +46 -0
  75. package/esm/commands/init/index.js +42 -0
  76. package/esm/commands/init/module.js +68 -0
  77. package/esm/commands/init/workspace.js +46 -0
  78. package/esm/commands/install.js +35 -0
  79. package/esm/commands/kill.js +105 -0
  80. package/esm/commands/migrate/deps.js +184 -0
  81. package/esm/commands/migrate/init.js +63 -0
  82. package/esm/commands/migrate/list.js +83 -0
  83. package/esm/commands/migrate/status.js +92 -0
  84. package/esm/commands/migrate.js +64 -0
  85. package/esm/commands/package.js +63 -0
  86. package/esm/commands/plan.js +60 -0
  87. package/esm/commands/remove.js +40 -0
  88. package/esm/commands/rename.js +30 -0
  89. package/esm/commands/revert.js +105 -0
  90. package/esm/commands/server.js +185 -0
  91. package/esm/commands/tag.js +133 -0
  92. package/esm/commands/verify.js +83 -0
  93. package/esm/commands.js +111 -0
  94. package/esm/index.js +20 -0
  95. package/esm/package.js +26 -0
  96. package/esm/utils/argv.js +92 -0
  97. package/esm/utils/cli-error.js +48 -0
  98. package/esm/utils/database.js +78 -0
  99. package/esm/utils/deployed-changes.js +68 -0
  100. package/esm/utils/display.js +58 -0
  101. package/esm/utils/index.js +3 -0
  102. package/esm/utils/module-utils.js +51 -0
  103. package/index.d.ts +3 -0
  104. package/index.js +23 -0
  105. package/package.d.ts +1 -0
  106. package/package.js +29 -0
  107. package/package.json +77 -0
  108. package/utils/argv.d.ts +46 -0
  109. package/utils/argv.js +100 -0
  110. package/utils/cli-error.d.ts +8 -0
  111. package/utils/cli-error.js +52 -0
  112. package/utils/database.d.ts +21 -0
  113. package/utils/database.js +83 -0
  114. package/utils/deployed-changes.d.ts +4 -0
  115. package/utils/deployed-changes.js +72 -0
  116. package/utils/display.d.ts +3 -0
  117. package/utils/display.js +66 -0
  118. package/utils/index.d.ts +3 -0
  119. package/utils/index.js +19 -0
  120. package/utils/module-utils.d.ts +8 -0
  121. package/utils/module-utils.js +54 -0
@@ -0,0 +1,7 @@
1
+ import { CLIOptions, Inquirerer } from 'inquirerer';
2
+ declare const _default: (argv: Partial<Record<string, any>>, prompter: Inquirerer, _options: CLIOptions) => Promise<{
3
+ [x: string]: any;
4
+ } | {
5
+ cwd: string;
6
+ }>;
7
+ export default _default;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const module_1 = __importDefault(require("./module"));
7
+ const workspace_1 = __importDefault(require("./workspace"));
8
+ const initUsageText = `
9
+ LaunchQL Init Command:
10
+
11
+ lql init [OPTIONS]
12
+
13
+ Initialize LaunchQL workspace or module.
14
+
15
+ Options:
16
+ --help, -h Show this help message
17
+ --workspace Initialize workspace instead of module
18
+ --cwd <directory> Working directory (default: current directory)
19
+ --repo <repo> Use templates from GitHub repository (e.g., owner/repo)
20
+ --template-path <path> Use templates from local path
21
+ --from-branch <branch> Specify branch when using --repo (default: main)
22
+
23
+ Examples:
24
+ lql init Initialize new module in existing workspace
25
+ lql init --workspace Initialize new workspace
26
+ lql init --repo owner/repo Use templates from GitHub repository
27
+ lql init --template-path ./custom-templates Use templates from local path
28
+ lql init --repo owner/repo --from-branch develop Use specific branch
29
+ `;
30
+ exports.default = async (argv, prompter, _options) => {
31
+ // Show usage if explicitly requested
32
+ if (argv.help || argv.h) {
33
+ console.log(initUsageText);
34
+ process.exit(0);
35
+ }
36
+ return handlePromptFlow(argv, prompter);
37
+ };
38
+ async function handlePromptFlow(argv, prompter) {
39
+ const { workspace } = argv;
40
+ switch (workspace) {
41
+ case true:
42
+ return (0, workspace_1.default)(argv, prompter);
43
+ case false:
44
+ default:
45
+ return (0, module_1.default)(argv, prompter);
46
+ }
47
+ }
@@ -0,0 +1,4 @@
1
+ import { Inquirerer } from 'inquirerer';
2
+ export default function runModuleSetup(argv: Partial<Record<string, any>>, prompter: Inquirerer): Promise<{
3
+ [x: string]: any;
4
+ }>;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = runModuleSetup;
4
+ const core_1 = require("@launchql/core");
5
+ const logger_1 = require("@launchql/logger");
6
+ const types_1 = require("@launchql/types");
7
+ const log = new logger_1.Logger('module-init');
8
+ async function runModuleSetup(argv, prompter) {
9
+ const { email, username } = (0, types_1.getGitConfigInfo)();
10
+ const { cwd = process.cwd() } = argv;
11
+ const project = new core_1.LaunchQLPackage(cwd);
12
+ if (!project.workspacePath) {
13
+ log.error('Not inside a LaunchQL workspace.');
14
+ throw types_1.errors.NOT_IN_WORKSPACE({});
15
+ }
16
+ if (!project.isInsideAllowedDirs(cwd) && !project.isInWorkspace()) {
17
+ log.error('You must be inside one of the workspace packages.');
18
+ throw types_1.errors.NOT_IN_WORKSPACE_MODULE({});
19
+ }
20
+ const availExtensions = project.getAvailableModules();
21
+ const moduleQuestions = [
22
+ {
23
+ name: 'MODULENAME',
24
+ message: 'Enter the module name',
25
+ required: true,
26
+ type: 'text',
27
+ },
28
+ {
29
+ name: 'extensions',
30
+ message: 'Which extensions?',
31
+ options: availExtensions,
32
+ type: 'checkbox',
33
+ allowCustomOptions: true,
34
+ required: true,
35
+ },
36
+ ];
37
+ const answers = await prompter.prompt(argv, moduleQuestions);
38
+ const modName = (0, core_1.sluggify)(answers.MODULENAME);
39
+ const extensions = answers.extensions
40
+ .filter((opt) => opt.selected)
41
+ .map((opt) => opt.name);
42
+ // Determine template source
43
+ let templateSource;
44
+ if (argv.repo) {
45
+ templateSource = {
46
+ type: 'github',
47
+ path: argv.repo,
48
+ branch: argv.fromBranch
49
+ };
50
+ log.info(`Loading templates from GitHub repository: ${argv.repo}`);
51
+ }
52
+ else if (argv.templatePath) {
53
+ templateSource = {
54
+ type: 'local',
55
+ path: argv.templatePath
56
+ };
57
+ log.info(`Loading templates from local path: ${argv.templatePath}`);
58
+ }
59
+ project.initModule({
60
+ ...argv,
61
+ ...answers,
62
+ name: modName,
63
+ // @ts-ignore
64
+ USERFULLNAME: username,
65
+ USEREMAIL: email,
66
+ extensions,
67
+ templateSource
68
+ });
69
+ log.success(`Initialized module: ${modName}`);
70
+ return { ...argv, ...answers };
71
+ }
@@ -0,0 +1,4 @@
1
+ import { Inquirerer } from 'inquirerer';
2
+ export default function runWorkspaceSetup(argv: Partial<Record<string, any>>, prompter: Inquirerer): Promise<{
3
+ cwd: string;
4
+ }>;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = runWorkspaceSetup;
7
+ const core_1 = require("@launchql/core");
8
+ const logger_1 = require("@launchql/logger");
9
+ // @ts-ignore - TypeScript module resolution issue with @launchql/templatizer
10
+ const templatizer_1 = require("@launchql/templatizer");
11
+ const fs_1 = require("fs");
12
+ const path_1 = __importDefault(require("path"));
13
+ const log = new logger_1.Logger('workspace-init');
14
+ async function runWorkspaceSetup(argv, prompter) {
15
+ const workspaceQuestions = [
16
+ {
17
+ name: 'name',
18
+ message: 'Enter workspace name',
19
+ required: true,
20
+ type: 'text',
21
+ }
22
+ ];
23
+ const answers = await prompter.prompt(argv, workspaceQuestions);
24
+ const { cwd } = argv;
25
+ const targetPath = path_1.default.join(cwd, (0, core_1.sluggify)(answers.name));
26
+ (0, fs_1.mkdirSync)(targetPath, { recursive: true });
27
+ log.success(`Created workspace directory: ${targetPath}`);
28
+ // Determine template source
29
+ let templates = templatizer_1.workspaceTemplate;
30
+ if (argv.repo) {
31
+ const source = {
32
+ type: 'github',
33
+ path: argv.repo,
34
+ branch: argv.fromBranch
35
+ };
36
+ log.info(`Loading templates from GitHub repository: ${argv.repo}`);
37
+ const compiledTemplates = (0, templatizer_1.loadTemplates)(source, 'workspace');
38
+ templates = compiledTemplates.map((t) => t.render);
39
+ }
40
+ else if (argv.templatePath) {
41
+ const source = {
42
+ type: 'local',
43
+ path: argv.templatePath
44
+ };
45
+ log.info(`Loading templates from local path: ${argv.templatePath}`);
46
+ const compiledTemplates = (0, templatizer_1.loadTemplates)(source, 'workspace');
47
+ templates = compiledTemplates.map((t) => t.render);
48
+ }
49
+ (0, templatizer_1.writeRenderedTemplates)(templates, targetPath, { ...argv, ...answers });
50
+ log.success('Workspace templates rendered.');
51
+ return { ...argv, ...answers, cwd: targetPath };
52
+ }
@@ -0,0 +1,4 @@
1
+ import { CLIOptions, Inquirerer } from 'inquirerer';
2
+ import { ParsedArgs } from 'minimist';
3
+ declare const _default: (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => Promise<void>;
4
+ export default _default;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@launchql/core");
4
+ const installUsageText = `
5
+ LaunchQL Install Command:
6
+
7
+ lql install <package>...
8
+
9
+ Install LaunchQL modules into current module.
10
+
11
+ Arguments:
12
+ package One or more package names to install
13
+
14
+ Options:
15
+ --help, -h Show this help message
16
+ --cwd <directory> Working directory (default: current directory)
17
+
18
+ Examples:
19
+ lql install @launchql/base32 Install single package
20
+ lql install @launchql/base32 @launchql/utils Install multiple packages
21
+ `;
22
+ exports.default = async (argv, prompter, _options) => {
23
+ // Show usage if explicitly requested
24
+ if (argv.help || argv.h) {
25
+ console.log(installUsageText);
26
+ process.exit(0);
27
+ }
28
+ const { cwd = process.cwd() } = argv;
29
+ const project = new core_1.LaunchQLPackage(cwd);
30
+ if (!project.isInModule()) {
31
+ throw new Error('You must run this command inside a LaunchQL module.');
32
+ }
33
+ if (argv._.length === 0) {
34
+ throw new Error('You must provide a package name to install, e.g. `@launchql/base32`');
35
+ }
36
+ await project.installModules(...argv._);
37
+ };
@@ -0,0 +1,3 @@
1
+ import { CLIOptions, Inquirerer } from 'inquirerer';
2
+ declare const _default: (argv: Partial<Record<string, any>>, prompter: Inquirerer, _options: CLIOptions) => Promise<void>;
3
+ export default _default;
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const logger_1 = require("@launchql/logger");
4
+ const pg_cache_1 = require("pg-cache");
5
+ const log = new logger_1.Logger('db-kill');
6
+ const killUsageText = `
7
+ LaunchQL Kill Command:
8
+
9
+ lql kill [OPTIONS]
10
+
11
+ Terminate database connections and optionally drop databases.
12
+
13
+ Options:
14
+ --help, -h Show this help message
15
+ --drop Drop databases after killing connections (default: true)
16
+ --no-drop Only kill connections, don't drop databases
17
+ --pattern <pattern> Pattern to match database names (supports SQL LIKE syntax)
18
+ --cwd <directory> Working directory (default: current directory)
19
+
20
+ Examples:
21
+ lql kill Kill connections and drop selected databases (interactive)
22
+ lql kill --no-drop Only kill connections, preserve databases (interactive)
23
+ lql kill --pattern test_% Kill connections to databases matching 'test_%' pattern
24
+ lql kill --pattern %dev --no-drop Kill connections to databases ending with 'dev' but don't drop
25
+ `;
26
+ exports.default = async (argv, prompter, _options) => {
27
+ // Show usage if explicitly requested
28
+ if (argv.help || argv.h) {
29
+ console.log(killUsageText);
30
+ process.exit(0);
31
+ }
32
+ const db = await (0, pg_cache_1.getPgPool)({
33
+ database: 'postgres'
34
+ });
35
+ let selectedDbNames;
36
+ if (argv.pattern) {
37
+ // Pattern mode: automatically find databases matching the pattern
38
+ const databasesResult = await db.query(`
39
+ SELECT datname FROM pg_catalog.pg_database
40
+ WHERE datistemplate = FALSE AND datname NOT IN ('postgres')
41
+ AND datname !~ '^pg_' AND datname LIKE $1;
42
+ `, [argv.pattern]);
43
+ if (!databasesResult.rows.length) {
44
+ log.info(`ā„¹ļø No databases found matching pattern "${argv.pattern}". Exiting.`);
45
+ return;
46
+ }
47
+ selectedDbNames = databasesResult.rows.map(row => row.datname);
48
+ log.info(`šŸŽÆ Found ${selectedDbNames.length} database(s) matching pattern "${argv.pattern}": ${selectedDbNames.join(', ')}`);
49
+ }
50
+ else {
51
+ // Interactive mode: prompt user to select databases
52
+ const databasesResult = await db.query(`
53
+ SELECT datname FROM pg_catalog.pg_database
54
+ WHERE datistemplate = FALSE AND datname NOT IN ('postgres')
55
+ AND datname !~ '^pg_';
56
+ `);
57
+ if (!databasesResult.rows.length) {
58
+ log.info('ā„¹ļø No databases found to process. Exiting.');
59
+ return;
60
+ }
61
+ let databases;
62
+ ({ databases } = await prompter.prompt(argv, [
63
+ {
64
+ type: 'checkbox',
65
+ name: 'databases',
66
+ message: 'Select database(s) to terminate connections and optionally drop',
67
+ options: databasesResult.rows.map(row => row.datname),
68
+ required: true
69
+ }
70
+ ]));
71
+ selectedDbNames = databases.filter(d => d.selected).map(d => d.value);
72
+ }
73
+ const actionText = argv.drop === false ? 'kill connections to' : 'kill connections and DROP';
74
+ const patternText = argv.pattern ? ` (matched by pattern "${argv.pattern}")` : '';
75
+ const { yes } = await prompter.prompt(argv, [
76
+ {
77
+ type: 'confirm',
78
+ name: 'yes',
79
+ message: `Are you sure you want to ${actionText}: ${selectedDbNames.join(', ')}${patternText}?`,
80
+ default: false
81
+ }
82
+ ]);
83
+ if (!yes) {
84
+ log.info('āŒ Aborted. No actions were taken.');
85
+ return;
86
+ }
87
+ for (const dbname of selectedDbNames) {
88
+ const killResult = await db.query(`
89
+ SELECT pg_terminate_backend(pid)
90
+ FROM pg_stat_activity
91
+ WHERE datname = $1 AND pid <> pg_backend_pid();
92
+ `, [dbname]);
93
+ log.warn(`šŸ’€ Terminated ${killResult.rowCount} connection(s) to "${dbname}".`);
94
+ if (argv.drop === false) {
95
+ log.info(`āš ļø Skipping DROP for "${dbname}" due to --no-drop flag.`);
96
+ continue;
97
+ }
98
+ try {
99
+ await db.query(`DROP DATABASE "${dbname}";`);
100
+ log.success(`šŸ—‘ļø Dropped database "${dbname}" successfully.`);
101
+ }
102
+ catch (err) {
103
+ log.error(`āŒ Failed to drop "${dbname}": ${err.message}`);
104
+ }
105
+ }
106
+ log.success('āœ… Done processing databases.');
107
+ };
@@ -0,0 +1,4 @@
1
+ import { CLIOptions, Inquirerer } from 'inquirerer';
2
+ import { ParsedArgs } from 'minimist';
3
+ declare const _default: (argv: Partial<ParsedArgs>, prompter: Inquirerer, options: CLIOptions) => Promise<void>;
4
+ export default _default;
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@launchql/core");
4
+ const core_2 = require("@launchql/core");
5
+ const logger_1 = require("@launchql/logger");
6
+ const fs_1 = require("fs");
7
+ const path_1 = require("path");
8
+ const pg_env_1 = require("pg-env");
9
+ const database_1 = require("../../utils/database");
10
+ const log = new logger_1.Logger('migrate-deps');
11
+ exports.default = async (argv, prompter, options) => {
12
+ const cwd = argv.cwd || process.cwd();
13
+ const planPath = (0, path_1.join)(cwd, 'launchql.plan');
14
+ if (!(0, fs_1.existsSync)(planPath)) {
15
+ log.error(`No launchql.plan found in ${cwd}`);
16
+ process.exit(1);
17
+ }
18
+ // Get specific change to analyze
19
+ let changeName = argv._?.[0] || argv.change;
20
+ const planResult = (0, core_2.parsePlanFile)(planPath);
21
+ if (!planResult.data || planResult.errors.length > 0) {
22
+ log.error('Failed to parse plan file:', planResult.errors);
23
+ process.exit(1);
24
+ }
25
+ const plan = planResult.data;
26
+ const allChanges = plan.changes;
27
+ // If no change specified, prompt
28
+ if (!changeName && !argv.all) {
29
+ const answer = await prompter.prompt(argv, [
30
+ {
31
+ type: 'autocomplete',
32
+ name: 'change',
33
+ message: 'Which change do you want to analyze?',
34
+ options: allChanges.map(c => ({
35
+ name: c.name,
36
+ value: c.name,
37
+ description: c.dependencies.length > 0 ? `Depends on: ${c.dependencies.join(', ')}` : 'No dependencies'
38
+ }))
39
+ }
40
+ ]);
41
+ changeName = answer.change;
42
+ }
43
+ try {
44
+ if (argv.all) {
45
+ // Show dependency graph for all changes
46
+ console.log('\nšŸ”— Dependency Graph\n');
47
+ console.log(`Package: ${plan.package}`);
48
+ console.log(`Total Changes: ${allChanges.length}\n`);
49
+ // Build dependency tree
50
+ const dependencyTree = buildDependencyTree(allChanges);
51
+ // Show changes with no dependencies first (roots)
52
+ const roots = allChanges.filter(c => c.dependencies.length === 0);
53
+ console.log('šŸ“Œ Root Changes (no dependencies):\n');
54
+ roots.forEach(change => {
55
+ console.log(` • ${change.name}`);
56
+ showDependents(change.name, dependencyTree, ' ');
57
+ });
58
+ // Show orphaned changes (have dependencies but aren't depended on)
59
+ const orphans = allChanges.filter(c => c.dependencies.length > 0 &&
60
+ !allChanges.some(other => other.dependencies.includes(c.name)));
61
+ if (orphans.length > 0) {
62
+ console.log('\nšŸ”ø Leaf Changes (not depended on by others):\n');
63
+ orphans.forEach(change => {
64
+ console.log(` • ${change.name} → [${change.dependencies.join(', ')}]`);
65
+ });
66
+ }
67
+ }
68
+ else {
69
+ // Show dependencies for specific change
70
+ const change = allChanges.find(c => c.name === changeName);
71
+ if (!change) {
72
+ log.error(`Change '${changeName}' not found in plan file`);
73
+ process.exit(1);
74
+ }
75
+ console.log(`\nšŸ” Dependency Analysis: ${changeName}\n`);
76
+ // Direct dependencies
77
+ if (change.dependencies.length > 0) {
78
+ console.log('šŸ“„ Direct Dependencies:');
79
+ change.dependencies.forEach(dep => {
80
+ console.log(` • ${dep}`);
81
+ });
82
+ }
83
+ else {
84
+ console.log('šŸ“„ Direct Dependencies: None');
85
+ }
86
+ // All dependencies (recursive)
87
+ const allDeps = getAllDependencies(change.name, allChanges);
88
+ if (allDeps.size > 0) {
89
+ console.log(`\nšŸ“¦ All Dependencies (${allDeps.size} total):`);
90
+ Array.from(allDeps).forEach(dep => {
91
+ console.log(` • ${dep}`);
92
+ });
93
+ }
94
+ // Dependents (what depends on this)
95
+ const dependents = allChanges.filter(c => c.dependencies.includes(changeName));
96
+ if (dependents.length > 0) {
97
+ console.log(`\nšŸ“¤ Depended on by (${dependents.length} changes):`);
98
+ dependents.forEach(dep => {
99
+ console.log(` • ${dep.name}`);
100
+ });
101
+ }
102
+ else {
103
+ console.log('\nšŸ“¤ Depended on by: None');
104
+ }
105
+ // Check deployment status if connected to database
106
+ const pgEnv = (0, pg_env_1.getPgEnvOptions)();
107
+ const targetDatabase = await (0, database_1.getTargetDatabase)(argv, prompter, {
108
+ message: 'Select database to check deployment status'
109
+ });
110
+ const client = new core_1.LaunchQLMigrate({
111
+ host: pgEnv.host,
112
+ port: pgEnv.port,
113
+ user: pgEnv.user,
114
+ password: pgEnv.password,
115
+ database: pgEnv.database
116
+ });
117
+ try {
118
+ const deployedChanges = await client.getDeployedChanges(targetDatabase, plan.package);
119
+ const deployedMap = new Map(deployedChanges.map(c => [c.change_name, c]));
120
+ console.log('\nšŸ“Š Deployment Status:');
121
+ // Check if this change is deployed
122
+ const isDeployed = deployedMap.has(changeName);
123
+ console.log(` This change: ${isDeployed ? 'āœ… Deployed' : 'ā³ Not deployed'}`);
124
+ // Check dependencies
125
+ const undeployedDeps = Array.from(allDeps).filter(dep => !deployedMap.has(dep));
126
+ if (undeployedDeps.length > 0) {
127
+ console.log(` āš ļø Undeployed dependencies: ${undeployedDeps.join(', ')}`);
128
+ }
129
+ else if (allDeps.size > 0) {
130
+ console.log(' āœ… All dependencies deployed');
131
+ }
132
+ // Check dependents
133
+ const deployedDependents = dependents.filter(d => deployedMap.has(d.name));
134
+ if (deployedDependents.length > 0) {
135
+ console.log(` āš ļø Deployed dependents: ${deployedDependents.map(d => d.name).join(', ')}`);
136
+ }
137
+ }
138
+ catch (dbError) {
139
+ // Database connection optional for dependency analysis
140
+ log.debug('Could not connect to database for deployment status');
141
+ }
142
+ }
143
+ }
144
+ catch (error) {
145
+ log.error('Failed to analyze dependencies:', error);
146
+ process.exit(1);
147
+ }
148
+ };
149
+ function buildDependencyTree(changes) {
150
+ const tree = new Map();
151
+ changes.forEach(change => {
152
+ change.dependencies.forEach((dep) => {
153
+ if (!tree.has(dep)) {
154
+ tree.set(dep, []);
155
+ }
156
+ tree.get(dep).push(change.name);
157
+ });
158
+ });
159
+ return tree;
160
+ }
161
+ function showDependents(changeName, tree, indent) {
162
+ const dependents = tree.get(changeName) || [];
163
+ dependents.forEach(dep => {
164
+ console.log(`${indent}└─ ${dep}`);
165
+ showDependents(dep, tree, indent + ' ');
166
+ });
167
+ }
168
+ function getAllDependencies(changeName, changes) {
169
+ const deps = new Set();
170
+ const change = changes.find(c => c.name === changeName);
171
+ if (!change)
172
+ return deps;
173
+ function addDeps(change) {
174
+ change.dependencies.forEach((dep) => {
175
+ if (!deps.has(dep)) {
176
+ deps.add(dep);
177
+ const depChange = changes.find(c => c.name === dep);
178
+ if (depChange) {
179
+ addDeps(depChange);
180
+ }
181
+ }
182
+ });
183
+ }
184
+ addDeps(change);
185
+ return deps;
186
+ }
@@ -0,0 +1,4 @@
1
+ import { CLIOptions, Inquirerer } from 'inquirerer';
2
+ import { ParsedArgs } from 'minimist';
3
+ declare const _default: (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => Promise<Partial<ParsedArgs>>;
4
+ export default _default;
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@launchql/core");
4
+ const logger_1 = require("@launchql/logger");
5
+ const pg_env_1 = require("pg-env");
6
+ const database_1 = require("../../utils/database");
7
+ const log = new logger_1.Logger('migrate-init');
8
+ exports.default = async (argv, prompter, _options) => {
9
+ const pgEnv = (0, pg_env_1.getPgEnvOptions)();
10
+ // Get target database
11
+ const database = await (0, database_1.getTargetDatabase)(argv, prompter, {
12
+ message: 'Select database to initialize migration tracking'
13
+ });
14
+ const questions = [
15
+ {
16
+ name: 'yes',
17
+ type: 'confirm',
18
+ message: `Initialize LaunchQL migration schema in database "${database}"?`,
19
+ required: true
20
+ }
21
+ ];
22
+ const { yes } = await prompter.prompt(argv, questions);
23
+ if (!yes) {
24
+ log.info('Operation cancelled.');
25
+ return;
26
+ }
27
+ log.info(`Initializing migration schema in database ${database}...`);
28
+ const config = {
29
+ host: pgEnv.host,
30
+ port: pgEnv.port,
31
+ user: pgEnv.user,
32
+ password: pgEnv.password,
33
+ database
34
+ };
35
+ const client = new core_1.LaunchQLMigrate(config);
36
+ try {
37
+ await client.initialize();
38
+ log.success('Migration schema initialized successfully.');
39
+ // Check if there's an existing Sqitch deployment to import
40
+ const hasSquitch = await client.hasSqitchTables();
41
+ if (hasSquitch) {
42
+ const { importSquitch } = await prompter.prompt(argv, [
43
+ {
44
+ name: 'importSquitch',
45
+ type: 'confirm',
46
+ message: 'Existing Sqitch deployment detected. Import it?',
47
+ required: true
48
+ }
49
+ ]);
50
+ if (importSquitch) {
51
+ log.info('Importing Sqitch deployment history...');
52
+ await client.importFromSqitch();
53
+ log.success('Sqitch deployment imported successfully.');
54
+ }
55
+ }
56
+ }
57
+ catch (error) {
58
+ log.error(`Failed to initialize migration schema: ${error instanceof Error ? error.message : error}`);
59
+ throw error;
60
+ }
61
+ finally {
62
+ await client.close();
63
+ }
64
+ return argv;
65
+ };
@@ -0,0 +1,4 @@
1
+ import { CLIOptions, Inquirerer } from 'inquirerer';
2
+ import { ParsedArgs } from 'minimist';
3
+ declare const _default: (argv: Partial<ParsedArgs>, prompter: Inquirerer, options: CLIOptions) => Promise<void>;
4
+ export default _default;