(homeDir: string)
| 192 | } |
| 193 | |
| 194 | function migrateOpenCodeOpenSpecPaths(homeDir: string): void { |
| 195 | const opencodePlatform = PLATFORMS.find((p) => p.id === 'opencode'); |
| 196 | if (!opencodePlatform?.globalSkillsDir) return; |
| 197 | |
| 198 | // OpenSpec hardcodes skillsDir as '.opencode' in its AI_TOOLS, so it writes |
| 199 | // to ~/.opencode/ even for global installs. OpenCode actually reads from |
| 200 | // ~/.config/opencode/ (Comet's globalSkillsDir). Move the files over. |
| 201 | const wrongDir = path.join(homeDir, opencodePlatform.skillsDir); |
| 202 | const correctDir = path.join(homeDir, opencodePlatform.globalSkillsDir); |
| 203 | |
| 204 | const migrations: Array<[string, string, string]> = [ |
| 205 | [path.join(wrongDir, 'skills'), path.join(correctDir, 'skills'), 'skills'], |
| 206 | [path.join(wrongDir, 'commands'), path.join(correctDir, 'commands'), 'commands'], |
| 207 | ]; |
| 208 | |
| 209 | for (const [srcDir, destDir, label] of migrations) { |
| 210 | if (srcDir === destDir) continue; |
| 211 | if (!fs.existsSync(srcDir)) continue; |
| 212 | try { |
| 213 | const entries = fs.readdirSync(srcDir); |
| 214 | if (entries.length === 0) continue; |
| 215 | |
| 216 | fs.mkdirSync(destDir, { recursive: true }); |
| 217 | for (const entry of entries) { |
| 218 | const srcPath = path.join(srcDir, entry); |
| 219 | const destPath = path.join(destDir, entry); |
| 220 | fs.cpSync(srcPath, destPath, { recursive: true, force: true }); |
| 221 | } |
| 222 | fs.rmSync(srcDir, { recursive: true, force: true }); |
| 223 | } catch (error) { |
| 224 | console.error( |
| 225 | ` Warning: failed to migrate OpenSpec ${label} from ${srcDir} to ${destDir}: ${(error as Error).message}`, |
| 226 | ); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | // Remove wrong parent directory if both skills and commands have been migrated |
| 231 | if (fs.existsSync(wrongDir)) { |
| 232 | try { |
| 233 | const remaining = fs.readdirSync(wrongDir); |
| 234 | if (remaining.length === 0) { |
| 235 | fs.rmdirSync(wrongDir); |
| 236 | } |
| 237 | } catch { |
| 238 | // Best-effort cleanup |
| 239 | } |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | async function installOpenSpec( |
| 244 | projectPath: string, |
no outgoing calls
no test coverage detected