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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ These tools have built-in OpenSpec commands. Select the OpenSpec integration whe
|------|----------|
| **Claude Code** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` |
| **CodeBuddy Code (CLI)** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.codebuddy/commands/`) — see [docs](https://www.codebuddy.ai/cli) |
| **Costrict** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.cospec/openspec/commands/`) — see [docs](https://costrict.ai)|
| **CoStrict** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.cospec/openspec/commands/`) — see [docs](https://costrict.ai)|
| **Cursor** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` |
| **Cline** | Rules in `.clinerules/` directory (`.clinerules/openspec-*.md`) |
| **Crush** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.crush/commands/openspec/`) |
Expand Down
2 changes: 1 addition & 1 deletion src/core/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const AI_TOOLS: AIToolOption[] = [
{ name: 'Claude Code', value: 'claude', available: true, successLabel: 'Claude Code' },
{ name: 'Cline', value: 'cline', available: true, successLabel: 'Cline' },
{ name: 'CodeBuddy Code (CLI)', value: 'codebuddy', available: true, successLabel: 'CodeBuddy Code' },
{ name: 'Costrict', value: 'costrict', available: true, successLabel: 'Costrict' },
{ name: 'CoStrict', value: 'costrict', available: true, successLabel: 'CoStrict' },
{ name: 'Crush', value: 'crush', available: true, successLabel: 'Crush' },
{ name: 'Cursor', value: 'cursor', available: true, successLabel: 'Cursor' },
{ name: 'Factory Droid', value: 'factory', available: true, successLabel: 'Factory Droid' },
Expand Down
2 changes: 1 addition & 1 deletion src/core/configurators/costrict.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { TemplateManager } from '../templates/index.js';
import { OPENSPEC_MARKERS } from '../config.js';

export class CostrictConfigurator implements ToolConfigurator {
name = 'Costrict';
name = 'CoStrict';
configFileName = 'COSTRICT.md';
isAvailable = true;

Expand Down
10 changes: 5 additions & 5 deletions src/core/configurators/slash/costrict.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { SlashCommandConfigurator } from './base.js';
import { SlashCommandId } from '../../templates/index.js';

const FILE_PATHS: Record<SlashCommandId, string> = {
const FILE_PATHS = {
proposal: '.cospec/openspec/commands/openspec-proposal.md',
apply: '.cospec/openspec/commands/openspec-apply.md',
archive: '.cospec/openspec/commands/openspec-archive.md'
};
archive: '.cospec/openspec/commands/openspec-archive.md',
} as const satisfies Record<SlashCommandId, string>;

const FRONTMATTER: Record<SlashCommandId, string> = {
const FRONTMATTER = {
proposal: `---
description: "Scaffold a new OpenSpec change and validate strictly."
argument-hint: feature description or request
Expand All @@ -20,7 +20,7 @@ argument-hint: change-id
description: "Archive a deployed OpenSpec change and update specs."
argument-hint: change-id
---`
};
} as const satisfies Record<SlashCommandId, string>;

export class CostrictSlashCommandConfigurator extends SlashCommandConfigurator {
readonly toolId = 'costrict';
Expand Down
8 changes: 4 additions & 4 deletions test/core/init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,7 @@ describe('InitCommand', () => {
expect(crushChoice.configured).toBe(true);
});

it('should create Costrict slash command files with templates', async () => {
it('should create CoStrict slash command files with templates', async () => {
queueSelections('costrict', DONE);

await initCommand.execute(testDir);
Expand Down Expand Up @@ -1038,7 +1038,7 @@ describe('InitCommand', () => {
expect(archiveContent).toContain('openspec archive <id> --yes');
});

it('should mark Costrict as already configured during extend mode', async () => {
it('should mark CoStrict as already configured during extend mode', async () => {
queueSelections('costrict', DONE, 'costrict', DONE);
await initCommand.execute(testDir);
await initCommand.execute(testDir);
Expand All @@ -1050,7 +1050,7 @@ describe('InitCommand', () => {
expect(costrictChoice.configured).toBe(true);
});

it('should create COSTRICT.md when Costrict is selected', async () => {
it('should create COSTRICT.md when CoStrict is selected', async () => {
queueSelections('costrict', DONE);

await initCommand.execute(testDir);
Expand All @@ -1070,7 +1070,7 @@ describe('InitCommand', () => {

const costrictPath = path.join(testDir, 'COSTRICT.md');
const existingContent =
'# My Costrict Instructions\nCustom instructions here';
'# My CoStrict Instructions\nCustom instructions here';
await fs.writeFile(costrictPath, existingContent);

await initCommand.execute(testDir);
Expand Down
17 changes: 7 additions & 10 deletions test/core/update.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ Old body
await expect(FileSystemUtils.fileExists(crushArchive)).resolves.toBe(false);
});

it('should refresh existing Costrict slash command files', async () => {
it('should refresh existing CoStrict slash command files', async () => {
const costrictPath = path.join(
testDir,
'.cospec/openspec/commands/openspec-proposal.md'
Expand Down Expand Up @@ -860,7 +860,7 @@ Old body
consoleSpy.mockRestore();
});

it('should not create missing Costrict slash command files on update', async () => {
it('should not create missing CoStrict slash command files on update', async () => {
const costrictApply = path.join(
testDir,
'.cospec/openspec/commands/openspec-apply.md'
Expand Down Expand Up @@ -898,9 +898,9 @@ Old
it('should update only existing COSTRICT.md file', async () => {
// Create COSTRICT.md file with initial content
const costrictPath = path.join(testDir, 'COSTRICT.md');
const initialContent = `# Costrict Instructions
const initialContent = `# CoStrict Instructions

Some existing Costrict instructions here.
Some existing CoStrict instructions here.

<!-- OPENSPEC:START -->
Old OpenSpec content
Expand All @@ -920,7 +920,7 @@ More instructions after.`;
expect(updatedContent).toContain('<!-- OPENSPEC:END -->');
expect(updatedContent).toContain("@/openspec/AGENTS.md");
expect(updatedContent).toContain('openspec update');
expect(updatedContent).toContain('Some existing Costrict instructions here');
expect(updatedContent).toContain('Some existing CoStrict instructions here');
expect(updatedContent).toContain('More instructions after');

// Check console output
Expand All @@ -945,7 +945,7 @@ More instructions after.`;
expect(fileExists).toBe(false);
});

it('should preserve Costrict content outside markers during update', async () => {
it('should preserve CoStrict content outside markers during update', async () => {
const costrictPath = path.join(
testDir,
'.cospec/openspec/commands/openspec-proposal.md'
Expand All @@ -963,14 +963,13 @@ More instructions after.`;
expect(updated).toContain('Validate with `openspec validate <id> --strict`');
});

it('should handle configurator errors gracefully for Costrict', async () => {
it('should handle configurator errors gracefully for CoStrict', async () => {
// Create COSTRICT.md file but make it read-only to cause an error
const costrictPath = path.join(testDir, 'COSTRICT.md');
await fs.writeFile(
costrictPath,
'<!-- OPENSPEC:START -->\nOld\n<!-- OPENSPEC:END -->'
);
await fs.chmod(costrictPath, 0o444); // Read-only

const consoleSpy = vi.spyOn(console, 'log');
const errorSpy = vi.spyOn(console, 'error');
Expand All @@ -997,8 +996,6 @@ More instructions after.`;
expect(logMessage).toContain('AGENTS.md (created)');
expect(logMessage).toContain('Failed to update: COSTRICT.md');

// Restore permissions for cleanup
await fs.chmod(costrictPath, 0o644);
consoleSpy.mockRestore();
errorSpy.mockRestore();
writeSpy.mockRestore();
Expand Down