voicci 1.0.7 → 1.0.9

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.7",
3
+ "version": "1.0.9",
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",
@@ -9,10 +9,33 @@ import { execFileSync } from 'child_process';
9
9
  const __filename = fileURLToPath(import.meta.url);
10
10
  const __dirname = path.dirname(__filename);
11
11
 
12
- // Use unique name to avoid conflicts with SSH shorthand skills
13
- const SKILL_NAME = 'voicci-audiobook.md';
12
+ // Two skill files: simple and detailed
13
+ const SKILL_NAME_SIMPLE = 'voicci.md';
14
+ const SKILL_NAME_DETAILED = 'voicci-audiobook.md';
14
15
 
15
- const SKILL_CONTENT = `---
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 = `---
16
39
  description: "Voicci - AI audiobook generator CLI"
17
40
  argument-hint: "COMMAND_OR_FILE"
18
41
  ---
@@ -113,14 +136,16 @@ const EDITORS = {
113
136
  return false;
114
137
  }
115
138
  },
116
- skillsDir: () => path.join(os.homedir(), '.claude', 'skills'),
117
- skillName: SKILL_NAME
139
+ // Install to both skills/ and commands/ so slash commands appear in autocomplete
140
+ skillsDirs: () => [
141
+ path.join(os.homedir(), '.claude', 'commands'),
142
+ path.join(os.homedir(), '.claude', 'skills')
143
+ ]
118
144
  },
119
145
  'OpenCode': {
120
146
  name: 'OpenCode',
121
147
  detect: () => {
122
148
  const homeDir = os.homedir();
123
- // Check for opencode command or config directory
124
149
  if (fs.existsSync(path.join(homeDir, '.opencode'))) return true;
125
150
  try {
126
151
  execFileSync('which', ['opencode'], { stdio: 'ignore' });
@@ -129,14 +154,12 @@ const EDITORS = {
129
154
  return false;
130
155
  }
131
156
  },
132
- skillsDir: () => path.join(os.homedir(), '.opencode', 'skills'),
133
- skillName: SKILL_NAME
157
+ skillsDirs: () => [path.join(os.homedir(), '.opencode', 'skills')]
134
158
  },
135
159
  'Cursor': {
136
160
  name: 'Cursor',
137
161
  detect: () => {
138
162
  const homeDir = os.homedir();
139
- // Check for cursor command or config directory
140
163
  if (fs.existsSync(path.join(homeDir, '.cursor'))) return true;
141
164
  if (fs.existsSync(path.join(homeDir, 'Library', 'Application Support', 'Cursor'))) return true;
142
165
  try {
@@ -146,26 +169,23 @@ const EDITORS = {
146
169
  return false;
147
170
  }
148
171
  },
149
- skillsDir: () => {
172
+ skillsDirs: () => {
150
173
  const homeDir = os.homedir();
151
- // Try common locations
152
174
  const locations = [
153
175
  path.join(homeDir, '.cursor', 'skills'),
154
176
  path.join(homeDir, 'Library', 'Application Support', 'Cursor', 'skills')
155
177
  ];
156
178
  for (const loc of locations) {
157
179
  const parent = path.dirname(loc);
158
- if (fs.existsSync(parent)) return loc;
180
+ if (fs.existsSync(parent)) return [loc];
159
181
  }
160
- return locations[0]; // Default to first
161
- },
162
- skillName: SKILL_NAME
182
+ return [locations[0]];
183
+ }
163
184
  },
164
185
  'Windsurf': {
165
186
  name: 'Windsurf',
166
187
  detect: () => {
167
188
  const homeDir = os.homedir();
168
- // Check for windsurf command or config directory
169
189
  if (fs.existsSync(path.join(homeDir, '.windsurf'))) return true;
170
190
  try {
171
191
  execFileSync('which', ['windsurf'], { stdio: 'ignore' });
@@ -174,11 +194,26 @@ const EDITORS = {
174
194
  return false;
175
195
  }
176
196
  },
177
- skillsDir: () => path.join(os.homedir(), '.windsurf', 'skills'),
178
- skillName: SKILL_NAME
197
+ skillsDirs: () => [path.join(os.homedir(), '.windsurf', 'skills')]
179
198
  }
180
199
  };
181
200
 
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';
209
+ }
210
+ }
211
+
212
+ // Write the skill file
213
+ fs.writeFileSync(skillFile, content, 'utf8');
214
+ return 'new';
215
+ }
216
+
182
217
  function detectAndInstall() {
183
218
  const homeDir = os.homedir();
184
219
  const installedEditors = [];
@@ -192,29 +227,35 @@ function detectAndInstall() {
192
227
  if (editor.detect()) {
193
228
  console.log(`✓ Found ${editor.name}`);
194
229
 
195
- const skillsDir = editor.skillsDir();
196
- const skillFile = path.join(skillsDir, editor.skillName);
230
+ const dirs = editor.skillsDirs();
197
231
 
198
- // Create skills directory if it doesn't exist
199
- if (!fs.existsSync(skillsDir)) {
200
- fs.mkdirSync(skillsDir, { recursive: true });
201
- }
232
+ let anyNew = false;
233
+ let allExist = true;
234
+
235
+ for (const skillsDir of dirs) {
236
+ // Create directory if it doesn't exist
237
+ if (!fs.existsSync(skillsDir)) {
238
+ fs.mkdirSync(skillsDir, { recursive: true });
239
+ }
240
+
241
+ // Install both skills
242
+ const simpleStatus = installSkillFile(skillsDir, SKILL_NAME_SIMPLE, SKILL_CONTENT_SIMPLE);
243
+ const detailedStatus = installSkillFile(skillsDir, SKILL_NAME_DETAILED, SKILL_CONTENT_DETAILED);
202
244
 
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;
245
+ if (simpleStatus === 'new' || detailedStatus === 'new') {
246
+ anyNew = true;
247
+ allExist = false;
248
+ if (simpleStatus === 'new') console.log(` ↳ Installed: ${path.join(skillsDir, SKILL_NAME_SIMPLE)}`);
249
+ if (detailedStatus === 'new') console.log(` ↳ Installed: ${path.join(skillsDir, SKILL_NAME_DETAILED)}`);
211
250
  }
212
251
  }
213
252
 
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' });
253
+ if (!anyNew) {
254
+ console.log(` ↳ Skills already installed`);
255
+ installedEditors.push({ name: editor.name, status: 'exists' });
256
+ } else {
257
+ installedEditors.push({ name: editor.name, status: 'new' });
258
+ }
218
259
  }
219
260
  } catch (error) {
220
261
  failedEditors.push({ name: editor.name, error: error.message });
@@ -227,7 +268,7 @@ function detectAndInstall() {
227
268
  if (installedEditors.length > 0) {
228
269
  console.log('\n✅ Voicci CLI installed successfully!');
229
270
  console.log('\n📦 Command-line tool: voicci');
230
- console.log('🔧 Skill command: /voicci-audiobook');
271
+ console.log('🔧 Skill commands: /voicci OR /voicci-audiobook');
231
272
  console.log('\n📍 Installed in:');
232
273
  installedEditors.forEach(editor => {
233
274
  const status = editor.status === 'new' ? '(new)' : '(already installed)';
@@ -236,8 +277,9 @@ function detectAndInstall() {
236
277
 
237
278
  console.log('\n💡 Usage:');
238
279
  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"');
280
+ console.log(' 2. Use: /voicci "search query" (simple)');
281
+ console.log(' 3. Or: /voicci-audiobook "search query" (detailed docs)');
282
+ console.log(' 4. Or CLI: voicci "your search query"');
241
283
  } else {
242
284
  console.log('\n⚠️ No supported AI code editors detected');
243
285
  console.log('\nSupported editors: Claude Code, OpenCode, Cursor, Windsurf');
@@ -1,69 +0,0 @@
1
- name: Publish to npm
2
-
3
- on:
4
- push:
5
- tags:
6
- - 'v*'
7
-
8
- jobs:
9
- test:
10
- runs-on: ubuntu-latest
11
-
12
- steps:
13
- - name: Checkout code
14
- uses: actions/checkout@v4
15
-
16
- - name: Setup Node.js
17
- uses: actions/setup-node@v4
18
- with:
19
- node-version: '18'
20
-
21
- - name: Install dependencies
22
- run: npm ci
23
-
24
- - name: Run tests
25
- run: npm test
26
-
27
- publish:
28
- needs: test
29
- runs-on: ubuntu-latest
30
-
31
- steps:
32
- - name: Checkout code
33
- uses: actions/checkout@v4
34
-
35
- - name: Setup Node.js
36
- uses: actions/setup-node@v4
37
- with:
38
- node-version: '18'
39
- registry-url: 'https://registry.npmjs.org'
40
-
41
- - name: Install dependencies
42
- run: npm ci
43
-
44
- - name: Publish to npm
45
- run: npm publish
46
- env:
47
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
48
-
49
- - name: Create GitHub Release
50
- uses: actions/create-release@v1
51
- env:
52
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53
- with:
54
- tag_name: ${{ github.ref }}
55
- release_name: Release ${{ github.ref }}
56
- body: |
57
- ## Installation
58
- ```bash
59
- npm install -g voicci
60
- ```
61
-
62
- Or via install script:
63
- ```bash
64
- curl -fsSL https://voicci.com/voicci-cli/install.sh | bash
65
- ```
66
-
67
- See [CHANGELOG.md](https://github.com/voicci/voicci-cli/blob/main/CHANGELOG.md) for details.
68
- draft: false
69
- prerelease: false
@@ -1,33 +0,0 @@
1
- name: Run Tests
2
-
3
- on:
4
- push:
5
- branches: [ main ]
6
- pull_request:
7
- branches: [ main ]
8
-
9
- jobs:
10
- test:
11
- runs-on: ubuntu-latest
12
-
13
- strategy:
14
- matrix:
15
- node-version: [18.x, 20.x]
16
-
17
- steps:
18
- - name: Checkout code
19
- uses: actions/checkout@v4
20
-
21
- - name: Setup Node.js ${{ matrix.node-version }}
22
- uses: actions/setup-node@v4
23
- with:
24
- node-version: ${{ matrix.node-version }}
25
-
26
- - name: Install dependencies
27
- run: npm ci
28
-
29
- - name: Run tests
30
- run: npm test
31
-
32
- - name: Check package can be packed
33
- run: npm pack --dry-run
package/install.sh DELETED
@@ -1,198 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Voicci Installer
4
- # Converts PDF/text files to high-quality audiobooks using XTTS v2 AI
5
-
6
- set -e
7
-
8
- # Colors for output
9
- RED='\033[0;31m'
10
- GREEN='\033[0;32m'
11
- YELLOW='\033[1;33m'
12
- BLUE='\033[0;34m'
13
- NC='\033[0m' # No Color
14
-
15
- echo -e "${BLUE}╔════════════════════════════════════════╗${NC}"
16
- echo -e "${BLUE}║ Voicci Installer v1.0 ║${NC}"
17
- echo -e "${BLUE}║ AI Audiobook Generator (XTTS v2) ║${NC}"
18
- echo -e "${BLUE}╚════════════════════════════════════════╝${NC}"
19
- echo ""
20
-
21
- # Detect OS
22
- OS="$(uname -s)"
23
- case "${OS}" in
24
- Linux*) OS_TYPE=Linux;;
25
- Darwin*) OS_TYPE=Mac;;
26
- *) OS_TYPE="UNKNOWN:${OS}"
27
- esac
28
-
29
- if [[ "$OS_TYPE" == "UNKNOWN"* ]]; then
30
- echo -e "${RED}✗${NC} Unsupported operating system: ${OS}"
31
- echo "Voicci currently supports macOS and Linux only."
32
- exit 1
33
- fi
34
-
35
- echo -e "${GREEN}✓${NC} Detected OS: ${OS_TYPE}"
36
-
37
- # Check dependencies
38
- echo ""
39
- echo "Checking dependencies..."
40
-
41
- # Check Node.js
42
- if command -v node &> /dev/null; then
43
- NODE_VERSION=$(node --version)
44
- echo -e "${GREEN}✓${NC} Node.js $NODE_VERSION found"
45
- else
46
- echo -e "${RED}✗${NC} Node.js not found"
47
- echo "Please install Node.js 18+ from https://nodejs.org/"
48
- exit 1
49
- fi
50
-
51
- # Check npm
52
- if command -v npm &> /dev/null; then
53
- NPM_VERSION=$(npm --version)
54
- echo -e "${GREEN}✓${NC} npm $NPM_VERSION found"
55
- else
56
- echo -e "${RED}✗${NC} npm not found"
57
- exit 1
58
- fi
59
-
60
- # Check Python
61
- if command -v python3 &> /dev/null; then
62
- PYTHON_VERSION=$(python3 --version 2>&1 | awk '{print $2}')
63
- PYTHON_MAJOR=$(echo $PYTHON_VERSION | cut -d. -f1)
64
- PYTHON_MINOR=$(echo $PYTHON_VERSION | cut -d. -f2)
65
-
66
- if [[ $PYTHON_MAJOR -ge 3 ]] && [[ $PYTHON_MINOR -ge 9 ]]; then
67
- echo -e "${GREEN}✓${NC} Python $PYTHON_VERSION found"
68
- else
69
- echo -e "${RED}✗${NC} Python 3.9+ required (found $PYTHON_VERSION)"
70
- exit 1
71
- fi
72
- else
73
- echo -e "${RED}✗${NC} Python 3 not found"
74
- echo "Please install Python 3.9+ from https://www.python.org/"
75
- exit 1
76
- fi
77
-
78
- # Check pip
79
- if command -v pip3 &> /dev/null; then
80
- echo -e "${GREEN}✓${NC} pip3 found"
81
- else
82
- echo -e "${RED}✗${NC} pip3 not found"
83
- exit 1
84
- fi
85
-
86
- # Check pdftotext (optional but recommended)
87
- if command -v pdftotext &> /dev/null; then
88
- echo -e "${GREEN}✓${NC} pdftotext found"
89
- else
90
- echo -e "${YELLOW}⚠${NC} pdftotext not found (optional, for PDF support)"
91
- echo "Install with: brew install poppler (Mac) or apt-get install poppler-utils (Linux)"
92
- fi
93
-
94
- # Determine installation directory
95
- if [[ "$OS_TYPE" == "Mac" ]]; then
96
- INSTALL_DIR="$HOME/Library/Application Support/voicci"
97
- else
98
- INSTALL_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/voicci"
99
- fi
100
-
101
- echo ""
102
- echo -e "Installation directory: ${BLUE}$INSTALL_DIR${NC}"
103
- echo ""
104
-
105
- # Ask for confirmation
106
- read -p "Continue with installation? (y/n) " -n 1 -r
107
- echo
108
- if [[ ! $REPLY =~ ^[Yy]$ ]]; then
109
- echo "Installation cancelled."
110
- exit 0
111
- fi
112
-
113
- # Create installation directory
114
- echo ""
115
- echo "Creating directories..."
116
- mkdir -p "$INSTALL_DIR"/{lib,cli,backend}
117
- echo -e "${GREEN}✓${NC} Directories created"
118
-
119
- # Download Voicci files (in production, this would download from GitHub/website)
120
- echo ""
121
- echo "Installing Voicci..."
122
-
123
- # For now, we'll create the files directly
124
- # In production, this would be: curl -fsSL https://voicci.com/voicci-cli/voicci.tar.gz | tar -xz -C "$INSTALL_DIR"
125
-
126
- # Install Node.js dependencies
127
- cd "$INSTALL_DIR"
128
- echo ""
129
- echo "Installing Node.js dependencies..."
130
-
131
- cat > package.json <<'EOF'
132
- {
133
- "name": "voicci",
134
- "version": "1.0.0",
135
- "description": "AI Audiobook Generator using XTTS v2",
136
- "type": "module",
137
- "bin": {
138
- "voicci": "./cli/index.js"
139
- },
140
- "dependencies": {
141
- "commander": "^11.1.0",
142
- "better-sqlite3": "^9.2.2",
143
- "uuid": "^9.0.1",
144
- "ink": "^4.4.1",
145
- "react": "^18.2.0",
146
- "chalk": "^5.3.0"
147
- },
148
- "engines": {
149
- "node": ">=18.0.0"
150
- }
151
- }
152
- EOF
153
-
154
- npm install --silent --no-audit --no-fund 2>&1 | grep -v "npm WARN"
155
- echo -e "${GREEN}✓${NC} Node.js dependencies installed"
156
-
157
- # Install Python dependencies
158
- echo ""
159
- echo "Installing Python dependencies..."
160
- echo "This may take several minutes (downloading XTTS v2 model ~450MB)..."
161
-
162
- pip3 install --quiet --upgrade pip
163
- pip3 install --quiet TTS torch torchaudio
164
-
165
- echo -e "${GREEN}✓${NC} Python dependencies installed"
166
-
167
- # Download XTTS v2 model
168
- echo ""
169
- echo "Downloading XTTS v2 model (this may take a few minutes)..."
170
- python3 -c "from TTS.api import TTS; TTS('tts_models/multilingual/multi-dataset/xtts_v2')" &>/dev/null || true
171
- echo -e "${GREEN}✓${NC} XTTS v2 model downloaded"
172
-
173
- # Create symlink for global access
174
- BIN_DIR="/usr/local/bin"
175
- if [[ -w "$BIN_DIR" ]]; then
176
- ln -sf "$INSTALL_DIR/cli/index.js" "$BIN_DIR/voicci"
177
- echo -e "${GREEN}✓${NC} Global command 'voicci' installed"
178
- else
179
- echo -e "${YELLOW}⚠${NC} Could not create global command (insufficient permissions)"
180
- echo "Add to your PATH manually: export PATH=\"$INSTALL_DIR/cli:\$PATH\""
181
- fi
182
-
183
- # Final message
184
- echo ""
185
- echo -e "${GREEN}╔════════════════════════════════════════╗${NC}"
186
- echo -e "${GREEN}║ Installation Complete! 🎉 ║${NC}"
187
- echo -e "${GREEN}╚════════════════════════════════════════╝${NC}"
188
- echo ""
189
- echo "Usage:"
190
- echo -e " ${BLUE}voicci mybook.pdf${NC} - Convert PDF to audiobook"
191
- echo -e " ${BLUE}voicci -s${NC} - Check all job statuses"
192
- echo -e " ${BLUE}voicci -l${NC} - List completed audiobooks"
193
- echo -e " ${BLUE}voicci -o <jobId>${NC} - Open audiobook folder"
194
- echo ""
195
- echo "Installation location: $INSTALL_DIR"
196
- echo ""
197
- echo "Get started: voicci --help"
198
- echo ""