@@ -13,6 +13,7 @@ import { continueAdapter } from '../../../src/core/command-generation/adapters/c
1313import { costrictAdapter } from '../../../src/core/command-generation/adapters/costrict.js' ;
1414import { crushAdapter } from '../../../src/core/command-generation/adapters/crush.js' ;
1515import { cursorAdapter } from '../../../src/core/command-generation/adapters/cursor.js' ;
16+ import { devinAdapter } from '../../../src/core/command-generation/adapters/devin.js' ;
1617import { factoryAdapter } from '../../../src/core/command-generation/adapters/factory.js' ;
1718import { geminiAdapter } from '../../../src/core/command-generation/adapters/gemini.js' ;
1819import { githubCopilotAdapter } from '../../../src/core/command-generation/adapters/github-copilot.js' ;
@@ -126,6 +127,76 @@ describe('command-generation/adapters', () => {
126127 } ) ;
127128 } ) ;
128129
130+ describe ( 'devinAdapter' , ( ) => {
131+ it ( 'should have correct toolId' , ( ) => {
132+ expect ( devinAdapter . toolId ) . toBe ( 'devin' ) ;
133+ } ) ;
134+
135+ it ( 'should generate correct file path' , ( ) => {
136+ const filePath = devinAdapter . getFilePath ( 'explore' ) ;
137+ expect ( filePath ) . toBe ( path . join ( '.devin' , 'workflows' , 'opsx-explore.md' ) ) ;
138+ } ) ;
139+
140+ it ( 'should generate correct file paths for different commands' , ( ) => {
141+ expect ( devinAdapter . getFilePath ( 'new' ) ) . toBe ( path . join ( '.devin' , 'workflows' , 'opsx-new.md' ) ) ;
142+ expect ( devinAdapter . getFilePath ( 'bulk-archive' ) ) . toBe ( path . join ( '.devin' , 'workflows' , 'opsx-bulk-archive.md' ) ) ;
143+ } ) ;
144+
145+ it ( 'should format file with YAML frontmatter' , ( ) => {
146+ const output = devinAdapter . formatFile ( sampleContent ) ;
147+
148+ expect ( output ) . toContain ( '---\n' ) ;
149+ expect ( output ) . toContain ( 'name: OpenSpec Explore' ) ;
150+ expect ( output ) . toContain ( 'description: Enter explore mode for thinking' ) ;
151+ expect ( output ) . toContain ( 'category: Workflow' ) ;
152+ expect ( output ) . toContain ( 'tags: [workflow, explore, experimental]' ) ;
153+ expect ( output ) . toContain ( '---\n\n' ) ;
154+ expect ( output ) . toContain ( 'This is the command body.' ) ;
155+ } ) ;
156+
157+ it ( 'should transform colon command references to hyphen format' , ( ) => {
158+ const contentWithRefs : CommandContent = {
159+ ...sampleContent ,
160+ body : 'Run /opsx:apply to implement. Then use /opsx:verify.' ,
161+ } ;
162+ const output = devinAdapter . formatFile ( contentWithRefs ) ;
163+ expect ( output ) . toContain ( '/opsx-apply' ) ;
164+ expect ( output ) . toContain ( '/opsx-verify' ) ;
165+ expect ( output ) . not . toContain ( '/opsx:apply' ) ;
166+ expect ( output ) . not . toContain ( '/opsx:verify' ) ;
167+ } ) ;
168+
169+ it ( 'should escape YAML special characters in frontmatter' , ( ) => {
170+ const contentWithSpecialChars : CommandContent = {
171+ ...sampleContent ,
172+ name : 'Test: Command' ,
173+ description : 'Fix "auth" feature' ,
174+ } ;
175+ const output = devinAdapter . formatFile ( contentWithSpecialChars ) ;
176+ expect ( output ) . toContain ( 'name: "Test: Command"' ) ;
177+ expect ( output ) . toContain ( 'description: "Fix \\"auth\\" feature"' ) ;
178+ } ) ;
179+
180+ it ( 'should escape implicit YAML scalars in frontmatter' , ( ) => {
181+ const contentWithImplicitScalar : CommandContent = {
182+ ...sampleContent ,
183+ name : 'true' ,
184+ description : 'null' ,
185+ category : 'on' ,
186+ } ;
187+ const output = devinAdapter . formatFile ( contentWithImplicitScalar ) ;
188+ expect ( output ) . toContain ( 'name: "true"' ) ;
189+ expect ( output ) . toContain ( 'description: "null"' ) ;
190+ expect ( output ) . toContain ( 'category: "on"' ) ;
191+ } ) ;
192+
193+ it ( 'should handle empty tags' , ( ) => {
194+ const contentNoTags : CommandContent = { ...sampleContent , tags : [ ] } ;
195+ const output = devinAdapter . formatFile ( contentNoTags ) ;
196+ expect ( output ) . toContain ( 'tags: []' ) ;
197+ } ) ;
198+ } ) ;
199+
129200 describe ( 'amazonQAdapter' , ( ) => {
130201 it ( 'should have correct toolId' , ( ) => {
131202 expect ( amazonQAdapter . toolId ) . toBe ( 'amazon-q' ) ;
0 commit comments