Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
52cd22f
Initial plan
Copilot Apr 24, 2026
2c18475
feat: make ai-config agent-agnostic with --agent and --skills-dir opt…
Copilot Apr 24, 2026
c67709e
refactor: improve analytics event and clean up skillsDir resolution
Copilot Apr 24, 2026
d4478a9
feat: update angular schematics ai-config to accept --agent and --ski…
Copilot Apr 24, 2026
5784c4a
feat: enhance ai-config to prompt for agent selection and improve ski…
Marina-L-Stoyanova Apr 27, 2026
39eff3d
feat: enhance ai-config command to handle agent selection and improve…
Marina-L-Stoyanova Apr 27, 2026
6c5d717
feat: make ai-config agent-agnostic by supporting multiple agents and…
Marina-L-Stoyanova Apr 28, 2026
14e062d
feat: refactor ai-config to support agent-based skills configuration …
Marina-L-Stoyanova Apr 28, 2026
026fb9e
Merge branch 'master' of https://github.com/IgniteUI/igniteui-cli int…
Marina-L-Stoyanova Apr 28, 2026
3669211
feat: add AI agent configuration options to project creation
Marina-L-Stoyanova Apr 28, 2026
f2f39a9
change():Moving skills to ai-config skills directory and updating the…
Marina-L-Stoyanova Apr 29, 2026
1379243
chore: enhance AI configuration options with labels and improved sele…
Marina-L-Stoyanova Apr 29, 2026
4fb65da
feat: update AI configuration options to include 'none' and improve p…
Marina-L-Stoyanova Apr 29, 2026
baee30a
feat: enhance AI configuration by adding instruction file handling an…
Marina-L-Stoyanova Apr 29, 2026
56ccdf8
Removing skills and instructions from _base templates
Marina-L-Stoyanova Apr 29, 2026
96f010b
Optimizing react ai-config template
Marina-L-Stoyanova Apr 29, 2026
9ca5b16
fix: remove unnecessary whitespace in PromptSession unit tests
Marina-L-Stoyanova Apr 30, 2026
100f1e4
chore: remove outdated AGENTS.md file from React template
Marina-L-Stoyanova Apr 30, 2026
fd28dde
feat: refactor AI agent selection to use promptForAgents function
Marina-L-Stoyanova May 4, 2026
f2656af
feat: add InquirerWrapper checkbox spy to new command tests
Marina-L-Stoyanova May 4, 2026
62a33a4
feat: update AI agent configuration and help command documentation
Marina-L-Stoyanova May 4, 2026
9d5d801
feat: enhance AI tooling configuration with agent selection and instr…
Marina-L-Stoyanova May 4, 2026
d30a1cd
feat: refactor AI configuration to use promptForAgents and update ski…
Marina-L-Stoyanova May 5, 2026
a892c47
feat: add required option to promptForAgents and update tests for ana…
Marina-L-Stoyanova May 5, 2026
ae4b10b
feat: apply review comments
Marina-L-Stoyanova May 5, 2026
ee143b8
Apply suggestion from @damyanpetev
Marina-L-Stoyanova May 5, 2026
dd7dff4
Apply suggestion from @damyanpetev
Marina-L-Stoyanova May 5, 2026
e9f9424
refactor: update skills directory resolution and clean up tests
Marina-L-Stoyanova May 5, 2026
2b5318e
chore():updating ai-config templates
Marina-L-Stoyanova May 5, 2026
bfc819f
feat: add template file resolution for AGENTS.md and update related t…
Marina-L-Stoyanova May 5, 2026
713f181
feat: enhance ai-config template validation and add file existence ch…
Marina-L-Stoyanova May 5, 2026
af0430a
chore: cleanup ai-config partials
damyanpetev May 7, 2026
d9ec603
refactor: call ai-config schematic w/ task for prompt reuse
damyanpetev May 7, 2026
829fde0
refactor: move dirs inside copy logic
damyanpetev May 7, 2026
1f8670b
refactor: restore `configureAI()` to call `configure()` entry and mov…
Copilot May 8, 2026
215bf05
refactor: cleanup agent options and dir exports
damyanpetev May 8, 2026
6e548d1
fix: new command argument name and adjust descriptions
damyanpetev May 8, 2026
f6916ea
refactor: constants for AI config project ID and skills directory
damyanpetev May 8, 2026
61b414b
Merge branch 'master' into copilot/update-ai-config-agent-agnostic
damyanpetev May 8, 2026
e72529a
fix: agents schematics param
damyanpetev May 8, 2026
22ad345
chore: schematics descr and redundant default
damyanpetev May 8, 2026
d13a60c
feat: add AI agents configuration tests to new command
Marina-L-Stoyanova May 8, 2026
c4cd106
test(schematics): fix async tests
damyanpetev May 8, 2026
53ef9c6
test(schematics): fix broken text expects/setup
damyanpetev May 8, 2026
750d75b
fix(schematics,new): filter out hidden projects
damyanpetev May 8, 2026
f8d1271
refactor(schematics,new): run full ai-config schematic for args/prompts
damyanpetev May 8, 2026
fa0fb97
doc(readme): missed arg rename
damyanpetev May 8, 2026
a271689
revert(schematics,new): early name use for move
damyanpetev May 8, 2026
11f6d71
fix: update Google Analytics tracking for AI configuration and adjust…
Marina-L-Stoyanova May 8, 2026
e22cb40
Merge branch 'copilot/update-ai-config-agent-agnostic' of https://git…
Marina-L-Stoyanova May 8, 2026
2824045
fix: update Google Analytics tracking for AI configuration to use cor…
Marina-L-Stoyanova May 8, 2026
e2da748
refactor(ai-config): TTY check for prompt and defaults handling
damyanpetev May 8, 2026
faffbaa
test(new): fix ai-config spies
damyanpetev May 8, 2026
46dff06
chore: unused import
damyanpetev May 8, 2026
3231e02
Merge branch 'master' into copilot/update-ai-config-agent-agnostic
damyanpetev May 8, 2026
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
22 changes: 17 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,21 @@ ig start

## Configure AI Tooling

To automatically configure Ignite UI AI tooling - MCP servers and AI coding skills, run:
To configure Ignite UI AI tooling MCP servers and AI coding skills run:

```bash
ig ai-config
```

This creates or updates `.vscode/mcp.json` in the current project with entries for both the [Ignite UI MCP](#mcp-server) and `igniteui-theming` MCP servers. Existing servers in the file are preserved. It also copies any AI coding skill files from installed Ignite UI packages into the project. New projects are created with AI tooling configuration out of the box.
You will be prompted to select which AI tools to configure (Claude and Generic are selected by default). You can also pass agents directly:

```bash
ig ai-config --agents claude copilot generic
```

This creates or updates `.vscode/mcp.json` with entries for the [Ignite UI MCP](#mcp-server) and `igniteui-theming` MCP servers (existing servers are preserved), copies AI coding skill files from installed Ignite UI packages, and generates agent-specific instruction files (e.g. `CLAUDE.md`, `AGENTS.md`).

The `ig new` command also prompts for AI tool configuration as part of project creation.

## MCP Server

Expand All @@ -170,14 +178,18 @@ ig mcp --debug # Enable debug logging to mcp-server.log

### Using with AI Assistants

For VS Code, the `ig ai-config` command handles configuration automatically (see above). For other MCP clients (e.g., Claude Desktop, Cursor), configure them manually to use the CLI as the MCP server:
For VS Code, the `ig ai-config` command handles configuration automatically (see above). For other MCP clients (e.g., Claude Desktop, Cursor), configure them manually:

```json
{
"mcpServers": {
"igniteui-cli": {
"command": "ig",
"args": ["mcp"]
"command": "npx",
"args": ["-y", "igniteui-cli", "mcp"]
},
"igniteui-theming": {
"command": "npx",
"args": ["-y", "igniteui-theming", "igniteui-theming-mcp"]
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/lib/PromptSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export class PromptSession extends BasePromptSession {
}
// move cwd to project folder
process.chdir(projectName);
await this.configureAI();
}
await this.chooseActionLoop(projLibrary);
//TODO: restore cwd?
Expand All @@ -105,8 +106,7 @@ export class PromptSession extends BasePromptSession {
}

protected async configureAI(): Promise<void> {
// skip adding skills since those are baked into the project template atm:
aiConfigure(false);
await aiConfigure();
}

/**
Expand Down
64 changes: 53 additions & 11 deletions packages/cli/lib/commands/ai-config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addMcpServers, copyAISkillsToProject, GoogleAnalytics, Util, VS_CODE_MCP_PATH } from "@igniteui/cli-core";
import { addMcpServers, AI_AGENT_LABELS, AI_AGENT_CHOICES, AIAgentTarget, copyAgentInstructionFiles, copyAISkillsToProject, GoogleAnalytics, InquirerWrapper, Util, VS_CODE_MCP_PATH } from "@igniteui/cli-core";
import { ArgumentsCamelCase, CommandModule } from "yargs";

export function configureMCP(): void {
Expand All @@ -11,8 +11,8 @@ export function configureMCP(): void {
Util.log(Util.greenCheck() + ` MCP servers configured in ${VS_CODE_MCP_PATH}`);
}

export function configureSkills(): void {
const result = copyAISkillsToProject();
export function configureSkills(agents: AIAgentTarget[]): void {
const result = copyAISkillsToProject(agents);
if (result.found === 0) {
Util.warn("No AI skill files found. Make sure packages are installed (npm install) " +
"and your Ignite UI packages are up-to-date.", "yellow");
Expand All @@ -26,30 +26,72 @@ export function configureSkills(): void {
}
}

export function configure(skills = true): void {
export async function configure(agents?: AIAgentTarget[], skills = true): Promise<void> {
if (!agents?.length) {
agents = await promptForAgents();
}
if (!agents.length) return;
configureMCP();
if (skills) {
configureSkills();
configureSkills(agents);
}
copyAgentInstructionFiles(agents);
}
const AI_AGENT_CHECKBOX_DEFAULTS: AIAgentTarget[] = ["generic", "claude"];
const AI_AGENT_CHECKBOX_CHOICES = [
{ value: "none", name: "None (skip AI configuration)" },
...AI_AGENT_CHOICES.map(agent => ({
value: agent,
name: AI_AGENT_LABELS[agent],
checked: AI_AGENT_CHECKBOX_DEFAULTS.includes(agent)
}))
];

export async function promptForAgents(): Promise<AIAgentTarget[]> {
let selected: AIAgentTarget[] = AI_AGENT_CHECKBOX_DEFAULTS;
if (Util.canPrompt()) {
const result = await InquirerWrapper.checkbox({
message: "Which AI tools do you want to generate configuration files for?",
required: true,
choices: AI_AGENT_CHECKBOX_CHOICES
});
selected = result.includes("none") ? [] : result as AIAgentTarget[];
}
return selected;
}

const command: CommandModule = {
command: "ai-config",
describe: "Configures Ignite UI AI tooling (MCP servers and AI coding skills)",
builder: (yargs) => yargs,
async handler(_argv: ArgumentsCamelCase) {
describe: "Configures Ignite UI AI tooling (MCP servers, AI coding skills and instructions)",
builder: (yargs) => yargs
.usage("")
.option("agent", {
alias: "a",
describe: "AI agents/tools to generate configuration files for",
choices: AI_AGENT_CHOICES,
type: "array"
}),
Comment thread
damyanpetev marked this conversation as resolved.
async handler(argv: ArgumentsCamelCase) {
let agents = argv.agent as AIAgentTarget[] | undefined;
GoogleAnalytics.post({
t: "screenview",
cd: "MCP"
cd: "Ai Config"
});

if (!agents?.length) {
agents = await promptForAgents();
}
GoogleAnalytics.post({
t: "event",
ec: "$ig ai-config",
ea: "client: vscode"
ea: `agent: ${agents.join(", ")}`
});

configure();
if (!agents.length) {
Util.log("No AI configuration selected. Skipping.");
return;
}
await configure(agents);
}
};

Expand Down
21 changes: 16 additions & 5 deletions packages/cli/lib/commands/new.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { GoogleAnalytics, PackageManager, ProjectConfig, ProjectLibrary, Util } from "@igniteui/cli-core";
import { AI_AGENT_CHOICES, AIAgentTarget, GoogleAnalytics, PackageManager, ProjectConfig, ProjectLibrary, Util } from "@igniteui/cli-core";
import * as path from "path";
import { PromptSession } from "./../PromptSession";
import { NewCommandType, PositionalArgs } from "./types";
import { TemplateManager } from "../TemplateManager";
import { ArgumentsCamelCase, Choices } from "yargs";
import { configure } from "./ai-config";

// explicit typing because `type: "string"` will be inferred as `type: string` which yargs will not like
const _framework: {
Expand Down Expand Up @@ -59,6 +60,12 @@ const command: NewCommandType = {
describe: "Project template",
type: "string"
})
.option("agents", {
alias: "a",
describe: "AI agents/tools to generate configuration files for",
choices: AI_AGENT_CHOICES,
type: "array"
})
.example("$0 new my-app", "Scaffold a new project interactively")
.example("$0 new my-app -f angular -t igx-ts", "Scaffold an Ignite UI for Angular project");
},
Expand Down Expand Up @@ -152,16 +159,20 @@ const command: NewCommandType = {

Util.log(Util.greenCheck() + " Project Created");

if (!argv["skip-git"] && !ProjectConfig.getConfig().skipGit) {
Util.gitInit(process.cwd(), argv.name);
}

if (!argv.skipInstall) {
process.chdir(argv.name);
await PackageManager.installPackages();
process.chdir("..");
}

process.chdir(argv.name);
await configure(argv.agents as AIAgentTarget[] | undefined);
process.chdir("..");

if (!argv["skip-git"] && !ProjectConfig.getConfig().skipGit) {
Util.gitInit(process.cwd(), argv.name);
}

Util.log("");
Util.log("Next Steps:");
Util.log(` cd ${argv.name}`);
Expand Down

This file was deleted.

This file was deleted.

38 changes: 38 additions & 0 deletions packages/cli/templates/react/igr-ts/projects/ai-config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ControlExtraConfiguration, defaultDelimiters, ProjectTemplate } from "@igniteui/cli-core";
import * as path from "path";

// currently reusing hidden project impl as components/views pipeline go through registerInProject
// ideally would define a separate type/category for those partial files
export class IgrTsAiConfigPartial implements ProjectTemplate {
public id: string = "ai-config";
public name = "ai-config";
public description = "Ignite UI CLI AI config for React partial project files";
public framework: string = "react";
public projectType: string = "tsx";
public dependencies: string[] = [];
public hasExtraConfiguration: boolean = false;
public isHidden: boolean = true;
public delimiters = defaultDelimiters;

public get templatePaths(): string[] {
return [path.join(__dirname, "files")];
}

public generateConfig(_name: string, _theme: string, ..._options: any[]): {[key: string]: any} {
return { /* partials not using Util.processTemplates atm */ };
}

public installModules(): void {
throw new Error("Method not implemented.");
}
public async upgradeIgniteUIPackages(_projectPath: string, _packagePath: string): Promise<boolean> {
throw new Error("Method not implemented.");
}
public getExtraConfiguration(): ControlExtraConfiguration[] {
throw new Error("Method not implemented.");
}
public setExtraConfiguration(_extraConfigKeys: {}) {
throw new Error("Method not implemented.");
}
}
export default new IgrTsAiConfigPartial();

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { ControlExtraConfiguration, defaultDelimiters, ProjectTemplate } from "@igniteui/cli-core";
import * as path from "path";

// currently reusing hidden project impl as components/views pipeline go through registerInProject
// ideally would define a separate type/category for those partial files
export class IgcTsAiConfigPartial implements ProjectTemplate {

public id: string = "ai-config";
public name = "ai-config";
public description = "Ignite UI CLI AI config for Web Components partial project files";
public framework: string = "webcomponents";
public projectType: string = "igc-ts";
public dependencies: string[];
public hasExtraConfiguration: boolean = false;
public isHidden: boolean = true;
public delimiters = defaultDelimiters;

public get templatePaths(): string[] {
return [path.join(__dirname, "files")];
}

installModules(): void {
throw new Error("Method not implemented.");
}
upgradeIgniteUIPackages(_projectPath: string, _packagePath: string): Promise<boolean> {
throw new Error("Method not implemented.");
}
generateConfig(_name: string, _theme: string, ..._options: any[]): { [key: string]: any; } {
throw new Error("Method not implemented.");
}
getExtraConfiguration(): ControlExtraConfiguration[] {
throw new Error("Method not implemented.");
}
setExtraConfiguration(_extraConfigKeys: {}) {
throw new Error("Method not implemented.");
Comment thread
damyanpetev marked this conversation as resolved.
}
}
export default new IgcTsAiConfigPartial();


3 changes: 1 addition & 2 deletions packages/core/prompt/BasePromptSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export abstract class BasePromptSession {
}
// move cwd to project folder
process.chdir(projectName);
await this.configureAI();
}
await this.chooseActionLoop(projLibrary);
//TODO: restore cwd?
Expand Down Expand Up @@ -423,8 +424,6 @@ export abstract class BasePromptSession {
}
}

await this.configureAI();

const defaultPort = config.project.defaultPort;
const port = await this.getUserInput({
type: "input",
Expand Down
12 changes: 8 additions & 4 deletions packages/core/prompt/InquirerWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@ type InputConfig = {
required?: boolean;
type?: string;
name?: string;
choices?: (string | Separator)[];
choices?: (string | Separator)[] | ({ value: string; name?: string; checked?: boolean } | Separator)[];
transformer?: (value: string, { isFinal }: {
isFinal: boolean;
}) => string;

// TODO: consider typing these by extracting the types from the inquirer package
validate?: any;
theme?: unknown;
theme?: any;
};

type InputChoicesConfig = InputConfig & {
choices: (string | Separator)[] | ({ value: string; name?: string; checked?: boolean } | Separator)[];
};

export class InquirerWrapper {
Expand All @@ -25,11 +29,11 @@ export class InquirerWrapper {
return input(message, context);
}

public static async select(message: InputConfig & { choices: (string | Separator)[] }, context?: Context): Promise<string> {
public static async select(message: InputChoicesConfig, context?: Context): Promise<string> {
return select(message, context);
}

public static async checkbox(message: InputConfig & { choices: (string | Separator)[] }, context?: Context): Promise<string[]> {
public static async checkbox(message: InputChoicesConfig, context?: Context): Promise<string[]> {
return checkbox(message, context);
}

Expand Down
7 changes: 7 additions & 0 deletions packages/core/util/Util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,13 @@ export class Util {
}
}

/**
* Checks if the terminal is TTY and is not in CI env
*/
public static canPrompt() {
return process.stdout.isTTY && process.stdin.isTTY && !process.env.CI;
}

/**
* Fairly aggressive sanitize removing anything but ASCII, numbers and a few needed chars that have no action:
* - semicolons (:), dots (.), underscores (_) for paths/URLs
Expand Down
Loading
Loading