@vocoder/cli 0.1.10 → 0.1.12

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/dist/bin.mjs CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  detectLocalEcosystem,
6
6
  getPackagesToInstall,
7
7
  getSetupSnippets
8
- } from "./chunk-OC5N5C5X.mjs";
8
+ } from "./chunk-KPIT5ETY.mjs";
9
9
 
10
10
  // src/bin.ts
11
11
  import { Command } from "commander";
@@ -305,7 +305,10 @@ async function selectGitHubInstallation(installations, canInstallNew) {
305
305
  ].filter(Boolean).join(" \xB7 ") || void 0
306
306
  }));
307
307
  if (canInstallNew) {
308
- options.push({ value: "install_new", label: "Install on a new account" });
308
+ options.push({
309
+ value: "install_new",
310
+ label: `Install on a new account ${chalk.dim("(creates a new personal workspace)")}`
311
+ });
309
312
  }
310
313
  const selected = await p.select({
311
314
  message: "Select a GitHub installation",
@@ -417,7 +420,8 @@ var VocoderAPI = class {
417
420
  organizationName: data.organizationName,
418
421
  sourceLocale: data.sourceLocale,
419
422
  targetLocales: data.targetLocales,
420
- targetBranches: data.targetBranches,
423
+ branchTriggers: data.branchTriggers ?? [],
424
+ primaryBranch: data.primaryBranch,
421
425
  syncPolicy: {
422
426
  blockingBranches: data.syncPolicy?.blockingBranches ?? ["main", "master"],
423
427
  blockingMode: data.syncPolicy?.blockingMode ?? "required",
@@ -1407,19 +1411,25 @@ async function runProjectCreate(params) {
1407
1411
  }
1408
1412
  const languageOptions = buildLanguageOptions(rawLocales);
1409
1413
  const localeOptions = buildLocaleOptions(rawLocales);
1410
- const rawScope = await p3.text({
1411
- message: "App directory (leave blank for the entire repo)",
1412
- placeholder: "e.g. apps/web",
1413
- initialValue: params.defaultScopePath ?? "",
1414
- validate(value) {
1415
- const v = value.trim();
1416
- if (!v) return;
1417
- if (v.startsWith("/")) return "Use a relative path, not an absolute path";
1418
- if (v.includes("..")) return 'Path must not contain ".."';
1419
- }
1420
- });
1421
- if (p3.isCancel(rawScope)) return null;
1422
- const scopePath = rawScope.trim();
1414
+ let scopePath;
1415
+ if (params.defaultScopePath) {
1416
+ scopePath = params.defaultScopePath;
1417
+ p3.log.success(`App directory: ${chalk4.bold(scopePath)}`);
1418
+ } else {
1419
+ const rawScope = await p3.text({
1420
+ message: "App directory (leave blank for the entire repo)",
1421
+ placeholder: "e.g. apps/web, packages/frontend",
1422
+ initialValue: "",
1423
+ validate(value) {
1424
+ const v = value.trim();
1425
+ if (!v) return;
1426
+ if (v.startsWith("/")) return "Use a relative path, not an absolute path";
1427
+ if (v.includes("..")) return 'Path must not contain ".."';
1428
+ }
1429
+ });
1430
+ if (p3.isCancel(rawScope)) return null;
1431
+ scopePath = (rawScope ?? "").trim();
1432
+ }
1423
1433
  const sourceLocale = await searchSelectLocale(
1424
1434
  languageOptions,
1425
1435
  "Source language (the language your code is written in)",
@@ -1437,12 +1447,12 @@ async function runProjectCreate(params) {
1437
1447
  }
1438
1448
  const detected = detectGitBranches();
1439
1449
  const initialBranches = params.defaultBranches?.length ? params.defaultBranches : [detected.defaultBranch];
1440
- let targetBranches = [];
1450
+ let selectedBranches = [];
1441
1451
  {
1442
1452
  let initial = initialBranches;
1443
- while (targetBranches.length === 0) {
1453
+ while (selectedBranches.length === 0) {
1444
1454
  const result = await filterableBranchSelect({
1445
- message: "Target branches (translations will run when you push to these)",
1455
+ message: "Target branches",
1446
1456
  branches: detected.branches,
1447
1457
  defaultBranch: detected.defaultBranch,
1448
1458
  initialValues: initial
@@ -1452,18 +1462,32 @@ async function runProjectCreate(params) {
1452
1462
  p3.log.warn("At least one branch is required. Please select at least one.");
1453
1463
  initial = [detected.defaultBranch];
1454
1464
  } else {
1455
- targetBranches = result;
1465
+ selectedBranches = result;
1456
1466
  }
1457
1467
  }
1458
1468
  }
1469
+ const triggerChoice = await p3.select({
1470
+ message: "When should translations run?",
1471
+ options: [
1472
+ { value: "push", label: "On push to target branches" },
1473
+ { value: "pull_request", label: "On pull requests" },
1474
+ { value: "push_and_pr", label: "On push and pull requests" },
1475
+ { value: "manual", label: "Manual only", hint: "use vocoder sync or trigger from dashboard" }
1476
+ ]
1477
+ });
1478
+ if (p3.isCancel(triggerChoice)) return null;
1479
+ const triggersForBranch = triggerChoice === "push_and_pr" ? ["push", "pull_request"] : [triggerChoice];
1480
+ const branchTriggers = selectedBranches.map((pattern) => ({
1481
+ pattern,
1482
+ triggers: triggersForBranch
1483
+ }));
1459
1484
  try {
1460
1485
  const result = await api.createProject(userToken, {
1461
1486
  organizationId,
1462
1487
  name: projectName,
1463
1488
  sourceLocale,
1464
1489
  targetLocales,
1465
- targetBranches,
1466
- translationTriggers: ["push"],
1490
+ branchTriggers,
1467
1491
  scopePaths: scopePath ? [scopePath] : [],
1468
1492
  repoCanonical
1469
1493
  });
@@ -1577,7 +1601,7 @@ function printPlanLimitMessage(apiUrl, message) {
1577
1601
  p5.log.info(`Manage subscription: ${getSubscriptionSettingsUrl(apiUrl)}`);
1578
1602
  }
1579
1603
  function runScaffold(params) {
1580
- const { projectName, organizationName, sourceLocale, translationTriggers } = params;
1604
+ const { projectName, organizationName, sourceLocale, branchTriggers } = params;
1581
1605
  p5.log.info(`Project: ${chalk6.bold(projectName)}`);
1582
1606
  p5.log.info(`Workspace: ${chalk6.bold(organizationName)}`);
1583
1607
  const detection = detectLocalEcosystem();
@@ -1606,7 +1630,7 @@ function runScaffold(params) {
1606
1630
  framework: detection.framework,
1607
1631
  ecosystem: detection.ecosystem,
1608
1632
  sourceLocale,
1609
- translationTriggers
1633
+ branchTriggers
1610
1634
  });
1611
1635
  let stepNum = 1;
1612
1636
  if (snippets.pluginStep) {
@@ -1677,8 +1701,11 @@ function printCodeBlock(code) {
1677
1701
  async function verifyStoredToken(api, token) {
1678
1702
  try {
1679
1703
  return await api.getCliUserInfo(token);
1680
- } catch {
1704
+ } catch (err) {
1681
1705
  clearAuthData();
1706
+ if (err instanceof VocoderAPIError && err.status === 404) {
1707
+ return { userGone: true };
1708
+ }
1682
1709
  return null;
1683
1710
  }
1684
1711
  }
@@ -1807,8 +1834,7 @@ async function runAuthFlow(api, options, reauth = false, repoCanonical) {
1807
1834
  return null;
1808
1835
  }
1809
1836
  const userInfo = await api.getCliUserInfo(rawToken);
1810
- authSpinner.stop();
1811
- p5.log.success(`Authenticated as ${chalk6.bold(userInfo.email)}`);
1837
+ authSpinner.stop(`Authenticated as ${chalk6.bold(userInfo.email)}`);
1812
1838
  return { token: rawToken, ...userInfo, organizationId: callbackOrganizationId, discoveryReady: callbackDiscoveryReady };
1813
1839
  }
1814
1840
  async function init(options = {}) {
@@ -1833,7 +1859,7 @@ async function init(options = {}) {
1833
1859
  projectName: existing.projectName,
1834
1860
  organizationName: existing.organizationName,
1835
1861
  sourceLocale: existing.sourceLocale ?? "en",
1836
- translationTriggers: existing.translationTriggers ?? ["push"]
1862
+ branchTriggers: existing.branchTriggers ?? [{ pattern: "main", triggers: ["push"] }]
1837
1863
  });
1838
1864
  p5.outro("Vocoder is already set up for this repository.");
1839
1865
  return 0;
@@ -1848,18 +1874,24 @@ async function init(options = {}) {
1848
1874
  const stored = readAuthData();
1849
1875
  if (stored && stored.apiUrl === apiUrl) {
1850
1876
  const verified = await verifyStoredToken(api, stored.token);
1851
- if (verified) {
1877
+ if (verified && !("userGone" in verified)) {
1852
1878
  p5.log.success(`Authenticated as ${chalk6.bold(verified.email)}`);
1853
1879
  userToken = stored.token;
1854
1880
  userEmail = verified.email;
1855
1881
  userName = verified.name;
1856
1882
  } else {
1857
- p5.log.warn("Stored credentials expired \u2014 signing in again");
1883
+ const isFirstTime = verified !== null && "userGone" in verified;
1884
+ if (isFirstTime) {
1885
+ p5.log.warn("Account not found \u2014 starting fresh setup");
1886
+ } else {
1887
+ p5.log.warn("Stored credentials expired \u2014 signing in again");
1888
+ }
1858
1889
  const authResult = await runAuthFlow(
1859
1890
  api,
1860
1891
  options,
1861
1892
  /* reauth */
1862
- true
1893
+ !isFirstTime,
1894
+ identity?.repoCanonical
1863
1895
  );
1864
1896
  if (!authResult) return 1;
1865
1897
  userToken = authResult.token;
@@ -1993,7 +2025,7 @@ async function init(options = {}) {
1993
2025
  }
1994
2026
  fixOptions.push({
1995
2027
  value: "install_new",
1996
- label: "Install on a different GitHub account"
2028
+ label: `Install on a different GitHub account ${chalk6.dim("(creates a new personal workspace)")}`
1997
2029
  });
1998
2030
  fixOptions.push({ value: "cancel", label: "Cancel" });
1999
2031
  const fix = await p5.select({
@@ -2151,7 +2183,7 @@ async function init(options = {}) {
2151
2183
  projectName: chosen.name,
2152
2184
  organizationName: selectedWorkspaceName,
2153
2185
  sourceLocale: chosen.sourceLocale,
2154
- translationTriggers: chosen.translationTriggers
2186
+ branchTriggers: chosen.branchTriggers ?? [{ pattern: "main", triggers: ["push"] }]
2155
2187
  });
2156
2188
  p5.log.info(
2157
2189
  `Get your project API key at:
@@ -2192,7 +2224,7 @@ Translations won't run automatically until you grant access.
2192
2224
  projectName: projectResult.projectName,
2193
2225
  organizationName: selectedWorkspaceName,
2194
2226
  sourceLocale: projectResult.sourceLocale,
2195
- translationTriggers: projectResult.translationTriggers
2227
+ branchTriggers: projectResult.branchTriggers
2196
2228
  });
2197
2229
  printMcpSetup(projectResult.apiKey);
2198
2230
  p5.outro("You're all set.");
@@ -2607,9 +2639,6 @@ function getSyncPolicyErrorGuidance(error) {
2607
2639
  if (error.branch) {
2608
2640
  lines2.push(`Current branch: ${error.branch}`);
2609
2641
  }
2610
- if (error.targetBranches && error.targetBranches.length > 0) {
2611
- lines2.push(`Allowed branches: ${error.targetBranches.join(", ")}`);
2612
- }
2613
2642
  lines2.push("Update your project target branches in the dashboard if needed.");
2614
2643
  return lines2;
2615
2644
  }