diff --git a/.claude/skills/add-template-generator/SKILL.md b/.claude/skills/add-template-generator/SKILL.md new file mode 100644 index 00000000..8e462544 --- /dev/null +++ b/.claude/skills/add-template-generator/SKILL.md @@ -0,0 +1,215 @@ +--- +name: add-template-generator +description: Add a new template generator command to the CLI +--- +Use this workflow whenever exposing a generator from salesforcedx-templates to CLI users. + +# Add Template Generator Command Workflow + +This workflow guides you through adding a new template generator command that exposes a template from `salesforcedx-templates` to the Salesforce CLI. + +## Prerequisites + +- Template generator already exists in `salesforcedx-templates` repository +- You know the metadata type name and any subtemplates +- You have the repo cloned and dependencies installed + +## Step 1: Bootstrap the Command + +// turbo +Run the command generator to create the initial command structure: + +```bash +sf dev generate command -n template:generate:{metadataType}:{optionalSubTemplate} --no-unit +``` + +**Notes:** +- Replace `{metadataType}` with your metadata type (e.g., `flexipage`, `apex`) +- Only add `{optionalSubTemplate}` if you need nested generators (e.g., `digital-experience:site`) +- This creates the command file, updates oclif metadata, and adds NUTs + +## Step 2: Update package.json Topics + +Open `package.json` and locate the `oclif.topics` section. Under `template > generate`, add a description for your new subtopic: + +```json +{ + "oclif": { + "topics": { + "template": { + "subtopics": { + "generate": { + "subtopics": { + "{metadataType}": { + "description": "Commands for generating {metadataType} metadata" + } + } + } + } + } + } + } +} +``` + +## Step 3: Set Command State (Optional) + +If your command is not GA-ready, add a state to the command class: + +```typescript +public static readonly state = 'beta'; // or 'preview' +``` + +**State options:** +- `beta`: Shows beta warning to users +- `preview`: Shows preview warning to users +- No state: Command is GA (requires backwards compatibility) + +If you want to hide the command from docs and autocomplete: + +```typescript +public static readonly hidden = true; +``` + +**Note:** Hidden commands won't be included in release notes. + +## Step 4: Verify File Path + +Ensure your command file follows the correct path convention: + +- **Single top-level generator**: `src/commands/template/generate/{metadataType}/index.ts` +- **Nested generator**: `src/commands/template/generate/{metadataType}/{subTemplate}.ts` + +## Step 5: Define CLI Flags + +Before defining flags, inspect the generator TypeScript interface in `salesforcedx-templates`. The interface is the source of truth for flag structure. If it is unavailable, request it instead of guessing. + +**Important:** Do NOT add flags manually. The `sf dev generate flag` command is interactive and requires the user to run it themselves—the agent cannot respond to its prompts. When adding flags, instruct the user to run the command and provide guidance for the interactive flow. + +### Agent instructions for adding flags + +1. Tell user to run `sf dev generate flag` from plugin root. +2. **Flow order:** (1) select command, (2) type (string/boolean/etc.), (3) name (kebab-case), (4) summary, (5) short name (optional), (6) required?, (7) multiple? +3. List flags to add with suggested name, type, summary from generator interface. +4. After user completes: (a) add mappings to options object if command passes opts to `runGenerator`; (b) if generator created `messages/template.generate.{metadataType}.md` instead of updating the existing file, merge those entries into `messages/{metadataType}.md` and delete the generated file. + +### Running the flag generator + +```bash +sf dev generate flag +``` + +This will: +- Add the flag to your command's `flags` object +- Generate TypeScript types +- Add entries to the `messages.md` file + +**Common flags to consider:** +- `--name` / `-n`: Name of the generated item (usually required) +- `--output-dir` / `-d`: Output directory (default: '.') +- `--template` / `-t`: Template type selection (if multiple templates) +- `--api-version`: API version override + +## Step 6: Review Message Files + +Check `messages/{metadataType}.md` (merge from `template.generate.{metadataType}.md` if generator created a separate file) and ensure: +- Summary is clear and concise +- Description provides helpful context +- Flag descriptions are detailed and explain constraints +- Examples are practical and cover common use cases + +**Optional:** Add links to developer.salesforce.com docs in descriptions if helpful. + +## Step 7: Implement the run() Method + +Update the `run()` method to call `runGenerator`: + +```typescript +import { runGenerator } from '../../utils/templateCommand.js'; + +public async run(): Promise { + const { flags } = await this.parse(CommandClass); + + // Add any pre-processing or validation here + + return runGenerator({ + templateType: TemplateType.{YourMetadataType}, + opts: flags, + ux: new Ux({ jsonEnabled: this.jsonEnabled() }), + }); +} +``` + +## Step 8: Write/Update NUTs + +Review the auto-generated NUTs in `test/commands/template/generate/{metadataType}/`. Add tests to validate: +- Required flags work correctly +- Optional flags are respected +- Correct files are created in the right locations +- Flag combinations work as expected + +Most template generators don't require scratch org connections. + +## Step 9: Test Locally + +// turbo +Build and link the plugin: + +```bash +yarn build +sf plugins link . +``` + +Test your command: + +```bash +sf template generate {metadataType} --name TestExample --output-dir ./test-output +``` + +Verify the generated files are correct. + +## Step 10: Run Tests + +// turbo +Run the NUTs to ensure everything works: + +```bash +yarn test +``` + +## Local Development with salesforcedx-templates + +If you're also working on the template in `salesforcedx-templates`: + +1. Ensure you're using yarn 1 +2. Update `package.json` to reference your local `salesforcedx-templates`: + ```json + "dependencies": { + "salesforcedx-templates": "file:../path/to/salesforcedx-templates" + } + ``` +3. After template changes: `yarn build` in salesforcedx-templates +4. Then: `yarn install --force && yarn build` in plugin-templates + +## Troubleshooting + +If your command does not appear: + +- confirm file path matches convention +- run yarn build +- ensure oclif topics updated +- relink plugin: + + sf plugins unlink @salesforce/plugin-templates + sf plugins link . + +## Final Validation Checklist + +Before opening PR ensure: + +- command runs locally +- files generate correctly +- flags validated +- messages documented +- NUTs pass +- topics updated \ No newline at end of file diff --git a/.claude/skills/concise/SKILL.md b/.claude/skills/concise/SKILL.md new file mode 100644 index 00000000..0f4cbdab --- /dev/null +++ b/.claude/skills/concise/SKILL.md @@ -0,0 +1,14 @@ +--- +name: concise +description: when creating/modifying md files in skills/rules for AI +disable-model-invocation: false +--- + +# Concise + +We want to save tokens and preserve context window size. + +- use fragments/bullets, not full sentences +- remove as many words as possible without altering meaning +- cut repetition +- prefer shorter words that mean the same thing \ No newline at end of file diff --git a/.windsurf/workflows/add-template-generator.md b/.windsurf/workflows/add-template-generator.md new file mode 100644 index 00000000..c966b13f --- /dev/null +++ b/.windsurf/workflows/add-template-generator.md @@ -0,0 +1,205 @@ +--- +description: Add a new template generator command to the CLI +--- +Use this workflow whenever exposing a generator from salesforcedx-templates to CLI users. + +# Add Template Generator Command Workflow + +This workflow guides you through adding a new template generator command that exposes a template from `salesforcedx-templates` to the Salesforce CLI. + +## Prerequisites + +- Template generator already exists in `salesforcedx-templates` repository +- You know the metadata type name and any subtemplates +- You have the repo cloned and dependencies installed + +## Step 1: Bootstrap the Command + +// turbo +Run the command generator to create the initial command structure: + +```bash +sf dev generate command -n template:generate:{metadataType}:{optionalSubTemplate} --no-unit +``` + +**Notes:** +- Replace `{metadataType}` with your metadata type (e.g., `flexipage`, `apex`) +- Only add `{optionalSubTemplate}` if you need nested generators (e.g., `digital-experience:site`) +- This creates the command file, updates oclif metadata, and adds NUTs + +## Step 2: Update package.json Topics + +Open `package.json` and locate the `oclif.topics` section. Under `template > generate`, add a description for your new subtopic: + +```json +{ + "oclif": { + "topics": { + "template": { + "subtopics": { + "generate": { + "subtopics": { + "{metadataType}": { + "description": "Commands for generating {metadataType} metadata" + } + } + } + } + } + } + } +} +``` + +## Step 3: Set Command State (Optional) + +If your command is not GA-ready, add a state to the command class: + +```typescript +public static readonly state = 'beta'; // or 'preview' +``` + +**State options:** +- `beta`: Shows beta warning to users +- `preview`: Shows preview warning to users +- No state: Command is GA (requires backwards compatibility) + +If you want to hide the command from docs and autocomplete: + +```typescript +public static readonly hidden = true; +``` + +**Note:** Hidden commands won't be included in release notes. + +## Step 4: Verify File Path + +Ensure your command file follows the correct path convention: + +- **Single top-level generator**: `src/commands/template/generate/{metadataType}/index.ts` +- **Nested generator**: `src/commands/template/generate/{metadataType}/{subTemplate}.ts` + +## Step 5: Define CLI Flags +Before defining flags, inspect the generator TypeScript interface in `salesforcedx-templates`. The interface is the source of truth for flag structure. If it is unavailable, request it instead of guessing. + +// turbo +Use the interactive flag generator for each flag you need: + +```bash +sf dev generate flag +``` + +This will: +- Add the flag to your command's `flags` object +- Generate TypeScript types +- Add entries to the `messages.md` file + +**Common flags to consider:** +- `--name` / `-n`: Name of the generated item (usually required) +- `--output-dir` / `-d`: Output directory (default: '.') +- `--template` / `-t`: Template type selection (if multiple templates) +- `--api-version`: API version override + +## Step 6: Review Message Files + +Check the generated `messages/{command}.md` file and ensure: +- Summary is clear and concise +- Description provides helpful context +- Flag descriptions are detailed and explain constraints +- Examples are practical and cover common use cases + +**Optional:** Add links to developer.salesforce.com docs in descriptions if helpful. + +## Step 7: Implement the run() Method + +Update the `run()` method to call `runGenerator`: + +```typescript +import { runGenerator } from '../../utils/templateCommand.js'; + +public async run(): Promise { + const { flags } = await this.parse(CommandClass); + + // Add any pre-processing or validation here + + return runGenerator({ + templateType: TemplateType.{YourMetadataType}, + opts: flags, + ux: new Ux({ jsonEnabled: this.jsonEnabled() }), + }); +} +``` + +## Step 8: Write/Update NUTs + +Review the auto-generated NUTs in `test/commands/template/generate/{metadataType}/`. Add tests to validate: +- Required flags work correctly +- Optional flags are respected +- Correct files are created in the right locations +- Flag combinations work as expected + +Most template generators don't require scratch org connections. + +## Step 9: Test Locally + +// turbo +Build and link the plugin: + +```bash +yarn build +sf plugins link . +``` + +Test your command: + +```bash +sf template generate {metadataType} --name TestExample --output-dir ./test-output +``` + +Verify the generated files are correct. + +## Step 10: Run Tests + +// turbo +Run the NUTs to ensure everything works: + +```bash +yarn test +``` + +## Local Development with salesforcedx-templates + +If you're also working on the template in `salesforcedx-templates`: + +1. Ensure you're using yarn 1 +2. Update `package.json` to reference your local `salesforcedx-templates`: + ```json + "dependencies": { + "salesforcedx-templates": "file:../path/to/salesforcedx-templates" + } + ``` +3. After template changes: `yarn build` in salesforcedx-templates +4. Then: `yarn install --force && yarn build` in plugin-templates + +## Troubleshooting + +If your command does not appear: + +- confirm file path matches convention +- run yarn build +- ensure oclif topics updated +- relink plugin: + + sf plugins unlink @salesforce/plugin-templates + sf plugins link . + +## Final Validation Checklist + +Before opening PR ensure: + +- command runs locally +- files generate correctly +- flags validated +- messages documented +- NUTs pass +- topics updated \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..6da899cb --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,104 @@ +# Salesforce CLI Plugin Templates — AI Context + +## Purpose + +This repository (`plugin-templates`) exposes template generators to Salesforce CLI users via `sf template generate` commands. + +It works alongside a separate repo: + +- `salesforcedx-templates` → contains generator logic +- `plugin-templates` → exposes generators as CLI commands + +**Important:** +Creating a generator in `salesforcedx-templates` does NOT expose it to CLI users. +A command must be added in this repo. + +--- + +## When Performing Tasks + +- Adding a generator command → use the **add-template-generator skill** +- Do not manually scaffold commands unless necessary +- Follow conventions exactly — CLI discovery depends on them + +--- + +## Command Architecture + +Command structure: + +src/commands/template/generate/{metadataType}/ + +Files: +- index.ts → top-level generator +- {subTemplate}.ts → nested generator + +Naming pattern: + +sf template generate {metadataType} {optionalSubTemplate} + +Examples: +- sf template generate flexipage +- sf template generate digital-experience site + +--- + +## Flag Definitions Source of Truth + +CLI flags should be derived from the TypeScript interface of the corresponding template generator in `salesforcedx-templates`. + +When implementing a command: + +- Prefer inspecting the generator interface to determine flags +- If the interface is not available in context, request it +- Do not invent flags unless explicitly instructed + +## Critical Rules + +These must always be followed: + +- File paths must match conventions exactly +- All flags must have message file entries +- GA commands must remain backward compatible +- Hidden commands: + + static hidden = true; + + will not appear in docs or autocomplete + +--- + +## Command States + +beta +preview +GA (default) + +Only GA commands require permanent backwards compatibility. + +--- + +## Tech Stack + +- TypeScript +- oclif framework +- sf-plugins-core utilities +- Yarn 1 only + +--- + +## Core Implementation Pattern + +All generators should call: + +runGenerator({ + templateType: TemplateType.X, + opts: flags, + ux +}) + +--- + +## Reference Docs + +Use official Salesforce CLI docs when needed. \ No newline at end of file diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 00000000..8d9b90d4 --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,151 @@ +## Add Template Generator to CLI + +**Repo**: [salesforcecli/plugin-templates](https://github.com/salesforcecli/plugin-templates/tree/main/src/commands) (Public GitHub, requires access to `salesforcecli` org) + +### Table of Contents + +- [Understanding the Two-Repo Workflow](#understanding-the-two-repo-workflow) +- [Declare your Metadata Subtopic and Create Plugin Command](#declare-your-metadata-subtopic-and-create-plugin-command-and-topic) +- [Define your CLI Input Shape](#define-your-cli-input-shape) +- [Message Labels](#message-labels) +- [Call your Template Generator](#call-your-template-generator) +- [Testing Your Command](#aw-nuts-its-time-to-test-your-new-command) +- [Release Timelines](#release-timelines) +- [Release Notes](#release-notes) +- [Local Development Guidance](#local-development-guidance) + +### Understanding the Two-Repo Workflow + +This guide covers adding template generators to the Salesforce CLI. It's important to understand the relationship between two repositories: + +- **[salesforcedx-templates](https://github.com/forcedotcom/salesforcedx-templates)**: Contains the actual template definitions and generator logic for various metadata types +- **[plugin-templates](https://github.com/salesforcecli/plugin-templates)** (this repo): Contains the CLI commands that expose those generators to users + +Creating a template generator in `salesforcedx-templates` does not immediately expose it to the CLI. It is up to each metadata owner to create a corresponding CLI command in this repo to expose their generator to users. + +It's critical to remember that creating a new CLI command isn't just about getting the functionality working. You need to be very intentional about the name, description, flag names, flag types, and command names that you are using. + +**Recommended Reading: Salesforce Developer Documentation** + +* [https://developer.salesforce.com/docs/platform/salesforce-cli-plugin/guide/topics.html](https://developer.salesforce.com/docs/platform/salesforce-cli-plugin/guide/topics.html) +* [https://developer.salesforce.com/docs/platform/salesforce-cli-plugin/guide/flags.html](https://developer.salesforce.com/docs/platform/salesforce-cli-plugin/guide/flags.html) +* [https://developer.salesforce.com/docs/platform/salesforce-cli-plugin/guide/command-flags.html](https://developer.salesforce.com/docs/platform/salesforce-cli-plugin/guide/command-flags.html) +* If all this is new to you, check out [Get Started Building a Salesforce CLI Plugin](https://developer.salesforce.com/docs/platform/salesforce-cli-plugin/guide/get-started.html) which walks you through a simple example. + +### Declare your Metadata Subtopic and Create Plugin Command (and Topic) + +1. Use `sf dev generate command -n template:generate:{metadataType}:{optionalSubTemplate} --no-unit` to bootstrap your new command. + 1. This will create all the files you need for introducing a new command, including updating the oclif metadata + 2. Only create a subtemplate if you want to add nested generators (e.g. `template:generate:site:brand`) +2. Go to the [`package.json`](./package.json) and update the placeholder description for your new subtopic in the `oclif` section underneath `template > generate` +3. (Optional) If your command is not ready to be Generally Available (GA), add a "state" to your command with `public static readonly state = 'beta|preview'` + 1. Accepted values are `beta` or `preview` ([source](https://github.com/salesforcecli/sf-plugins-core/blob/5a4f73b05b286651ea177a6d16015ee6dafa58f7/src/sfCommand.ts#L340-L344)). Review the corresponding messages and choose which describes your command best + 1. [beta message](https://github.com/salesforcecli/sf-plugins-core/blob/main/messages/messages.md#warningcommandinbeta) + 2. [preview message](https://github.com/salesforcecli/sf-plugins-core/blob/main/messages/messages.md#warningcommandinpreview) + 2. Once your generator is GA-ready, you can remove this state. Just know that if you do, you’ll be responsible for ensuring backwards compatibility for all new releases. +4. (Optional) If you do not want your command to show up in the [command reference guide](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_unified.htm), locally when running `sf commands`, or in autocompletion results, set `public static readonly hidden = true` + 1. NOTE: We will **not** document your command in our [weekly release notes](https://github.com/forcedotcom/cli/tree/main/releasenotes) if your command is hidden. + +> If you have a single top-level metadata generator, be sure the file path to your command follows `src/commands/template/generate/{metadataType}/index.ts` + +### Define your CLI Input Shape + +For each new flag, the best and fastest way to get an error-proof flag added is to use the `sf dev generate flag` interactive command. + +This will walk you through the addition of a new flag and also generate all required TypeScript scaffolding as well as appending the flag to the `messages.md` file. + +Each new flag is added to a `readonly` flags object, with the type, required parameter, character alias, etc… defined. + +```ts +public static readonly flags = { + name: Flags.string({ // <-- string parameter + char: 'n', // <-- character alias + summary: messages.getMessage('flags.name.summary'), + description: messages.getMessage('flags.name.description'), + required: true, // <-- CLI fails if parameter is not provided + }), + template: Flags.option({ // <-- string enum + char: 't', + summary: messages.getMessage('flags.template.summary'), + description: messages.getMessage('flags.template.description'), + required: true, + options: ['RecordPage', 'AppPage', 'HomePage'] as const, // enum options + })(), ... +} +``` + +### Message Labels +> Dev Hint: If you use `sf dev generate flag` for all new flags, all the scaffolding will be taken care of for you! + +See the existing developer documentation for learning how to write useful messages: +[https://developer.salesforce.com/docs/platform/salesforce-cli-plugin/guide/messages.html](https://developer.salesforce.com/docs/platform/salesforce-cli-plugin/guide/messages.html) + +See [here](https://developer.salesforce.com/docs/platform/salesforce-cli-plugin/guide/messages-impl-guidelines.html) for how to implement and dynamically load your messages in your command implementation. **Each new flag requires a "summary" entry in the messages file. Flag descriptions are optional.** + +If appropriate, link to developer.salesforce.com docs in command descriptions. + +### Call your Template Generator + +After defining your input contract, you’ll be able to use `runGenerator`, passing in the templateType and input options for your metadata type. This should be encapsulated inside of a `run()` method which outputs a `Promise`. + +```ts +import { getCustomTemplates, runGenerator } from '../../utils/templateCommand.js'; +... +public async run(): Promise { + // ... input definition + // pre-processing/sanitization + return runGenerator({ + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + templateType: TemplateType.[YourMetadataType], + opts: flags, + ux: new Ux({ jsonEnabled: this.jsonEnabled() }), + }); +} +``` + +### Aw NUTS\! It’s time to test your new command + +If you use the `sf dev generate command` command to bootstrap your command, you’ll see that some NUTs (Not Unit Tests) are added. + +If you did not use the `generate command`, then you are expected to add your own tests. The purpose of these is to validate the integration between the CLI flags and what is ultimately passed to the generator, and to ensure that the correct files are created based on those flags. + +Unless you’re in the minority, most template generators do not require a scratch org connection, so it should be fairly straightforward to create new NUTs based on the examples in the repo. + +## Release Timelines + +Your PR has now been merged into plugin-templates; congratulations! How long do you have to wait until it is available for consumption? + +Release information is communicated through official Salesforce CLI channels. + +#### Nightly + +The CLI has a `nightly` release. The day after your PR is merged, you can update to the latest with `sf update nightly` or `npm install @salesforce/cli@nightly --global`. Keep in mind that if you have previously run `sf plugins link .` during development, you have to run `sf plugins unlink @salesforce/plugin-templates`. + +#### Release Candidate + +The release candidate is updated weekly, on Wednesdays, around noon CST (10am PST). To update to the release candidate, you can run `sf update stable-rc` or `npm install @salesforce/cli@latest-rc --global`. + +After your change is merged into the `nightly` release, your team should QA/QC ahead of the promotion to the release candidate and make any necessary changes. + +#### Latest + +A week after promotion to the release candidate, the RC is promoted to `latest`. Final sanity checks should be done during this week, and emergency patch fixes can be made if required. Update with `sf update stable` or `npm install @salesforce/cli --global`. + +This promotion also happens around 12pm CST (10am PST) on Wednesdays. + +## Release Notes + +Release notes are updated weekly and merged here: [https://github.com/forcedotcom/cli/tree/main/releasenotes](https://github.com/forcedotcom/cli/tree/main/releasenotes). + +If you'd like to have your new template generator command specifically included or excluded in the release notes, please coordinate with the CLI team. + +## Local Development Guidance + +In order to get this all to work locally, you’ll need to do a few things: + +1. Ensure you’re working with `yarn 1`, not yarn 3 or 4\. +2. If you're introducing new templates in `salesforcedx-templates`, update your `package.json` in plugin-templates to reference your local path to the root directory of `salesforcedx-templates` +3. Run `yarn build` after all changes to your templates or generator (in dx-templates) +4. Run `yarn install --force` and `yarn build` in `plugin-templates` to fetch newly built changes from your local salesforcedx-templates directory +5. When introducing your CLI command for the **first time**, run `sf plugins link .` from `plugin-templates`, which will override your local CLI with the new command that you’re working on. + a. Alternatively, you can run your new command directly from the plugin-templates directory with: `./bin/run.js template generate your-command` \ No newline at end of file diff --git a/README.md b/README.md index 7157c143..088df9e7 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ Please report any issues to https://github.com/salesforcecli/plugin-templates/is ## Contributing 1. Familiarize yourself with the codebase by reading the docs and the templates [library](https://github.com/salesforcecli/plugin-templates). + - If you're adding a new template generator, see the [Development Guide](./DEVELOPMENT.md) for detailed instructions. 1. Create a new issue before starting your project so that we can keep track of what you're trying to add/fix. That way, we can also offer suggestions or let you know if there is already an effort in progress.