@baseplate-dev/project-builder-cli 0.1.3 → 0.2.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.
@@ -1,4 +1,3 @@
1
- import { buildProject } from '@baseplate-dev/project-builder-server';
2
1
  import { createSchemaParserContext } from '#src/services/schema-parser-context.js';
3
2
  import { getUserConfig } from '#src/services/user-config.js';
4
3
  import { expandPathWithTilde } from '#src/utils/path.js';
@@ -12,6 +11,7 @@ export function addBuildCommand(program) {
12
11
  .command('generate [directory]')
13
12
  .description('Builds project from project-definition.json in baseplate/ directory')
14
13
  .action(async (directory) => {
14
+ const { buildProject } = await import('@baseplate-dev/project-builder-server');
15
15
  const resolvedDirectory = directory
16
16
  ? expandPathWithTilde(directory)
17
17
  : '.';
@@ -22,6 +22,7 @@ export function addBuildCommand(program) {
22
22
  logger,
23
23
  context,
24
24
  userConfig,
25
+ cliFilePath: process.argv[1],
25
26
  });
26
27
  });
27
28
  }
@@ -1,4 +1,3 @@
1
- import { userConfigSchema } from '@baseplate-dev/project-builder-server';
2
1
  import { stringifyPrettyStable } from '@baseplate-dev/utils';
3
2
  import { ZodError } from 'zod';
4
3
  import { getUserConfig, writeUserConfig } from '../services/user-config.js';
@@ -25,6 +24,7 @@ export function addConfigCommand(program) {
25
24
  .command('set <path> <value>')
26
25
  .description('Set a configuration value e.g. "config set sync.editor vscode"')
27
26
  .action(async (path, value) => {
27
+ const { userConfigSchema } = await import('@baseplate-dev/project-builder-server');
28
28
  const currentConfig = await getUserConfig();
29
29
  const parsedValue = value === 'true' ? true : value === 'false' ? false : value;
30
30
  const newConfig = setConfigValue(currentConfig, path.split('.'), parsedValue);
@@ -1,7 +1,7 @@
1
+ import type { BuilderServiceManager } from '@baseplate-dev/project-builder-server';
1
2
  import type { Command } from 'commander';
2
3
  import type { FastifyInstance } from 'fastify';
3
4
  import type { Logger } from 'pino';
4
- import { BuilderServiceManager } from '@baseplate-dev/project-builder-server';
5
5
  interface ServeCommandOptions {
6
6
  browser: boolean;
7
7
  port?: number;
@@ -1,5 +1,4 @@
1
1
  import { getDefaultPlugins } from '@baseplate-dev/project-builder-common';
2
- import { BuilderServiceManager, DEFAULT_SERVER_PORT, startWebServer, } from '@baseplate-dev/project-builder-server';
3
2
  import path from 'node:path';
4
3
  import { packageDirectory } from 'pkg-dir';
5
4
  import { getUserConfig } from '#src/services/user-config.js';
@@ -9,6 +8,7 @@ import { expandPathWithTilde } from '../utils/path.js';
9
8
  import { resolveModule } from '../utils/resolve.js';
10
9
  import { getPackageVersion } from '../utils/version.js';
11
10
  export async function serveWebServer(directories, { browser, port, logger: overrideLogger, skipCommands }) {
11
+ const { BuilderServiceManager, DEFAULT_SERVER_PORT, startWebServer } = await import('@baseplate-dev/project-builder-server');
12
12
  const projectBuilderWebDir = await packageDirectory({
13
13
  cwd: resolveModule('@baseplate-dev/project-builder-web/package.json'),
14
14
  });
@@ -25,6 +25,7 @@ export async function serveWebServer(directories, { browser, port, logger: overr
25
25
  builtInPlugins,
26
26
  userConfig,
27
27
  skipCommands,
28
+ cliFilePath: process.argv[1],
28
29
  });
29
30
  const fastifyInstance = await startWebServer({
30
31
  serviceManager,
@@ -0,0 +1,6 @@
1
+ import type { Command } from 'commander';
2
+ /**
3
+ * Adds template management commands to the program.
4
+ * @param program - The program to add the commands to.
5
+ */
6
+ export declare function addTemplatesCommand(program: Command): void;
@@ -0,0 +1,110 @@
1
+ import { getDefaultPlugins } from '@baseplate-dev/project-builder-common';
2
+ import path from 'node:path';
3
+ import { logger } from '#src/services/logger.js';
4
+ import { expandPathWithTilde } from '#src/utils/path.js';
5
+ /**
6
+ * Adds template management commands to the program.
7
+ * @param program - The program to add the commands to.
8
+ */
9
+ export function addTemplatesCommand(program) {
10
+ const templatesCommand = program
11
+ .command('templates')
12
+ .description('Manage generator templates');
13
+ // Templates list subcommand
14
+ templatesCommand
15
+ .command('list [directory]')
16
+ .description('Lists all available generators with their templates')
17
+ .option('--json', 'Output in JSON format', false)
18
+ .action(async (directory, options) => {
19
+ await handleListTemplates(directory, options);
20
+ });
21
+ // Templates delete subcommand
22
+ templatesCommand
23
+ .command('delete <generator-name> <template-name>')
24
+ .description('Delete a specific template from a generator')
25
+ .option('--force', 'Skip confirmation prompt', false)
26
+ .option('--directory <directory>', 'Directory to search for generators')
27
+ .action(async (generatorName, templateName, options) => {
28
+ await handleDeleteTemplate(generatorName, templateName, options);
29
+ });
30
+ // Templates extract subcommand
31
+ templatesCommand
32
+ .command('extract <directory> <app>')
33
+ .description('Extracts templates from the specified directory and saves them to the templates directory')
34
+ .option('--auto-generate-extractor', 'Auto-generate extractor.json files', true)
35
+ .option('--skip-clean', 'Skip cleaning the output directories (templates and generated)', false)
36
+ .action(async (directory, app, options) => {
37
+ await handleExtractTemplates(directory, app, options);
38
+ });
39
+ }
40
+ async function handleListTemplates(directory, options) {
41
+ const { discoverGenerators } = await import('@baseplate-dev/project-builder-server/template-extractor');
42
+ const resolvedDirectory = directory
43
+ ? expandPathWithTilde(directory)
44
+ : path.resolve('.');
45
+ const defaultPlugins = await getDefaultPlugins(logger);
46
+ try {
47
+ const generators = await discoverGenerators(resolvedDirectory, defaultPlugins, logger);
48
+ // Use existing basic listing logic
49
+ if (options.json) {
50
+ console.info(JSON.stringify(generators.map((g) => ({
51
+ ...g,
52
+ templates: Object.fromEntries(Object.entries(g.templates).map(([templatePath, template]) => [
53
+ templatePath,
54
+ {
55
+ name: template.name,
56
+ type: template.type,
57
+ },
58
+ ])),
59
+ })), null, 2));
60
+ }
61
+ else {
62
+ if (generators.length === 0) {
63
+ console.info('No generators found with extractor.json files.');
64
+ return;
65
+ }
66
+ console.info(`Found ${generators.length} generator(s):\n`);
67
+ for (const generator of generators) {
68
+ console.info(`📦 ${generator.name}`);
69
+ console.info(` Package: ${generator.packageName}`);
70
+ console.info(` Path: ${generator.generatorDirectory}`);
71
+ console.info(` Templates: ${Object.values(generator.templates)
72
+ .map((t) => t.name)
73
+ .join(', ')}`);
74
+ console.info();
75
+ }
76
+ }
77
+ }
78
+ catch (error) {
79
+ logger.error(`Failed to discover generators: ${error instanceof Error ? error.message : String(error)}`);
80
+ throw error;
81
+ }
82
+ }
83
+ async function handleDeleteTemplate(generatorName, templateName, options) {
84
+ const { deleteTemplate } = await import('@baseplate-dev/project-builder-server/template-extractor');
85
+ const resolvedDirectory = options.directory
86
+ ? expandPathWithTilde(options.directory)
87
+ : path.resolve('.');
88
+ const defaultPlugins = await getDefaultPlugins(logger);
89
+ try {
90
+ await deleteTemplate(generatorName, templateName, {
91
+ defaultPlugins,
92
+ logger,
93
+ directory: resolvedDirectory,
94
+ });
95
+ console.info(`✅ Successfully deleted template '${templateName}' from generator '${generatorName}'`);
96
+ }
97
+ catch (error) {
98
+ logger.error(`Failed to delete template: ${error instanceof Error ? error.message : String(error)}`);
99
+ throw error;
100
+ }
101
+ }
102
+ async function handleExtractTemplates(directory, app, options) {
103
+ const { runTemplateExtractorsForProject } = await import('@baseplate-dev/project-builder-server/template-extractor');
104
+ const resolvedDirectory = expandPathWithTilde(directory);
105
+ const defaultPlugins = await getDefaultPlugins(logger);
106
+ await runTemplateExtractorsForProject(resolvedDirectory, app, defaultPlugins, logger, {
107
+ autoGenerateExtractor: options.autoGenerateExtractor,
108
+ skipClean: options.skipClean,
109
+ });
110
+ }
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { program } from 'commander';
2
2
  import { addBuildCommand } from './commands/build.js';
3
3
  import { addConfigCommand } from './commands/config.js';
4
- import { addExtractTemplatesCommand } from './commands/extract-templates.js';
5
4
  import { addServeCommand } from './commands/server.js';
5
+ import { addTemplatesCommand } from './commands/templates.js';
6
6
  import { getEnabledFeatureFlags } from './services/feature-flags.js';
7
7
  import { getPackageVersion } from './utils/version.js';
8
8
  /**
@@ -14,7 +14,7 @@ export async function runCli() {
14
14
  const enabledFlags = getEnabledFeatureFlags();
15
15
  program.version(version, '-v, --version');
16
16
  if (enabledFlags.includes('TEMPLATE_EXTRACTOR')) {
17
- addExtractTemplatesCommand(program);
17
+ addTemplatesCommand(program);
18
18
  }
19
19
  addBuildCommand(program);
20
20
  addServeCommand(program);
@@ -1,5 +1,4 @@
1
1
  import { getDefaultPlugins } from '@baseplate-dev/project-builder-common';
2
- import { createNodeSchemaParserContext } from '@baseplate-dev/project-builder-server';
3
2
  import { logger } from './logger.js';
4
3
  /**
5
4
  * Creates a schema parser context for the given directory.
@@ -7,6 +6,8 @@ import { logger } from './logger.js';
7
6
  * @returns A promise that resolves to the schema parser context.
8
7
  */
9
8
  export async function createSchemaParserContext(directory) {
9
+ // dynamically import to avoid loading the server package unnecessarily
10
+ const { createNodeSchemaParserContext } = await import('@baseplate-dev/project-builder-server/plugins');
10
11
  const builtInPlugins = await getDefaultPlugins(logger);
11
12
  return createNodeSchemaParserContext(directory, logger, builtInPlugins);
12
13
  }
@@ -1,4 +1,3 @@
1
- import { userConfigSchema } from '@baseplate-dev/project-builder-server';
2
1
  import { handleFileNotFoundError, readJsonWithSchema, writeStablePrettyJson, } from '@baseplate-dev/utils/node';
3
2
  import { mkdir } from 'node:fs/promises';
4
3
  import os from 'node:os';
@@ -13,6 +12,7 @@ function getConfigPath() {
13
12
  * @returns The user config for the project builder.
14
13
  */
15
14
  export async function getUserConfig() {
15
+ const { userConfigSchema } = await import('@baseplate-dev/project-builder-server');
16
16
  const configPath = getConfigPath();
17
17
  const config = await readJsonWithSchema(configPath, userConfigSchema).catch(handleFileNotFoundError);
18
18
  return config ?? {};
package/package.json CHANGED
@@ -1,7 +1,16 @@
1
1
  {
2
2
  "name": "@baseplate-dev/project-builder-cli",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Full-stack CLI builder using Baseplate generators",
5
+ "keywords": [
6
+ "cli",
7
+ "full-stack",
8
+ "code-generation",
9
+ "development-tools",
10
+ "scaffolding",
11
+ "baseplate",
12
+ "typescript"
13
+ ],
5
14
  "homepage": "https://www.baseplate.dev",
6
15
  "repository": {
7
16
  "type": "git",
@@ -36,11 +45,11 @@
36
45
  "pino-pretty": "13.0.0",
37
46
  "pkg-dir": "^8.0.0",
38
47
  "zod": "3.24.1",
39
- "@baseplate-dev/project-builder-common": "0.1.3",
40
- "@baseplate-dev/project-builder-lib": "0.1.3",
41
- "@baseplate-dev/project-builder-server": "0.1.3",
42
- "@baseplate-dev/project-builder-web": "0.1.3",
43
- "@baseplate-dev/utils": "0.1.3"
48
+ "@baseplate-dev/project-builder-common": "0.2.0",
49
+ "@baseplate-dev/project-builder-lib": "0.2.0",
50
+ "@baseplate-dev/project-builder-server": "0.2.0",
51
+ "@baseplate-dev/project-builder-web": "0.2.0",
52
+ "@baseplate-dev/utils": "0.2.0"
44
53
  },
45
54
  "devDependencies": {
46
55
  "@playwright/test": "1.51.0",
@@ -52,7 +61,7 @@
52
61
  "tsx": "4.19.3",
53
62
  "typescript": "5.7.3",
54
63
  "vitest": "3.0.7",
55
- "@baseplate-dev/tools": "0.1.3"
64
+ "@baseplate-dev/tools": "0.2.0"
56
65
  },
57
66
  "engines": {
58
67
  "node": "^22.0.0"
@@ -69,10 +78,11 @@
69
78
  "clean": "rm -rf ./dist",
70
79
  "dev": "tsx watch --tsconfig ./tsconfig.app.json --exclude /**/node_modules/** -r dotenv/config -C development ./src/cli.ts",
71
80
  "dev:serve": "pnpm dev serve",
72
- "extract:templates": "pnpm start extract-templates",
81
+ "extract:templates": "pnpm start templates extract",
73
82
  "lint": "eslint .",
74
83
  "prettier:check": "prettier --check .",
75
84
  "prettier:write": "prettier -w .",
85
+ "project:generate": "pnpm start generate",
76
86
  "start": "tsx --tsconfig ./tsconfig.app.json -r dotenv/config -C development ./src/cli.ts",
77
87
  "test": "vitest",
78
88
  "test:e2e": "playwright test",
@@ -1,7 +0,0 @@
1
- import type { Command } from 'commander';
2
- /**
3
- * Runs the template extraction flow on the target directory.
4
- *
5
- * @param program - The program to add the command to.
6
- */
7
- export declare function addExtractTemplatesCommand(program: Command): void;
@@ -1,19 +0,0 @@
1
- import { runTemplateExtractorsForProject } from '@baseplate-dev/project-builder-server';
2
- import { logger } from '#src/services/logger.js';
3
- import { createSchemaParserContext } from '#src/services/schema-parser-context.js';
4
- import { expandPathWithTilde } from '#src/utils/path.js';
5
- /**
6
- * Runs the template extraction flow on the target directory.
7
- *
8
- * @param program - The program to add the command to.
9
- */
10
- export function addExtractTemplatesCommand(program) {
11
- program
12
- .command('extract-templates directory app')
13
- .description('Extracts templates from the specified directory and saves them to the templates directory')
14
- .action(async (directory, app) => {
15
- const resolvedDirectory = expandPathWithTilde(directory);
16
- const context = await createSchemaParserContext(resolvedDirectory);
17
- await runTemplateExtractorsForProject(resolvedDirectory, app, context, logger);
18
- });
19
- }