Skip to content

Commit 5439ab0

Browse files
authored
Document Gemini CLI slash updates (#301)
1 parent 9b6a763 commit 5439ab0

File tree

4 files changed

+61
-13
lines changed

4 files changed

+61
-13
lines changed

.repo-updates-log

Lines changed: 0 additions & 13 deletions
This file was deleted.

openspec/specs/cli-init/spec.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,13 @@ The init command SHALL generate slash command files for supported editors using
231231
- **AND** wrap the shared template body with OpenSpec markers so `openspec update` can refresh the content
232232
- **AND** each template includes instructions for the relevant OpenSpec workflow stage
233233

234+
#### Scenario: Generating slash commands for Gemini CLI
235+
- **WHEN** the user selects Gemini CLI during initialization
236+
- **THEN** create `.gemini/commands/openspec/proposal.toml`, `.gemini/commands/openspec/apply.toml`, and `.gemini/commands/openspec/archive.toml`
237+
- **AND** populate each file as TOML that sets a stage-specific `description = "<summary>"` and a multi-line `prompt = """` block with the shared OpenSpec template
238+
- **AND** wrap the OpenSpec managed markers (`<!-- OPENSPEC:START -->` / `<!-- OPENSPEC:END -->`) inside the `prompt` value so `openspec update` can safely refresh the body between markers without touching the TOML framing
239+
- **AND** ensure the slash-command copy matches the existing proposal/apply/archive templates used by other tools
240+
234241
### Requirement: Non-Interactive Mode
235242
The command SHALL support non-interactive operation through command-line options for automation and CI/CD use cases.
236243

openspec/specs/cli-update/spec.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ The update command SHALL refresh existing slash command files for configured too
117117
- **AND** update only the OpenSpec-managed block between markers
118118
- **AND** ensure templates include instructions for the relevant workflow stage
119119

120+
#### Scenario: Updating slash commands for Gemini CLI
121+
- **WHEN** `.gemini/commands/openspec/` contains `proposal.toml`, `apply.toml`, and `archive.toml`
122+
- **THEN** refresh the body of each file using the shared proposal/apply/archive templates
123+
- **AND** replace only the content between `<!-- OPENSPEC:START -->` and `<!-- OPENSPEC:END -->` markers inside the `prompt = """` block so the TOML framing (`description`, `prompt`) stays intact
124+
- **AND** skip creating any missing `.toml` files during update; only pre-existing Gemini commands are refreshed
125+
120126
#### Scenario: Missing slash command file
121127
- **WHEN** a tool lacks a slash command file
122128
- **THEN** do not create a new file during update

test/core/update.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,54 @@ Old body
588588
await expect(FileSystemUtils.fileExists(ghArchive)).resolves.toBe(false);
589589
});
590590

591+
it('should refresh existing Gemini CLI TOML files without creating new ones', async () => {
592+
const geminiProposal = path.join(
593+
testDir,
594+
'.gemini/commands/openspec/proposal.toml'
595+
);
596+
await fs.mkdir(path.dirname(geminiProposal), { recursive: true });
597+
const initialContent = `description = "Scaffold a new OpenSpec change and validate strictly."
598+
599+
prompt = """
600+
<!-- OPENSPEC:START -->
601+
Old Gemini body
602+
<!-- OPENSPEC:END -->
603+
"""
604+
`;
605+
await fs.writeFile(geminiProposal, initialContent);
606+
607+
const consoleSpy = vi.spyOn(console, 'log');
608+
609+
await updateCommand.execute(testDir);
610+
611+
const updated = await fs.readFile(geminiProposal, 'utf-8');
612+
expect(updated).toContain('description = "Scaffold a new OpenSpec change and validate strictly."');
613+
expect(updated).toContain('prompt = """');
614+
expect(updated).toContain('<!-- OPENSPEC:START -->');
615+
expect(updated).toContain('**Guardrails**');
616+
expect(updated).toContain('<!-- OPENSPEC:END -->');
617+
expect(updated).not.toContain('Old Gemini body');
618+
619+
const geminiApply = path.join(
620+
testDir,
621+
'.gemini/commands/openspec/apply.toml'
622+
);
623+
const geminiArchive = path.join(
624+
testDir,
625+
'.gemini/commands/openspec/archive.toml'
626+
);
627+
628+
await expect(FileSystemUtils.fileExists(geminiApply)).resolves.toBe(false);
629+
await expect(FileSystemUtils.fileExists(geminiArchive)).resolves.toBe(false);
630+
631+
const [logMessage] = consoleSpy.mock.calls[0];
632+
expect(logMessage).toContain(
633+
'Updated slash commands: .gemini/commands/openspec/proposal.toml'
634+
);
635+
636+
consoleSpy.mockRestore();
637+
});
638+
591639
it('should refresh existing Factory slash commands', async () => {
592640
const factoryPath = path.join(
593641
testDir,

0 commit comments

Comments
 (0)