@holdyourvoice/hyv 2.9.3 → 2.9.4
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/CHANGELOG.md +9 -0
- package/dist/index.js +61 -100
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable CLI changes. Also mirrored to [holdyourvoice.com/changelog](https://holdyourvoice.com/changelog) for user-facing releases.
|
|
4
4
|
|
|
5
|
+
## [2.9.4] — 2026-06-12
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- Welcome step 4 — one sign-in only; opens dashboard billing tab (no second Google login on marketing site)
|
|
9
|
+
- `hyv plan --upgrade` opens authenticated dashboard billing instead of public pricing page
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Step 4 copy tightened; spinners while account + profile sync run
|
|
13
|
+
|
|
5
14
|
## [2.9.3] — 2026-06-12
|
|
6
15
|
|
|
7
16
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -4612,40 +4612,6 @@ var require_source = __commonJS({
|
|
|
4612
4612
|
});
|
|
4613
4613
|
|
|
4614
4614
|
// src/lib/config.ts
|
|
4615
|
-
var config_exports = {};
|
|
4616
|
-
__export(config_exports, {
|
|
4617
|
-
API_BASE: () => API_BASE,
|
|
4618
|
-
AUTH_FILE: () => AUTH_FILE,
|
|
4619
|
-
CACHE_DIR: () => CACHE_DIR,
|
|
4620
|
-
CONFIG_FILE: () => CONFIG_FILE,
|
|
4621
|
-
HYV_DIR: () => HYV_DIR,
|
|
4622
|
-
LAST_SESSION_FILE: () => LAST_SESSION_FILE,
|
|
4623
|
-
PROFILES_DIR: () => PROFILES_DIR,
|
|
4624
|
-
QUEUE_DIR: () => QUEUE_DIR,
|
|
4625
|
-
appendSecureLine: () => appendSecureLine,
|
|
4626
|
-
assertSafeOAuthUrl: () => assertSafeOAuthUrl,
|
|
4627
|
-
assertSafeOpenUrl: () => assertSafeOpenUrl,
|
|
4628
|
-
assertSafeProfileName: () => assertSafeProfileName,
|
|
4629
|
-
clearAuth: () => clearAuth,
|
|
4630
|
-
clearQueuedSignals: () => clearQueuedSignals,
|
|
4631
|
-
cliApiUrl: () => cliApiUrl,
|
|
4632
|
-
ensureHyvDir: () => ensureHyvDir,
|
|
4633
|
-
getQueuedSignals: () => getQueuedSignals,
|
|
4634
|
-
getToken: () => getToken,
|
|
4635
|
-
isInitialized: () => isInitialized,
|
|
4636
|
-
listCachedProfiles: () => listCachedProfiles,
|
|
4637
|
-
profilePathForName: () => profilePathForName,
|
|
4638
|
-
queueSignal: () => queueSignal,
|
|
4639
|
-
readAuth: () => readAuth,
|
|
4640
|
-
readCachedProfile: () => readCachedProfile,
|
|
4641
|
-
readConfig: () => readConfig,
|
|
4642
|
-
readLastEditSession: () => readLastEditSession,
|
|
4643
|
-
saveLastEditSession: () => saveLastEditSession,
|
|
4644
|
-
writeAuth: () => writeAuth,
|
|
4645
|
-
writeCachedProfile: () => writeCachedProfile,
|
|
4646
|
-
writeConfig: () => writeConfig,
|
|
4647
|
-
writeSecureFile: () => writeSecureFile
|
|
4648
|
-
});
|
|
4649
4615
|
function validateApiBase(raw) {
|
|
4650
4616
|
const trimmed = raw.replace(/\/$/, "");
|
|
4651
4617
|
let parsed;
|
|
@@ -4666,7 +4632,7 @@ function cliApiUrl(apiPath) {
|
|
|
4666
4632
|
const p = apiPath.startsWith("/") ? apiPath : `/${apiPath}`;
|
|
4667
4633
|
return `${API_BASE}${p}`;
|
|
4668
4634
|
}
|
|
4669
|
-
function
|
|
4635
|
+
function assertSafeOpenUrl2(url) {
|
|
4670
4636
|
let parsed;
|
|
4671
4637
|
try {
|
|
4672
4638
|
parsed = new URL(url);
|
|
@@ -4737,10 +4703,6 @@ function ensureHyvDir() {
|
|
|
4737
4703
|
}
|
|
4738
4704
|
}
|
|
4739
4705
|
}
|
|
4740
|
-
function writeSecureFile(filePath, content) {
|
|
4741
|
-
ensureHyvDir();
|
|
4742
|
-
fs.writeFileSync(filePath, content, { mode: 384 });
|
|
4743
|
-
}
|
|
4744
4706
|
function appendSecureLine(filePath, line, dir) {
|
|
4745
4707
|
if (dir) {
|
|
4746
4708
|
if (!fs.existsSync(dir))
|
|
@@ -4779,11 +4741,6 @@ function writeAuth(auth) {
|
|
|
4779
4741
|
ensureHyvDir();
|
|
4780
4742
|
fs.writeFileSync(AUTH_FILE, JSON.stringify(auth, null, 2), { mode: 384 });
|
|
4781
4743
|
}
|
|
4782
|
-
function clearAuth() {
|
|
4783
|
-
if (fs.existsSync(AUTH_FILE)) {
|
|
4784
|
-
fs.unlinkSync(AUTH_FILE);
|
|
4785
|
-
}
|
|
4786
|
-
}
|
|
4787
4744
|
function readConfig() {
|
|
4788
4745
|
try {
|
|
4789
4746
|
if (!fs.existsSync(CONFIG_FILE))
|
|
@@ -4854,17 +4811,6 @@ function queueSignal(signal) {
|
|
|
4854
4811
|
const filePath = path.join(QUEUE_DIR, `${id}.json`);
|
|
4855
4812
|
fs.writeFileSync(filePath, JSON.stringify(signal, null, 2), { mode: 384 });
|
|
4856
4813
|
}
|
|
4857
|
-
function clearQueuedSignals() {
|
|
4858
|
-
try {
|
|
4859
|
-
if (!fs.existsSync(QUEUE_DIR))
|
|
4860
|
-
return;
|
|
4861
|
-
const files = fs.readdirSync(QUEUE_DIR).filter((f) => f.endsWith(".json"));
|
|
4862
|
-
for (const f of files) {
|
|
4863
|
-
fs.unlinkSync(path.join(QUEUE_DIR, f));
|
|
4864
|
-
}
|
|
4865
|
-
} catch {
|
|
4866
|
-
}
|
|
4867
|
-
}
|
|
4868
4814
|
function saveLastEditSession(session) {
|
|
4869
4815
|
ensureHyvDir();
|
|
4870
4816
|
const data = { ...session, saved_at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
@@ -5355,6 +5301,7 @@ __export(auth_exports, {
|
|
|
5355
5301
|
authenticatedRequest: () => authenticatedRequest,
|
|
5356
5302
|
checkSession: () => checkSession,
|
|
5357
5303
|
getValidToken: () => getValidToken,
|
|
5304
|
+
openAuthenticatedDashboard: () => openAuthenticatedDashboard,
|
|
5358
5305
|
refreshToken: () => refreshToken,
|
|
5359
5306
|
verifyOAuthState: () => verifyOAuthState
|
|
5360
5307
|
});
|
|
@@ -5543,6 +5490,23 @@ async function authenticateWithBrowser() {
|
|
|
5543
5490
|
writeAuth(authData);
|
|
5544
5491
|
return authData;
|
|
5545
5492
|
}
|
|
5493
|
+
async function openAuthenticatedDashboard(opts = {}) {
|
|
5494
|
+
const response = await authenticatedRequest(cliApiUrl("/cli/auth/web-handoff"), {
|
|
5495
|
+
method: "POST",
|
|
5496
|
+
body: {
|
|
5497
|
+
next: opts.next || "/dashboard",
|
|
5498
|
+
tab: opts.tab || "billing"
|
|
5499
|
+
}
|
|
5500
|
+
});
|
|
5501
|
+
if (response.status !== 200) {
|
|
5502
|
+
throw new Error("Could not open dashboard \u2014 try https://holdyourvoice.com/dashboard");
|
|
5503
|
+
}
|
|
5504
|
+
const { url } = response.data;
|
|
5505
|
+
if (!url) {
|
|
5506
|
+
throw new Error("Dashboard handoff URL missing");
|
|
5507
|
+
}
|
|
5508
|
+
await (0, import_open.default)(assertSafeOpenUrl(url));
|
|
5509
|
+
}
|
|
5546
5510
|
async function refreshToken(tokenOverride) {
|
|
5547
5511
|
const token = tokenOverride || readAuth()?.token;
|
|
5548
5512
|
if (!token)
|
|
@@ -5634,7 +5598,7 @@ function printFreePaidMatrix(opts = {}) {
|
|
|
5634
5598
|
First month $1 \u2192 ${PRICING_URL}`));
|
|
5635
5599
|
console.log(import_chalk2.default.dim(" hyv init | hyv plan --upgrade\n"));
|
|
5636
5600
|
}
|
|
5637
|
-
var import_chalk2, NPX_EXAMPLES, FREE_CLI_COMMANDS, PAID_FEATURES, FREE_WEB_TOOLS, COMMUNITY_URL, PRICING_URL;
|
|
5601
|
+
var import_chalk2, NPX_EXAMPLES, FREE_CLI_COMMANDS, PAID_FEATURES, FREE_WEB_TOOLS, COMMUNITY_URL, PRICING_URL, DASHBOARD_BILLING_URL;
|
|
5638
5602
|
var init_free_paid = __esm({
|
|
5639
5603
|
"src/lib/free-paid.ts"() {
|
|
5640
5604
|
"use strict";
|
|
@@ -5682,6 +5646,7 @@ var init_free_paid = __esm({
|
|
|
5682
5646
|
];
|
|
5683
5647
|
COMMUNITY_URL = "https://holdyourvoice.com/community";
|
|
5684
5648
|
PRICING_URL = "https://holdyourvoice.com/#pricing";
|
|
5649
|
+
DASHBOARD_BILLING_URL = "https://holdyourvoice.com/dashboard?tab=billing";
|
|
5685
5650
|
}
|
|
5686
5651
|
});
|
|
5687
5652
|
|
|
@@ -11452,12 +11417,12 @@ function buildStepGuide(step, profileName) {
|
|
|
11452
11417
|
return [
|
|
11453
11418
|
"### Step 4 \u2014 save & unlock",
|
|
11454
11419
|
"",
|
|
11455
|
-
"Explain warmly:
|
|
11420
|
+
"Explain warmly: local profile until signup. One browser sign-in via CLI \u2014 then open dashboard billing (no second login).",
|
|
11456
11421
|
"Paid unlock is **$1 for the first month** \u2014 profiles that learn, hybrid rewrite, dashboard.",
|
|
11457
11422
|
"Scanning/fix/MCP stay free forever without an account.",
|
|
11458
11423
|
"",
|
|
11459
|
-
"1. `hyv init` \u2014
|
|
11460
|
-
"2.
|
|
11424
|
+
"1. `hyv init` or welcome step 4 \u2014 single Google sign-in from terminal",
|
|
11425
|
+
"2. Dashboard opens on billing tab \u2014 user picks plan there",
|
|
11461
11426
|
"",
|
|
11462
11427
|
`Pricing: ${PRICING_URL}`
|
|
11463
11428
|
].join("\n");
|
|
@@ -11784,14 +11749,13 @@ async function stepTest(profileName) {
|
|
|
11784
11749
|
}
|
|
11785
11750
|
async function stepSignup(profileName) {
|
|
11786
11751
|
console.log(import_chalk12.default.bold("\nstep 4 \xB7 save & unlock\n"));
|
|
11787
|
-
console.log(" your
|
|
11788
|
-
console.log("
|
|
11789
|
-
console.log("
|
|
11790
|
-
console.log("
|
|
11791
|
-
console.log("
|
|
11792
|
-
console.log(" access to profiles that learn, hybrid rewrite, and your dashboard.\n");
|
|
11752
|
+
console.log(" your profile works on this machine. scan anything, anytime \u2014 free forever.");
|
|
11753
|
+
console.log("");
|
|
11754
|
+
console.log(" create a free account to back it up and sync everywhere.");
|
|
11755
|
+
console.log(" then unlock learning for " + import_chalk12.default.bold("$1 your first month") + " \u2014 profiles that");
|
|
11756
|
+
console.log(" get sharper every rewrite, hybrid rewrites, and your dashboard.\n");
|
|
11793
11757
|
console.log(import_chalk12.default.dim(" free forever (no account): scan, fix, check, mcp"));
|
|
11794
|
-
console.log(import_chalk12.default.dim("
|
|
11758
|
+
console.log(import_chalk12.default.dim(" $1 first month: learning loop, rich rewrites, sync across devices\n"));
|
|
11795
11759
|
const ready = await askYesNo(" create your free account now? ($1 first month to unlock everything)");
|
|
11796
11760
|
if (!ready) {
|
|
11797
11761
|
console.log(import_chalk12.default.dim("\n no rush \u2014 your profile stays on this machine."));
|
|
@@ -11803,18 +11767,25 @@ async function stepSignup(profileName) {
|
|
|
11803
11767
|
return;
|
|
11804
11768
|
}
|
|
11805
11769
|
if (!isInitialized() || !getToken()) {
|
|
11806
|
-
console.log(import_chalk12.default.cyan("\n opening browser for signup...\n"));
|
|
11807
|
-
await authenticateWithBrowser();
|
|
11770
|
+
console.log(import_chalk12.default.cyan("\n opening browser for signup (one sign-in)...\n"));
|
|
11771
|
+
await withSpinner("creating your account\u2026", () => authenticateWithBrowser());
|
|
11772
|
+
await briefPause();
|
|
11773
|
+
console.log(import_chalk12.default.green(" \u2713 account created"));
|
|
11774
|
+
} else {
|
|
11775
|
+
console.log(import_chalk12.default.dim("\n already signed in \u2014 syncing profile..."));
|
|
11808
11776
|
}
|
|
11809
11777
|
const content = fs13.readFileSync(
|
|
11810
11778
|
path13.join(os7.homedir(), ".hyv", "profiles", `${profileName}.md`),
|
|
11811
11779
|
"utf-8"
|
|
11812
11780
|
);
|
|
11813
11781
|
try {
|
|
11814
|
-
const response = await
|
|
11815
|
-
|
|
11816
|
-
|
|
11817
|
-
|
|
11782
|
+
const response = await withSpinner(
|
|
11783
|
+
"syncing profile\u2026",
|
|
11784
|
+
() => authenticatedRequest(cliApiUrl("/cli/profiles/new"), {
|
|
11785
|
+
method: "POST",
|
|
11786
|
+
body: { name: profileName, content, source: "welcome" }
|
|
11787
|
+
})
|
|
11788
|
+
);
|
|
11818
11789
|
if (response.status === 200) {
|
|
11819
11790
|
console.log(import_chalk12.default.green(" \u2713 profile synced to your account"));
|
|
11820
11791
|
} else {
|
|
@@ -11823,12 +11794,15 @@ async function stepSignup(profileName) {
|
|
|
11823
11794
|
} catch {
|
|
11824
11795
|
console.log(import_chalk12.default.yellow(" profile saved locally \u2014 run `hyv sync` after you upgrade"));
|
|
11825
11796
|
}
|
|
11826
|
-
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
11797
|
+
try {
|
|
11798
|
+
console.log(import_chalk12.default.cyan("\n opening billing in your dashboard ($1 first month)..."));
|
|
11799
|
+
await withSpinner("opening dashboard\u2026", () => openAuthenticatedDashboard({ tab: "billing" }));
|
|
11800
|
+
await briefPause();
|
|
11801
|
+
} catch {
|
|
11802
|
+
console.log(import_chalk12.default.yellow(" could not auto-open dashboard \u2014 visit holdyourvoice.com/dashboard"));
|
|
11803
|
+
}
|
|
11830
11804
|
markStepComplete("signup");
|
|
11831
|
-
console.log(import_chalk12.default.dim("\n
|
|
11805
|
+
console.log(import_chalk12.default.dim("\n you're signed in \u2014 pick a plan in billing, no second login.\n"));
|
|
11832
11806
|
}
|
|
11833
11807
|
async function runInteractiveWelcome() {
|
|
11834
11808
|
recordEvent("welcome_interactive");
|
|
@@ -16854,28 +16828,15 @@ async function showPlan() {
|
|
|
16854
16828
|
}
|
|
16855
16829
|
}
|
|
16856
16830
|
async function upgradePlan() {
|
|
16857
|
-
console.log(import_chalk14.default.cyan("\nOpening
|
|
16858
|
-
|
|
16859
|
-
|
|
16860
|
-
|
|
16861
|
-
|
|
16862
|
-
|
|
16863
|
-
|
|
16864
|
-
|
|
16865
|
-
|
|
16866
|
-
const data = response.data;
|
|
16867
|
-
const checkoutUrl = data.checkout_url;
|
|
16868
|
-
if (checkoutUrl) {
|
|
16869
|
-
console.log(import_chalk14.default.dim("Opening browser..."));
|
|
16870
|
-
await (0, import_open2.default)(assertSafeOpenUrl(checkoutUrl));
|
|
16871
|
-
console.log(import_chalk14.default.green("\n\u2713 Checkout opened in browser"));
|
|
16872
|
-
console.log(import_chalk14.default.dim("Complete the checkout to activate your plan."));
|
|
16873
|
-
} else {
|
|
16874
|
-
console.log(import_chalk14.default.yellow("No checkout URL received."));
|
|
16875
|
-
}
|
|
16876
|
-
} else {
|
|
16877
|
-
console.log(import_chalk14.default.yellow("Could not create checkout session."));
|
|
16878
|
-
console.log(import_chalk14.default.dim("Visit https://holdyourvoice.com/pricing to subscribe."));
|
|
16831
|
+
console.log(import_chalk14.default.cyan("\nOpening billing in your dashboard ($1 first month)...\n"));
|
|
16832
|
+
try {
|
|
16833
|
+
await openAuthenticatedDashboard({ tab: "billing" });
|
|
16834
|
+
console.log(import_chalk14.default.green("\n\u2713 Dashboard opened \u2014 you're already signed in"));
|
|
16835
|
+
console.log(import_chalk14.default.dim("Pick a plan in billing. No second login."));
|
|
16836
|
+
} catch {
|
|
16837
|
+
console.log(import_chalk14.default.yellow("Could not open dashboard automatically."));
|
|
16838
|
+
console.log(import_chalk14.default.dim(`Visit ${DASHBOARD_BILLING_URL} after running hyv init`));
|
|
16839
|
+
console.log(import_chalk14.default.dim(`Or see plans: ${PRICING_URL}`));
|
|
16879
16840
|
}
|
|
16880
16841
|
}
|
|
16881
16842
|
async function openBillingPortal() {
|
|
@@ -16889,7 +16850,7 @@ async function openBillingPortal() {
|
|
|
16889
16850
|
const portalUrl = data.portal_url;
|
|
16890
16851
|
if (portalUrl) {
|
|
16891
16852
|
console.log(import_chalk14.default.dim("Opening browser..."));
|
|
16892
|
-
await (0, import_open2.default)(
|
|
16853
|
+
await (0, import_open2.default)(assertSafeOpenUrl2(portalUrl));
|
|
16893
16854
|
console.log(import_chalk14.default.green("\n\u2713 Billing portal opened"));
|
|
16894
16855
|
} else {
|
|
16895
16856
|
console.log(import_chalk14.default.yellow("No portal URL received."));
|
package/package.json
CHANGED