pgpm 5.32.0 → 5.34.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.
@@ -7,6 +7,7 @@ export interface BoilerplateSource {
7
7
  branch?: string;
8
8
  dir?: string;
9
9
  }
10
+ export declare function isScaffoldableInPlace(dir: string): boolean;
10
11
  /**
11
12
  * Resolve the template repo for an `init` invocation from its flags.
12
13
  *
@@ -3,12 +3,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.isScaffoldableInPlace = isScaffoldableInPlace;
6
7
  exports.resolveInitTemplateRepo = resolveInitTemplateRepo;
7
8
  exports.persistBoilerplateSource = persistBoilerplateSource;
8
9
  exports.readBoilerplateSource = readBoilerplateSource;
9
10
  const core_1 = require("@pgpmjs/core");
10
11
  const fs_1 = __importDefault(require("fs"));
11
12
  const path_1 = __importDefault(require("path"));
13
+ function isScaffoldableInPlace(dir) {
14
+ try {
15
+ return fs_1.default.statSync(dir).isDirectory() &&
16
+ fs_1.default.readdirSync(dir).filter((entry) => entry !== '.git').length === 0;
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ }
12
22
  /**
13
23
  * Resolve the template repo for an `init` invocation from its flags.
14
24
  *
@@ -36,6 +36,7 @@ Options:
36
36
  Sugar for --repo https://github.com/constructive-io/pglite-boilerplates.git.
37
37
  Recorded on the workspace so later \`init\` calls inherit it automatically.
38
38
  --from-branch <branch> Branch/tag to use when cloning repo
39
+ --refresh, --no-cache Re-fetch the template repo instead of using the cached copy
39
40
  --dir <variant> Template variant directory (e.g., supabase, drizzle)
40
41
  --template, -t <path> Full template path (e.g., pnpm/module) - combines dir and fromPath
41
42
  --boilerplate Prompt to select from available boilerplates
@@ -45,6 +46,8 @@ Options:
45
46
  Add them later instead with \`${binaryName} extension\`.
46
47
  --with-extensions Prompt interactively for extensions during module init
47
48
 
49
+ Non-interactive runs must answer every question with flags; use --no-tty.
50
+
48
51
  Examples:
49
52
  ${binaryName} init Initialize new module (default, no extensions)
50
53
  ${binaryName} init workspace Initialize new workspace
@@ -80,6 +83,10 @@ async function handleInit(argv, prompter) {
80
83
  pglite: Boolean(argv.pglite),
81
84
  });
82
85
  const branch = argv.fromBranch;
86
+ const forceRefresh = Boolean(argv.refresh ||
87
+ argv['no-cache'] ||
88
+ argv.noCache ||
89
+ argv.cache === false);
83
90
  const noTty = (0, utils_1.isNoTtyRequested)(argv);
84
91
  const useBoilerplatePrompt = Boolean(argv.boilerplate);
85
92
  const createWorkspace = Boolean(argv.createWorkspace || argv['create-workspace'] || argv.w);
@@ -105,6 +112,13 @@ async function handleInit(argv, prompter) {
105
112
  }
106
113
  // Handle --boilerplate flag: separate path from regular init
107
114
  if (useBoilerplatePrompt) {
115
+ const source = (0, core_1.refreshTemplateCache)({
116
+ templateRepo,
117
+ branch,
118
+ toolName: core_1.DEFAULT_TEMPLATE_TOOL_NAME,
119
+ cwd,
120
+ force: forceRefresh,
121
+ });
108
122
  return handleBoilerplateInit(argv, prompter, {
109
123
  positionalFromPath,
110
124
  templateRepo,
@@ -113,12 +127,21 @@ async function handleInit(argv, prompter) {
113
127
  noTty,
114
128
  cwd,
115
129
  useNpxSkills,
130
+ forceRefresh,
131
+ source,
116
132
  });
117
133
  }
118
134
  // Regular init path: --template takes precedence, then positional arg, then default to 'module'
119
135
  const fromPath = templateFromPath || positionalFromPath || 'module';
120
136
  // Track if user explicitly requested module (e.g., `pgpm init module` or `--template pnpm/module`)
121
137
  const wasExplicitModuleRequest = positionalFromPath === 'module' || templateFromPath === 'module';
138
+ const source = (0, core_1.refreshTemplateCache)({
139
+ templateRepo,
140
+ branch,
141
+ toolName: core_1.DEFAULT_TEMPLATE_TOOL_NAME,
142
+ cwd,
143
+ force: forceRefresh,
144
+ });
122
145
  // Inspect the template to get its type
123
146
  const inspection = (0, core_1.inspectTemplate)({
124
147
  fromPath,
@@ -140,6 +163,8 @@ async function handleInit(argv, prompter) {
140
163
  cwd,
141
164
  useNpxSkills,
142
165
  repoWasExplicit,
166
+ source,
167
+ forceRefresh,
143
168
  });
144
169
  }
145
170
  // Default to module init (for 'module' type, 'generic' type, or unknown types)
@@ -154,6 +179,8 @@ async function handleInit(argv, prompter) {
154
179
  createWorkspace,
155
180
  useNpxSkills,
156
181
  repoWasExplicit,
182
+ source,
183
+ forceRefresh,
157
184
  }, wasExplicitModuleRequest);
158
185
  }
159
186
  async function handleBoilerplateInit(argv, prompter, ctx) {
@@ -220,6 +247,7 @@ async function handleBoilerplateInit(argv, prompter, ctx) {
220
247
  noTty: ctx.noTty,
221
248
  cwd: ctx.cwd,
222
249
  useNpxSkills: ctx.useNpxSkills,
250
+ source: ctx.source,
223
251
  });
224
252
  }
225
253
  // Default to module init (for 'module' type, 'generic' type, or unknown types)
@@ -233,6 +261,8 @@ async function handleBoilerplateInit(argv, prompter, ctx) {
233
261
  cwd: ctx.cwd,
234
262
  requiresWorkspace: inspection.config?.requiresWorkspace,
235
263
  useNpxSkills: ctx.useNpxSkills,
264
+ forceRefresh: ctx.forceRefresh,
265
+ source: ctx.source,
236
266
  }, true);
237
267
  }
238
268
  function installSkills(skills, cwd, useNpxSkills) {
@@ -303,7 +333,20 @@ async function handleWorkspaceInit(argv, prompter, ctx) {
303
333
  }
304
334
  ];
305
335
  const answers = await prompter.prompt(argv, workspaceQuestions);
306
- const targetPath = path_1.default.join(ctx.cwd, (0, core_1.sluggify)(answers.name));
336
+ let targetPath = path_1.default.join(ctx.cwd, (0, core_1.sluggify)(answers.name));
337
+ const slug = (0, core_1.sluggify)(answers.name);
338
+ const inPlace = path_1.default.basename(ctx.cwd) === slug && (0, boilerplate_1.isScaffoldableInPlace)(ctx.cwd);
339
+ if (inPlace) {
340
+ targetPath = ctx.cwd;
341
+ process.stdout.write(`Scaffolding into current directory ./ (it is empty and named "${answers.name}")\n`);
342
+ }
343
+ const source = ctx.source ?? (0, core_1.refreshTemplateCache)({
344
+ templateRepo: ctx.templateRepo,
345
+ branch: ctx.branch,
346
+ toolName: core_1.DEFAULT_TEMPLATE_TOOL_NAME,
347
+ cwd: ctx.cwd,
348
+ });
349
+ process.stdout.write(`${(0, core_1.describeTemplateSource)(source)}\n`);
307
350
  // Register workspace.dirname resolver so boilerplate templates can use it via defaultFrom/setFrom
308
351
  const dirName = path_1.default.basename(targetPath);
309
352
  (0, inquirerer_1.registerDefaultResolver)('workspace.dirname', () => dirName);
@@ -362,7 +405,9 @@ async function handleWorkspaceInit(argv, prompter, ctx) {
362
405
  installSkills(templateInfo.config.skills, targetPath, Boolean(ctx.useNpxSkills));
363
406
  }
364
407
  const relPath = path_1.default.relative(process.cwd(), targetPath);
365
- process.stdout.write(`\n✨ Enjoy!\n\ncd ./${relPath}\n`);
408
+ process.stdout.write('\n✨ Enjoy!\n');
409
+ if (relPath)
410
+ process.stdout.write(`\ncd ./${relPath}\n`);
366
411
  return { ...argv, ...answers, cwd: targetPath };
367
412
  }
368
413
  function resolveWorkspaceTemplateRepo(options) {
@@ -415,8 +460,22 @@ async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest =
415
460
  ctx.templateRepo = inherited.repo;
416
461
  ctx.branch = inherited.branch;
417
462
  ctx.dir = inherited.dir;
463
+ ctx.source = (0, core_1.refreshTemplateCache)({
464
+ templateRepo: ctx.templateRepo,
465
+ branch: ctx.branch,
466
+ toolName: core_1.DEFAULT_TEMPLATE_TOOL_NAME,
467
+ cwd: ctx.cwd,
468
+ force: ctx.forceRefresh,
469
+ });
418
470
  }
419
471
  }
472
+ const source = ctx.source ?? (0, core_1.refreshTemplateCache)({
473
+ templateRepo: ctx.templateRepo,
474
+ branch: ctx.branch,
475
+ toolName: core_1.DEFAULT_TEMPLATE_TOOL_NAME,
476
+ cwd: ctx.cwd,
477
+ force: ctx.forceRefresh,
478
+ });
420
479
  // Determine workspace requirement (defaults to 'pgpm' for backward compatibility)
421
480
  const workspaceType = ctx.requiresWorkspace ?? 'pgpm';
422
481
  // Whether this is a pgpm-managed template (creates pgpm.plan, .control files)
@@ -456,6 +515,13 @@ async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest =
456
515
  noTty: ctx.noTty,
457
516
  cwd: ctx.cwd,
458
517
  repoWasExplicit: ctx.repoWasExplicit,
518
+ source: (0, core_1.refreshTemplateCache)({
519
+ templateRepo: workspaceTemplateConfig.repo,
520
+ branch: workspaceTemplateConfig.branch,
521
+ toolName: core_1.DEFAULT_TEMPLATE_TOOL_NAME,
522
+ cwd: ctx.cwd,
523
+ force: ctx.forceRefresh,
524
+ }),
459
525
  });
460
526
  // Update context to point to new workspace and continue with module creation
461
527
  const newCwd = workspaceResult.cwd;
@@ -500,6 +566,13 @@ async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest =
500
566
  noTty: ctx.noTty,
501
567
  cwd: ctx.cwd,
502
568
  repoWasExplicit: ctx.repoWasExplicit,
569
+ source: (0, core_1.refreshTemplateCache)({
570
+ templateRepo: ctx.templateRepo,
571
+ branch: ctx.branch,
572
+ toolName: core_1.DEFAULT_TEMPLATE_TOOL_NAME,
573
+ cwd: ctx.cwd,
574
+ force: ctx.forceRefresh,
575
+ }),
503
576
  });
504
577
  }
505
578
  }
@@ -568,6 +641,7 @@ async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest =
568
641
  };
569
642
  // Determine output path based on whether we're in a workspace
570
643
  let modulePath;
644
+ process.stdout.write(`${(0, core_1.describeTemplateSource)(source)}\n`);
571
645
  if (project.workspacePath) {
572
646
  // PGPM workspace - use workspace-aware initModule
573
647
  await project.initModule({
@@ -656,6 +730,8 @@ async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest =
656
730
  installSkills(moduleTemplateInfo.config.skills, skillsCwd, Boolean(ctx.useNpxSkills));
657
731
  }
658
732
  const relPath = path_1.default.relative(process.cwd(), modulePath);
659
- process.stdout.write(`\n✨ Enjoy!\n\ncd ./${relPath}\n`);
733
+ process.stdout.write('\n✨ Enjoy!\n');
734
+ if (relPath)
735
+ process.stdout.write(`\ncd ./${relPath}\n`);
660
736
  return { ...argv, ...answers };
661
737
  }
@@ -0,0 +1,3 @@
1
+ import { CLIOptions, Inquirerer, ParsedArgs } from 'inquirerer';
2
+ declare const _default: (argv: Partial<ParsedArgs>, _prompter: Inquirerer, _options: CLIOptions) => Promise<void>;
3
+ export default _default;
package/commands/ls.js ADDED
@@ -0,0 +1,86 @@
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 core_1 = require("@pgpmjs/core");
7
+ const inquirerer_1 = require("inquirerer");
8
+ const path_1 = __importDefault(require("path"));
9
+ const lsUsageText = `
10
+ List Command:
11
+
12
+ pgpm ls [OPTIONS]
13
+
14
+ List the pgpm modules in the current workspace.
15
+
16
+ Options:
17
+ --help, -h Show this help message
18
+ --json Print JSON output
19
+ --names Print module names only
20
+ --paths Print workspace-relative module paths only
21
+ --cwd <dir> Working directory (default: current directory)
22
+
23
+ Examples:
24
+ pgpm ls
25
+ pgpm ls --names
26
+ pgpm ls --paths --json
27
+ `;
28
+ exports.default = async (argv, _prompter, _options) => {
29
+ if (argv.help || argv.h) {
30
+ console.log(lsUsageText);
31
+ process.exit(0);
32
+ }
33
+ const names = Boolean(argv.names);
34
+ const paths = Boolean(argv.paths);
35
+ const json = Boolean(argv.json);
36
+ if (names && paths) {
37
+ await (0, inquirerer_1.cliExitWithError)('--names and --paths cannot be used together.');
38
+ }
39
+ const cwd = path_1.default.resolve(argv.cwd || process.cwd());
40
+ const workspace = new core_1.PgpmPackage(cwd);
41
+ const workspacePath = workspace.getWorkspacePath();
42
+ if (!workspacePath) {
43
+ await (0, inquirerer_1.cliExitWithError)(`Not inside a pgpm workspace: ${cwd}. Pass --cwd <workspace-directory>.`);
44
+ }
45
+ const entries = Object.entries(workspace.getModuleMap())
46
+ .sort(([left], [right]) => left.localeCompare(right))
47
+ .map(([name, module]) => ({
48
+ name,
49
+ version: module.version || 'unknown',
50
+ path: module.path,
51
+ requires: [...module.requires]
52
+ }));
53
+ if (json) {
54
+ if (names) {
55
+ process.stdout.write(JSON.stringify(entries.map(entry => entry.name)));
56
+ return;
57
+ }
58
+ if (paths) {
59
+ process.stdout.write(JSON.stringify(entries.map(entry => entry.path)));
60
+ return;
61
+ }
62
+ process.stdout.write(`${JSON.stringify(entries, null, 2)}\n`);
63
+ return;
64
+ }
65
+ if (names) {
66
+ process.stdout.write(entries.map(entry => entry.name).join('\n'));
67
+ if (entries.length > 0)
68
+ process.stdout.write('\n');
69
+ return;
70
+ }
71
+ if (paths) {
72
+ process.stdout.write(entries.map(entry => entry.path).join('\n'));
73
+ if (entries.length > 0)
74
+ process.stdout.write('\n');
75
+ return;
76
+ }
77
+ if (entries.length === 0) {
78
+ process.stdout.write('No modules found.\n');
79
+ return;
80
+ }
81
+ const nameWidth = Math.max(...entries.map(entry => entry.name.length));
82
+ const versionWidth = Math.max(...entries.map(entry => entry.version.length));
83
+ process.stdout.write(entries
84
+ .map(entry => `${entry.name.padEnd(nameWidth)} ${entry.version.padEnd(versionWidth)} ${entry.path}`)
85
+ .join('\n') + '\n');
86
+ };
package/commands.js CHANGED
@@ -24,6 +24,7 @@ const import_1 = __importDefault(require("./commands/import"));
24
24
  const init_1 = __importDefault(require("./commands/init"));
25
25
  const install_1 = __importDefault(require("./commands/install"));
26
26
  const kill_1 = __importDefault(require("./commands/kill"));
27
+ const ls_1 = __importDefault(require("./commands/ls"));
27
28
  const materialize_1 = __importDefault(require("./commands/materialize"));
28
29
  const migrate_1 = __importDefault(require("./commands/migrate"));
29
30
  const package_1 = __importDefault(require("./commands/package"));
@@ -59,6 +60,8 @@ const ENGINE_EXEMPT_COMMANDS = new Set([
59
60
  'import',
60
61
  'init',
61
62
  'install',
63
+ 'ls',
64
+ 'list',
62
65
  'package',
63
66
  'materialize',
64
67
  'plan',
@@ -107,6 +110,8 @@ const createPgpmCommandMap = (skipPgTeardown = false) => {
107
110
  tag: pgt(tag_1.default),
108
111
  kill: pgt(kill_1.default),
109
112
  install: pgt(install_1.default),
113
+ ls: ls_1.default,
114
+ list: ls_1.default,
110
115
  migrate: pgt(migrate_1.default),
111
116
  materialize: materialize_1.default,
112
117
  analyze: pgt(analyze_1.default),
@@ -1,6 +1,15 @@
1
1
  import { DEFAULT_TEMPLATE_REPO, PgpmPackage, TEMPLATE_REPOS } from '@pgpmjs/core';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
+ export function isScaffoldableInPlace(dir) {
5
+ try {
6
+ return fs.statSync(dir).isDirectory() &&
7
+ fs.readdirSync(dir).filter((entry) => entry !== '.git').length === 0;
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
4
13
  /**
5
14
  * Resolve the template repo for an `init` invocation from its flags.
6
15
  *
@@ -1,11 +1,11 @@
1
- import { DEFAULT_TEMPLATE_REPO, DEFAULT_TEMPLATE_TOOL_NAME, inspectTemplate, PgpmPackage, resolveBoilerplateBaseDir, scaffoldTemplate, scanBoilerplates, SkillInstaller, sluggify, spawnSyncChecked, } from '@pgpmjs/core';
1
+ import { DEFAULT_TEMPLATE_REPO, DEFAULT_TEMPLATE_TOOL_NAME, describeTemplateSource, inspectTemplate, PgpmPackage, refreshTemplateCache, resolveBoilerplateBaseDir, scaffoldTemplate, scanBoilerplates, SkillInstaller, sluggify, spawnSyncChecked, } from '@pgpmjs/core';
2
2
  import { resolveWorkspaceByType } from '@pgpmjs/env';
3
3
  import { errors } from '@pgpmjs/types';
4
4
  import fs from 'fs';
5
5
  import { registerDefaultResolver } from 'inquirerer';
6
6
  import path from 'path';
7
7
  import { isNoTtyRequested } from '../../utils';
8
- import { persistBoilerplateSource, readBoilerplateSource, resolveInitTemplateRepo, } from './boilerplate';
8
+ import { isScaffoldableInPlace, persistBoilerplateSource, readBoilerplateSource, resolveInitTemplateRepo, } from './boilerplate';
9
9
  const DEFAULT_MOTD = `
10
10
  | _ _
11
11
  === |.===. '\\-//\`
@@ -30,6 +30,7 @@ Options:
30
30
  Sugar for --repo https://github.com/constructive-io/pglite-boilerplates.git.
31
31
  Recorded on the workspace so later \`init\` calls inherit it automatically.
32
32
  --from-branch <branch> Branch/tag to use when cloning repo
33
+ --refresh, --no-cache Re-fetch the template repo instead of using the cached copy
33
34
  --dir <variant> Template variant directory (e.g., supabase, drizzle)
34
35
  --template, -t <path> Full template path (e.g., pnpm/module) - combines dir and fromPath
35
36
  --boilerplate Prompt to select from available boilerplates
@@ -39,6 +40,8 @@ Options:
39
40
  Add them later instead with \`${binaryName} extension\`.
40
41
  --with-extensions Prompt interactively for extensions during module init
41
42
 
43
+ Non-interactive runs must answer every question with flags; use --no-tty.
44
+
42
45
  Examples:
43
46
  ${binaryName} init Initialize new module (default, no extensions)
44
47
  ${binaryName} init workspace Initialize new workspace
@@ -73,6 +76,10 @@ async function handleInit(argv, prompter) {
73
76
  pglite: Boolean(argv.pglite),
74
77
  });
75
78
  const branch = argv.fromBranch;
79
+ const forceRefresh = Boolean(argv.refresh ||
80
+ argv['no-cache'] ||
81
+ argv.noCache ||
82
+ argv.cache === false);
76
83
  const noTty = isNoTtyRequested(argv);
77
84
  const useBoilerplatePrompt = Boolean(argv.boilerplate);
78
85
  const createWorkspace = Boolean(argv.createWorkspace || argv['create-workspace'] || argv.w);
@@ -98,6 +105,13 @@ async function handleInit(argv, prompter) {
98
105
  }
99
106
  // Handle --boilerplate flag: separate path from regular init
100
107
  if (useBoilerplatePrompt) {
108
+ const source = refreshTemplateCache({
109
+ templateRepo,
110
+ branch,
111
+ toolName: DEFAULT_TEMPLATE_TOOL_NAME,
112
+ cwd,
113
+ force: forceRefresh,
114
+ });
101
115
  return handleBoilerplateInit(argv, prompter, {
102
116
  positionalFromPath,
103
117
  templateRepo,
@@ -106,12 +120,21 @@ async function handleInit(argv, prompter) {
106
120
  noTty,
107
121
  cwd,
108
122
  useNpxSkills,
123
+ forceRefresh,
124
+ source,
109
125
  });
110
126
  }
111
127
  // Regular init path: --template takes precedence, then positional arg, then default to 'module'
112
128
  const fromPath = templateFromPath || positionalFromPath || 'module';
113
129
  // Track if user explicitly requested module (e.g., `pgpm init module` or `--template pnpm/module`)
114
130
  const wasExplicitModuleRequest = positionalFromPath === 'module' || templateFromPath === 'module';
131
+ const source = refreshTemplateCache({
132
+ templateRepo,
133
+ branch,
134
+ toolName: DEFAULT_TEMPLATE_TOOL_NAME,
135
+ cwd,
136
+ force: forceRefresh,
137
+ });
115
138
  // Inspect the template to get its type
116
139
  const inspection = inspectTemplate({
117
140
  fromPath,
@@ -133,6 +156,8 @@ async function handleInit(argv, prompter) {
133
156
  cwd,
134
157
  useNpxSkills,
135
158
  repoWasExplicit,
159
+ source,
160
+ forceRefresh,
136
161
  });
137
162
  }
138
163
  // Default to module init (for 'module' type, 'generic' type, or unknown types)
@@ -147,6 +172,8 @@ async function handleInit(argv, prompter) {
147
172
  createWorkspace,
148
173
  useNpxSkills,
149
174
  repoWasExplicit,
175
+ source,
176
+ forceRefresh,
150
177
  }, wasExplicitModuleRequest);
151
178
  }
152
179
  async function handleBoilerplateInit(argv, prompter, ctx) {
@@ -213,6 +240,7 @@ async function handleBoilerplateInit(argv, prompter, ctx) {
213
240
  noTty: ctx.noTty,
214
241
  cwd: ctx.cwd,
215
242
  useNpxSkills: ctx.useNpxSkills,
243
+ source: ctx.source,
216
244
  });
217
245
  }
218
246
  // Default to module init (for 'module' type, 'generic' type, or unknown types)
@@ -226,6 +254,8 @@ async function handleBoilerplateInit(argv, prompter, ctx) {
226
254
  cwd: ctx.cwd,
227
255
  requiresWorkspace: inspection.config?.requiresWorkspace,
228
256
  useNpxSkills: ctx.useNpxSkills,
257
+ forceRefresh: ctx.forceRefresh,
258
+ source: ctx.source,
229
259
  }, true);
230
260
  }
231
261
  function installSkills(skills, cwd, useNpxSkills) {
@@ -296,7 +326,20 @@ async function handleWorkspaceInit(argv, prompter, ctx) {
296
326
  }
297
327
  ];
298
328
  const answers = await prompter.prompt(argv, workspaceQuestions);
299
- const targetPath = path.join(ctx.cwd, sluggify(answers.name));
329
+ let targetPath = path.join(ctx.cwd, sluggify(answers.name));
330
+ const slug = sluggify(answers.name);
331
+ const inPlace = path.basename(ctx.cwd) === slug && isScaffoldableInPlace(ctx.cwd);
332
+ if (inPlace) {
333
+ targetPath = ctx.cwd;
334
+ process.stdout.write(`Scaffolding into current directory ./ (it is empty and named "${answers.name}")\n`);
335
+ }
336
+ const source = ctx.source ?? refreshTemplateCache({
337
+ templateRepo: ctx.templateRepo,
338
+ branch: ctx.branch,
339
+ toolName: DEFAULT_TEMPLATE_TOOL_NAME,
340
+ cwd: ctx.cwd,
341
+ });
342
+ process.stdout.write(`${describeTemplateSource(source)}\n`);
300
343
  // Register workspace.dirname resolver so boilerplate templates can use it via defaultFrom/setFrom
301
344
  const dirName = path.basename(targetPath);
302
345
  registerDefaultResolver('workspace.dirname', () => dirName);
@@ -355,7 +398,9 @@ async function handleWorkspaceInit(argv, prompter, ctx) {
355
398
  installSkills(templateInfo.config.skills, targetPath, Boolean(ctx.useNpxSkills));
356
399
  }
357
400
  const relPath = path.relative(process.cwd(), targetPath);
358
- process.stdout.write(`\n✨ Enjoy!\n\ncd ./${relPath}\n`);
401
+ process.stdout.write('\n✨ Enjoy!\n');
402
+ if (relPath)
403
+ process.stdout.write(`\ncd ./${relPath}\n`);
359
404
  return { ...argv, ...answers, cwd: targetPath };
360
405
  }
361
406
  function resolveWorkspaceTemplateRepo(options) {
@@ -408,8 +453,22 @@ async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest =
408
453
  ctx.templateRepo = inherited.repo;
409
454
  ctx.branch = inherited.branch;
410
455
  ctx.dir = inherited.dir;
456
+ ctx.source = refreshTemplateCache({
457
+ templateRepo: ctx.templateRepo,
458
+ branch: ctx.branch,
459
+ toolName: DEFAULT_TEMPLATE_TOOL_NAME,
460
+ cwd: ctx.cwd,
461
+ force: ctx.forceRefresh,
462
+ });
411
463
  }
412
464
  }
465
+ const source = ctx.source ?? refreshTemplateCache({
466
+ templateRepo: ctx.templateRepo,
467
+ branch: ctx.branch,
468
+ toolName: DEFAULT_TEMPLATE_TOOL_NAME,
469
+ cwd: ctx.cwd,
470
+ force: ctx.forceRefresh,
471
+ });
413
472
  // Determine workspace requirement (defaults to 'pgpm' for backward compatibility)
414
473
  const workspaceType = ctx.requiresWorkspace ?? 'pgpm';
415
474
  // Whether this is a pgpm-managed template (creates pgpm.plan, .control files)
@@ -449,6 +508,13 @@ async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest =
449
508
  noTty: ctx.noTty,
450
509
  cwd: ctx.cwd,
451
510
  repoWasExplicit: ctx.repoWasExplicit,
511
+ source: refreshTemplateCache({
512
+ templateRepo: workspaceTemplateConfig.repo,
513
+ branch: workspaceTemplateConfig.branch,
514
+ toolName: DEFAULT_TEMPLATE_TOOL_NAME,
515
+ cwd: ctx.cwd,
516
+ force: ctx.forceRefresh,
517
+ }),
452
518
  });
453
519
  // Update context to point to new workspace and continue with module creation
454
520
  const newCwd = workspaceResult.cwd;
@@ -493,6 +559,13 @@ async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest =
493
559
  noTty: ctx.noTty,
494
560
  cwd: ctx.cwd,
495
561
  repoWasExplicit: ctx.repoWasExplicit,
562
+ source: refreshTemplateCache({
563
+ templateRepo: ctx.templateRepo,
564
+ branch: ctx.branch,
565
+ toolName: DEFAULT_TEMPLATE_TOOL_NAME,
566
+ cwd: ctx.cwd,
567
+ force: ctx.forceRefresh,
568
+ }),
496
569
  });
497
570
  }
498
571
  }
@@ -561,6 +634,7 @@ async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest =
561
634
  };
562
635
  // Determine output path based on whether we're in a workspace
563
636
  let modulePath;
637
+ process.stdout.write(`${describeTemplateSource(source)}\n`);
564
638
  if (project.workspacePath) {
565
639
  // PGPM workspace - use workspace-aware initModule
566
640
  await project.initModule({
@@ -649,6 +723,8 @@ async function handleModuleInit(argv, prompter, ctx, wasExplicitModuleRequest =
649
723
  installSkills(moduleTemplateInfo.config.skills, skillsCwd, Boolean(ctx.useNpxSkills));
650
724
  }
651
725
  const relPath = path.relative(process.cwd(), modulePath);
652
- process.stdout.write(`\n✨ Enjoy!\n\ncd ./${relPath}\n`);
726
+ process.stdout.write('\n✨ Enjoy!\n');
727
+ if (relPath)
728
+ process.stdout.write(`\ncd ./${relPath}\n`);
653
729
  return { ...argv, ...answers };
654
730
  }
@@ -0,0 +1,81 @@
1
+ import { PgpmPackage } from '@pgpmjs/core';
2
+ import { cliExitWithError } from 'inquirerer';
3
+ import path from 'path';
4
+ const lsUsageText = `
5
+ List Command:
6
+
7
+ pgpm ls [OPTIONS]
8
+
9
+ List the pgpm modules in the current workspace.
10
+
11
+ Options:
12
+ --help, -h Show this help message
13
+ --json Print JSON output
14
+ --names Print module names only
15
+ --paths Print workspace-relative module paths only
16
+ --cwd <dir> Working directory (default: current directory)
17
+
18
+ Examples:
19
+ pgpm ls
20
+ pgpm ls --names
21
+ pgpm ls --paths --json
22
+ `;
23
+ export default async (argv, _prompter, _options) => {
24
+ if (argv.help || argv.h) {
25
+ console.log(lsUsageText);
26
+ process.exit(0);
27
+ }
28
+ const names = Boolean(argv.names);
29
+ const paths = Boolean(argv.paths);
30
+ const json = Boolean(argv.json);
31
+ if (names && paths) {
32
+ await cliExitWithError('--names and --paths cannot be used together.');
33
+ }
34
+ const cwd = path.resolve(argv.cwd || process.cwd());
35
+ const workspace = new PgpmPackage(cwd);
36
+ const workspacePath = workspace.getWorkspacePath();
37
+ if (!workspacePath) {
38
+ await cliExitWithError(`Not inside a pgpm workspace: ${cwd}. Pass --cwd <workspace-directory>.`);
39
+ }
40
+ const entries = Object.entries(workspace.getModuleMap())
41
+ .sort(([left], [right]) => left.localeCompare(right))
42
+ .map(([name, module]) => ({
43
+ name,
44
+ version: module.version || 'unknown',
45
+ path: module.path,
46
+ requires: [...module.requires]
47
+ }));
48
+ if (json) {
49
+ if (names) {
50
+ process.stdout.write(JSON.stringify(entries.map(entry => entry.name)));
51
+ return;
52
+ }
53
+ if (paths) {
54
+ process.stdout.write(JSON.stringify(entries.map(entry => entry.path)));
55
+ return;
56
+ }
57
+ process.stdout.write(`${JSON.stringify(entries, null, 2)}\n`);
58
+ return;
59
+ }
60
+ if (names) {
61
+ process.stdout.write(entries.map(entry => entry.name).join('\n'));
62
+ if (entries.length > 0)
63
+ process.stdout.write('\n');
64
+ return;
65
+ }
66
+ if (paths) {
67
+ process.stdout.write(entries.map(entry => entry.path).join('\n'));
68
+ if (entries.length > 0)
69
+ process.stdout.write('\n');
70
+ return;
71
+ }
72
+ if (entries.length === 0) {
73
+ process.stdout.write('No modules found.\n');
74
+ return;
75
+ }
76
+ const nameWidth = Math.max(...entries.map(entry => entry.name.length));
77
+ const versionWidth = Math.max(...entries.map(entry => entry.version.length));
78
+ process.stdout.write(entries
79
+ .map(entry => `${entry.name.padEnd(nameWidth)} ${entry.version.padEnd(versionWidth)} ${entry.path}`)
80
+ .join('\n') + '\n');
81
+ };
package/esm/commands.js CHANGED
@@ -18,6 +18,7 @@ import _import from './commands/import';
18
18
  import init from './commands/init';
19
19
  import install from './commands/install';
20
20
  import kill from './commands/kill';
21
+ import ls from './commands/ls';
21
22
  import materialize from './commands/materialize';
22
23
  import migrate from './commands/migrate';
23
24
  import _package from './commands/package';
@@ -53,6 +54,8 @@ const ENGINE_EXEMPT_COMMANDS = new Set([
53
54
  'import',
54
55
  'init',
55
56
  'install',
57
+ 'ls',
58
+ 'list',
56
59
  'package',
57
60
  'materialize',
58
61
  'plan',
@@ -101,6 +104,8 @@ export const createPgpmCommandMap = (skipPgTeardown = false) => {
101
104
  tag: pgt(tag),
102
105
  kill: pgt(kill),
103
106
  install: pgt(install),
107
+ ls,
108
+ list: ls,
104
109
  migrate: pgt(migrate),
105
110
  materialize,
106
111
  analyze: pgt(analyze),
package/esm/index.js CHANGED
@@ -16,6 +16,7 @@ export { default as _export } from './commands/export';
16
16
  export { default as extension } from './commands/extension';
17
17
  export { default as install } from './commands/install';
18
18
  export { default as kill } from './commands/kill';
19
+ export { default as ls } from './commands/ls';
19
20
  export { default as migrate } from './commands/migrate';
20
21
  export { default as _package } from './commands/package';
21
22
  export { default as plan } from './commands/plan';
@@ -9,6 +9,7 @@ export const usageText = `
9
9
 
10
10
  Project Management:
11
11
  init Initialize workspace or module
12
+ ls List the modules in the current workspace (alias: list)
12
13
  extension Manage module dependencies
13
14
  plan Generate module deployment plans
14
15
  regen Generate revert/verify scripts from deploy scripts
package/esm/utils/tty.js CHANGED
@@ -5,11 +5,13 @@
5
5
  export const isNoTtyRequested = (argv) => Boolean(argv.noTty ||
6
6
  argv['no-tty'] ||
7
7
  argv.tty === false ||
8
- process.env.CI === 'true');
8
+ process.env.CI === 'true' ||
9
+ process.stdin.isTTY !== true);
9
10
  /**
10
11
  * Detect noTty mode from raw process argv, before minimist parsing. Used at
11
12
  * CLI construction time so the shared prompter itself is non-interactive.
12
13
  */
13
14
  export const detectNoTtyFromProcess = (argv = process.argv) => argv.includes('--no-tty') ||
14
15
  argv.includes('--noTty') ||
15
- process.env.CI === 'true';
16
+ process.env.CI === 'true' ||
17
+ process.stdin.isTTY !== true;
package/index.d.ts CHANGED
@@ -15,6 +15,7 @@ export { default as _export } from './commands/export';
15
15
  export { default as extension } from './commands/extension';
16
16
  export { default as install } from './commands/install';
17
17
  export { default as kill } from './commands/kill';
18
+ export { default as ls } from './commands/ls';
18
19
  export { default as migrate } from './commands/migrate';
19
20
  export { default as _package } from './commands/package';
20
21
  export { default as plan } from './commands/plan';
package/index.js CHANGED
@@ -18,7 +18,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
18
18
  return (mod && mod.__esModule) ? mod : { "default": mod };
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.options = exports.verify = exports.testPackages = exports.tag = exports.slice = exports.revert = exports.renameCmd = exports.remove = exports.plan = exports._package = exports.migrate = exports.kill = exports.install = exports.extension = exports._export = exports.env = exports.dump = exports.docker = exports.deploy = exports.clear = exports.analyze = exports.adminUsers = exports.add = exports.createPgpmCommandMap = exports.createInitUsageText = void 0;
21
+ exports.options = exports.verify = exports.testPackages = exports.tag = exports.slice = exports.revert = exports.renameCmd = exports.remove = exports.plan = exports._package = exports.migrate = exports.ls = exports.kill = exports.install = exports.extension = exports._export = exports.env = exports.dump = exports.docker = exports.deploy = exports.clear = exports.analyze = exports.adminUsers = exports.add = exports.createPgpmCommandMap = exports.createInitUsageText = void 0;
22
22
  const inquirerer_1 = require("inquirerer");
23
23
  const commands_1 = require("./commands");
24
24
  Object.defineProperty(exports, "createPgpmCommandMap", { enumerable: true, get: function () { return commands_1.createPgpmCommandMap; } });
@@ -49,6 +49,8 @@ var install_1 = require("./commands/install");
49
49
  Object.defineProperty(exports, "install", { enumerable: true, get: function () { return __importDefault(install_1).default; } });
50
50
  var kill_1 = require("./commands/kill");
51
51
  Object.defineProperty(exports, "kill", { enumerable: true, get: function () { return __importDefault(kill_1).default; } });
52
+ var ls_1 = require("./commands/ls");
53
+ Object.defineProperty(exports, "ls", { enumerable: true, get: function () { return __importDefault(ls_1).default; } });
52
54
  var migrate_1 = require("./commands/migrate");
53
55
  Object.defineProperty(exports, "migrate", { enumerable: true, get: function () { return __importDefault(migrate_1).default; } });
54
56
  var package_1 = require("./commands/package");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgpm",
3
- "version": "5.32.0",
3
+ "version": "5.34.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",
@@ -47,14 +47,14 @@
47
47
  },
48
48
  "dependencies": {
49
49
  "@inquirerer/utils": "^3.3.13",
50
- "@pgpmjs/core": "^7.29.0",
51
- "@pgpmjs/diff": "^0.7.0",
50
+ "@pgpmjs/core": "^7.31.0",
51
+ "@pgpmjs/diff": "^0.8.0",
52
52
  "@pgpmjs/env": "^2.45.0",
53
- "@pgpmjs/export": "^1.22.0",
54
- "@pgpmjs/import": "^0.7.0",
53
+ "@pgpmjs/export": "^1.23.0",
54
+ "@pgpmjs/import": "^0.8.0",
55
55
  "@pgpmjs/logger": "^2.26.0",
56
- "@pgpmjs/slice": "^0.18.0",
57
- "@pgpmjs/transform": "^0.27.0",
56
+ "@pgpmjs/slice": "^0.19.0",
57
+ "@pgpmjs/transform": "^0.28.0",
58
58
  "@pgpmjs/types": "^2.55.0",
59
59
  "@pgsql/quotes": "^18.2.4",
60
60
  "appstash": "^0.8.0",
@@ -65,7 +65,7 @@
65
65
  "js-yaml": "^4.1.0",
66
66
  "pg-cache": "^3.29.0",
67
67
  "pg-env": "^1.32.0",
68
- "pgsql-deparser": "^18.3.6",
68
+ "pgsql-deparser": "^18.3.7",
69
69
  "semver": "^7.8.5",
70
70
  "shelljs": "^0.10.0",
71
71
  "yanse": "^0.2.2"
@@ -82,5 +82,5 @@
82
82
  "pg",
83
83
  "pgsql"
84
84
  ],
85
- "gitHead": "baa84094b8541eb5000701b0060aa5b298032dc7"
85
+ "gitHead": "75b888926505b473eeef7a76fea1554e5a1cf4cc"
86
86
  }
@@ -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 regen Generate revert/verify scripts from deploy scripts\n transform Re-dial a module through the dials pipeline (granularity/naming/partition)\n import pgpm-itize an arbitrary SQL dump into a deployable module\n diff Identity-keyed semantic diff between two schema sources (+ migration generation)\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, --rustfs)\n doctor Check local dependencies (node, docker, psql) with install guidance\n env Manage environment variables (--supabase, --rustfs)\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 ls List the modules in the current workspace (alias: list)\n extension Manage module dependencies\n plan Generate module deployment plans\n regen Generate revert/verify scripts from deploy scripts\n transform Re-dial a module through the dials pipeline (granularity/naming/partition)\n import pgpm-itize an arbitrary SQL dump into a deployable module\n diff Identity-keyed semantic diff between two schema sources (+ migration generation)\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, --rustfs)\n doctor Check local dependencies (node, docker, psql) with install guidance\n env Manage environment variables (--supabase, --rustfs)\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
@@ -12,6 +12,7 @@ exports.usageText = `
12
12
 
13
13
  Project Management:
14
14
  init Initialize workspace or module
15
+ ls List the modules in the current workspace (alias: list)
15
16
  extension Manage module dependencies
16
17
  plan Generate module deployment plans
17
18
  regen Generate revert/verify scripts from deploy scripts
package/utils/tty.js CHANGED
@@ -8,7 +8,8 @@ exports.detectNoTtyFromProcess = exports.isNoTtyRequested = void 0;
8
8
  const isNoTtyRequested = (argv) => Boolean(argv.noTty ||
9
9
  argv['no-tty'] ||
10
10
  argv.tty === false ||
11
- process.env.CI === 'true');
11
+ process.env.CI === 'true' ||
12
+ process.stdin.isTTY !== true);
12
13
  exports.isNoTtyRequested = isNoTtyRequested;
13
14
  /**
14
15
  * Detect noTty mode from raw process argv, before minimist parsing. Used at
@@ -16,5 +17,6 @@ exports.isNoTtyRequested = isNoTtyRequested;
16
17
  */
17
18
  const detectNoTtyFromProcess = (argv = process.argv) => argv.includes('--no-tty') ||
18
19
  argv.includes('--noTty') ||
19
- process.env.CI === 'true';
20
+ process.env.CI === 'true' ||
21
+ process.stdin.isTTY !== true;
20
22
  exports.detectNoTtyFromProcess = detectNoTtyFromProcess;