@vocoder/cli 0.15.0 → 0.16.0
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 +184 -154
- package/dist/bin.mjs.map +1 -1
- package/dist/{chunk-62KCB6C6.mjs → chunk-IK4ZCESQ.mjs} +10 -168
- package/dist/chunk-IK4ZCESQ.mjs.map +1 -0
- package/dist/lib.d.mts +7 -7
- package/dist/lib.mjs +159 -2
- package/dist/lib.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-62KCB6C6.mjs.map +0 -1
package/dist/bin.mjs
CHANGED
|
@@ -9,12 +9,11 @@ import {
|
|
|
9
9
|
computeFingerprint,
|
|
10
10
|
detectLocalEcosystem,
|
|
11
11
|
getPackagesToInstall,
|
|
12
|
-
getSetupSnippets,
|
|
13
12
|
loadVocoderConfig,
|
|
14
13
|
readAuthData,
|
|
15
14
|
verifyStoredAuth,
|
|
16
15
|
writeAuthData
|
|
17
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-IK4ZCESQ.mjs";
|
|
18
17
|
|
|
19
18
|
// src/bin.ts
|
|
20
19
|
import { Command } from "commander";
|
|
@@ -172,7 +171,7 @@ ${symbol(this.state)} App directories
|
|
|
172
171
|
];
|
|
173
172
|
for (let i = 0; i < added.length; i++) {
|
|
174
173
|
const isCursor = i === cursor && !addCursor;
|
|
175
|
-
const icon =
|
|
174
|
+
const icon = active("\u25FC");
|
|
176
175
|
const label = isCursor ? bld(added[i]) : added[i];
|
|
177
176
|
lines.push(`${info(S_BAR)} ${icon} ${label}`);
|
|
178
177
|
}
|
|
@@ -373,7 +372,7 @@ function buildList(filtered, cursor, scrollOffset, selected, filter, customPatte
|
|
|
373
372
|
const item = filtered[i];
|
|
374
373
|
const isCursor = i === cursor && !addCursor;
|
|
375
374
|
const isChecked = selected.has(item.value);
|
|
376
|
-
const icon = isChecked ?
|
|
375
|
+
const icon = isChecked ? active("\u25FC") : isCursor ? active("\u25FB") : dim("\u25FB");
|
|
377
376
|
let label = item.isCustom ? `${item.label} ${dim("(custom)")}` : item.label;
|
|
378
377
|
if (isCursor) label = bld(label);
|
|
379
378
|
lines.push(`${info(S_BAR2)} ${icon} ${label}`);
|
|
@@ -389,7 +388,7 @@ function buildList(filtered, cursor, scrollOffset, selected, filter, customPatte
|
|
|
389
388
|
lines.push(dim(`${S_BAR2} No branches detected`));
|
|
390
389
|
}
|
|
391
390
|
const hidden = filtered.length - (end - scrollOffset);
|
|
392
|
-
if (hidden > 0) lines.push(dim(`${S_BAR2} ${hidden} more`));
|
|
391
|
+
if (hidden > 0) lines.push(dim(`${S_BAR2} ${hidden} more \u2014 keep typing to narrow`));
|
|
393
392
|
return lines.join("\n");
|
|
394
393
|
}
|
|
395
394
|
async function filterableBranchSelect(params) {
|
|
@@ -434,7 +433,16 @@ async function filterableBranchSelect(params) {
|
|
|
434
433
|
${symbol2(this.state)} ${message}
|
|
435
434
|
`;
|
|
436
435
|
const inputHint = filter.length > 0 ? filter : dim("type to filter \xB7 type a custom pattern to add it");
|
|
437
|
-
const
|
|
436
|
+
const trimmedFilter = filter.trim();
|
|
437
|
+
const footer = (() => {
|
|
438
|
+
if (trimmedFilter.length > 0 && isNewPattern()) {
|
|
439
|
+
return dim(`${S_BAR2} Space to add "${trimmedFilter}" \xB7 \u2191\u2193 navigate \xB7 Enter to confirm`);
|
|
440
|
+
}
|
|
441
|
+
if (selected.size > 0) {
|
|
442
|
+
return dim(`${S_BAR2} ${selected.size} selected \xB7 \u2191\u2193 navigate \xB7 Space to select \xB7 Enter to confirm`);
|
|
443
|
+
}
|
|
444
|
+
return optional ? dim(`${S_BAR2} \u2191\u2193 navigate \xB7 Space to select \xB7 Enter to skip`) : dim(`${S_BAR2} \u2191\u2193 navigate \xB7 Space to select \xB7 Enter to confirm`);
|
|
445
|
+
})();
|
|
438
446
|
switch (this.state) {
|
|
439
447
|
case "submit": {
|
|
440
448
|
const summary = selected.size > 0 ? bld(Array.from(selected).join(", ")) : dim("none");
|
|
@@ -479,6 +487,9 @@ ${symbol2(this.state)} ${message}
|
|
|
479
487
|
scrollOffset = 0;
|
|
480
488
|
addCursor = false;
|
|
481
489
|
}
|
|
490
|
+
if (isNewPattern()) {
|
|
491
|
+
addCursor = true;
|
|
492
|
+
}
|
|
482
493
|
});
|
|
483
494
|
prompt.on("cursor", (action) => {
|
|
484
495
|
const filtered = getFiltered();
|
|
@@ -495,9 +506,9 @@ ${symbol2(this.state)} ${message}
|
|
|
495
506
|
addCursor = true;
|
|
496
507
|
else if (!addCursor) cursor = Math.min(filtered.length - 1, cursor + 1);
|
|
497
508
|
break;
|
|
498
|
-
case "space":
|
|
499
|
-
|
|
500
|
-
|
|
509
|
+
case "space": {
|
|
510
|
+
const t = filter.trim();
|
|
511
|
+
if (addCursor || t.length > 0 && isNewPattern()) {
|
|
501
512
|
const err = validateBranchPattern(t) ?? (excludedSet.has(t) ? "Already used for automatic translation" : null);
|
|
502
513
|
if (!err) {
|
|
503
514
|
customPatterns.push(t);
|
|
@@ -515,6 +526,7 @@ ${symbol2(this.state)} ${message}
|
|
|
515
526
|
}
|
|
516
527
|
}
|
|
517
528
|
break;
|
|
529
|
+
}
|
|
518
530
|
}
|
|
519
531
|
});
|
|
520
532
|
prompt.on("finalize", () => {
|
|
@@ -564,14 +576,13 @@ function buildList2(filtered, cursor, scrollOffset, selected) {
|
|
|
564
576
|
const opt = filtered[i];
|
|
565
577
|
const isCursor = i === cursor;
|
|
566
578
|
const isChecked = isMulti && selected.has(opt.bcp47);
|
|
567
|
-
const icon = isMulti ? isChecked ?
|
|
579
|
+
const icon = isMulti ? isChecked ? active("\u25FC") : isCursor ? active("\u25FB") : dim("\u25FB") : isCursor ? active("\u25CF") : dim("\u25CB");
|
|
568
580
|
visibleLines.push(
|
|
569
581
|
`${info(S_BAR3)} ${icon} ${isCursor ? bld(opt.label) : opt.label}`
|
|
570
582
|
);
|
|
571
583
|
}
|
|
572
584
|
const hidden = filtered.length - (end - scrollOffset);
|
|
573
|
-
if (hidden > 0)
|
|
574
|
-
visibleLines.push(dim(`${S_BAR3} ${hidden} more \u2014 keep typing to narrow`));
|
|
585
|
+
if (hidden > 0) visibleLines.push(dim(`${S_BAR3} ${hidden} more \u2014 keep typing to narrow`));
|
|
575
586
|
if (filtered.length === 0) visibleLines.push(dim(`${S_BAR3} No matches`));
|
|
576
587
|
return visibleLines.join("\n");
|
|
577
588
|
}
|
|
@@ -793,51 +804,45 @@ async function runProjectCreate(params) {
|
|
|
793
804
|
{
|
|
794
805
|
let initial = initialBranches;
|
|
795
806
|
while (pushBranches.length === 0) {
|
|
796
|
-
const
|
|
807
|
+
const result2 = await filterableBranchSelect({
|
|
797
808
|
message: "Which branches should trigger translations?",
|
|
798
809
|
branches: detected.branches,
|
|
799
810
|
defaultBranch: detected.defaultBranch,
|
|
800
811
|
initialValues: initial
|
|
801
812
|
});
|
|
802
|
-
if (
|
|
803
|
-
if (
|
|
813
|
+
if (result2 === null) return null;
|
|
814
|
+
if (result2.length === 0) {
|
|
804
815
|
p3.log.warn(
|
|
805
816
|
"At least one branch is required. Please select at least one."
|
|
806
817
|
);
|
|
807
818
|
initial = [detected.defaultBranch];
|
|
808
819
|
} else {
|
|
809
|
-
pushBranches =
|
|
820
|
+
pushBranches = result2;
|
|
810
821
|
}
|
|
811
822
|
}
|
|
812
823
|
}
|
|
813
824
|
const targetBranches = pushBranches;
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
};
|
|
836
|
-
} catch (error) {
|
|
837
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
838
|
-
p3.log.error(`Failed to create project: ${message}`);
|
|
839
|
-
return null;
|
|
840
|
-
}
|
|
825
|
+
const result = await api.createProject(userToken, {
|
|
826
|
+
organizationId,
|
|
827
|
+
name: projectName,
|
|
828
|
+
sourceLocale,
|
|
829
|
+
targetLocales,
|
|
830
|
+
targetBranches,
|
|
831
|
+
appDirs,
|
|
832
|
+
repoCanonical
|
|
833
|
+
});
|
|
834
|
+
p3.log.success(`Project ${chalk2.bold(result.projectName)} created!`);
|
|
835
|
+
return {
|
|
836
|
+
projectId: result.projectId,
|
|
837
|
+
projectName: result.projectName,
|
|
838
|
+
apiKey: result.apiKey,
|
|
839
|
+
sourceLocale,
|
|
840
|
+
targetLocales,
|
|
841
|
+
targetBranches,
|
|
842
|
+
repositoryBound: result.repositoryBound,
|
|
843
|
+
configureUrl: result.configureUrl,
|
|
844
|
+
apps: result.apps
|
|
845
|
+
};
|
|
841
846
|
}
|
|
842
847
|
async function runAppCreate(params) {
|
|
843
848
|
const { api, userToken, projectId, projectName, repoCanonical } = params;
|
|
@@ -890,48 +895,42 @@ async function runAppCreate(params) {
|
|
|
890
895
|
{
|
|
891
896
|
let initial = [detectedApp.defaultBranch];
|
|
892
897
|
while (appPushBranches.length === 0) {
|
|
893
|
-
const
|
|
898
|
+
const result2 = await filterableBranchSelect({
|
|
894
899
|
message: "Which branches should trigger translations?",
|
|
895
900
|
branches: detectedApp.branches,
|
|
896
901
|
defaultBranch: detectedApp.defaultBranch,
|
|
897
902
|
initialValues: initial
|
|
898
903
|
});
|
|
899
|
-
if (
|
|
900
|
-
if (
|
|
904
|
+
if (result2 === null) return null;
|
|
905
|
+
if (result2.length === 0) {
|
|
901
906
|
p3.log.warn("At least one branch is required.");
|
|
902
907
|
initial = [detectedApp.defaultBranch];
|
|
903
908
|
} else {
|
|
904
|
-
appPushBranches =
|
|
909
|
+
appPushBranches = result2;
|
|
905
910
|
}
|
|
906
911
|
}
|
|
907
912
|
}
|
|
908
913
|
const targetBranches = appPushBranches;
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
};
|
|
930
|
-
} catch (error) {
|
|
931
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
932
|
-
p3.log.error(`Failed to add app: ${message}`);
|
|
933
|
-
return null;
|
|
934
|
-
}
|
|
914
|
+
const result = await api.createApp(userToken, {
|
|
915
|
+
projectId,
|
|
916
|
+
appDir,
|
|
917
|
+
sourceLocale,
|
|
918
|
+
targetLocales,
|
|
919
|
+
targetBranches,
|
|
920
|
+
repoCanonical: repoCanonical ?? ""
|
|
921
|
+
});
|
|
922
|
+
p3.log.success(
|
|
923
|
+
`App ${chalk2.bold(appDir || "(root)")} added to ${chalk2.bold(projectName)}!`
|
|
924
|
+
);
|
|
925
|
+
return {
|
|
926
|
+
projectId: result.projectId,
|
|
927
|
+
projectName: result.projectName,
|
|
928
|
+
appDir: result.appDir,
|
|
929
|
+
appId: result.appId,
|
|
930
|
+
sourceLocale,
|
|
931
|
+
targetLocales,
|
|
932
|
+
targetBranches
|
|
933
|
+
};
|
|
935
934
|
}
|
|
936
935
|
|
|
937
936
|
// src/utils/github-connect.ts
|
|
@@ -1141,7 +1140,6 @@ async function runGitHubDiscoveryFlow(params) {
|
|
|
1141
1140
|
callbackPort: server?.port
|
|
1142
1141
|
});
|
|
1143
1142
|
p4.log.info("Opening GitHub to authorize your account...");
|
|
1144
|
-
p4.note("Complete authorization in your browser.");
|
|
1145
1143
|
if (process.stdin.isTTY && process.stdout.isTTY && process.env.CI !== "true") {
|
|
1146
1144
|
const shouldOpen = params.yes ? true : await p4.confirm({ message: "Open in your browser?" });
|
|
1147
1145
|
if (p4.isCancel(shouldOpen)) {
|
|
@@ -1193,7 +1191,7 @@ async function selectGitHubInstallation(installations, canInstallNew) {
|
|
|
1193
1191
|
value: String(inst.installationId),
|
|
1194
1192
|
label: inst.accountLogin,
|
|
1195
1193
|
hint: [
|
|
1196
|
-
inst.accountType === "Organization" ? "
|
|
1194
|
+
inst.accountType === "Organization" ? "GitHub org" : "personal account",
|
|
1197
1195
|
inst.conflictLabel ? `connected to ${inst.conflictLabel}` : "",
|
|
1198
1196
|
inst.isSuspended ? "suspended" : ""
|
|
1199
1197
|
].filter(Boolean).join(" \xB7 ") || void 0
|
|
@@ -1201,11 +1199,11 @@ async function selectGitHubInstallation(installations, canInstallNew) {
|
|
|
1201
1199
|
if (canInstallNew) {
|
|
1202
1200
|
options.push({
|
|
1203
1201
|
value: "install_new",
|
|
1204
|
-
label: `Install on a new account ${chalk3.dim("(creates a new
|
|
1202
|
+
label: `Install on a new account ${chalk3.dim("(creates a new workspace)")}`
|
|
1205
1203
|
});
|
|
1206
1204
|
}
|
|
1207
1205
|
const selected = await p4.select({
|
|
1208
|
-
message: "
|
|
1206
|
+
message: "Which GitHub account should this workspace connect to?",
|
|
1209
1207
|
options
|
|
1210
1208
|
});
|
|
1211
1209
|
if (p4.isCancel(selected)) return null;
|
|
@@ -1416,7 +1414,7 @@ function printPlanLimitMessage(apiUrl, message) {
|
|
|
1416
1414
|
p6.log.info(`Manage subscription: ${getSubscriptionSettingsUrl(apiUrl)}`);
|
|
1417
1415
|
}
|
|
1418
1416
|
function runScaffold(params) {
|
|
1419
|
-
const {
|
|
1417
|
+
const { targetBranches } = params;
|
|
1420
1418
|
const detection = detectLocalEcosystem();
|
|
1421
1419
|
const useTypeScript = detection.isTypeScript;
|
|
1422
1420
|
if (detection.ecosystem) {
|
|
@@ -1459,43 +1457,8 @@ function runScaffold(params) {
|
|
|
1459
1457
|
} else if (detection.ecosystem) {
|
|
1460
1458
|
p6.log.info(`Packages: ${chalk5.green("already installed")}`);
|
|
1461
1459
|
}
|
|
1462
|
-
const snippets = getSetupSnippets({
|
|
1463
|
-
framework: detection.framework,
|
|
1464
|
-
ecosystem: detection.ecosystem,
|
|
1465
|
-
sourceLocale,
|
|
1466
|
-
targetBranches
|
|
1467
|
-
});
|
|
1468
|
-
const steps = [];
|
|
1469
|
-
if (snippets.pluginStep) {
|
|
1470
|
-
steps.push({
|
|
1471
|
-
label: snippets.pluginStep.file,
|
|
1472
|
-
hint: "register the build plugin so Vocoder can extract your strings",
|
|
1473
|
-
code: snippets.pluginStep.code
|
|
1474
|
-
});
|
|
1475
|
-
}
|
|
1476
|
-
if (snippets.providerStep) {
|
|
1477
|
-
steps.push({
|
|
1478
|
-
label: snippets.providerStep.file,
|
|
1479
|
-
hint: "wrap your app so translations load at runtime",
|
|
1480
|
-
code: snippets.providerStep.code
|
|
1481
|
-
});
|
|
1482
|
-
}
|
|
1483
|
-
steps.push({
|
|
1484
|
-
label: "wrap translatable text",
|
|
1485
|
-
hint: "mark strings for extraction \u2014 Vocoder picks these up on push",
|
|
1486
|
-
code: snippets.wrapStep.code
|
|
1487
|
-
});
|
|
1488
|
-
p6.log.message("");
|
|
1489
|
-
p6.log.message(chalk5.bold("Finish setup in your code"));
|
|
1490
|
-
p6.log.message("");
|
|
1491
|
-
for (let i = 0; i < steps.length; i++) {
|
|
1492
|
-
const step = steps[i];
|
|
1493
|
-
p6.log.step(`${chalk5.bold(step.label)} ${chalk5.dim(`\u2014 ${step.hint}`)}`);
|
|
1494
|
-
printCodeBlock(step.code);
|
|
1495
|
-
if (i < steps.length - 1) p6.log.message("");
|
|
1496
|
-
}
|
|
1497
|
-
p6.log.message("");
|
|
1498
1460
|
const branchList = targetBranches.length > 0 ? targetBranches.map((b) => highlight(b)).join(" or ") : highlight("your target branch");
|
|
1461
|
+
p6.log.message("");
|
|
1499
1462
|
p6.log.success(`Push to ${branchList} to trigger your first translation run.`);
|
|
1500
1463
|
p6.log.message(info(" Docs: https://vocoder.app/docs/getting-started"));
|
|
1501
1464
|
}
|
|
@@ -1551,28 +1514,100 @@ function writeAppConfigs(apps, targetBranches, useTypeScript, repoRoot) {
|
|
|
1551
1514
|
}
|
|
1552
1515
|
}
|
|
1553
1516
|
}
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1517
|
+
var MCP_DOCS_URL = "https://vocoder.app/docs/mcp";
|
|
1518
|
+
function mcpServerJson(apiKey) {
|
|
1519
|
+
return JSON.stringify(
|
|
1520
|
+
{
|
|
1521
|
+
mcpServers: {
|
|
1522
|
+
vocoder: {
|
|
1523
|
+
type: "stdio",
|
|
1524
|
+
command: "npx",
|
|
1525
|
+
args: ["-y", "@vocoder/mcp"],
|
|
1526
|
+
env: { VOCODER_API_KEY: apiKey }
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
},
|
|
1530
|
+
null,
|
|
1531
|
+
2
|
|
1559
1532
|
);
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1533
|
+
}
|
|
1534
|
+
async function runMcpSetup(apiKey) {
|
|
1535
|
+
const tool = await p6.select({
|
|
1536
|
+
message: "Which AI editor?",
|
|
1537
|
+
options: [
|
|
1538
|
+
{ value: "claude", label: "Claude Code" },
|
|
1539
|
+
{ value: "cursor", label: "Cursor" },
|
|
1540
|
+
{ value: "windsurf", label: "Windsurf" },
|
|
1541
|
+
{ value: "vscode", label: "VS Code (GitHub Copilot)" },
|
|
1542
|
+
{ value: "other", label: "Other \u2014 show the config JSON" }
|
|
1543
|
+
]
|
|
1544
|
+
});
|
|
1545
|
+
if (p6.isCancel(tool)) return;
|
|
1546
|
+
if (tool === "claude") {
|
|
1547
|
+
try {
|
|
1548
|
+
execSync3(
|
|
1549
|
+
`claude mcp add --scope user --transport stdio --env VOCODER_API_KEY=${apiKey} vocoder -- npx -y @vocoder/mcp`,
|
|
1550
|
+
{ stdio: "pipe" }
|
|
1551
|
+
);
|
|
1552
|
+
p6.log.success("Vocoder MCP server registered in Claude Code.");
|
|
1553
|
+
} catch {
|
|
1554
|
+
p6.log.message("Run this to register the MCP server:");
|
|
1555
|
+
printCommand(
|
|
1556
|
+
`claude mcp add --scope user --transport stdio --env VOCODER_API_KEY=${apiKey} vocoder -- npx -y @vocoder/mcp`
|
|
1557
|
+
);
|
|
1558
|
+
p6.log.message(info(` Docs: ${MCP_DOCS_URL}`));
|
|
1559
|
+
}
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
const configPaths = {
|
|
1563
|
+
cursor: { path: "~/.cursor/mcp.json", merge: true },
|
|
1564
|
+
windsurf: { path: "~/.codeium/windsurf/mcp_config.json", merge: true },
|
|
1565
|
+
vscode: { path: ".vscode/mcp.json", merge: true },
|
|
1566
|
+
other: { path: ".mcp.json", merge: false }
|
|
1567
|
+
};
|
|
1568
|
+
const { path: configPath, merge } = configPaths[tool];
|
|
1569
|
+
const mergeNote = merge ? chalk5.dim(` Merge into ${highlight(configPath)} (create if missing):`) : chalk5.dim(` Add to ${highlight(configPath)}:`);
|
|
1570
|
+
p6.log.message(mergeNote);
|
|
1571
|
+
printCodeBlock(mcpServerJson(apiKey));
|
|
1572
|
+
p6.log.message(info(` Docs: ${MCP_DOCS_URL}`));
|
|
1573
|
+
}
|
|
1574
|
+
function tryClipboard(text2) {
|
|
1575
|
+
const tools = [
|
|
1576
|
+
{ cmd: "pbcopy" },
|
|
1577
|
+
{ cmd: "xclip", args: ["-selection", "clipboard"] },
|
|
1578
|
+
{ cmd: "xsel", args: ["--clipboard", "--input"] },
|
|
1579
|
+
{ cmd: "wl-copy" },
|
|
1580
|
+
{ cmd: "clip" }
|
|
1581
|
+
];
|
|
1582
|
+
for (const { cmd, args = [] } of tools) {
|
|
1583
|
+
try {
|
|
1584
|
+
execSync3([cmd, ...args].join(" "), {
|
|
1585
|
+
input: text2,
|
|
1586
|
+
stdio: ["pipe", "ignore", "ignore"]
|
|
1587
|
+
});
|
|
1588
|
+
return true;
|
|
1589
|
+
} catch {
|
|
1590
|
+
continue;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
return false;
|
|
1594
|
+
}
|
|
1595
|
+
function printCommand(cmd) {
|
|
1596
|
+
const copied = tryClipboard(cmd);
|
|
1597
|
+
process.stdout.write("\n");
|
|
1598
|
+
process.stdout.write(` ${chalk5.dim("$")} ${chalk5.cyan(cmd)}
|
|
1563
1599
|
`);
|
|
1564
|
-
process.stdout.write(
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1600
|
+
if (copied) process.stdout.write(` ${chalk5.dim("\u2191 copied to clipboard")}
|
|
1601
|
+
`);
|
|
1602
|
+
process.stdout.write("\n");
|
|
1603
|
+
}
|
|
1604
|
+
function printCodeBlock(code) {
|
|
1605
|
+
process.stdout.write("\n");
|
|
1606
|
+
for (const line of code.split("\n")) {
|
|
1607
|
+
process.stdout.write(` ${line}
|
|
1570
1608
|
`);
|
|
1571
1609
|
}
|
|
1572
|
-
process.stdout.write(
|
|
1573
|
-
`${chalk5.gray("\u2502")} ${chalk5.gray(`\u2514${"\u2500".repeat(maxLen + 2)}\u2518`)}
|
|
1574
|
-
`
|
|
1575
|
-
);
|
|
1610
|
+
process.stdout.write("\n");
|
|
1576
1611
|
}
|
|
1577
1612
|
async function runAuthFlow(api, options, reauth = false, repoCanonical) {
|
|
1578
1613
|
let server = null;
|
|
@@ -1585,6 +1620,7 @@ async function runAuthFlow(api, options, reauth = false, repoCanonical) {
|
|
|
1585
1620
|
const session = await api.startCliAuthSession(server?.port, repoCanonical);
|
|
1586
1621
|
const browserUrl = reauth ? session.verificationUrl : session.installUrl ?? session.verificationUrl;
|
|
1587
1622
|
const expiresAt = new Date(session.expiresAt).getTime();
|
|
1623
|
+
p6.log.info(browserUrl);
|
|
1588
1624
|
if (options.ci) {
|
|
1589
1625
|
process.stdout.write(`VOCODER_AUTH_URL: ${browserUrl}
|
|
1590
1626
|
`);
|
|
@@ -2145,10 +2181,7 @@ async function init(options = {}) {
|
|
|
2145
2181
|
return 1;
|
|
2146
2182
|
}
|
|
2147
2183
|
const detection2 = detectLocalEcosystem();
|
|
2148
|
-
runScaffold({
|
|
2149
|
-
sourceLocale: appResult.sourceLocale,
|
|
2150
|
-
targetBranches: appResult.targetBranches
|
|
2151
|
-
});
|
|
2184
|
+
runScaffold({ targetBranches: appResult.targetBranches });
|
|
2152
2185
|
writeAppConfigs(
|
|
2153
2186
|
[{ appDir: appResult.appDir, appId: appResult.appId }],
|
|
2154
2187
|
appResult.targetBranches,
|
|
@@ -2192,6 +2225,7 @@ async function init(options = {}) {
|
|
|
2192
2225
|
remainingApps = ws.maxApps === -1 ? void 0 : Math.max(0, ws.maxApps - ws.appCount);
|
|
2193
2226
|
}
|
|
2194
2227
|
} catch {
|
|
2228
|
+
p6.log.warn("Could not verify plan limits \u2014 proceeding, the server will enforce them.");
|
|
2195
2229
|
}
|
|
2196
2230
|
const projectResult = await runProjectCreate({
|
|
2197
2231
|
api,
|
|
@@ -2204,10 +2238,7 @@ async function init(options = {}) {
|
|
|
2204
2238
|
defaultBranches: ["main"],
|
|
2205
2239
|
maxAppDirs: remainingApps
|
|
2206
2240
|
});
|
|
2207
|
-
if (!projectResult)
|
|
2208
|
-
p6.log.error("Project creation failed. Run `vocoder init` again.");
|
|
2209
|
-
return 1;
|
|
2210
|
-
}
|
|
2241
|
+
if (!projectResult) return 1;
|
|
2211
2242
|
if (!projectResult.repositoryBound && identity?.repoCanonical) {
|
|
2212
2243
|
p6.log.warn(
|
|
2213
2244
|
`This repository isn't accessible to your GitHub App installation.
|
|
@@ -2221,10 +2252,7 @@ Translations won't run automatically until you grant access.
|
|
|
2221
2252
|
);
|
|
2222
2253
|
}
|
|
2223
2254
|
const detection = detectLocalEcosystem();
|
|
2224
|
-
runScaffold({
|
|
2225
|
-
sourceLocale: projectResult.sourceLocale,
|
|
2226
|
-
targetBranches: projectResult.targetBranches
|
|
2227
|
-
});
|
|
2255
|
+
runScaffold({ targetBranches: projectResult.targetBranches });
|
|
2228
2256
|
writeAppConfigs(
|
|
2229
2257
|
projectResult.apps,
|
|
2230
2258
|
projectResult.targetBranches,
|
|
@@ -2232,17 +2260,20 @@ Translations won't run automatically until you grant access.
|
|
|
2232
2260
|
identity?.repoRoot
|
|
2233
2261
|
);
|
|
2234
2262
|
printApiKey(projectResult.apiKey, identity?.repoRoot);
|
|
2263
|
+
const wantsMcp = await p6.confirm({
|
|
2264
|
+
message: "Set up the Vocoder MCP server for your AI editor?"
|
|
2265
|
+
});
|
|
2266
|
+
if (!p6.isCancel(wantsMcp) && wantsMcp) {
|
|
2267
|
+
await runMcpSetup(projectResult.apiKey);
|
|
2268
|
+
}
|
|
2235
2269
|
p6.outro("You're all set.");
|
|
2236
2270
|
return 0;
|
|
2237
2271
|
} catch (error) {
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
return 1;
|
|
2242
|
-
}
|
|
2243
|
-
p6.log.error(`Error: ${error.message}`);
|
|
2272
|
+
const message = error instanceof Error ? error.message : "Unknown setup error";
|
|
2273
|
+
if (isPlanLimitFailure(message)) {
|
|
2274
|
+
printPlanLimitMessage(apiUrl, message);
|
|
2244
2275
|
} else {
|
|
2245
|
-
p6.log.error(
|
|
2276
|
+
p6.log.error(message);
|
|
2246
2277
|
}
|
|
2247
2278
|
return 1;
|
|
2248
2279
|
}
|
|
@@ -2762,7 +2793,7 @@ async function sync(options = {}) {
|
|
|
2762
2793
|
includePattern: mergedConfig.includePattern,
|
|
2763
2794
|
excludePattern: mergedConfig.excludePattern,
|
|
2764
2795
|
timeout: waitTimeoutMs,
|
|
2765
|
-
...fileConfig?.appIndustry ? {
|
|
2796
|
+
...fileConfig?.industry ?? fileConfig?.appIndustry ? { industry: fileConfig?.industry ?? fileConfig?.appIndustry } : {},
|
|
2766
2797
|
...fileConfig?.formality ? { formality: fileConfig.formality } : {}
|
|
2767
2798
|
};
|
|
2768
2799
|
spinner7.stop(`Branch: ${highlight(branch)}`);
|
|
@@ -2855,8 +2886,7 @@ async function sync(options = {}) {
|
|
|
2855
2886
|
requestedMaxWaitMs: waitTimeoutMs,
|
|
2856
2887
|
clientRunId: randomUUID(),
|
|
2857
2888
|
force: options.force,
|
|
2858
|
-
|
|
2859
|
-
...config.appIndustry ? { appIndustry: config.appIndustry } : {}
|
|
2889
|
+
...config.industry ? { industry: config.industry } : {}
|
|
2860
2890
|
},
|
|
2861
2891
|
repoIdentity ? { ...repoIdentity, commitSha } : { commitSha }
|
|
2862
2892
|
);
|