@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 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 directly with npx:
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 a full TUI-based onboarding flow authentication, workspace selection, GitHub connection, and project configuration all happen in the terminal. A browser is opened only for steps that require OAuth (sign-in, GitHub App install).
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
- **Fast path:** If the current repository's remote is already linked to a Vocoder project, `init` detects it and prints the scaffold instructions immediately — no prompts, no browser.
27
+ **First-time setup:**
28
28
 
29
- **Full flow:**
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
- Vocoder Setup
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 authentication...
44
- ◇ Authenticated as eric@example.com
41
+ ◒ Waiting for GitHub authorization...
45
42
 
46
- Loading workspaces...
47
- ◆ Select workspace
48
- My Workspace (2 projects)
49
- Create new workspace
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
- Workspace: My Workspace
51
+ Target languages (type to search, space to select)
52
+ │ ◼ Spanish — es
53
53
 
54
- Project name › my-app
55
- Source language (type to search) › en → English — en
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 2: Add the provider to App.tsx
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
- You're all set.
68
+ You're all set.
73
69
  ```
74
70
 
75
- **Returning user (stored token, existing workspace):**
71
+ **Returning user (stored credentials):**
76
72
 
77
- No browser opens. The stored auth token is verified, workspaces are listed, and the flow continues directly in the terminal.
73
+ No browser opens. The stored token is verified and the flow continues in the terminal.
78
74
 
79
75
  ```
80
- Vocoder Setup
76
+ Vocoder Setup
81
77
 
82
- Checking authentication...
83
- ◇ Authenticated as eric@example.com
78
+ Authenticated as user@example.com
84
79
 
85
- ◒ Loading workspaces...
86
80
  ◆ Select workspace
87
- │ ● My Workspace (2 projects)
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
- ○ Opening GitHub to install the Vocoder App...
103
- Complete the installation in your browser.
85
+ **Monorepo support:**
104
86
 
105
- ◇ Connected to GitHub as itsmoops
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 the auth URL as `VOCODER_AUTH_URL: <url>` on its own line to stdout no browser opens, no interactive prompts, no local callback server. The CLI polls `GET /api/cli/auth/session` every 2 seconds until the browser completes authentication. Intended for automated test harnesses that drive the browser step externally. |
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
- Tokens never expire. Use `vocoder logout` to revoke.
96
+ **Stored credentials:**
131
97
 
132
- **Token priority:**
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
- | Command | Token source |
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
- Submit extracted strings for translation and retrieve results.
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`. Extracts `<T>` and `t()` usages from source files, submits them to Vocoder, and polls until translations are returned. Writes locale JSON files to the configured output path.
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 auth token and clear `~/.config/vocoder/auth.json`.
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
- Also revokes the token server-side so it can no longer be used for API calls.
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 eric@example.com (My Workspace)
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
- The CLI never redirects the terminal to a URL or relies on the browser to complete setup. Instead:
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
- - JSX text content is wrapped with `<T>`
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
- It tracks imports from `@vocoder/react` to avoid double-wrapping strings already marked for translation.
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 repository and branch:
165
+ The CLI auto-detects repository context from the working directory:
239
166
 
240
- - **Repository:** Reads the git remote URL and normalizes it to a canonical format (`github:owner/repo`)
241
- - **Branch:** Checks CI environment variables first (GitHub Actions, Vercel, Netlify, etc.), then falls back to reading `.git/HEAD`
242
- - **Scope path:** For monorepos, computes the relative path from the git root to the working directory
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 auth token (`vcu_` prefix) |
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(text) {
433
+ stableTextKey(text2) {
430
434
  let hash = 2166136261;
431
- for (let i = 0; i < text.length; i++) {
432
- hash ^= text.charCodeAt(i);
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((text) => ({
444
- key: this.stableTextKey(text),
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.");