@vocoder/cli 0.1.11 → 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";
@@ -420,7 +420,8 @@ var VocoderAPI = class {
420
420
  organizationName: data.organizationName,
421
421
  sourceLocale: data.sourceLocale,
422
422
  targetLocales: data.targetLocales,
423
- targetBranches: data.targetBranches,
423
+ branchTriggers: data.branchTriggers ?? [],
424
+ primaryBranch: data.primaryBranch,
424
425
  syncPolicy: {
425
426
  blockingBranches: data.syncPolicy?.blockingBranches ?? ["main", "master"],
426
427
  blockingMode: data.syncPolicy?.blockingMode ?? "required",
@@ -1410,19 +1411,25 @@ async function runProjectCreate(params) {
1410
1411
  }
1411
1412
  const languageOptions = buildLanguageOptions(rawLocales);
1412
1413
  const localeOptions = buildLocaleOptions(rawLocales);
1413
- const rawScope = await p3.text({
1414
- message: "App directory (leave blank for the entire repo)",
1415
- placeholder: "e.g. apps/web",
1416
- initialValue: params.defaultScopePath ?? "",
1417
- validate(value) {
1418
- const v = value.trim();
1419
- if (!v) return;
1420
- if (v.startsWith("/")) return "Use a relative path, not an absolute path";
1421
- if (v.includes("..")) return 'Path must not contain ".."';
1422
- }
1423
- });
1424
- if (p3.isCancel(rawScope)) return null;
1425
- 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
+ }
1426
1433
  const sourceLocale = await searchSelectLocale(
1427
1434
  languageOptions,
1428
1435
  "Source language (the language your code is written in)",
@@ -1440,12 +1447,12 @@ async function runProjectCreate(params) {
1440
1447
  }
1441
1448
  const detected = detectGitBranches();
1442
1449
  const initialBranches = params.defaultBranches?.length ? params.defaultBranches : [detected.defaultBranch];
1443
- let targetBranches = [];
1450
+ let selectedBranches = [];
1444
1451
  {
1445
1452
  let initial = initialBranches;
1446
- while (targetBranches.length === 0) {
1453
+ while (selectedBranches.length === 0) {
1447
1454
  const result = await filterableBranchSelect({
1448
- message: "Target branches (translations will run when you push to these)",
1455
+ message: "Target branches",
1449
1456
  branches: detected.branches,
1450
1457
  defaultBranch: detected.defaultBranch,
1451
1458
  initialValues: initial
@@ -1455,18 +1462,32 @@ async function runProjectCreate(params) {
1455
1462
  p3.log.warn("At least one branch is required. Please select at least one.");
1456
1463
  initial = [detected.defaultBranch];
1457
1464
  } else {
1458
- targetBranches = result;
1465
+ selectedBranches = result;
1459
1466
  }
1460
1467
  }
1461
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
+ }));
1462
1484
  try {
1463
1485
  const result = await api.createProject(userToken, {
1464
1486
  organizationId,
1465
1487
  name: projectName,
1466
1488
  sourceLocale,
1467
1489
  targetLocales,
1468
- targetBranches,
1469
- translationTriggers: ["push"],
1490
+ branchTriggers,
1470
1491
  scopePaths: scopePath ? [scopePath] : [],
1471
1492
  repoCanonical
1472
1493
  });
@@ -1580,7 +1601,7 @@ function printPlanLimitMessage(apiUrl, message) {
1580
1601
  p5.log.info(`Manage subscription: ${getSubscriptionSettingsUrl(apiUrl)}`);
1581
1602
  }
1582
1603
  function runScaffold(params) {
1583
- const { projectName, organizationName, sourceLocale, translationTriggers } = params;
1604
+ const { projectName, organizationName, sourceLocale, branchTriggers } = params;
1584
1605
  p5.log.info(`Project: ${chalk6.bold(projectName)}`);
1585
1606
  p5.log.info(`Workspace: ${chalk6.bold(organizationName)}`);
1586
1607
  const detection = detectLocalEcosystem();
@@ -1609,7 +1630,7 @@ function runScaffold(params) {
1609
1630
  framework: detection.framework,
1610
1631
  ecosystem: detection.ecosystem,
1611
1632
  sourceLocale,
1612
- translationTriggers
1633
+ branchTriggers
1613
1634
  });
1614
1635
  let stepNum = 1;
1615
1636
  if (snippets.pluginStep) {
@@ -1680,8 +1701,11 @@ function printCodeBlock(code) {
1680
1701
  async function verifyStoredToken(api, token) {
1681
1702
  try {
1682
1703
  return await api.getCliUserInfo(token);
1683
- } catch {
1704
+ } catch (err) {
1684
1705
  clearAuthData();
1706
+ if (err instanceof VocoderAPIError && err.status === 404) {
1707
+ return { userGone: true };
1708
+ }
1685
1709
  return null;
1686
1710
  }
1687
1711
  }
@@ -1810,8 +1834,7 @@ async function runAuthFlow(api, options, reauth = false, repoCanonical) {
1810
1834
  return null;
1811
1835
  }
1812
1836
  const userInfo = await api.getCliUserInfo(rawToken);
1813
- authSpinner.stop();
1814
- p5.log.success(`Authenticated as ${chalk6.bold(userInfo.email)}`);
1837
+ authSpinner.stop(`Authenticated as ${chalk6.bold(userInfo.email)}`);
1815
1838
  return { token: rawToken, ...userInfo, organizationId: callbackOrganizationId, discoveryReady: callbackDiscoveryReady };
1816
1839
  }
1817
1840
  async function init(options = {}) {
@@ -1836,7 +1859,7 @@ async function init(options = {}) {
1836
1859
  projectName: existing.projectName,
1837
1860
  organizationName: existing.organizationName,
1838
1861
  sourceLocale: existing.sourceLocale ?? "en",
1839
- translationTriggers: existing.translationTriggers ?? ["push"]
1862
+ branchTriggers: existing.branchTriggers ?? [{ pattern: "main", triggers: ["push"] }]
1840
1863
  });
1841
1864
  p5.outro("Vocoder is already set up for this repository.");
1842
1865
  return 0;
@@ -1851,18 +1874,24 @@ async function init(options = {}) {
1851
1874
  const stored = readAuthData();
1852
1875
  if (stored && stored.apiUrl === apiUrl) {
1853
1876
  const verified = await verifyStoredToken(api, stored.token);
1854
- if (verified) {
1877
+ if (verified && !("userGone" in verified)) {
1855
1878
  p5.log.success(`Authenticated as ${chalk6.bold(verified.email)}`);
1856
1879
  userToken = stored.token;
1857
1880
  userEmail = verified.email;
1858
1881
  userName = verified.name;
1859
1882
  } else {
1860
- 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
+ }
1861
1889
  const authResult = await runAuthFlow(
1862
1890
  api,
1863
1891
  options,
1864
1892
  /* reauth */
1865
- true
1893
+ !isFirstTime,
1894
+ identity?.repoCanonical
1866
1895
  );
1867
1896
  if (!authResult) return 1;
1868
1897
  userToken = authResult.token;
@@ -2154,7 +2183,7 @@ async function init(options = {}) {
2154
2183
  projectName: chosen.name,
2155
2184
  organizationName: selectedWorkspaceName,
2156
2185
  sourceLocale: chosen.sourceLocale,
2157
- translationTriggers: chosen.translationTriggers
2186
+ branchTriggers: chosen.branchTriggers ?? [{ pattern: "main", triggers: ["push"] }]
2158
2187
  });
2159
2188
  p5.log.info(
2160
2189
  `Get your project API key at:
@@ -2195,7 +2224,7 @@ Translations won't run automatically until you grant access.
2195
2224
  projectName: projectResult.projectName,
2196
2225
  organizationName: selectedWorkspaceName,
2197
2226
  sourceLocale: projectResult.sourceLocale,
2198
- translationTriggers: projectResult.translationTriggers
2227
+ branchTriggers: projectResult.branchTriggers
2199
2228
  });
2200
2229
  printMcpSetup(projectResult.apiKey);
2201
2230
  p5.outro("You're all set.");
@@ -2610,9 +2639,6 @@ function getSyncPolicyErrorGuidance(error) {
2610
2639
  if (error.branch) {
2611
2640
  lines2.push(`Current branch: ${error.branch}`);
2612
2641
  }
2613
- if (error.targetBranches && error.targetBranches.length > 0) {
2614
- lines2.push(`Allowed branches: ${error.targetBranches.join(", ")}`);
2615
- }
2616
2642
  lines2.push("Update your project target branches in the dashboard if needed.");
2617
2643
  return lines2;
2618
2644
  }