voicci 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "voicci",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "AI-Powered Audiobook Generator for Claude Code, OpenCode & AI Code Editors. Convert books and PDFs to audiobooks using natural language.",
5
5
  "type": "module",
6
6
  "main": "cli/index.js",
@@ -4,16 +4,20 @@ import fs from 'fs';
4
4
  import path from 'path';
5
5
  import os from 'os';
6
6
  import { fileURLToPath } from 'url';
7
+ import { execFileSync } from 'child_process';
7
8
 
8
9
  const __filename = fileURLToPath(import.meta.url);
9
10
  const __dirname = path.dirname(__filename);
10
11
 
12
+ // Use unique name to avoid conflicts with SSH shorthand skills
13
+ const SKILL_NAME = 'voicci-audiobook.md';
14
+
11
15
  const SKILL_CONTENT = `---
12
- description: "Voicci CLI - AI audiobook generator"
16
+ description: "Voicci - AI audiobook generator CLI"
13
17
  argument-hint: "COMMAND_OR_FILE"
14
18
  ---
15
19
 
16
- # Voicci CLI - AI Audiobook Generator
20
+ # Voicci - AI Audiobook Generator
17
21
 
18
22
  Convert books, PDFs, and documents to audiobooks using AI-powered text-to-speech (XTTS v2).
19
23
 
@@ -75,7 +79,7 @@ voicci memory
75
79
  \`\`\`!
76
80
  #!/bin/bash
77
81
  # Execute voicci with user-provided arguments
78
- voicci \$ARGUMENTS
82
+ voicci $ARGUMENTS
79
83
  \`\`\`
80
84
 
81
85
  ## Important Notes
@@ -87,41 +91,168 @@ voicci \$ARGUMENTS
87
91
  - Copyright warning will appear before first book search
88
92
 
89
93
  ## Usage Examples
90
- - \`/voicci-cli Lord of the Rings\` - Search and convert book
91
- - \`/voicci-cli ~/Documents/book.pdf\` - Convert local file
92
- - \`/voicci-cli -s\` - Check all job statuses
93
- - \`/voicci-cli summary book.pdf\` - Generate summary only
94
- - \`/voicci-cli --help\` - Show all options
94
+ - \`/voicci-audiobook "Lord of the Rings"\` - Search and convert book
95
+ - \`/voicci-audiobook ~/Documents/book.pdf\` - Convert local file
96
+ - \`/voicci-audiobook -s\` - Check all job statuses
97
+ - \`/voicci-audiobook summary book.pdf\` - Generate summary only
98
+ - \`/voicci-audiobook --help\` - Show all options
95
99
  `;
96
100
 
97
- function installSkill() {
98
- try {
99
- const homeDir = os.homedir();
100
- const skillsDir = path.join(homeDir, '.claude', 'skills');
101
- const skillFile = path.join(skillsDir, 'voicci-cli.md');
101
+ // Editor detection configurations
102
+ const EDITORS = {
103
+ 'Claude Code': {
104
+ name: 'Claude Code',
105
+ detect: () => {
106
+ const homeDir = os.homedir();
107
+ // Check for claude command or .claude directory
108
+ if (fs.existsSync(path.join(homeDir, '.claude'))) return true;
109
+ try {
110
+ execFileSync('which', ['claude'], { stdio: 'ignore' });
111
+ return true;
112
+ } catch {
113
+ return false;
114
+ }
115
+ },
116
+ skillsDir: () => path.join(os.homedir(), '.claude', 'skills'),
117
+ skillName: SKILL_NAME
118
+ },
119
+ 'OpenCode': {
120
+ name: 'OpenCode',
121
+ detect: () => {
122
+ const homeDir = os.homedir();
123
+ // Check for opencode command or config directory
124
+ if (fs.existsSync(path.join(homeDir, '.opencode'))) return true;
125
+ try {
126
+ execFileSync('which', ['opencode'], { stdio: 'ignore' });
127
+ return true;
128
+ } catch {
129
+ return false;
130
+ }
131
+ },
132
+ skillsDir: () => path.join(os.homedir(), '.opencode', 'skills'),
133
+ skillName: SKILL_NAME
134
+ },
135
+ 'Cursor': {
136
+ name: 'Cursor',
137
+ detect: () => {
138
+ const homeDir = os.homedir();
139
+ // Check for cursor command or config directory
140
+ if (fs.existsSync(path.join(homeDir, '.cursor'))) return true;
141
+ if (fs.existsSync(path.join(homeDir, 'Library', 'Application Support', 'Cursor'))) return true;
142
+ try {
143
+ execFileSync('which', ['cursor'], { stdio: 'ignore' });
144
+ return true;
145
+ } catch {
146
+ return false;
147
+ }
148
+ },
149
+ skillsDir: () => {
150
+ const homeDir = os.homedir();
151
+ // Try common locations
152
+ const locations = [
153
+ path.join(homeDir, '.cursor', 'skills'),
154
+ path.join(homeDir, 'Library', 'Application Support', 'Cursor', 'skills')
155
+ ];
156
+ for (const loc of locations) {
157
+ const parent = path.dirname(loc);
158
+ if (fs.existsSync(parent)) return loc;
159
+ }
160
+ return locations[0]; // Default to first
161
+ },
162
+ skillName: SKILL_NAME
163
+ },
164
+ 'Windsurf': {
165
+ name: 'Windsurf',
166
+ detect: () => {
167
+ const homeDir = os.homedir();
168
+ // Check for windsurf command or config directory
169
+ if (fs.existsSync(path.join(homeDir, '.windsurf'))) return true;
170
+ try {
171
+ execFileSync('which', ['windsurf'], { stdio: 'ignore' });
172
+ return true;
173
+ } catch {
174
+ return false;
175
+ }
176
+ },
177
+ skillsDir: () => path.join(os.homedir(), '.windsurf', 'skills'),
178
+ skillName: SKILL_NAME
179
+ }
180
+ };
181
+
182
+ function detectAndInstall() {
183
+ const homeDir = os.homedir();
184
+ const installedEditors = [];
185
+ const failedEditors = [];
186
+
187
+ console.log('šŸ” Detecting AI code editors...\n');
188
+
189
+ // Detect and install for each editor
190
+ for (const [key, editor] of Object.entries(EDITORS)) {
191
+ try {
192
+ if (editor.detect()) {
193
+ console.log(`āœ“ Found ${editor.name}`);
194
+
195
+ const skillsDir = editor.skillsDir();
196
+ const skillFile = path.join(skillsDir, editor.skillName);
197
+
198
+ // Create skills directory if it doesn't exist
199
+ if (!fs.existsSync(skillsDir)) {
200
+ fs.mkdirSync(skillsDir, { recursive: true });
201
+ }
102
202
 
103
- // Create .claude/skills directory if it doesn't exist
104
- if (!fs.existsSync(skillsDir)) {
105
- fs.mkdirSync(skillsDir, { recursive: true });
203
+ // Check for conflicts with existing files
204
+ if (fs.existsSync(skillFile)) {
205
+ const existingContent = fs.readFileSync(skillFile, 'utf8');
206
+ // Only skip if it's already our skill
207
+ if (existingContent.includes('voicci $ARGUMENTS')) {
208
+ console.log(` ↳ Skill already installed at: ${skillFile}`);
209
+ installedEditors.push({ name: editor.name, path: skillFile, status: 'exists' });
210
+ continue;
211
+ }
212
+ }
213
+
214
+ // Write the skill file
215
+ fs.writeFileSync(skillFile, SKILL_CONTENT, 'utf8');
216
+ console.log(` ↳ Installed skill: ${skillFile}`);
217
+ installedEditors.push({ name: editor.name, path: skillFile, status: 'new' });
218
+ }
219
+ } catch (error) {
220
+ failedEditors.push({ name: editor.name, error: error.message });
106
221
  }
222
+ }
223
+
224
+ // Summary
225
+ console.log('\n' + '═'.repeat(60));
226
+
227
+ if (installedEditors.length > 0) {
228
+ console.log('\nāœ… Voicci CLI installed successfully!');
229
+ console.log('\nšŸ“¦ Command-line tool: voicci');
230
+ console.log('šŸ”§ Skill command: /voicci-audiobook');
231
+ console.log('\nšŸ“ Installed in:');
232
+ installedEditors.forEach(editor => {
233
+ const status = editor.status === 'new' ? '(new)' : '(already installed)';
234
+ console.log(` • ${editor.name} ${status}`);
235
+ });
107
236
 
108
- // Write the skill file
109
- fs.writeFileSync(skillFile, SKILL_CONTENT, 'utf8');
110
-
111
- console.log('āœ… Voicci CLI installed successfully!');
112
- console.log('');
113
- console.log('šŸ“¦ Command-line tool: voicci');
114
- console.log('šŸ”§ Claude Code skill: /voicci-cli');
115
- console.log('');
116
- console.log('To use in Claude Code:');
117
- console.log(' 1. Restart your Claude Code session');
118
- console.log(' 2. Use: /voicci-cli "search query" or /voicci-cli mybook.pdf');
119
- console.log('');
120
- console.log('Or use directly: voicci "your search query"');
121
- } catch (error) {
122
- console.error('āš ļø Failed to install Claude Code skill:', error.message);
123
- console.log('You can still use: voicci <command>');
237
+ console.log('\nšŸ’” Usage:');
238
+ console.log(' 1. Restart your AI code editor');
239
+ console.log(' 2. Use: /voicci-audiobook "search query"');
240
+ console.log(' 3. Or use CLI directly: voicci "your search query"');
241
+ } else {
242
+ console.log('\nāš ļø No supported AI code editors detected');
243
+ console.log('\nSupported editors: Claude Code, OpenCode, Cursor, Windsurf');
244
+ console.log('\nāœ“ You can still use the CLI: voicci <command>');
124
245
  }
246
+
247
+ if (failedEditors.length > 0) {
248
+ console.log('\nāš ļø Failed to install for:');
249
+ failedEditors.forEach(({ name, error }) => {
250
+ console.log(` • ${name}: ${error}`);
251
+ });
252
+ }
253
+
254
+ console.log('\n' + '═'.repeat(60));
255
+ console.log();
125
256
  }
126
257
 
127
- installSkill();
258
+ detectAndInstall();