11#!/usr/bin/env node
22import fs from 'node:fs'
33import path from 'node:path'
4- import * as converter from './lib/converter.js'
4+ import {
5+ type AgentMode ,
6+ type ContentType ,
7+ convertContent ,
8+ } from './lib/converter.js'
59import * as skillsCore from './lib/skills-core.js'
610
711const VERSION = '0.1.0'
@@ -14,23 +18,23 @@ Usage:
1418
1519Commands:
1620 list [type] List available skills, agents, or commands
17- convert <type> <source> [--output <path>] [--dry-run]
18- Convert Claude Code content to OpenCode format
19- Types: skill, agent, command
21+ convert <type> <file> [--mode=primary|subagent]
22+ Convert and inspect a file (outputs to stdout)
2023 config [subcommand] Configuration management
2124 show Show configuration
2225 path Print config file locations
2326
2427Options:
25- --output, -o Output path for convert command
26- --dry-run Preview conversion without writing files
2728 -h, --help Show this help message
2829 -v, --version Show version
2930
3031Examples:
3132 systematic list skills
32- systematic convert skill /path/to/cep/skills/agent-browser -o ./skills/agent-browser
33- systematic convert agent /path/to/agent.md --dry-run
33+ systematic list agents
34+ systematic convert agent ./agents/my-agent.md
35+ systematic convert agent ./agents/my-agent.md --mode=primary
36+ systematic convert skill ./skills/my-skill/SKILL.md
37+ systematic config show
3438`
3539
3640function getUserConfigDir ( ) : string {
@@ -85,6 +89,40 @@ function listItems(type: string): void {
8589 }
8690}
8791
92+ function runConvert ( type : string , filePath : string , modeArg ?: string ) : void {
93+ const validTypes = [ 'skill' , 'agent' , 'command' ]
94+ if ( ! validTypes . includes ( type ) ) {
95+ console . error (
96+ `Invalid type: ${ type } . Must be one of: ${ validTypes . join ( ', ' ) } ` ,
97+ )
98+ process . exit ( 1 )
99+ }
100+
101+ const resolvedPath = path . resolve ( filePath )
102+ if ( ! fs . existsSync ( resolvedPath ) ) {
103+ console . error ( `File not found: ${ resolvedPath } ` )
104+ process . exit ( 1 )
105+ }
106+
107+ let agentMode : AgentMode = 'subagent '
108+ if ( modeArg ) {
109+ const modeMatch = modeArg . match ( / ^ - - m o d e = ( p r i m a r y | s u b a g e n t ) $ / )
110+ if ( modeMatch ) {
111+ agentMode = modeMatch [ 1 ] as AgentMode
112+ } else {
113+ console . error (
114+ 'Invalid --mode flag. Use: --mode=primary or --mode=subagent' ,
115+ )
116+ process . exit ( 1 )
117+ }
118+ }
119+
120+ const content = fs . readFileSync ( resolvedPath , 'utf8' )
121+ const converted = convertContent ( content , type as ContentType , { agentMode } )
122+
123+ console . log ( converted )
124+ }
125+
88126function configShow ( ) : void {
89127 const userDir = getUserConfigDir ( )
90128 const projectDir = getProjectConfigDir ( )
@@ -115,61 +153,6 @@ function configPath(): void {
115153 console . log ( ` Project: ${ path . join ( projectDir , 'systematic.json' ) } ` )
116154}
117155
118- function runConvert ( args : string [ ] ) : void {
119- const typeArg = args [ 1 ]
120- const sourceArg = args [ 2 ]
121-
122- if ( ! typeArg || ! sourceArg ) {
123- console . error (
124- 'Usage: systematic convert <type> <source> [--output <path>] [--dry-run]' ,
125- )
126- console . error ( 'Types: skill, agent, command' )
127- process . exit ( 1 )
128- }
129-
130- const validTypes = [ 'skill' , 'agent' , 'command' ]
131- if ( ! validTypes . includes ( typeArg ) ) {
132- console . error (
133- `Invalid type: ${ typeArg } . Must be one of: ${ validTypes . join ( ', ' ) } ` ,
134- )
135- process . exit ( 1 )
136- }
137-
138- const sourcePath = path . resolve ( sourceArg )
139- if ( ! fs . existsSync ( sourcePath ) ) {
140- console . error ( `Source not found: ${ sourcePath } ` )
141- process . exit ( 1 )
142- }
143-
144- const outputIndex = args . findIndex ( ( a ) => a === '--output' || a === '-o' )
145- const outputPath =
146- outputIndex !== - 1 ? path . resolve ( args [ outputIndex + 1 ] ) : undefined
147- const dryRun = args . includes ( '--dry-run' )
148-
149- try {
150- const result = converter . convert (
151- typeArg as converter . ConvertType ,
152- sourcePath ,
153- { output : outputPath , dryRun } ,
154- )
155-
156- if ( dryRun ) {
157- console . log ( `[DRY RUN] Would convert ${ result . type } :` )
158- } else {
159- console . log ( `Converted ${ result . type } :` )
160- }
161- console . log ( ` Source: ${ result . sourcePath } ` )
162- console . log ( ` Output: ${ result . outputPath } ` )
163- console . log ( ' Files:' )
164- for ( const file of result . files ) {
165- console . log ( ` - ${ file } ` )
166- }
167- } catch ( err ) {
168- console . error ( `Conversion failed: ${ ( err as Error ) . message } ` )
169- process . exit ( 1 )
170- }
171- }
172-
173156const args = process . argv . slice ( 2 )
174157const command = args [ 0 ]
175158
@@ -178,7 +161,14 @@ switch (command) {
178161 listItems ( args [ 1 ] || 'skills' )
179162 break
180163 case 'convert ':
181- runConvert ( args )
164+ if ( ! args [ 1 ] || ! args [ 2 ] ) {
165+ console . error (
166+ 'Usage: systematic convert <type> <file> [--mode=primary|subagent]' ,
167+ )
168+ console . error ( ' type: skill, agent, or command' )
169+ process . exit ( 1 )
170+ }
171+ runConvert ( args [ 1 ] , args [ 2 ] , args [ 3 ] )
182172 break
183173 case 'config ':
184174 switch ( args [ 1 ] ) {
0 commit comments