Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/agentforce-vibes-manual-directory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@salesforce/b2c-cli': minor
'@salesforce/b2c-tooling-sdk': minor
---

Add Agentforce Vibes (`--ide agentforce-vibes`) as a supported IDE target for `setup skills`, installing to `.a4drules/skills/`. Add `--directory` flag for custom installation paths. Change `manual` default directory to `.agents/skills/`.
50 changes: 29 additions & 21 deletions docs/cli/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,30 +375,32 @@ b2c setup skills [SKILLSET]

### Flags

| Flag | Description | Default |
| ---------------- | ----------------------------------------------------------------------------- | ----------- |
| `--list`, `-l` | List available skills without installing | `false` |
| `--skill` | Install specific skill(s) (can be repeated) | |
| `--ide` | Target IDE(s): claude-code, cursor, windsurf, vscode, codex, opencode, manual | Auto-detect |
| `--global`, `-g` | Install to user home directory (global scope) | `false` |
| `--update`, `-u` | Update existing skills (overwrite) | `false` |
| `--version` | Specific release version | `latest` |
| `--force` | Skip confirmation prompts (non-interactive) | `false` |
| `--json` | Output results as JSON | `false` |
| Flag | Description | Default |
| --------------------- | ---------------------------------------------------------------------------------------------- | ----------- |
| `--list`, `-l` | List available skills without installing | `false` |
| `--skill` | Install specific skill(s) (can be repeated) | |
| `--ide` | Target IDE(s): claude-code, cursor, windsurf, vscode, codex, opencode, agentforce-vibes, manual | Auto-detect |
| `--directory`, `-d` | Custom installation directory (overrides IDE default path) | |
| `--global`, `-g` | Install to user home directory (global scope) | `false` |
| `--update`, `-u` | Update existing skills (overwrite) | `false` |
| `--version` | Specific release version | `latest` |
| `--force` | Skip confirmation prompts (non-interactive) | `false` |
| `--json` | Output results as JSON | `false` |

### Supported IDEs

| IDE Value | IDE Name | Project Path | Global Path |
| ------------- | ------------------------ | ------------------- | ----------------------------- |
| `claude-code` | Claude Code | `.claude/skills/` | `~/.claude/skills/` |
| `cursor` | Cursor | `.cursor/skills/` | `~/.cursor/skills/` |
| `windsurf` | Windsurf | `.windsurf/skills/` | `~/.codeium/windsurf/skills/` |
| `vscode` | VS Code / GitHub Copilot | `.github/skills/` | `~/.copilot/skills/` |
| `codex` | OpenAI Codex CLI | `.codex/skills/` | `~/.codex/skills/` |
| `opencode` | OpenCode | `.opencode/skills/` | `~/.config/opencode/skills/` |
| `manual` | Manual | `.claude/skills/` | `~/.claude/skills/` |
| IDE Value | IDE Name | Project Path | Global Path |
| ------------------ | ------------------------ | --------------------- | --------------------------------------------------- |
| `claude-code` | Claude Code | `.claude/skills/` | `~/.claude/skills/` |
| `cursor` | Cursor | `.cursor/skills/` | `~/.cursor/skills/` |
| `windsurf` | Windsurf | `.windsurf/skills/` | `~/.codeium/windsurf/skills/` |
| `vscode` | VS Code / GitHub Copilot | `.github/skills/` | `~/.copilot/skills/` |
| `codex` | OpenAI Codex CLI | `.codex/skills/` | `~/.codex/skills/` |
| `opencode` | OpenCode | `.opencode/skills/` | `~/.config/opencode/skills/` |
| `agentforce-vibes` | Agentforce Vibes | `.a4drules/skills/` | `~/Library/Application Support/Code/User/globalStorage` (macOS) |
| `manual` | Manual | `.agents/skills/` | `~/.agents/skills/` |

Use `manual` when you want to install to the Claude Code paths without marketplace recommendations.
Use `agentforce-vibes` for Salesforce Agentforce for VS Code. Use `manual` for generic installation with a custom `--directory` path.

### Examples

Expand All @@ -422,6 +424,12 @@ b2c setup skills b2c --ide cursor --ide windsurf
# Install specific skills only
b2c setup skills b2c-cli --skill b2c-code --skill b2c-webdav --ide cursor

# Install to Agentforce Vibes (.a4drules/skills/)
b2c setup skills b2c --ide agentforce-vibes

# Install to a custom directory
b2c setup skills b2c --ide manual --directory ./my-skills

# Update existing skills
b2c setup skills b2c --ide cursor --update

Expand Down Expand Up @@ -465,7 +473,7 @@ The marketplace provides:
- Centralized plugin management
- Version tracking

Use `--ide manual` if you prefer manual installation to the same paths.
Use `--ide manual` if you prefer manual installation, or `--ide agentforce-vibes` to install to the `.a4drules/skills/` directory used by Salesforce Agentforce for VS Code.

### Skill Sets

Expand Down
40 changes: 39 additions & 1 deletion docs/guide/agent-skills.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,34 @@ b2c setup skills b2c-cli --ide cursor --global --force

See [Setup Commands](/cli/setup) for full CLI documentation.

## Installation with Agentforce Vibes

[Agentforce for VS Code](https://developer.salesforce.com/docs/einstein/genai/guide/agentforce-in-ide.html) (Agentforce Vibes) automatically detects skills placed in the `.a4drules/skills/` directory.

### Using B2C CLI

```bash
# Install to project .a4drules/skills/ directory
b2c setup skills b2c --ide agentforce-vibes
b2c setup skills b2c-cli --ide agentforce-vibes

# Install globally
b2c setup skills b2c --ide agentforce-vibes --global
```

### Manual Setup

Place skill directories in `.a4drules/skills/` (project) or your global storage directory:

| Location | Scope |
|----------|-------|
| `.a4drules/skills/` | Project (recommended) |
| `~/Library/Application Support/Code/User/globalStorage` | Global (macOS) |
| `~/.config/Code/User/globalStorage` | Global (Linux) |
| `%APPDATA%\Code\User\globalStorage` | Global (Windows) |

When a global skill and project skill have the same name, the global skill takes precedence. Version control your project skills by committing `.a4drules/skills/` to your source repository so your team can share, review, and improve them together.

## Installation with Other IDEs

The B2C skills follow the [Agent Skills](https://agentskills.io/home) standard and can be used with other AI-powered development tools.
Expand Down Expand Up @@ -253,7 +281,17 @@ Skills are installed to:

### Manual Installation

For other AI-powered IDEs, download the skills zip files from the [latest GitHub release](https://github.com/SalesforceCommerceCloud/b2c-developer-tooling/releases/latest):
Use `--ide manual` to install to the default `.agents/skills/` directory, or specify a custom path with `--directory`:

```bash
# Install to .agents/skills/ (default for manual)
b2c setup skills b2c --ide manual

# Install to a custom directory
b2c setup skills b2c --ide manual --directory ./my-skills
```

You can also download the skills zip files directly from the [latest GitHub release](https://github.com/SalesforceCommerceCloud/b2c-developer-tooling/releases/latest):

| Artifact | Contents |
|----------|----------|
Expand Down
27 changes: 23 additions & 4 deletions packages/b2c-cli/src/commands/setup/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
*/
import {Args, Flags, ux} from '@oclif/core';
import {checkbox, confirm} from '@inquirer/prompts';
import {checkbox, confirm, input} from '@inquirer/prompts';
import {BaseCommand, createTable, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli';
import {
type IdeType,
Expand Down Expand Up @@ -77,6 +77,8 @@ export default class SetupSkills extends BaseCommand<typeof SetupSkills> {
'<%= config.bin %> <%= command.id %> b2c --list',
'<%= config.bin %> <%= command.id %> b2c-cli --skill b2c-code --skill b2c-webdav --ide cursor',
'<%= config.bin %> <%= command.id %> b2c --global --update --force',
'<%= config.bin %> <%= command.id %> b2c --ide agentforce-vibes',
'<%= config.bin %> <%= command.id %> b2c --ide manual --directory ./my-skills',
];

static flags = {
Expand All @@ -91,10 +93,14 @@ export default class SetupSkills extends BaseCommand<typeof SetupSkills> {
multiple: true,
}),
ide: Flags.string({
description: 'Target IDE(s): claude-code, cursor, windsurf, vscode, codex, opencode, manual',
description: 'Target IDE(s): claude-code, cursor, windsurf, vscode, codex, opencode, agentforce-vibes, manual',
options: ALL_IDE_TYPES,
multiple: true,
}),
directory: Flags.string({
char: 'd',
description: 'Custom installation directory (overrides IDE default path)',
}),
global: Flags.boolean({
char: 'g',
description: 'Install to user home directory (global)',
Expand Down Expand Up @@ -218,12 +224,15 @@ export default class SetupSkills extends BaseCommand<typeof SetupSkills> {
return {};
}

// Always include 'manual' as an option in the IDE list
const ideChoices: IdeType[] = detectedIdes.includes('manual') ? detectedIdes : [...detectedIdes, 'manual'];

// Non-interactive: use all detected IDEs; Interactive: let user select
targetIdes = this.flags.force
? detectedIdes
: await checkbox({
message: t('commands.setup.skills.selectIdes', 'Select target IDEs:'),
choices: detectedIdes.map((ide) => ({
choices: ideChoices.map((ide) => ({
name: getIdeDisplayName(ide),
value: ide,
})),
Expand Down Expand Up @@ -264,8 +273,17 @@ export default class SetupSkills extends BaseCommand<typeof SetupSkills> {
}
}

// Prompt for manual installation directory
let directory = this.flags.directory;
if (targetIdes.includes('manual') && !directory && !this.flags.force) {
directory = await input({
message: t('commands.setup.skills.manualDirectory', 'Installation directory:'),
default: '.agents/skills',
});
}

// Show installation preview
const scope = this.flags.global ? 'global (user home)' : 'project';
const scope = directory ? `directory: ${directory}` : this.flags.global ? 'global (user home)' : 'project';
ux.stdout('');
ux.stdout(
t('commands.setup.skills.preview', 'Installing {{count}} skills to {{ides}} ({{scope}})', {
Expand Down Expand Up @@ -297,6 +315,7 @@ export default class SetupSkills extends BaseCommand<typeof SetupSkills> {
global: this.flags.global,
update: this.flags.update,
projectRoot: process.cwd(),
directory,
});
})
.filter((p): p is Promise<InstallSkillsResult> => p !== null);
Expand Down
52 changes: 47 additions & 5 deletions packages/b2c-tooling-sdk/src/skills/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ import type {IdeConfig, IdeType} from './types.js';

const home = os.homedir();

/**
* Get the Agentforce Vibes global skills directory based on platform.
*/
function getAgentforceVibesGlobalDir(): string {
const platform = process.platform;
if (platform === 'darwin') {
return path.join(home, 'Library', 'Application Support', 'Code', 'User', 'globalStorage');
} else if (platform === 'win32') {
return path.join(process.env.APPDATA || path.join(home, 'AppData', 'Roaming'), 'Code', 'User', 'globalStorage');
}
return path.join(home, '.config', 'Code', 'User', 'globalStorage');
}

/**
* IDE configurations with paths and detection logic.
*/
Expand Down Expand Up @@ -88,13 +101,26 @@ export const IDE_CONFIGS: Record<IdeType, IdeConfig> = {
},
docsUrl: 'https://opencode.ai/',
},
'agentforce-vibes': {
id: 'agentforce-vibes',
displayName: 'Agentforce Vibes',
paths: {
projectDir: '.a4drules/skills',
globalDir: getAgentforceVibesGlobalDir(),
},
detectInstalled: async () => {
// Check for the Agentforce extension's globalStorage entry
const globalStorageDir = getAgentforceVibesGlobalDir();
return fs.existsSync(path.join(globalStorageDir, 'salesforce.salesforcedx-einstein-gpt'));
},
docsUrl: 'https://developer.salesforce.com/docs/einstein/genai/guide/agentforce-in-ide.html',
},
manual: {
id: 'manual',
displayName: 'Manual Installation',
paths: {
// Manual mode uses same paths as Claude Code
projectDir: '.claude/skills',
globalDir: path.join(home, '.claude/skills'),
projectDir: '.agents/skills',
globalDir: path.join(home, '.agents/skills'),
},
detectInstalled: async () => {
// Manual is always "available" as a fallback
Expand All @@ -106,7 +132,16 @@ export const IDE_CONFIGS: Record<IdeType, IdeConfig> = {
/**
* All supported IDE types in display order.
*/
export const ALL_IDE_TYPES: IdeType[] = ['claude-code', 'cursor', 'windsurf', 'vscode', 'codex', 'opencode', 'manual'];
export const ALL_IDE_TYPES: IdeType[] = [
'claude-code',
'cursor',
'windsurf',
'vscode',
'codex',
'opencode',
'agentforce-vibes',
'manual',
];

/**
* Detect which IDEs are installed on the system.
Expand Down Expand Up @@ -143,8 +178,15 @@ export async function detectInstalledIdes(): Promise<IdeType[]> {
export function getSkillInstallPath(
ide: IdeType,
skillName: string,
options: {global: boolean; projectRoot?: string},
options: {global: boolean; projectRoot?: string; directory?: string},
): string {
// Custom directory override — used as the base path directly
if (options.directory) {
const projectRoot = options.projectRoot || process.cwd();
const dir = path.isAbsolute(options.directory) ? options.directory : path.join(projectRoot, options.directory);
return path.join(dir, skillName);
}

const config = IDE_CONFIGS[ide];

if (options.global) {
Expand Down
1 change: 1 addition & 0 deletions packages/b2c-tooling-sdk/src/skills/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export async function installSkills(
const targetPath = getSkillInstallPath(ide, sanitizedName, {
global: options.global,
projectRoot: options.projectRoot,
directory: options.directory,
});

// Get the base directory for path safety validation
Expand Down
12 changes: 11 additions & 1 deletion packages/b2c-tooling-sdk/src/skills/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@
/**
* Supported IDE types for skill installation.
*/
export type IdeType = 'claude-code' | 'cursor' | 'windsurf' | 'vscode' | 'codex' | 'opencode' | 'manual';
export type IdeType =
| 'claude-code'
| 'cursor'
| 'windsurf'
| 'vscode'
| 'codex'
| 'opencode'
| 'agentforce-vibes'
| 'manual';

/**
* Skill set categories matching the plugins directory structure.
Expand Down Expand Up @@ -98,6 +106,8 @@ export interface InstallSkillsOptions {
update: boolean;
/** Project root for project-level installations */
projectRoot?: string;
/** Custom directory override (used instead of IDE-specific project path) */
directory?: string;
}

/**
Expand Down
Loading