Skip to content

Commit f82e243

Browse files
authored
feat: add Auggie (Augment CLI) support to configuration and documenta… (#196)
* feat: add Auggie (Augment CLI) support to configuration and documentation - Added Auggie (Augment CLI) to the AI tools configuration in `config.ts`. - Updated the slash command registry to include Auggie's configurator. - Documented Auggie's commands in the README.md for better visibility. This enhances the integration of Auggie within the existing toolset. * test: add tests for Auggie command file creation and updates - Implemented tests to verify the creation of Auggie slash command files with appropriate templates. - Added checks to ensure existing Auggie command files are refreshed correctly during updates. - Confirmed that missing command files are not created during the update process. These changes enhance the test coverage for Auggie's integration and ensure proper functionality of command file management.
1 parent 88b260d commit f82e243

File tree

6 files changed

+157
-0
lines changed

6 files changed

+157
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ These tools have built-in OpenSpec commands. Select the OpenSpec integration whe
9999
| **Codex** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (global: `~/.codex/prompts`, auto-installed) |
100100
| **GitHub Copilot** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.github/prompts/`) |
101101
| **Amazon Q Developer** | `@openspec-proposal`, `@openspec-apply`, `@openspec-archive` (`.amazonq/prompts/`) |
102+
| **Auggie (Augment CLI)** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.augment/commands/`) |
102103

103104
Kilo Code discovers team workflows automatically. Save the generated files under `.kilocode/workflows/` and trigger them from the command palette with `/openspec-proposal.md`, `/openspec-apply.md`, or `/openspec-archive.md`.
104105

src/core/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export interface AIToolOption {
1717
}
1818

1919
export const AI_TOOLS: AIToolOption[] = [
20+
{ name: 'Auggie (Augment CLI)', value: 'auggie', available: true, successLabel: 'Auggie' },
2021
{ name: 'Claude Code', value: 'claude', available: true, successLabel: 'Claude Code' },
2122
{ name: 'Cursor', value: 'cursor', available: true, successLabel: 'Cursor' },
2223
{ name: 'Factory Droid', value: 'factory', available: true, successLabel: 'Factory Droid' },
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { SlashCommandConfigurator } from './base.js';
2+
import { SlashCommandId } from '../../templates/index.js';
3+
4+
const FILE_PATHS: Record<SlashCommandId, string> = {
5+
proposal: '.augment/commands/openspec-proposal.md',
6+
apply: '.augment/commands/openspec-apply.md',
7+
archive: '.augment/commands/openspec-archive.md'
8+
};
9+
10+
const FRONTMATTER: Record<SlashCommandId, string> = {
11+
proposal: `---
12+
description: Scaffold a new OpenSpec change and validate strictly.
13+
argument-hint: feature description or request
14+
---`,
15+
apply: `---
16+
description: Implement an approved OpenSpec change and keep tasks in sync.
17+
argument-hint: change-id
18+
---`,
19+
archive: `---
20+
description: Archive a deployed OpenSpec change and update specs.
21+
argument-hint: change-id
22+
---`
23+
};
24+
25+
export class AuggieSlashCommandConfigurator extends SlashCommandConfigurator {
26+
readonly toolId = 'auggie';
27+
readonly isAvailable = true;
28+
29+
protected getRelativePath(id: SlashCommandId): string {
30+
return FILE_PATHS[id];
31+
}
32+
33+
protected getFrontmatter(id: SlashCommandId): string {
34+
return FRONTMATTER[id];
35+
}
36+
}
37+

src/core/configurators/slash/registry.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { CodexSlashCommandConfigurator } from './codex.js';
88
import { GitHubCopilotSlashCommandConfigurator } from './github-copilot.js';
99
import { AmazonQSlashCommandConfigurator } from './amazon-q.js';
1010
import { FactorySlashCommandConfigurator } from './factory.js';
11+
import { AuggieSlashCommandConfigurator } from './auggie.js';
1112

1213
export class SlashCommandRegistry {
1314
private static configurators: Map<string, SlashCommandConfigurator> = new Map();
@@ -22,6 +23,7 @@ export class SlashCommandRegistry {
2223
const githubCopilot = new GitHubCopilotSlashCommandConfigurator();
2324
const amazonQ = new AmazonQSlashCommandConfigurator();
2425
const factory = new FactorySlashCommandConfigurator();
26+
const auggie = new AuggieSlashCommandConfigurator();
2527

2628
this.configurators.set(claude.toolId, claude);
2729
this.configurators.set(cursor.toolId, cursor);
@@ -32,6 +34,7 @@ export class SlashCommandRegistry {
3234
this.configurators.set(githubCopilot.toolId, githubCopilot);
3335
this.configurators.set(amazonQ.toolId, amazonQ);
3436
this.configurators.set(factory.toolId, factory);
37+
this.configurators.set(auggie.toolId, auggie);
3538
}
3639

3740
static register(configurator: SlashCommandConfigurator): void {

test/core/init.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,60 @@ describe('InitCommand', () => {
683683
);
684684
expect(amazonQChoice.configured).toBe(true);
685685
});
686+
687+
it('should create Auggie slash command files with templates', async () => {
688+
queueSelections('auggie', DONE);
689+
690+
await initCommand.execute(testDir);
691+
692+
const auggieProposal = path.join(
693+
testDir,
694+
'.augment/commands/openspec-proposal.md'
695+
);
696+
const auggieApply = path.join(
697+
testDir,
698+
'.augment/commands/openspec-apply.md'
699+
);
700+
const auggieArchive = path.join(
701+
testDir,
702+
'.augment/commands/openspec-archive.md'
703+
);
704+
705+
expect(await fileExists(auggieProposal)).toBe(true);
706+
expect(await fileExists(auggieApply)).toBe(true);
707+
expect(await fileExists(auggieArchive)).toBe(true);
708+
709+
const proposalContent = await fs.readFile(auggieProposal, 'utf-8');
710+
expect(proposalContent).toContain('---');
711+
expect(proposalContent).toContain('description: Scaffold a new OpenSpec change and validate strictly.');
712+
expect(proposalContent).toContain('argument-hint: feature description or request');
713+
expect(proposalContent).toContain('<!-- OPENSPEC:START -->');
714+
expect(proposalContent).toContain('**Guardrails**');
715+
716+
const applyContent = await fs.readFile(auggieApply, 'utf-8');
717+
expect(applyContent).toContain('---');
718+
expect(applyContent).toContain('description: Implement an approved OpenSpec change and keep tasks in sync.');
719+
expect(applyContent).toContain('argument-hint: change-id');
720+
expect(applyContent).toContain('Work through tasks sequentially');
721+
722+
const archiveContent = await fs.readFile(auggieArchive, 'utf-8');
723+
expect(archiveContent).toContain('---');
724+
expect(archiveContent).toContain('description: Archive a deployed OpenSpec change and update specs.');
725+
expect(archiveContent).toContain('argument-hint: change-id');
726+
expect(archiveContent).toContain('openspec archive <id> --yes');
727+
});
728+
729+
it('should mark Auggie as already configured during extend mode', async () => {
730+
queueSelections('auggie', DONE, 'auggie', DONE);
731+
await initCommand.execute(testDir);
732+
await initCommand.execute(testDir);
733+
734+
const secondRunArgs = mockPrompt.mock.calls[1][0];
735+
const auggieChoice = secondRunArgs.choices.find(
736+
(choice: any) => choice.value === 'auggie'
737+
);
738+
expect(auggieChoice.configured).toBe(true);
739+
});
686740
});
687741

688742
describe('non-interactive mode', () => {

test/core/update.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,67 @@ Old body
513513
await expect(FileSystemUtils.fileExists(aqArchive)).resolves.toBe(false);
514514
});
515515

516+
it('should refresh existing Auggie slash command files', async () => {
517+
const auggiePath = path.join(
518+
testDir,
519+
'.augment/commands/openspec-apply.md'
520+
);
521+
await fs.mkdir(path.dirname(auggiePath), { recursive: true });
522+
const initialContent = `---
523+
description: Implement an approved OpenSpec change and keep tasks in sync.
524+
argument-hint: change-id
525+
---
526+
<!-- OPENSPEC:START -->
527+
Old body
528+
<!-- OPENSPEC:END -->`;
529+
await fs.writeFile(auggiePath, initialContent);
530+
531+
const consoleSpy = vi.spyOn(console, 'log');
532+
533+
await updateCommand.execute(testDir);
534+
535+
const updatedContent = await fs.readFile(auggiePath, 'utf-8');
536+
expect(updatedContent).toContain('**Guardrails**');
537+
expect(updatedContent).toContain('<!-- OPENSPEC:START -->');
538+
expect(updatedContent).toContain('<!-- OPENSPEC:END -->');
539+
expect(updatedContent).not.toContain('Old body');
540+
541+
expect(consoleSpy).toHaveBeenCalledWith(
542+
expect.stringContaining('.augment/commands/openspec-apply.md')
543+
);
544+
545+
consoleSpy.mockRestore();
546+
});
547+
548+
it('should not create missing Auggie slash command files on update', async () => {
549+
const auggieApply = path.join(
550+
testDir,
551+
'.augment/commands/openspec-apply.md'
552+
);
553+
554+
// Only create apply; leave proposal and archive missing
555+
await fs.mkdir(path.dirname(auggieApply), { recursive: true });
556+
await fs.writeFile(
557+
auggieApply,
558+
'---\ndescription: Old\nargument-hint: old\n---\n<!-- OPENSPEC:START -->\nOld\n<!-- OPENSPEC:END -->'
559+
);
560+
561+
await updateCommand.execute(testDir);
562+
563+
const auggieProposal = path.join(
564+
testDir,
565+
'.augment/commands/openspec-proposal.md'
566+
);
567+
const auggieArchive = path.join(
568+
testDir,
569+
'.augment/commands/openspec-archive.md'
570+
);
571+
572+
// Confirm they weren't created by update
573+
await expect(FileSystemUtils.fileExists(auggieProposal)).resolves.toBe(false);
574+
await expect(FileSystemUtils.fileExists(auggieArchive)).resolves.toBe(false);
575+
});
576+
516577
it('should preserve Windsurf content outside markers during update', async () => {
517578
const wsPath = path.join(
518579
testDir,

0 commit comments

Comments
 (0)