voicci 1.0.6 → 1.0.8

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.8",
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,43 @@ 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
 
11
- const SKILL_CONTENT = `---
12
- description: "Voicci CLI - AI audiobook generator"
12
+ // Two skill files: simple and detailed
13
+ const SKILL_NAME_SIMPLE = 'voicci.md';
14
+ const SKILL_NAME_DETAILED = 'voicci-audiobook.md';
15
+
16
+ const SKILL_CONTENT_SIMPLE = `---
17
+ description: "Voicci - AI audiobook generator"
18
+ argument-hint: "COMMAND_OR_FILE"
19
+ ---
20
+
21
+ # Voicci - AI Audiobook Generator
22
+
23
+ Convert books, PDFs, and documents to audiobooks using AI text-to-speech.
24
+
25
+ ## Quick Examples
26
+ - \`/voicci "Lord of the Rings"\` - Search and convert book
27
+ - \`/voicci mybook.pdf\` - Convert local file
28
+ - \`/voicci -s\` - Check job status
29
+ - \`/voicci -l\` - List audiobooks
30
+ - \`/voicci --help\` - Show all options
31
+
32
+ \`\`\`!
33
+ #!/bin/bash
34
+ voicci $ARGUMENTS
35
+ \`\`\`
36
+ `;
37
+
38
+ const SKILL_CONTENT_DETAILED = `---
39
+ description: "Voicci - AI audiobook generator CLI"
13
40
  argument-hint: "COMMAND_OR_FILE"
14
41
  ---
15
42
 
16
- # Voicci CLI - AI Audiobook Generator
43
+ # Voicci - AI Audiobook Generator
17
44
 
18
45
  Convert books, PDFs, and documents to audiobooks using AI-powered text-to-speech (XTTS v2).
19
46
 
@@ -75,7 +102,7 @@ voicci memory
75
102
  \`\`\`!
76
103
  #!/bin/bash
77
104
  # Execute voicci with user-provided arguments
78
- voicci \$ARGUMENTS
105
+ voicci $ARGUMENTS
79
106
  \`\`\`
80
107
 
81
108
  ## Important Notes
@@ -87,41 +114,180 @@ voicci \$ARGUMENTS
87
114
  - Copyright warning will appear before first book search
88
115
 
89
116
  ## 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
117
+ - \`/voicci-audiobook "Lord of the Rings"\` - Search and convert book
118
+ - \`/voicci-audiobook ~/Documents/book.pdf\` - Convert local file
119
+ - \`/voicci-audiobook -s\` - Check all job statuses
120
+ - \`/voicci-audiobook summary book.pdf\` - Generate summary only
121
+ - \`/voicci-audiobook --help\` - Show all options
95
122
  `;
96
123
 
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');
124
+ // Editor detection configurations
125
+ const EDITORS = {
126
+ 'Claude Code': {
127
+ name: 'Claude Code',
128
+ detect: () => {
129
+ const homeDir = os.homedir();
130
+ // Check for claude command or .claude directory
131
+ if (fs.existsSync(path.join(homeDir, '.claude'))) return true;
132
+ try {
133
+ execFileSync('which', ['claude'], { stdio: 'ignore' });
134
+ return true;
135
+ } catch {
136
+ return false;
137
+ }
138
+ },
139
+ skillsDir: () => path.join(os.homedir(), '.claude', 'skills')
140
+ },
141
+ 'OpenCode': {
142
+ name: 'OpenCode',
143
+ detect: () => {
144
+ const homeDir = os.homedir();
145
+ // Check for opencode command or config directory
146
+ if (fs.existsSync(path.join(homeDir, '.opencode'))) return true;
147
+ try {
148
+ execFileSync('which', ['opencode'], { stdio: 'ignore' });
149
+ return true;
150
+ } catch {
151
+ return false;
152
+ }
153
+ },
154
+ skillsDir: () => path.join(os.homedir(), '.opencode', 'skills')
155
+ },
156
+ 'Cursor': {
157
+ name: 'Cursor',
158
+ detect: () => {
159
+ const homeDir = os.homedir();
160
+ // Check for cursor command or config directory
161
+ if (fs.existsSync(path.join(homeDir, '.cursor'))) return true;
162
+ if (fs.existsSync(path.join(homeDir, 'Library', 'Application Support', 'Cursor'))) return true;
163
+ try {
164
+ execFileSync('which', ['cursor'], { stdio: 'ignore' });
165
+ return true;
166
+ } catch {
167
+ return false;
168
+ }
169
+ },
170
+ skillsDir: () => {
171
+ const homeDir = os.homedir();
172
+ // Try common locations
173
+ const locations = [
174
+ path.join(homeDir, '.cursor', 'skills'),
175
+ path.join(homeDir, 'Library', 'Application Support', 'Cursor', 'skills')
176
+ ];
177
+ for (const loc of locations) {
178
+ const parent = path.dirname(loc);
179
+ if (fs.existsSync(parent)) return loc;
180
+ }
181
+ return locations[0]; // Default to first
182
+ }
183
+ },
184
+ 'Windsurf': {
185
+ name: 'Windsurf',
186
+ detect: () => {
187
+ const homeDir = os.homedir();
188
+ // Check for windsurf command or config directory
189
+ if (fs.existsSync(path.join(homeDir, '.windsurf'))) return true;
190
+ try {
191
+ execFileSync('which', ['windsurf'], { stdio: 'ignore' });
192
+ return true;
193
+ } catch {
194
+ return false;
195
+ }
196
+ },
197
+ skillsDir: () => path.join(os.homedir(), '.windsurf', 'skills')
198
+ }
199
+ };
102
200
 
103
- // Create .claude/skills directory if it doesn't exist
104
- if (!fs.existsSync(skillsDir)) {
105
- fs.mkdirSync(skillsDir, { recursive: true });
201
+ function installSkillFile(skillsDir, skillName, content) {
202
+ const skillFile = path.join(skillsDir, skillName);
203
+
204
+ // Check if already installed
205
+ if (fs.existsSync(skillFile)) {
206
+ const existingContent = fs.readFileSync(skillFile, 'utf8');
207
+ if (existingContent.includes('voicci $ARGUMENTS')) {
208
+ return 'exists';
106
209
  }
210
+ }
211
+
212
+ // Write the skill file
213
+ fs.writeFileSync(skillFile, content, 'utf8');
214
+ return 'new';
215
+ }
107
216
 
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>');
217
+ function detectAndInstall() {
218
+ const homeDir = os.homedir();
219
+ const installedEditors = [];
220
+ const failedEditors = [];
221
+
222
+ console.log('šŸ” Detecting AI code editors...\n');
223
+
224
+ // Detect and install for each editor
225
+ for (const [key, editor] of Object.entries(EDITORS)) {
226
+ try {
227
+ if (editor.detect()) {
228
+ console.log(`āœ“ Found ${editor.name}`);
229
+
230
+ const skillsDir = editor.skillsDir();
231
+
232
+ // Create skills directory if it doesn't exist
233
+ if (!fs.existsSync(skillsDir)) {
234
+ fs.mkdirSync(skillsDir, { recursive: true });
235
+ }
236
+
237
+ // Install both skills
238
+ const simpleStatus = installSkillFile(skillsDir, SKILL_NAME_SIMPLE, SKILL_CONTENT_SIMPLE);
239
+ const detailedStatus = installSkillFile(skillsDir, SKILL_NAME_DETAILED, SKILL_CONTENT_DETAILED);
240
+
241
+ const simpleFile = path.join(skillsDir, SKILL_NAME_SIMPLE);
242
+ const detailedFile = path.join(skillsDir, SKILL_NAME_DETAILED);
243
+
244
+ if (simpleStatus === 'exists' && detailedStatus === 'exists') {
245
+ console.log(` ↳ Skills already installed`);
246
+ installedEditors.push({ name: editor.name, status: 'exists' });
247
+ } else {
248
+ if (simpleStatus === 'new') console.log(` ↳ Installed: ${simpleFile}`);
249
+ if (detailedStatus === 'new') console.log(` ↳ Installed: ${detailedFile}`);
250
+ installedEditors.push({ name: editor.name, status: 'new' });
251
+ }
252
+ }
253
+ } catch (error) {
254
+ failedEditors.push({ name: editor.name, error: error.message });
255
+ }
124
256
  }
257
+
258
+ // Summary
259
+ console.log('\n' + '═'.repeat(60));
260
+
261
+ if (installedEditors.length > 0) {
262
+ console.log('\nāœ… Voicci CLI installed successfully!');
263
+ console.log('\nšŸ“¦ Command-line tool: voicci');
264
+ console.log('šŸ”§ Skill commands: /voicci OR /voicci-audiobook');
265
+ console.log('\nšŸ“ Installed in:');
266
+ installedEditors.forEach(editor => {
267
+ const status = editor.status === 'new' ? '(new)' : '(already installed)';
268
+ console.log(` • ${editor.name} ${status}`);
269
+ });
270
+
271
+ console.log('\nšŸ’” Usage:');
272
+ console.log(' 1. Restart your AI code editor');
273
+ console.log(' 2. Use: /voicci "search query" (simple)');
274
+ console.log(' 3. Or: /voicci-audiobook "search query" (detailed docs)');
275
+ console.log(' 4. Or CLI: voicci "your search query"');
276
+ } else {
277
+ console.log('\nāš ļø No supported AI code editors detected');
278
+ console.log('\nSupported editors: Claude Code, OpenCode, Cursor, Windsurf');
279
+ console.log('\nāœ“ You can still use the CLI: voicci <command>');
280
+ }
281
+
282
+ if (failedEditors.length > 0) {
283
+ console.log('\nāš ļø Failed to install for:');
284
+ failedEditors.forEach(({ name, error }) => {
285
+ console.log(` • ${name}: ${error}`);
286
+ });
287
+ }
288
+
289
+ console.log('\n' + '═'.repeat(60));
290
+ console.log();
125
291
  }
126
292
 
127
- installSkill();
293
+ detectAndInstall();