setup-agents

System shape

Architecture

Thin commands. Clear layers. Testable by design.

Design Principles

The plugin follows the same architectural patterns as profiler and JT_DynamicQueries: each layer has a single responsibility, and the command layer stays as thin as possible.

Thin Commands

Parse flags, delegate to setup layer, return typed results.

Dependency Injection

promptScope and printToConsole are injected into setup functions so tests avoid global mocks.

Result Monad

Result<T, E> in src/types/index.ts keeps error handling composable without exceptions.

Pure Generators

All content generation is side-effect free: inputs in, strings out. Zero I/O.

Boundaries

Layer Overview

Commands Layer

sf setup-agents local  ·  sf setup-agents mcp  ·  sf setup-agents update

Parse flags · Call detectTools / resolveProfiles · Delegate to Setup Layer · Return typed result

Setup Layer — src/setup/

cursor-setup.ts  ·  vscode-setup.ts  ·  codex-setup.ts  ·  claude-setup.ts  ·  agentforce-setup.ts

Orchestrates file creation. Calls Generators to build content. Calls FileWriter to persist. Receives promptScope and printToConsole as injected functions.

Generators — src/generators/
mdc-generator
agent-guidelines, sf-standards, sub-agent-protocol
workflow-generator
deploy, run-tests, validate, profile workflows
copilot-generator
copilot-instructions.md content
codex-generator
AGENTS.md content
claude-generator
CLAUDE.md content
extensions-generator
extensions.json union
agentforce-generator
.a4drules/ numbered files
Services — src/services/

FileWriter — centralises force/skip logic, calls writeFileSync, invokes log/warn callbacks.
ensureDir — creates directories recursively if they don't exist.

Repository map

Source Structure

src/
├── commands/
│   └── setup-agents/
│       ├── local.ts         ← sf setup-agents local
│       ├── mcp.ts           ← sf setup-agents mcp
│       └── update.ts        ← sf setup-agents update
├── generators/
│   ├── mdc-generator.ts
│   ├── workflow-generator.ts
│   ├── copilot-generator.ts
│   ├── codex-generator.ts
│   ├── claude-generator.ts
│   ├── extensions-generator.ts
│   ├── agentforce-generator.ts
│   ├── shared.ts
│   └── index.ts
├── setup/
│   ├── cursor-setup.ts
│   ├── vscode-setup.ts
│   ├── codex-setup.ts
│   ├── claude-setup.ts
│   ├── agentforce-setup.ts
│   └── index.ts
├── profiles/
│   ├── types.ts             ← Profile interface
│   ├── developer.ts
│   ├── architect.ts
│   ├── ba.ts  mulesoft.ts  ux.ts  cgcloud.ts
│   ├── devops.ts  qa.ts  crma.ts  data360.ts
│   └── index.ts
├── services/
│   └── file-writer.ts       ← FileWriter + ensureDir
├── types/
│   └── index.ts             ← SupportedTool, Result<T,E>, SetupLocalResult
└── version.ts               ← PLUGIN_VERSION constant

Contracts

Key Types

Result<T, E>

Lightweight Result monad. ok<T>(value) and err<E>(error) constructors. Enables composable error flows without throw/catch chains.

type Result<T, E = Error> =
  | { ok: true; value: T }
  | { ok: false; error: E }

Profile

Interface every profile object implements. detect?(cwd) for auto-detection, ruleContent() for .mdc generation, workflows?(version) for Agentforce workflows.

interface Profile {
  id: ProfileId
  label: string
  ruleFile: string
  ruleContent(): string
  extensions?: string[]
  detect?(cwd: string): boolean
  workflows?(v: string): Record<string, string>
}

SupportedTool

Union type for the 5 supported AI tools. Used by detectTools() and the --rules flag.

type SupportedTool =
  | 'cursor'
  | 'vscode'
  | 'codex'
  | 'claude'
  | 'agentforce'

FileWriter

Injected into every setup function. Centralises the force/skip decision so all setup modules share the same write behaviour.

class FileWriter {
  write(path: string, content: string)
    : 'written' | 'skipped'
}

Explore the testing methodology

Tests were written error-first following the EDD (Error-Driven Development) philosophy.