@holdyourvoice/hyv 2.9.5 → 2.9.6

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.
Files changed (2) hide show
  1. package/dist/index.js +119 -184
  2. package/package.json +1 -1
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: () => assertSafeOpenUrl2,
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 assertSafeOpenUrl2(url) {
4635
+ function assertSafeOpenUrl(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() };
@@ -5245,6 +5191,91 @@ var require_open = __commonJS({
5245
5191
  }
5246
5192
  });
5247
5193
 
5194
+ // src/lib/free-paid.ts
5195
+ function printFreePaidMatrix(opts = {}) {
5196
+ if (opts.compact) {
5197
+ console.log(import_chalk.default.bold("\nFree forever (local)"));
5198
+ console.log(import_chalk.default.dim(" scan, fix, check, score, diff, mcp, all web tools"));
5199
+ console.log(import_chalk.default.bold("\nPaid power"));
5200
+ console.log(import_chalk.default.dim(" profiles, learning, hybrid analysis, rich rewrites"));
5201
+ console.log(import_chalk.default.dim(` ${PRICING_URL} | hyv plan --upgrade
5202
+ `));
5203
+ return;
5204
+ }
5205
+ console.log(import_chalk.default.bold("\n\u2500\u2500 Free forever (no account) \u2500\u2500\n"));
5206
+ console.log(import_chalk.default.dim("CLI (offline):"));
5207
+ for (const line of FREE_CLI_COMMANDS) {
5208
+ console.log(import_chalk.default.dim(" \u2022 ") + line);
5209
+ }
5210
+ console.log(import_chalk.default.dim("\nTry without installing:"));
5211
+ for (const line of NPX_EXAMPLES) {
5212
+ console.log(import_chalk.default.cyan(` ${line}`));
5213
+ }
5214
+ console.log(import_chalk.default.dim("\nWeb tools (30+ free):"));
5215
+ for (const t of FREE_WEB_TOOLS.slice(0, 8)) {
5216
+ console.log(import_chalk.default.dim(` \u2022 ${t.name}`) + import_chalk.default.cyan(` \u2014 ${t.url}`));
5217
+ }
5218
+ console.log(import_chalk.default.dim(` \u2022 \u2026and more \u2014 ${FREE_WEB_TOOLS[0].url}`));
5219
+ console.log(import_chalk.default.bold("\n\u2500\u2500 Paid unlocks \u2500\u2500\n"));
5220
+ for (const line of PAID_FEATURES) {
5221
+ console.log(import_chalk.default.dim(" \u2022 ") + line);
5222
+ }
5223
+ console.log(import_chalk.default.dim(`
5224
+ First month $1 \u2192 ${PRICING_URL}`));
5225
+ console.log(import_chalk.default.dim(" hyv init | hyv plan --upgrade\n"));
5226
+ }
5227
+ var import_chalk, NPX_EXAMPLES, FREE_CLI_COMMANDS, PAID_FEATURES, FREE_WEB_TOOLS, COMMUNITY_URL, PRICING_URL, DASHBOARD_BILLING_URL;
5228
+ var init_free_paid = __esm({
5229
+ "src/lib/free-paid.ts"() {
5230
+ "use strict";
5231
+ import_chalk = __toESM(require_source());
5232
+ NPX_EXAMPLES = [
5233
+ "npx @holdyourvoice/hyv welcome",
5234
+ "npx @holdyourvoice/hyv scan draft.md",
5235
+ "npx @holdyourvoice/hyv fix draft.md",
5236
+ "npx @holdyourvoice/hyv init",
5237
+ "npx @holdyourvoice/hyv mcp"
5238
+ ];
5239
+ FREE_CLI_COMMANDS = [
5240
+ "hyv scan / fix / check / score / diff / batch / watch",
5241
+ "hyv rules / history / demo / doctor / upgrade",
5242
+ "hyv export (local profile markdown)",
5243
+ "hyv mcp \u2014 agent tools (hyv_scan, hyv_clean, hyv_analyze, \u2026)",
5244
+ "hyv welcome / hyv free \u2014 full capability tour",
5245
+ "hyv content \u2014 blog & share templates",
5246
+ "hyv plan --free \u2014 see what paid unlocks"
5247
+ ];
5248
+ PAID_FEATURES = [
5249
+ "Voice profiles synced from your account (never-list, anchors, learned patterns)",
5250
+ "Learning loop: hyv reinforce, hyv add \u2014 profile gets sharper every week",
5251
+ "Rich profile-aware rewrite prompts (hyv rewrite)",
5252
+ "Hybrid server analysis (hyv scan --server, MCP hyv_analyze)",
5253
+ "Multiple profiles + team voices (Team plan)",
5254
+ "Dashboard at holdyourvoice.com/app"
5255
+ ];
5256
+ FREE_WEB_TOOLS = [
5257
+ { name: "All free tools", url: "https://holdyourvoice.com/tools" },
5258
+ { name: "Headline Analyzer", url: "https://holdyourvoice.com/tools/headline-analyzer" },
5259
+ { name: "Brand Voice Analyzer", url: "https://holdyourvoice.com/tools/brand-voice-analyzer" },
5260
+ { name: "AI Writing Analyzer", url: "https://holdyourvoice.com/tools/ai-writing-analyzer" },
5261
+ { name: "Voice Audit (AI score)", url: "https://holdyourvoice.com/tools/voice-audit" },
5262
+ { name: "Readability Checker", url: "https://holdyourvoice.com/tools/readability-checker" },
5263
+ { name: "Email Subject Scorer", url: "https://holdyourvoice.com/tools/email-subject-scorer" },
5264
+ { name: "Customer Persona Builder", url: "https://holdyourvoice.com/tools/customer-persona-builder" },
5265
+ { name: "Brand Positioning Template", url: "https://holdyourvoice.com/tools/brand-positioning-template" },
5266
+ { name: "Value Proposition Generator", url: "https://holdyourvoice.com/tools/value-proposition-generator" },
5267
+ { name: "Grammar Checker", url: "https://holdyourvoice.com/tools/grammar-checker" },
5268
+ { name: "Paraphrasing Tool", url: "https://holdyourvoice.com/tools/paraphrasing-tool" },
5269
+ { name: "Tagline Generator", url: "https://holdyourvoice.com/tools/tagline-generator" },
5270
+ { name: "Public voice profiles", url: "https://holdyourvoice.com/profiles" },
5271
+ { name: "Blog", url: "https://holdyourvoice.com/blog" }
5272
+ ];
5273
+ COMMUNITY_URL = "https://holdyourvoice.com/community";
5274
+ PRICING_URL = "https://holdyourvoice.com/#pricing";
5275
+ DASHBOARD_BILLING_URL = "https://holdyourvoice.com/app/billing";
5276
+ }
5277
+ });
5278
+
5248
5279
  // src/lib/version.ts
5249
5280
  function pkgRoot() {
5250
5281
  const candidates = [
@@ -5468,7 +5499,7 @@ async function authenticateWithBrowser() {
5468
5499
  server.close();
5469
5500
  throw new Error("Authentication server did not return OAuth state");
5470
5501
  }
5471
- console.log(import_chalk.default.cyan("\nOpening browser for authentication..."));
5502
+ console.log(import_chalk2.default.cyan("\nOpening browser for authentication..."));
5472
5503
  await (0, import_open.default)(assertSafeOAuthUrl(auth_url));
5473
5504
  const authData = await new Promise((resolve15, reject) => {
5474
5505
  const timeout = setTimeout(() => {
@@ -5545,20 +5576,23 @@ async function authenticateWithBrowser() {
5545
5576
  return authData;
5546
5577
  }
5547
5578
  async function openAuthenticatedDashboard(opts = {}) {
5548
- const response = await authenticatedRequest(cliApiUrl("/cli/auth/web-handoff"), {
5549
- method: "POST",
5550
- body: {
5551
- next: opts.next || "/app/billing"
5579
+ const nextPath = opts.next || "/app/billing";
5580
+ try {
5581
+ const response = await authenticatedRequest(cliApiUrl("/cli/auth/web-handoff"), {
5582
+ method: "POST",
5583
+ body: { next: nextPath }
5584
+ });
5585
+ if (response.status === 200) {
5586
+ const { url } = response.data;
5587
+ if (url) {
5588
+ await (0, import_open.default)(assertSafeOpenUrl(url));
5589
+ return;
5590
+ }
5552
5591
  }
5553
- });
5554
- if (response.status !== 200) {
5555
- throw new Error("Could not open dashboard \u2014 try https://holdyourvoice.com/dashboard");
5556
- }
5557
- const { url } = response.data;
5558
- if (!url) {
5559
- throw new Error("Dashboard handoff URL missing");
5592
+ } catch {
5560
5593
  }
5561
- await (0, import_open.default)(assertSafeOpenUrl(url));
5594
+ const billingUrl = nextPath === "/app/billing" ? DASHBOARD_BILLING_URL : assertSafeOpenUrl(`https://holdyourvoice.com${nextPath}`);
5595
+ await (0, import_open.default)(billingUrl);
5562
5596
  }
5563
5597
  async function refreshToken(tokenOverride) {
5564
5598
  const token = tokenOverride || readAuth()?.token;
@@ -5604,116 +5638,21 @@ async function checkSession() {
5604
5638
  return { valid: false };
5605
5639
  }
5606
5640
  }
5607
- var http, https, import_chalk, import_open;
5641
+ var http, https, import_chalk2, import_open;
5608
5642
  var init_auth = __esm({
5609
5643
  "src/lib/auth.ts"() {
5610
5644
  "use strict";
5611
5645
  http = __toESM(require("http"));
5612
5646
  https = __toESM(require("https"));
5613
- import_chalk = __toESM(require_source());
5647
+ import_chalk2 = __toESM(require_source());
5614
5648
  import_open = __toESM(require_open());
5615
5649
  init_config();
5650
+ init_free_paid();
5616
5651
  init_version();
5617
5652
  init_auth_refresh();
5618
5653
  }
5619
5654
  });
5620
5655
 
5621
- // src/lib/free-paid.ts
5622
- var free_paid_exports = {};
5623
- __export(free_paid_exports, {
5624
- COMMUNITY_URL: () => COMMUNITY_URL,
5625
- DASHBOARD_BILLING_URL: () => DASHBOARD_BILLING_URL,
5626
- FREE_CLI_COMMANDS: () => FREE_CLI_COMMANDS,
5627
- FREE_WEB_TOOLS: () => FREE_WEB_TOOLS,
5628
- NPX_EXAMPLES: () => NPX_EXAMPLES,
5629
- PAID_FEATURES: () => PAID_FEATURES,
5630
- PRICING_URL: () => PRICING_URL,
5631
- printFreePaidMatrix: () => printFreePaidMatrix
5632
- });
5633
- function printFreePaidMatrix(opts = {}) {
5634
- if (opts.compact) {
5635
- console.log(import_chalk2.default.bold("\nFree forever (local)"));
5636
- console.log(import_chalk2.default.dim(" scan, fix, check, score, diff, mcp, all web tools"));
5637
- console.log(import_chalk2.default.bold("\nPaid power"));
5638
- console.log(import_chalk2.default.dim(" profiles, learning, hybrid analysis, rich rewrites"));
5639
- console.log(import_chalk2.default.dim(` ${PRICING_URL} | hyv plan --upgrade
5640
- `));
5641
- return;
5642
- }
5643
- console.log(import_chalk2.default.bold("\n\u2500\u2500 Free forever (no account) \u2500\u2500\n"));
5644
- console.log(import_chalk2.default.dim("CLI (offline):"));
5645
- for (const line of FREE_CLI_COMMANDS) {
5646
- console.log(import_chalk2.default.dim(" \u2022 ") + line);
5647
- }
5648
- console.log(import_chalk2.default.dim("\nTry without installing:"));
5649
- for (const line of NPX_EXAMPLES) {
5650
- console.log(import_chalk2.default.cyan(` ${line}`));
5651
- }
5652
- console.log(import_chalk2.default.dim("\nWeb tools (30+ free):"));
5653
- for (const t of FREE_WEB_TOOLS.slice(0, 8)) {
5654
- console.log(import_chalk2.default.dim(` \u2022 ${t.name}`) + import_chalk2.default.cyan(` \u2014 ${t.url}`));
5655
- }
5656
- console.log(import_chalk2.default.dim(` \u2022 \u2026and more \u2014 ${FREE_WEB_TOOLS[0].url}`));
5657
- console.log(import_chalk2.default.bold("\n\u2500\u2500 Paid unlocks \u2500\u2500\n"));
5658
- for (const line of PAID_FEATURES) {
5659
- console.log(import_chalk2.default.dim(" \u2022 ") + line);
5660
- }
5661
- console.log(import_chalk2.default.dim(`
5662
- First month $1 \u2192 ${PRICING_URL}`));
5663
- console.log(import_chalk2.default.dim(" hyv init | hyv plan --upgrade\n"));
5664
- }
5665
- var import_chalk2, NPX_EXAMPLES, FREE_CLI_COMMANDS, PAID_FEATURES, FREE_WEB_TOOLS, COMMUNITY_URL, PRICING_URL, DASHBOARD_BILLING_URL;
5666
- var init_free_paid = __esm({
5667
- "src/lib/free-paid.ts"() {
5668
- "use strict";
5669
- import_chalk2 = __toESM(require_source());
5670
- NPX_EXAMPLES = [
5671
- "npx @holdyourvoice/hyv welcome",
5672
- "npx @holdyourvoice/hyv scan draft.md",
5673
- "npx @holdyourvoice/hyv fix draft.md",
5674
- "npx @holdyourvoice/hyv init",
5675
- "npx @holdyourvoice/hyv mcp"
5676
- ];
5677
- FREE_CLI_COMMANDS = [
5678
- "hyv scan / fix / check / score / diff / batch / watch",
5679
- "hyv rules / history / demo / doctor / upgrade",
5680
- "hyv export (local profile markdown)",
5681
- "hyv mcp \u2014 agent tools (hyv_scan, hyv_clean, hyv_analyze, \u2026)",
5682
- "hyv welcome / hyv free \u2014 full capability tour",
5683
- "hyv content \u2014 blog & share templates",
5684
- "hyv plan --free \u2014 see what paid unlocks"
5685
- ];
5686
- PAID_FEATURES = [
5687
- "Voice profiles synced from your account (never-list, anchors, learned patterns)",
5688
- "Learning loop: hyv reinforce, hyv add \u2014 profile gets sharper every week",
5689
- "Rich profile-aware rewrite prompts (hyv rewrite)",
5690
- "Hybrid server analysis (hyv scan --server, MCP hyv_analyze)",
5691
- "Multiple profiles + team voices (Team plan)",
5692
- "Dashboard at holdyourvoice.com/dashboard"
5693
- ];
5694
- FREE_WEB_TOOLS = [
5695
- { name: "All free tools", url: "https://holdyourvoice.com/tools" },
5696
- { name: "Headline Analyzer", url: "https://holdyourvoice.com/tools/headline-analyzer" },
5697
- { name: "Brand Voice Analyzer", url: "https://holdyourvoice.com/tools/brand-voice-analyzer" },
5698
- { name: "AI Writing Analyzer", url: "https://holdyourvoice.com/tools/ai-writing-analyzer" },
5699
- { name: "Voice Audit (AI score)", url: "https://holdyourvoice.com/tools/voice-audit" },
5700
- { name: "Readability Checker", url: "https://holdyourvoice.com/tools/readability-checker" },
5701
- { name: "Email Subject Scorer", url: "https://holdyourvoice.com/tools/email-subject-scorer" },
5702
- { name: "Customer Persona Builder", url: "https://holdyourvoice.com/tools/customer-persona-builder" },
5703
- { name: "Brand Positioning Template", url: "https://holdyourvoice.com/tools/brand-positioning-template" },
5704
- { name: "Value Proposition Generator", url: "https://holdyourvoice.com/tools/value-proposition-generator" },
5705
- { name: "Grammar Checker", url: "https://holdyourvoice.com/tools/grammar-checker" },
5706
- { name: "Paraphrasing Tool", url: "https://holdyourvoice.com/tools/paraphrasing-tool" },
5707
- { name: "Tagline Generator", url: "https://holdyourvoice.com/tools/tagline-generator" },
5708
- { name: "Public voice profiles", url: "https://holdyourvoice.com/profiles" },
5709
- { name: "Blog", url: "https://holdyourvoice.com/blog" }
5710
- ];
5711
- COMMUNITY_URL = "https://holdyourvoice.com/community";
5712
- PRICING_URL = "https://holdyourvoice.com/#pricing";
5713
- DASHBOARD_BILLING_URL = "https://holdyourvoice.com/app/billing";
5714
- }
5715
- });
5716
-
5717
5656
  // src/lib/marketing-hints.ts
5718
5657
  var marketing_hints_exports = {};
5719
5658
  __export(marketing_hints_exports, {
@@ -11853,22 +11792,17 @@ async function stepSignup(profileName) {
11853
11792
  if (response.status === 200) {
11854
11793
  console.log(import_chalk12.default.green(" \u2713 profile synced to your account"));
11855
11794
  } else {
11856
- console.log(import_chalk12.default.yellow(" profile saved locally \u2014 sync again with `hyv sync` after upgrade"));
11795
+ const detail = response.data?.error;
11796
+ console.log(import_chalk12.default.yellow(
11797
+ ` profile saved locally \u2014 sync with \`hyv sync\`${detail ? ` (${detail})` : ` (HTTP ${response.status})`}`
11798
+ ));
11857
11799
  }
11858
- } catch {
11859
- console.log(import_chalk12.default.yellow(" profile saved locally \u2014 run `hyv sync` after you upgrade"));
11860
- }
11861
- try {
11862
- console.log(import_chalk12.default.cyan("\n opening billing in your dashboard ($1 first month)..."));
11863
- await withSpinner("opening dashboard\u2026", () => openAuthenticatedDashboard({ next: "/app/billing" }));
11864
- await briefPause();
11865
- } catch {
11866
- const { DASHBOARD_BILLING_URL: DASHBOARD_BILLING_URL2 } = await Promise.resolve().then(() => (init_free_paid(), free_paid_exports));
11867
- const { assertSafeOpenUrl: assertSafeOpenUrl3 } = await Promise.resolve().then(() => (init_config(), config_exports));
11868
- const { default: open3 } = await Promise.resolve().then(() => __toESM(require_open()));
11869
- console.log(import_chalk12.default.yellow(" handoff unavailable \u2014 opening billing (sign in if prompted)..."));
11870
- await open3(assertSafeOpenUrl3(DASHBOARD_BILLING_URL2));
11800
+ } catch (err) {
11801
+ console.log(import_chalk12.default.yellow(` profile saved locally \u2014 run \`hyv sync\` (${err?.message || "sync failed"})`));
11871
11802
  }
11803
+ console.log(import_chalk12.default.cyan("\n opening billing in your dashboard ($1 first month)..."));
11804
+ await withSpinner("opening billing\u2026", () => openAuthenticatedDashboard({ next: "/app/billing" }));
11805
+ await briefPause();
11872
11806
  markStepComplete("signup");
11873
11807
  console.log(import_chalk12.default.dim("\n you're signed in \u2014 pick a plan in billing, no second login.\n"));
11874
11808
  }
@@ -16918,7 +16852,7 @@ async function openBillingPortal() {
16918
16852
  const portalUrl = data.portal_url;
16919
16853
  if (portalUrl) {
16920
16854
  console.log(import_chalk14.default.dim("Opening browser..."));
16921
- await (0, import_open2.default)(assertSafeOpenUrl2(portalUrl));
16855
+ await (0, import_open2.default)(assertSafeOpenUrl(portalUrl));
16922
16856
  console.log(import_chalk14.default.green("\n\u2713 Billing portal opened"));
16923
16857
  } else {
16924
16858
  console.log(import_chalk14.default.yellow("No portal URL received."));
@@ -18480,10 +18414,11 @@ function registerDemoCommand(program3) {
18480
18414
  // src/commands/open.ts
18481
18415
  var import_chalk29 = __toESM(require_source());
18482
18416
  var PAGES = {
18483
- dashboard: "https://holdyourvoice.com/dashboard",
18484
- profiles: "https://holdyourvoice.com/dashboard",
18417
+ dashboard: "https://holdyourvoice.com/app",
18418
+ profiles: "https://holdyourvoice.com/app",
18485
18419
  pricing: "https://holdyourvoice.com/app/billing",
18486
- settings: "https://holdyourvoice.com/dashboard"
18420
+ settings: "https://holdyourvoice.com/app/settings",
18421
+ billing: "https://holdyourvoice.com/app/billing"
18487
18422
  };
18488
18423
  function registerOpenCommand(program3) {
18489
18424
  program3.command("open").description("Open the web dashboard in your browser").option("--page <path>", "Page: dashboard, profiles, pricing, settings", "dashboard").option("--profile <name>", "Deep-link to a specific profile").option("--no-browser", "Print URL only, don't open").action(async (options) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holdyourvoice/hyv",
3
- "version": "2.9.5",
3
+ "version": "2.9.6",
4
4
  "description": "Free local AI writing scan for cursor & claude. MCP server, 220+ pattern detection, voice profiles. npx @holdyourvoice/hyv welcome",
5
5
  "main": "dist/index.js",
6
6
  "bin": {