@vocoder/cli 0.1.7 → 0.1.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/README.md +53 -126
- package/dist/bin.mjs +26 -8
- package/dist/bin.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Command-line tool for Vocoder. Handles project setup, string extraction, and tra
|
|
|
8
8
|
npm install -g @vocoder/cli
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Or use
|
|
11
|
+
Or use without installing:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
npx vocoder <command>
|
|
@@ -18,120 +18,88 @@ npx vocoder <command>
|
|
|
18
18
|
|
|
19
19
|
### `vocoder init`
|
|
20
20
|
|
|
21
|
-
Connect your repository to Vocoder. Runs
|
|
21
|
+
Connect your repository to Vocoder. Runs an interactive TUI that handles authentication, workspace setup, and project configuration — all in the terminal. Only one browser step is required (GitHub authorization), and only on first run.
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
vocoder init
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
**
|
|
27
|
+
**First-time setup:**
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
The CLI opens the Vocoder GitHub App installation page. Authorizing the App creates your account and workspace in one step — no separate sign-up required.
|
|
30
30
|
|
|
31
31
|
```
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
● Open the link below to sign in or create your account:
|
|
35
|
-
◇ Authentication URL ──────────────────────────────────────╮
|
|
36
|
-
│ │
|
|
37
|
-
│ https://vocoder.app/auth/cli?session=<token> │
|
|
38
|
-
│ │
|
|
39
|
-
├────────────────────────────────────────────────────────────
|
|
32
|
+
┌ Vocoder Setup
|
|
40
33
|
|
|
34
|
+
◆ Opening GitHub to connect your account...
|
|
35
|
+
│ Authorize Vocoder and install the GitHub App in one step.
|
|
36
|
+
│
|
|
37
|
+
│ https://github.com/apps/vocoder/installations/new?state=...
|
|
38
|
+
│
|
|
41
39
|
◆ Open in your browser? › Yes
|
|
42
40
|
|
|
43
|
-
◒ Waiting for
|
|
44
|
-
◇ Authenticated as eric@example.com
|
|
41
|
+
◒ Waiting for GitHub authorization...
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
│
|
|
50
|
-
|
|
43
|
+
◇ Connected as @username — workspace: username
|
|
44
|
+
|
|
45
|
+
◆ App Directory (Optional)
|
|
46
|
+
│ Leave blank to cover the entire repository (or enter a subdirectory for monorepos)
|
|
47
|
+
|
|
48
|
+
◆ Source language (type to search)
|
|
49
|
+
│ English — en
|
|
51
50
|
|
|
52
|
-
|
|
51
|
+
◆ Target languages (type to search, space to select)
|
|
52
|
+
│ ◼ Spanish — es
|
|
53
53
|
|
|
54
|
-
◆
|
|
55
|
-
|
|
56
|
-
◆ Target languages (type to search) › es → Spanish — es
|
|
57
|
-
◆ Target branches (comma-separated) › main
|
|
54
|
+
◆ Target branches
|
|
55
|
+
│ ◼ main
|
|
58
56
|
|
|
59
57
|
◒ Creating project...
|
|
60
58
|
|
|
61
59
|
◆ Step 1: Add the plugin to vite.config.ts
|
|
62
|
-
|
|
63
|
-
◆ Step
|
|
64
|
-
│ ...
|
|
65
|
-
◆ Step 3: Wrap translatable strings
|
|
60
|
+
◆ Step 2: Wrap your app with VocoderProvider
|
|
61
|
+
◆ Step 3: Mark strings for translation with <T>
|
|
66
62
|
|
|
67
63
|
◆ Use Vocoder with Claude Code
|
|
68
64
|
│ claude mcp add --scope project --transport stdio \
|
|
69
65
|
│ --env VOCODER_API_KEY=vc_xxxx \
|
|
70
66
|
│ vocoder -- npx -y @vocoder/mcp
|
|
71
67
|
|
|
72
|
-
|
|
68
|
+
◇ You're all set.
|
|
73
69
|
```
|
|
74
70
|
|
|
75
|
-
**Returning user (stored
|
|
71
|
+
**Returning user (stored credentials):**
|
|
76
72
|
|
|
77
|
-
No browser opens. The stored
|
|
73
|
+
No browser opens. The stored token is verified and the flow continues in the terminal.
|
|
78
74
|
|
|
79
75
|
```
|
|
80
|
-
|
|
76
|
+
┌ Vocoder Setup
|
|
81
77
|
|
|
82
|
-
|
|
83
|
-
◇ Authenticated as eric@example.com
|
|
78
|
+
◇ Authenticated as user@example.com
|
|
84
79
|
|
|
85
|
-
◒ Loading workspaces...
|
|
86
80
|
◆ Select workspace
|
|
87
|
-
│ ●
|
|
88
|
-
│ ○ Create new workspace
|
|
89
|
-
└
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
**New workspace (GitHub App install):**
|
|
93
|
-
|
|
94
|
-
If creating a new workspace, a second browser step installs the GitHub App. The CLI opens the install URL and waits for the browser to redirect back to a local callback server.
|
|
95
|
-
|
|
81
|
+
│ ● my-workspace (3 projects)
|
|
82
|
+
│ ○ + Create new workspace
|
|
96
83
|
```
|
|
97
|
-
◆ Connect your new workspace to GitHub
|
|
98
|
-
│ ● Install the Vocoder GitHub App
|
|
99
|
-
│ ○ Link an existing installation
|
|
100
|
-
└
|
|
101
84
|
|
|
102
|
-
|
|
103
|
-
Complete the installation in your browser.
|
|
85
|
+
**Monorepo support:**
|
|
104
86
|
|
|
105
|
-
|
|
106
|
-
```
|
|
87
|
+
When running `vocoder init` from a subdirectory of a git repository, the CLI automatically suggests that subdirectory as the app directory. Each app in a monorepo should be set up as a separate Vocoder project.
|
|
107
88
|
|
|
108
89
|
**Options:**
|
|
109
90
|
|
|
110
91
|
| Flag | Description |
|
|
111
92
|
|---|---|
|
|
112
|
-
| `--yes` | Skip "Open in your browser?" confirmation |
|
|
113
|
-
| `--ci` | Non-interactive mode. Prints
|
|
114
|
-
|
|
115
|
-
**Auth storage:**
|
|
116
|
-
|
|
117
|
-
After sign-in, the CLI stores a persistent auth token at `~/.config/vocoder/auth.json` (mode `0600`). The file contains:
|
|
118
|
-
|
|
119
|
-
```json
|
|
120
|
-
{
|
|
121
|
-
"token": "vcu_...",
|
|
122
|
-
"apiUrl": "https://vocoder.app",
|
|
123
|
-
"userId": "...",
|
|
124
|
-
"email": "user@example.com",
|
|
125
|
-
"name": "User Name",
|
|
126
|
-
"createdAt": "2026-04-25T12:00:00.000Z"
|
|
127
|
-
}
|
|
128
|
-
```
|
|
93
|
+
| `--yes` | Skip the "Open in your browser?" confirmation |
|
|
94
|
+
| `--ci` | Non-interactive mode. Prints `VOCODER_AUTH_URL: <url>` to stdout instead of opening a browser. Intended for CI environments where the browser step is driven externally. |
|
|
129
95
|
|
|
130
|
-
|
|
96
|
+
**Stored credentials:**
|
|
131
97
|
|
|
132
|
-
|
|
98
|
+
After first sign-in, the CLI stores credentials at `~/.config/vocoder/auth.json` (mode `0600`). Tokens do not expire. Use `vocoder logout` to revoke.
|
|
133
99
|
|
|
134
|
-
|
|
100
|
+
**Token resolution:**
|
|
101
|
+
|
|
102
|
+
| Command | Source |
|
|
135
103
|
|---|---|
|
|
136
104
|
| `vocoder init` | `VOCODER_AUTH_TOKEN` env var → `~/.config/vocoder/auth.json` |
|
|
137
105
|
| `vocoder sync` | `VOCODER_API_KEY` env var → `.env` file |
|
|
@@ -141,13 +109,13 @@ Tokens never expire. Use `vocoder logout` to revoke.
|
|
|
141
109
|
|
|
142
110
|
### `vocoder sync`
|
|
143
111
|
|
|
144
|
-
|
|
112
|
+
Extract translatable strings from your source code and submit them for translation.
|
|
145
113
|
|
|
146
114
|
```bash
|
|
147
115
|
vocoder sync
|
|
148
116
|
```
|
|
149
117
|
|
|
150
|
-
Reads `VOCODER_API_KEY` from environment or `.env`.
|
|
118
|
+
Reads `VOCODER_API_KEY` from environment or `.env`. Detects `<T>` and `t()` usages, submits them to Vocoder, and polls until translations are returned. Writes locale JSON files to the configured output path.
|
|
151
119
|
|
|
152
120
|
**Options:**
|
|
153
121
|
|
|
@@ -161,13 +129,13 @@ Reads `VOCODER_API_KEY` from environment or `.env`. Extracts `<T>` and `t()` usa
|
|
|
161
129
|
|
|
162
130
|
### `vocoder logout`
|
|
163
131
|
|
|
164
|
-
Revoke the stored
|
|
132
|
+
Revoke the stored credentials and clear `~/.config/vocoder/auth.json`.
|
|
165
133
|
|
|
166
134
|
```bash
|
|
167
135
|
vocoder logout
|
|
168
136
|
```
|
|
169
137
|
|
|
170
|
-
|
|
138
|
+
The token is also revoked server-side.
|
|
171
139
|
|
|
172
140
|
---
|
|
173
141
|
|
|
@@ -177,69 +145,28 @@ Print the currently authenticated user.
|
|
|
177
145
|
|
|
178
146
|
```bash
|
|
179
147
|
vocoder whoami
|
|
180
|
-
# Authenticated as
|
|
148
|
+
# Authenticated as user@example.com (my-workspace)
|
|
181
149
|
```
|
|
182
150
|
|
|
183
151
|
---
|
|
184
152
|
|
|
185
|
-
### `vocoder wrap`
|
|
186
|
-
|
|
187
|
-
Automatically wrap string literals in your source code with `<T>` and `t()`.
|
|
188
|
-
|
|
189
|
-
```bash
|
|
190
|
-
vocoder wrap
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
Scans JSX/TSX files for user-facing string literals and wraps them with the appropriate translation markers. Uses AST analysis to detect strings that are likely user-facing (not keys, classnames, or internal identifiers).
|
|
194
|
-
|
|
195
|
-
**Options:**
|
|
196
|
-
|
|
197
|
-
| Flag | Description |
|
|
198
|
-
|---|---|
|
|
199
|
-
| `--include <pattern>` | Glob pattern(s) to include (repeatable) |
|
|
200
|
-
| `--exclude <pattern>` | Glob pattern(s) to exclude (repeatable) |
|
|
201
|
-
| `--dry-run` | Preview changes without modifying files |
|
|
202
|
-
| `--interactive` | Confirm each string interactively |
|
|
203
|
-
| `--confidence <level>` | Minimum confidence: `high`, `medium`, `low` (default: `high`) |
|
|
204
|
-
| `--verbose` | Detailed output |
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
153
|
## How `init` interacts with the browser
|
|
209
154
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
1. The CLI starts a local HTTP server on a random available port.
|
|
213
|
-
2. It requests an auth session from Vocoder, passing the local port as the callback destination.
|
|
214
|
-
3. The terminal displays the verification URL and (optionally) opens it in the system browser.
|
|
215
|
-
4. After the user signs in, `vocoder.app/auth/cli` silently pings `localhost:<port>/callback?token=...` in the background.
|
|
216
|
-
5. The CLI's local server receives the token instantly and the TUI continues — no polling delay.
|
|
217
|
-
|
|
218
|
-
If the local server fails to bind (port conflict, firewall), the CLI falls back to polling `GET /api/cli/auth/session` every 2 seconds until the token is available.
|
|
219
|
-
|
|
220
|
-
The same local server pattern is used for the GitHub App install callback.
|
|
221
|
-
|
|
222
|
-
---
|
|
223
|
-
|
|
224
|
-
## String Extraction
|
|
225
|
-
|
|
226
|
-
The `wrap` command uses Babel to parse JSX/TSX files and detect strings that are likely user-facing:
|
|
155
|
+
`vocoder init` opens exactly one browser window, and only on first run. The browser is used to authorize the Vocoder GitHub App — this simultaneously authenticates you and connects your GitHub account, so no separate sign-up is needed.
|
|
227
156
|
|
|
228
|
-
|
|
229
|
-
- String props like `placeholder`, `title`, `aria-label` are wrapped with `t()`
|
|
230
|
-
- Non-translatable strings (class names, keys, URLs) are left alone
|
|
157
|
+
Once the GitHub authorization is complete, the browser redirects back and the CLI receives your credentials automatically via a local callback server. The rest of setup happens in the terminal.
|
|
231
158
|
|
|
232
|
-
|
|
159
|
+
On subsequent runs, the stored token is used directly and no browser is needed.
|
|
233
160
|
|
|
234
161
|
---
|
|
235
162
|
|
|
236
163
|
## Git Integration
|
|
237
164
|
|
|
238
|
-
The CLI auto-detects the
|
|
165
|
+
The CLI auto-detects repository context from the working directory:
|
|
239
166
|
|
|
240
|
-
- **Repository:** Reads the git remote URL and normalizes it to
|
|
241
|
-
- **Branch:** Checks CI environment variables first (GitHub Actions, Vercel, Netlify, etc.), then falls back to
|
|
242
|
-
- **
|
|
167
|
+
- **Repository:** Reads the git remote URL and normalizes it to `github:owner/repo`
|
|
168
|
+
- **Branch:** Checks CI environment variables first (GitHub Actions, Vercel, Netlify, etc.), then falls back to `.git/HEAD`
|
|
169
|
+
- **App directory:** For monorepos, computes the relative path from the git root to `process.cwd()`
|
|
243
170
|
|
|
244
171
|
---
|
|
245
172
|
|
|
@@ -248,7 +175,7 @@ The CLI auto-detects the repository and branch:
|
|
|
248
175
|
| Variable | Used by | Purpose |
|
|
249
176
|
|---|---|---|
|
|
250
177
|
| `VOCODER_API_KEY` | `sync`, MCP | Project API key (`vc_` prefix) |
|
|
251
|
-
| `VOCODER_AUTH_TOKEN` | `init` | Override stored user
|
|
178
|
+
| `VOCODER_AUTH_TOKEN` | `init` | Override stored user token (`vcu_` prefix) |
|
|
252
179
|
| `VOCODER_API_URL` | All commands | Override API base URL (default: `https://vocoder.app`) |
|
|
253
180
|
|
|
254
181
|
---
|
package/dist/bin.mjs
CHANGED
|
@@ -348,6 +348,10 @@ function parsePayload(raw) {
|
|
|
348
348
|
if (raw.length === 0) {
|
|
349
349
|
return null;
|
|
350
350
|
}
|
|
351
|
+
const trimmed = raw.trimStart();
|
|
352
|
+
if (trimmed.startsWith("<!DOCTYPE") || trimmed.startsWith("<html")) {
|
|
353
|
+
return { message: "Unexpected response from server (received HTML). Check your network connection or try again." };
|
|
354
|
+
}
|
|
351
355
|
try {
|
|
352
356
|
return JSON.parse(raw);
|
|
353
357
|
} catch {
|
|
@@ -426,10 +430,10 @@ var VocoderAPI = class {
|
|
|
426
430
|
* Submit strings for translation
|
|
427
431
|
* Project is determined from the API key
|
|
428
432
|
*/
|
|
429
|
-
stableTextKey(
|
|
433
|
+
stableTextKey(text2) {
|
|
430
434
|
let hash = 2166136261;
|
|
431
|
-
for (let i = 0; i <
|
|
432
|
-
hash ^=
|
|
435
|
+
for (let i = 0; i < text2.length; i++) {
|
|
436
|
+
hash ^= text2.charCodeAt(i);
|
|
433
437
|
hash = Math.imul(hash, 16777619);
|
|
434
438
|
}
|
|
435
439
|
return `SK_TEXT_${(hash >>> 0).toString(16).toUpperCase().padStart(8, "0")}`;
|
|
@@ -440,9 +444,9 @@ var VocoderAPI = class {
|
|
|
440
444
|
}
|
|
441
445
|
const first = entries[0];
|
|
442
446
|
if (typeof first === "string") {
|
|
443
|
-
return entries.map((
|
|
444
|
-
key: this.stableTextKey(
|
|
445
|
-
text
|
|
447
|
+
return entries.map((text2) => ({
|
|
448
|
+
key: this.stableTextKey(text2),
|
|
449
|
+
text: text2
|
|
446
450
|
}));
|
|
447
451
|
}
|
|
448
452
|
return entries.map((entry, index) => ({
|
|
@@ -1384,6 +1388,19 @@ async function runProjectCreate(params) {
|
|
|
1384
1388
|
}
|
|
1385
1389
|
const languageOptions = buildLanguageOptions(rawLocales);
|
|
1386
1390
|
const localeOptions = buildLocaleOptions(rawLocales);
|
|
1391
|
+
const rawScope = await p3.text({
|
|
1392
|
+
message: "App directory (leave blank for the entire repo)",
|
|
1393
|
+
placeholder: "e.g. apps/web",
|
|
1394
|
+
initialValue: params.defaultScopePath ?? "",
|
|
1395
|
+
validate(value) {
|
|
1396
|
+
const v = value.trim();
|
|
1397
|
+
if (!v) return;
|
|
1398
|
+
if (v.startsWith("/")) return "Use a relative path, not an absolute path";
|
|
1399
|
+
if (v.includes("..")) return 'Path must not contain ".."';
|
|
1400
|
+
}
|
|
1401
|
+
});
|
|
1402
|
+
if (p3.isCancel(rawScope)) return null;
|
|
1403
|
+
const scopePath = rawScope.trim();
|
|
1387
1404
|
const sourceLocale = await searchSelectLocale(
|
|
1388
1405
|
languageOptions,
|
|
1389
1406
|
"Source language (the language your code is written in)",
|
|
@@ -1428,7 +1445,7 @@ async function runProjectCreate(params) {
|
|
|
1428
1445
|
targetLocales,
|
|
1429
1446
|
targetBranches,
|
|
1430
1447
|
translationTriggers: ["push"],
|
|
1431
|
-
scopePaths: [],
|
|
1448
|
+
scopePaths: scopePath ? [scopePath] : [],
|
|
1432
1449
|
repoCanonical
|
|
1433
1450
|
});
|
|
1434
1451
|
p3.log.success(`Project ${chalk4.bold(result.projectName)} created!`);
|
|
@@ -2019,7 +2036,8 @@ async function init(options = {}) {
|
|
|
2019
2036
|
defaultName: identity?.repoCanonical ? identity.repoCanonical.split("/").pop() : void 0,
|
|
2020
2037
|
defaultSourceLocale: "en",
|
|
2021
2038
|
repoCanonical: identity?.repoCanonical,
|
|
2022
|
-
defaultBranches: ["main"]
|
|
2039
|
+
defaultBranches: ["main"],
|
|
2040
|
+
defaultScopePath: identity?.repoScopePath
|
|
2023
2041
|
});
|
|
2024
2042
|
if (!projectResult) {
|
|
2025
2043
|
p5.log.error("Project creation failed. Run `vocoder init` again.");
|