@holdyourvoice/hyv 2.9.11 → 2.9.13

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/index.js CHANGED
@@ -5385,7 +5385,7 @@ var init_free_paid = __esm({
5385
5385
  "Rich profile-aware rewrite prompts (hyv rewrite)",
5386
5386
  "Hybrid server analysis (hyv scan --server, MCP hyv_analyze)",
5387
5387
  "Multiple profiles + team voices (Team plan)",
5388
- "Dashboard at holdyourvoice.com/app"
5388
+ "Dashboard at holdyourvoice.com/dashboard"
5389
5389
  ];
5390
5390
  FREE_WEB_TOOLS = [
5391
5391
  { name: "All free tools", url: "https://holdyourvoice.com/tools" },
@@ -5406,7 +5406,7 @@ var init_free_paid = __esm({
5406
5406
  ];
5407
5407
  COMMUNITY_URL = "https://holdyourvoice.com/community";
5408
5408
  PRICING_URL = "https://holdyourvoice.com/#pricing";
5409
- DASHBOARD_BILLING_URL = "https://holdyourvoice.com/app/billing";
5409
+ DASHBOARD_BILLING_URL = "https://holdyourvoice.com/dashboard?tab=billing";
5410
5410
  }
5411
5411
  });
5412
5412
 
@@ -5710,7 +5710,7 @@ async function authenticateWithBrowser() {
5710
5710
  return authData;
5711
5711
  }
5712
5712
  async function openAuthenticatedDashboard(opts = {}) {
5713
- const nextPath = opts.next || "/app/billing";
5713
+ const nextPath = opts.next || "/dashboard?tab=billing";
5714
5714
  try {
5715
5715
  const response = await authenticatedRequest(cliApiUrl("/cli/auth/web-handoff"), {
5716
5716
  method: "POST",
@@ -5725,7 +5725,7 @@ async function openAuthenticatedDashboard(opts = {}) {
5725
5725
  }
5726
5726
  } catch {
5727
5727
  }
5728
- const billingUrl = nextPath === "/app/billing" ? DASHBOARD_BILLING_URL : assertSafeOpenUrl(`https://holdyourvoice.com${nextPath}`);
5728
+ const billingUrl = nextPath === "/dashboard?tab=billing" || nextPath === "/app/billing" ? DASHBOARD_BILLING_URL : assertSafeOpenUrl(`https://holdyourvoice.com${nextPath}`);
5729
5729
  await (0, import_open.default)(billingUrl);
5730
5730
  }
5731
5731
  async function refreshToken(tokenOverride) {
@@ -5883,7 +5883,7 @@ async function request2(method, path27, body) {
5883
5883
  if (res.status === 401)
5884
5884
  throw new Error("your session expired. run: hyv init to sign in again.");
5885
5885
  if (res.status === 403)
5886
- throw new Error("you don't have access to this feature. check your plan at holdyourvoice.com/app/billing");
5886
+ throw new Error("you don't have access to this feature. check your plan at holdyourvoice.com/dashboard?tab=billing");
5887
5887
  if (!res.ok) {
5888
5888
  throw new Error(`something went wrong (${res.status}). try again or contact support.`);
5889
5889
  }
@@ -5943,7 +5943,7 @@ async function getAccessState() {
5943
5943
  try {
5944
5944
  const session = await checkSession();
5945
5945
  const plan = (session.plan || "none").toLowerCase();
5946
- const hasPaidPlan = session.valid && plan !== "none" && plan !== "free";
5946
+ const hasPaidPlan = session.valid && plan !== "none" && plan !== "free" && plan !== "expired" && plan !== "unknown";
5947
5947
  const state = {
5948
5948
  authenticated: session.valid,
5949
5949
  hasPaidPlan,
@@ -5979,7 +5979,8 @@ async function requirePaidFeature(feature) {
5979
5979
  throw new Error("can't reach the server. check your internet connection and try again.");
5980
5980
  }
5981
5981
  const plan = (data.plan || "none").toLowerCase();
5982
- if (!data.plan || plan === "none" || data.status === "none") {
5982
+ const subStatus = String(data.subscription_status || data.status || "").toLowerCase();
5983
+ if (!data.plan || plan === "none" || plan === "free" || plan === "expired" || subStatus === "trialing" || subStatus === "none") {
5983
5984
  throw new Error(FEATURE_MESSAGES[feature]);
5984
5985
  }
5985
5986
  }
@@ -5994,7 +5995,7 @@ async function maybeShowLimitedModeHint(hasProfile) {
5994
5995
  } else if (!access.authenticated) {
5995
5996
  console.log(import_chalk5.default.dim("\n local mode \u2014 free scan engine. profiles + learning: hyv init"));
5996
5997
  } else {
5997
- console.log(import_chalk5.default.dim("\n local mode \u2014 upgrade for full profiles + learning: hyv plan --upgrade"));
5998
+ console.log(import_chalk5.default.dim("\n local mode \u2014 upgrade for full profiles + learning: hyv upgrade"));
5998
5999
  }
5999
6000
  }
6000
6001
  function formatModeLabel(access, hasFullProfile) {
@@ -6017,10 +6018,10 @@ var init_access = __esm({
6017
6018
  init_auth();
6018
6019
  init_api();
6019
6020
  FEATURE_MESSAGES = {
6020
- profiles: "syncing voice profiles from your account requires a paid plan. run: hyv plan --upgrade",
6021
- learning: "the learning loop (reinforce, add) requires a paid plan. run: hyv plan --upgrade",
6022
- premiumPrompts: "rich profile-aware rewrite prompts require a paid plan. run: hyv plan --upgrade",
6023
- serverAnalysis: "server-assisted analysis requires a paid plan. run: hyv plan --upgrade"
6021
+ profiles: "syncing voice profiles from your account requires a paid plan. run: hyv upgrade",
6022
+ learning: "the learning loop (reinforce, add) requires a paid plan. run: hyv upgrade",
6023
+ premiumPrompts: "rich profile-aware rewrite prompts require a paid plan. run: hyv upgrade",
6024
+ serverAnalysis: "server-assisted analysis requires a paid plan. run: hyv upgrade"
6024
6025
  };
6025
6026
  localOnlyOverride = false;
6026
6027
  cachedAccess = null;
@@ -11956,7 +11957,7 @@ async function stepSignup(profileName) {
11956
11957
  ));
11957
11958
  }
11958
11959
  console.log(import_chalk12.default.cyan("\n opening billing in your dashboard ($1 first month)..."));
11959
- await withSpinner("opening billing\u2026", () => openAuthenticatedDashboard({ next: "/app/billing" }));
11960
+ await withSpinner("opening billing\u2026", () => openAuthenticatedDashboard({ next: "/dashboard?tab=billing" }));
11960
11961
  await briefPause();
11961
11962
  markStepComplete("signup");
11962
11963
  console.log(import_chalk12.default.dim("\n you're signed in \u2014 pick a plan in billing, no second login.\n"));
@@ -12136,6 +12137,54 @@ In conclusion, the key to success is to empower your team with actionable insigh
12136
12137
  }
12137
12138
  });
12138
12139
 
12140
+ // src/lib/billing-upgrade.ts
12141
+ var billing_upgrade_exports = {};
12142
+ __export(billing_upgrade_exports, {
12143
+ openBillingUpgrade: () => openBillingUpgrade
12144
+ });
12145
+ async function openBillingUpgrade(opts = {}) {
12146
+ const plan = opts.plan || "individual";
12147
+ const next = `/dashboard?tab=billing&checkout=${plan}`;
12148
+ const token = getToken();
12149
+ if (!token) {
12150
+ console.log(import_chalk14.default.cyan("\nSign in to upgrade \u2014 opening browser...\n"));
12151
+ try {
12152
+ await authenticateWithBrowser();
12153
+ } catch {
12154
+ console.log(import_chalk14.default.yellow("Sign-in cancelled or failed."));
12155
+ console.log(import_chalk14.default.dim(`Visit ${DASHBOARD_BILLING_URL} after running hyv init`));
12156
+ return;
12157
+ }
12158
+ }
12159
+ const access = await getAccessState();
12160
+ if (access.hasPaidPlan) {
12161
+ console.log(import_chalk14.default.green(`
12162
+ \u2713 You already have a paid plan (${access.plan}).`));
12163
+ console.log(import_chalk14.default.dim("Manage billing: hyv plan --manage\n"));
12164
+ return;
12165
+ }
12166
+ console.log(import_chalk14.default.cyan("\nOpening billing in your dashboard ($1 first month)...\n"));
12167
+ try {
12168
+ await openAuthenticatedDashboard({ next });
12169
+ console.log(import_chalk14.default.green("\n\u2713 Dashboard opened \u2014 pick a plan in billing"));
12170
+ console.log(import_chalk14.default.dim("Checkout opens automatically when you arrive from the CLI."));
12171
+ } catch {
12172
+ console.log(import_chalk14.default.yellow("Could not open dashboard automatically."));
12173
+ console.log(import_chalk14.default.dim(`Visit https://holdyourvoice.com${next} after hyv init`));
12174
+ }
12175
+ }
12176
+ var import_chalk14;
12177
+ var init_billing_upgrade = __esm({
12178
+ "src/lib/billing-upgrade.ts"() {
12179
+ "use strict";
12180
+ import_chalk14 = __toESM(require_source());
12181
+ init_access();
12182
+ init_config();
12183
+ init_auth();
12184
+ init_free_paid();
12185
+ }
12186
+ });
12187
+
12139
12188
  // node_modules/glob/dist/commonjs/index.min.js
12140
12189
  var require_index_min = __commonJS({
12141
12190
  "node_modules/glob/dist/commonjs/index.min.js"(exports2) {
@@ -15624,7 +15673,7 @@ function registerInitCommand(program3) {
15624
15673
  } else if (options?.browser === false) {
15625
15674
  console.log(import_chalk4.default.red("License key required when --no-browser is set."));
15626
15675
  console.log("\nUsage: hyv init <license-key>");
15627
- console.log("\nGenerate a license key at: https://holdyourvoice.com/app");
15676
+ console.log("\nGenerate a license key at: https://holdyourvoice.com/dashboard");
15628
15677
  process.exit(1);
15629
15678
  } else {
15630
15679
  authData = await authenticateWithBrowser();
@@ -15817,7 +15866,7 @@ function registerStatusCommand(program3) {
15817
15866
  if (latest && current !== "unknown" && compareSemver(current, latest) < 0) {
15818
15867
  console.log(import_chalk7.default.bold("\nUpdate"));
15819
15868
  console.log(import_chalk7.default.cyan(` ${current} \u2192 ${latest} available`));
15820
- console.log(import_chalk7.default.dim(" Run: hyv upgrade"));
15869
+ console.log(import_chalk7.default.dim(" Run: npm i -g @holdyourvoice/hyv@latest"));
15821
15870
  }
15822
15871
  console.log("");
15823
15872
  });
@@ -16913,7 +16962,7 @@ function generateLocalProfileFromStats(name, stats) {
16913
16962
  }
16914
16963
 
16915
16964
  // src/commands/plan.ts
16916
- var import_chalk14 = __toESM(require_source());
16965
+ var import_chalk15 = __toESM(require_source());
16917
16966
  init_config();
16918
16967
  init_auth();
16919
16968
  var import_open2 = __toESM(require_open());
@@ -16928,10 +16977,10 @@ function registerPlanCommand(program3) {
16928
16977
  }
16929
16978
  const token = getToken();
16930
16979
  if (!token) {
16931
- console.log(import_chalk14.default.yellow("\nNot authenticated \u2014 free tier still works.\n"));
16932
- console.log(import_chalk14.default.dim(" hyv scan draft.md | hyv welcome | npx @holdyourvoice/hyv scan draft.md"));
16980
+ console.log(import_chalk15.default.yellow("\nNot authenticated \u2014 free tier still works.\n"));
16981
+ console.log(import_chalk15.default.dim(" hyv scan draft.md | hyv welcome | npx @holdyourvoice/hyv scan draft.md"));
16933
16982
  printFreePaidMatrix({ compact: true });
16934
- console.log(import_chalk14.default.dim(" Run `hyv init` for profiles + learning.\n"));
16983
+ console.log(import_chalk15.default.dim(" Run `hyv init` for profiles + learning.\n"));
16935
16984
  return;
16936
16985
  }
16937
16986
  if (options.upgrade) {
@@ -16944,20 +16993,20 @@ function registerPlanCommand(program3) {
16944
16993
  await showPlan();
16945
16994
  }
16946
16995
  } catch (error) {
16947
- console.error(import_chalk14.default.red(`
16996
+ console.error(import_chalk15.default.red(`
16948
16997
  Error: ${error.message}`));
16949
16998
  process.exit(1);
16950
16999
  }
16951
17000
  });
16952
17001
  }
16953
17002
  async function showPlan() {
16954
- console.log(import_chalk14.default.bold("\nSubscription Plan\n"));
17003
+ console.log(import_chalk15.default.bold("\nSubscription Plan\n"));
16955
17004
  const response = await authenticatedRequest(
16956
17005
  cliApiUrl("/cli/heartbeat"),
16957
17006
  { method: "GET" }
16958
17007
  );
16959
17008
  if (response.status !== 200) {
16960
- console.log(import_chalk14.default.yellow("Could not fetch plan info."));
17009
+ console.log(import_chalk15.default.yellow("Could not fetch plan info."));
16961
17010
  return;
16962
17011
  }
16963
17012
  const data = response.data;
@@ -16975,39 +17024,31 @@ async function showPlan() {
16975
17024
  team: "$29/mo",
16976
17025
  agency: "Custom"
16977
17026
  };
16978
- console.log(import_chalk14.default.dim("Plan:"), import_chalk14.default.bold(planNames[plan] || plan));
16979
- console.log(import_chalk14.default.dim("Price:"), planPrices[plan] || "-");
16980
- console.log(import_chalk14.default.dim("Status:"), data.subscription_status || "none");
17027
+ console.log(import_chalk15.default.dim("Plan:"), import_chalk15.default.bold(planNames[plan] || plan));
17028
+ console.log(import_chalk15.default.dim("Price:"), planPrices[plan] || "-");
17029
+ console.log(import_chalk15.default.dim("Status:"), data.subscription_status || "none");
16981
17030
  if (license) {
16982
- console.log(import_chalk14.default.dim("License:"), license.key_hint);
17031
+ console.log(import_chalk15.default.dim("License:"), license.key_hint);
16983
17032
  }
16984
17033
  const access = await getAccessState();
16985
- console.log(import_chalk14.default.bold("\nFree tier (always)"));
16986
- console.log(import_chalk14.default.dim(" local scan, fix, check, mcp, all web tools \u2014 hyv welcome"));
17034
+ console.log(import_chalk15.default.bold("\nFree tier (always)"));
17035
+ console.log(import_chalk15.default.dim(" local scan, fix, check, mcp, all web tools \u2014 hyv welcome"));
16987
17036
  if (plan === "none" || !access.hasPaidPlan) {
16988
- console.log(import_chalk14.default.bold("\nUpgrade unlocks"));
16989
- console.log(import_chalk14.default.dim(" profiles, learning loop, hybrid analysis, rich rewrites"));
16990
- console.log(import_chalk14.default.dim(` ${PRICING_URL}`));
16991
- console.log(import_chalk14.default.dim("\n hyv plan --upgrade | hyv plan --free for full matrix"));
17037
+ console.log(import_chalk15.default.bold("\nUpgrade unlocks"));
17038
+ console.log(import_chalk15.default.dim(" profiles, learning loop, hybrid analysis, rich rewrites"));
17039
+ console.log(import_chalk15.default.dim(` ${PRICING_URL}`));
17040
+ console.log(import_chalk15.default.dim("\n hyv plan --upgrade | hyv plan --free for full matrix"));
16992
17041
  } else {
16993
17042
  console.log("\nManage your subscription:");
16994
- console.log(import_chalk14.default.dim(" hyv plan --manage"));
17043
+ console.log(import_chalk15.default.dim(" hyv plan --manage"));
16995
17044
  }
16996
17045
  }
16997
17046
  async function upgradePlan() {
16998
- console.log(import_chalk14.default.cyan("\nOpening billing in your dashboard ($1 first month)...\n"));
16999
- try {
17000
- await openAuthenticatedDashboard({ next: "/app/billing" });
17001
- console.log(import_chalk14.default.green("\n\u2713 Dashboard opened \u2014 you're already signed in"));
17002
- console.log(import_chalk14.default.dim("Pick a plan in billing. No second login."));
17003
- } catch {
17004
- console.log(import_chalk14.default.yellow("Could not open dashboard automatically."));
17005
- console.log(import_chalk14.default.dim(`Visit ${DASHBOARD_BILLING_URL} after running hyv init`));
17006
- console.log(import_chalk14.default.dim(`Or see plans: ${PRICING_URL}`));
17007
- }
17047
+ const { openBillingUpgrade: openBillingUpgrade2 } = await Promise.resolve().then(() => (init_billing_upgrade(), billing_upgrade_exports));
17048
+ await openBillingUpgrade2({ plan: "individual" });
17008
17049
  }
17009
17050
  async function openBillingPortal() {
17010
- console.log(import_chalk14.default.cyan("\nOpening billing portal...\n"));
17051
+ console.log(import_chalk15.default.cyan("\nOpening billing portal...\n"));
17011
17052
  const response = await authenticatedRequest(
17012
17053
  cliApiUrl("/cli/subscribe/manage"),
17013
17054
  { method: "POST" }
@@ -17016,41 +17057,41 @@ async function openBillingPortal() {
17016
17057
  const data = response.data;
17017
17058
  const portalUrl = data.portal_url;
17018
17059
  if (portalUrl) {
17019
- console.log(import_chalk14.default.dim("Opening browser..."));
17060
+ console.log(import_chalk15.default.dim("Opening browser..."));
17020
17061
  await (0, import_open2.default)(assertSafeOpenUrl(portalUrl));
17021
- console.log(import_chalk14.default.green("\n\u2713 Billing portal opened"));
17062
+ console.log(import_chalk15.default.green("\n\u2713 Billing portal opened"));
17022
17063
  } else {
17023
- console.log(import_chalk14.default.yellow("No portal URL received."));
17064
+ console.log(import_chalk15.default.yellow("No portal URL received."));
17024
17065
  }
17025
17066
  } else {
17026
- console.log(import_chalk14.default.yellow("Could not open billing portal."));
17027
- console.log(import_chalk14.default.dim(`Visit ${DASHBOARD_BILLING_URL} to manage billing.`));
17067
+ console.log(import_chalk15.default.yellow("Could not open billing portal."));
17068
+ console.log(import_chalk15.default.dim(`Visit ${DASHBOARD_BILLING_URL} to manage billing.`));
17028
17069
  }
17029
17070
  }
17030
17071
  async function downgradePlan() {
17031
- console.log(import_chalk14.default.yellow("\nDowngrade Plan\n"));
17072
+ console.log(import_chalk15.default.yellow("\nDowngrade Plan\n"));
17032
17073
  console.log("To downgrade your plan, please visit:");
17033
- console.log(import_chalk14.default.dim(` ${DASHBOARD_BILLING_URL}`));
17074
+ console.log(import_chalk15.default.dim(` ${DASHBOARD_BILLING_URL}`));
17034
17075
  console.log("\nOr contact support at shashank@holdyourvoice.com");
17035
17076
  }
17036
17077
 
17037
17078
  // src/commands/scan.ts
17038
- var import_chalk17 = __toESM(require_source());
17079
+ var import_chalk18 = __toESM(require_source());
17039
17080
  init_pipeline();
17040
17081
  init_local_profile();
17041
17082
  init_access();
17042
17083
 
17043
17084
  // src/lib/output.ts
17044
- var import_chalk15 = __toESM(require_source());
17085
+ var import_chalk16 = __toESM(require_source());
17045
17086
  var c = {
17046
- dim: (s) => import_chalk15.default.dim(s),
17047
- bold: (s) => import_chalk15.default.bold(s),
17048
- accent: (s) => import_chalk15.default.hex("#C4441A")(s),
17049
- green: (s) => import_chalk15.default.green(s),
17050
- red: (s) => import_chalk15.default.red(s),
17051
- yellow: (s) => import_chalk15.default.yellow(s),
17052
- cyan: (s) => import_chalk15.default.cyan(s),
17053
- white: (s) => import_chalk15.default.white(s)
17087
+ dim: (s) => import_chalk16.default.dim(s),
17088
+ bold: (s) => import_chalk16.default.bold(s),
17089
+ accent: (s) => import_chalk16.default.hex("#C4441A")(s),
17090
+ green: (s) => import_chalk16.default.green(s),
17091
+ red: (s) => import_chalk16.default.red(s),
17092
+ yellow: (s) => import_chalk16.default.yellow(s),
17093
+ cyan: (s) => import_chalk16.default.cyan(s),
17094
+ white: (s) => import_chalk16.default.white(s)
17054
17095
  };
17055
17096
  function logo() {
17056
17097
  return `${c.bold("hold your ")}${c.accent("voice")}`;
@@ -17198,7 +17239,7 @@ async function runHybridAnalysis(text, profile, opts = {}) {
17198
17239
  }
17199
17240
 
17200
17241
  // src/commands/history.ts
17201
- var import_chalk16 = __toESM(require_source());
17242
+ var import_chalk17 = __toESM(require_source());
17202
17243
  var fs17 = __toESM(require("fs"));
17203
17244
  var path16 = __toESM(require("path"));
17204
17245
  init_config();
@@ -17250,7 +17291,7 @@ function registerHistoryCommand(program3) {
17250
17291
  if (fs17.existsSync(HISTORY_FILE)) {
17251
17292
  fs17.unlinkSync(HISTORY_FILE);
17252
17293
  }
17253
- console.log(import_chalk16.default.green("\n\u2713 History cleared"));
17294
+ console.log(import_chalk17.default.green("\n\u2713 History cleared"));
17254
17295
  return;
17255
17296
  }
17256
17297
  let entries = readHistory();
@@ -17264,14 +17305,14 @@ function registerHistoryCommand(program3) {
17264
17305
  const limit = parseInt(options.limit, 10);
17265
17306
  entries = entries.slice(-limit);
17266
17307
  if (entries.length === 0) {
17267
- console.log(import_chalk16.default.dim("\nNo scan history yet. Run hyv scan or hyv score to start tracking."));
17308
+ console.log(import_chalk17.default.dim("\nNo scan history yet. Run hyv scan or hyv score to start tracking."));
17268
17309
  return;
17269
17310
  }
17270
17311
  if (options.format === "json") {
17271
17312
  console.log(JSON.stringify(entries, null, 2));
17272
17313
  return;
17273
17314
  }
17274
- console.log(import_chalk16.default.bold(`
17315
+ console.log(import_chalk17.default.bold(`
17275
17316
  score history (last ${entries.length} scans)
17276
17317
  `));
17277
17318
  if (options.chart) {
@@ -17283,7 +17324,7 @@ function registerHistoryCommand(program3) {
17283
17324
  if (min !== max) {
17284
17325
  console.log(` ${min} \u2524`);
17285
17326
  }
17286
- console.log(import_chalk16.default.dim(` \u2514${"\u2500".repeat(sl.length + 1)}`));
17327
+ console.log(import_chalk17.default.dim(` \u2514${"\u2500".repeat(sl.length + 1)}`));
17287
17328
  console.log("");
17288
17329
  }
17289
17330
  const scores = entries.map((e) => e.score);
@@ -17296,22 +17337,22 @@ function registerHistoryCommand(program3) {
17296
17337
  const firstAvg = firstHalf.reduce((s, e) => s + e.score, 0) / (firstHalf.length || 1);
17297
17338
  const secondAvg = secondHalf.reduce((s, e) => s + e.score, 0) / (secondHalf.length || 1);
17298
17339
  const trend = Math.round(secondAvg - firstAvg);
17299
- const trendStr = trend > 0 ? import_chalk16.default.green(`\u2191 improving (+${trend})`) : trend < 0 ? import_chalk16.default.red(`\u2193 declining (${trend})`) : import_chalk16.default.dim("\u2192 stable");
17300
- console.log(import_chalk16.default.dim(` avg: ${avg} best: ${best.score} worst: ${worst.score}`));
17301
- console.log(import_chalk16.default.dim(` trend: ${trendStr}`));
17302
- console.log(import_chalk16.default.bold("\n recent:\n"));
17340
+ const trendStr = trend > 0 ? import_chalk17.default.green(`\u2191 improving (+${trend})`) : trend < 0 ? import_chalk17.default.red(`\u2193 declining (${trend})`) : import_chalk17.default.dim("\u2192 stable");
17341
+ console.log(import_chalk17.default.dim(` avg: ${avg} best: ${best.score} worst: ${worst.score}`));
17342
+ console.log(import_chalk17.default.dim(` trend: ${trendStr}`));
17343
+ console.log(import_chalk17.default.bold("\n recent:\n"));
17303
17344
  const recent = entries.slice(-10).reverse();
17304
17345
  for (const entry of recent) {
17305
17346
  const time = new Date(entry.timestamp).toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit" });
17306
- const icon = entry.issues === 0 ? import_chalk16.default.green("\u2713") : import_chalk16.default.red("\u25CF");
17307
- const score = entry.score < 60 ? import_chalk16.default.red(`${entry.score}/100`) : entry.score < 80 ? import_chalk16.default.yellow(`${entry.score}/100`) : import_chalk16.default.green(`${entry.score}/100`);
17308
- const issues = entry.issues > 0 ? import_chalk16.default.red(`${entry.issues} issues`) : import_chalk16.default.dim("clean");
17347
+ const icon = entry.issues === 0 ? import_chalk17.default.green("\u2713") : import_chalk17.default.red("\u25CF");
17348
+ const score = entry.score < 60 ? import_chalk17.default.red(`${entry.score}/100`) : entry.score < 80 ? import_chalk17.default.yellow(`${entry.score}/100`) : import_chalk17.default.green(`${entry.score}/100`);
17349
+ const issues = entry.issues > 0 ? import_chalk17.default.red(`${entry.issues} issues`) : import_chalk17.default.dim("clean");
17309
17350
  const file = path16.basename(entry.file).slice(0, 25).padEnd(25);
17310
- console.log(` ${import_chalk16.default.dim(time)} ${icon} ${file} ${score} ${issues}`);
17351
+ console.log(` ${import_chalk17.default.dim(time)} ${icon} ${file} ${score} ${issues}`);
17311
17352
  }
17312
17353
  console.log("");
17313
17354
  } catch (error) {
17314
- console.error(import_chalk16.default.red(`Error: ${error.message}`));
17355
+ console.error(import_chalk17.default.red(`Error: ${error.message}`));
17315
17356
  process.exit(1);
17316
17357
  }
17317
17358
  });
@@ -17326,7 +17367,7 @@ function registerScanCommand(program3) {
17326
17367
  const profile = await loadProfileForCommand(options.profile);
17327
17368
  const { text, path: filePath } = readText(file);
17328
17369
  if (!text.trim()) {
17329
- console.warn(import_chalk17.default.yellow("File is empty or contains only whitespace."));
17370
+ console.warn(import_chalk18.default.yellow("File is empty or contains only whitespace."));
17330
17371
  process.exit(0);
17331
17372
  }
17332
17373
  const ignoreRules = options.ignore ? new Set(options.ignore.split(",").map((r) => r.trim())) : /* @__PURE__ */ new Set();
@@ -17369,26 +17410,26 @@ function registerScanCommand(program3) {
17369
17410
  }, null, 2));
17370
17411
  } else {
17371
17412
  if (signals.length === 0) {
17372
- console.log(import_chalk17.default.green(`
17413
+ console.log(import_chalk18.default.green(`
17373
17414
  \u2713 No issues found in ${filePath}`));
17374
- console.log(import_chalk17.default.dim(` score: ${score}/100`));
17415
+ console.log(import_chalk18.default.dim(` score: ${score}/100`));
17375
17416
  } else {
17376
- console.log(import_chalk17.default.bold(`
17417
+ console.log(import_chalk18.default.bold(`
17377
17418
  hyv scan ${filePath}`));
17378
17419
  if (profile) {
17379
- console.log(import_chalk17.default.dim(` profile: ${profile.slug || profile.name}${hasRichProfile(profile) ? " (full)" : ""}`));
17420
+ console.log(import_chalk18.default.dim(` profile: ${profile.slug || profile.name}${hasRichProfile(profile) ? " (full)" : ""}`));
17380
17421
  }
17381
17422
  if (analysis.message) {
17382
- console.log(import_chalk17.default.dim(` engine: ${analysis.message}`));
17423
+ console.log(import_chalk18.default.dim(` engine: ${analysis.message}`));
17383
17424
  }
17384
17425
  console.log("");
17385
17426
  printGroupedSignals(signals, profile);
17386
- console.log(import_chalk17.default.yellow(`
17427
+ console.log(import_chalk18.default.yellow(`
17387
17428
  ${signals.length} issues (${signals.filter((s) => s.severity === "red").length} red, ${signals.filter((s) => s.severity === "yellow").length} yellow)`));
17388
- console.log(import_chalk17.default.dim(` score: ${score}/100`));
17389
- console.log(import_chalk17.default.dim(`
17429
+ console.log(import_chalk18.default.dim(` score: ${score}/100`));
17430
+ console.log(import_chalk18.default.dim(`
17390
17431
  fix: hyv fix ${file}`));
17391
- console.log(import_chalk17.default.dim(` diff: hyv diff ${file}
17432
+ console.log(import_chalk18.default.dim(` diff: hyv diff ${file}
17392
17433
  `));
17393
17434
  }
17394
17435
  await maybeShowLimitedModeHint(!!profile);
@@ -17406,14 +17447,14 @@ hyv scan ${filePath}`));
17406
17447
  process.exit(2);
17407
17448
  }
17408
17449
  } catch (error) {
17409
- console.error(import_chalk17.default.red(`Error: ${error.message}`));
17450
+ console.error(import_chalk18.default.red(`Error: ${error.message}`));
17410
17451
  process.exit(1);
17411
17452
  }
17412
17453
  });
17413
17454
  }
17414
17455
 
17415
17456
  // src/commands/doctor.ts
17416
- var import_chalk18 = __toESM(require_source());
17457
+ var import_chalk19 = __toESM(require_source());
17417
17458
  var fs19 = __toESM(require("fs"));
17418
17459
  var path18 = __toESM(require("path"));
17419
17460
  var os9 = __toESM(require("os"));
@@ -17530,6 +17571,33 @@ function claudeDesktopDir() {
17530
17571
  return path18.join(HOME, ".config", "Claude");
17531
17572
  return path18.join(HOME, "Library", "Application Support", "Claude");
17532
17573
  }
17574
+ function windsurfRulePath() {
17575
+ const dirs = [
17576
+ path18.join(HOME, ".windsurf"),
17577
+ IS_WIN ? path18.join(HOME, "AppData", "Roaming", "Windsurf") : path18.join(HOME, "Library", "Application Support", "Windsurf")
17578
+ ];
17579
+ for (const dir of dirs) {
17580
+ const file = path18.join(dir, "rules", "hyv.md");
17581
+ if (fs19.existsSync(file))
17582
+ return file;
17583
+ }
17584
+ return null;
17585
+ }
17586
+ function opencodeAgentsPath() {
17587
+ return path18.join(HOME, ".config", "opencode", "AGENTS.md");
17588
+ }
17589
+ function readOpencodeHyv() {
17590
+ const file = path18.join(HOME, ".config", "opencode", "opencode.jsonc");
17591
+ if (!fs19.existsSync(file))
17592
+ return false;
17593
+ try {
17594
+ const raw = fs19.readFileSync(file, "utf-8").replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
17595
+ const cfg = JSON.parse(raw);
17596
+ return Boolean(cfg.mcp?.hyv);
17597
+ } catch {
17598
+ return false;
17599
+ }
17600
+ }
17533
17601
  function isOwnerOnlyFile(filePath) {
17534
17602
  try {
17535
17603
  if (!fs19.existsSync(filePath))
@@ -17551,129 +17619,135 @@ function readMcpHyv(configFile) {
17551
17619
  }
17552
17620
  }
17553
17621
  function registerDoctorCommand(program3) {
17554
- program3.command("doctor").description("Diagnose CLI health: engine, cache, auth, agents").option("--fix-agents", "Re-run agent config copy (idempotent)").action(async (opts) => {
17555
- console.log(import_chalk18.default.bold("\nhold your voice \u2014 doctor\n"));
17622
+ program3.command("doctor").description("Diagnose CLI health: engine, cache, auth, agents").option("--fix-agents", "Re-run agent config copy (idempotent)").option("--verify-hosts", "Spawn MCP using each host config and report pass/fail").action(async (opts) => {
17623
+ console.log(import_chalk19.default.bold("\nhold your voice \u2014 doctor\n"));
17556
17624
  let issues = 0;
17557
17625
  let fixed = 0;
17558
- console.log(import_chalk18.default.dim(`engine: ${getEngineLabel()} (node ${process.version})`));
17626
+ console.log(import_chalk19.default.dim(`engine: ${getEngineLabel()} (node ${process.version})`));
17559
17627
  if (isLocalOnlyMode()) {
17560
- console.log(import_chalk18.default.yellow(" local-only mode: HYV_LOCAL_ONLY is set"));
17628
+ console.log(import_chalk19.default.yellow(" local-only mode: HYV_LOCAL_ONLY is set"));
17561
17629
  }
17562
17630
  const access = await getAccessState();
17563
17631
  const profile = await loadProfileForCommand();
17564
- console.log(import_chalk18.default.dim(`mode: ${formatModeLabel(access, hasRichProfile(profile))}`));
17565
- console.log(import_chalk18.default.dim("tip: run hyv welcome for free capabilities\n"));
17566
- console.log(import_chalk18.default.dim("checking cli installation..."));
17632
+ console.log(import_chalk19.default.dim(`mode: ${formatModeLabel(access, hasRichProfile(profile))}`));
17633
+ console.log(import_chalk19.default.dim("tip: run hyv welcome for free capabilities\n"));
17634
+ console.log(import_chalk19.default.dim("checking cli installation..."));
17567
17635
  const cliPath = process.argv[1];
17568
17636
  if (cliPath && fs19.existsSync(cliPath)) {
17569
- console.log(import_chalk18.default.green(" \u2713 cli installed"));
17637
+ console.log(import_chalk19.default.green(" \u2713 cli installed"));
17570
17638
  } else {
17571
- console.log(import_chalk18.default.red(" \u2717 cli not found"));
17639
+ console.log(import_chalk19.default.red(" \u2717 cli not found"));
17572
17640
  issues++;
17573
17641
  }
17574
- console.log(import_chalk18.default.dim("checking .hyv directory..."));
17642
+ console.log(import_chalk19.default.dim("checking .hyv directory..."));
17575
17643
  if (fs19.existsSync(HYV_DIR)) {
17576
- console.log(import_chalk18.default.green(" \u2713 .hyv directory exists"));
17644
+ console.log(import_chalk19.default.green(" \u2713 .hyv directory exists"));
17577
17645
  } else {
17578
- console.log(import_chalk18.default.yellow(" ! .hyv directory missing \u2014 creating..."));
17646
+ console.log(import_chalk19.default.yellow(" ! .hyv directory missing \u2014 creating..."));
17579
17647
  fs19.mkdirSync(HYV_DIR, { recursive: true, mode: 448 });
17580
17648
  fixed++;
17581
17649
  }
17582
- console.log(import_chalk18.default.dim("checking cache..."));
17650
+ console.log(import_chalk19.default.dim("checking cache..."));
17583
17651
  const diskProfiles = listDiskCachedProfiles();
17584
17652
  const syncMeta = path18.join(CACHE_DIR2, "sync-meta.json");
17585
17653
  if (diskProfiles.length > 0 || fs19.existsSync(syncMeta)) {
17586
- console.log(import_chalk18.default.green(` \u2713 profile cache (${diskProfiles.length} full profile(s))`));
17654
+ console.log(import_chalk19.default.green(` \u2713 profile cache (${diskProfiles.length} full profile(s))`));
17587
17655
  if (fs19.existsSync(syncMeta)) {
17588
17656
  try {
17589
17657
  const meta = JSON.parse(fs19.readFileSync(syncMeta, "utf-8"));
17590
- console.log(import_chalk18.default.dim(` last sync: ${meta.synced_at || "unknown"}`));
17658
+ console.log(import_chalk19.default.dim(` last sync: ${meta.synced_at || "unknown"}`));
17591
17659
  } catch {
17592
17660
  }
17593
17661
  }
17594
17662
  } else {
17595
- console.log(import_chalk18.default.dim(" - no full profile cache (free local engine still works)"));
17663
+ console.log(import_chalk19.default.dim(" - no full profile cache (free local engine still works)"));
17596
17664
  }
17597
- console.log(import_chalk18.default.dim("checking file permissions..."));
17665
+ console.log(import_chalk19.default.dim("checking file permissions..."));
17598
17666
  if (fs19.existsSync(HYV_DIR)) {
17599
17667
  const hyvMode = fs19.statSync(HYV_DIR).mode & 511;
17600
17668
  if ((hyvMode & 63) === 0) {
17601
- console.log(import_chalk18.default.green(" \u2713 .hyv directory permissions"));
17669
+ console.log(import_chalk19.default.green(" \u2713 .hyv directory permissions"));
17602
17670
  } else {
17603
- console.log(import_chalk18.default.yellow(" ! .hyv directory is world/group accessible"));
17604
- console.log(import_chalk18.default.dim(" run: chmod 700 ~/.hyv"));
17671
+ console.log(import_chalk19.default.yellow(" ! .hyv directory is world/group accessible"));
17672
+ console.log(import_chalk19.default.dim(" run: chmod 700 ~/.hyv"));
17605
17673
  issues++;
17606
17674
  }
17607
17675
  }
17608
17676
  if (fs19.existsSync(AUTH_FILE)) {
17609
17677
  if (isOwnerOnlyFile(AUTH_FILE)) {
17610
- console.log(import_chalk18.default.green(" \u2713 auth.json permissions"));
17678
+ console.log(import_chalk19.default.green(" \u2713 auth.json permissions"));
17611
17679
  } else {
17612
- console.log(import_chalk18.default.yellow(" ! auth.json is world/group readable"));
17613
- console.log(import_chalk18.default.dim(" run: chmod 600 ~/.hyv/auth.json"));
17680
+ console.log(import_chalk19.default.yellow(" ! auth.json is world/group readable"));
17681
+ console.log(import_chalk19.default.dim(" run: chmod 600 ~/.hyv/auth.json"));
17614
17682
  issues++;
17615
17683
  }
17616
17684
  }
17617
- console.log(import_chalk18.default.dim("checking authentication..."));
17685
+ console.log(import_chalk19.default.dim("checking authentication..."));
17618
17686
  if (isInitialized()) {
17619
17687
  const auth = readAuth();
17620
17688
  if (auth) {
17621
- console.log(import_chalk18.default.green(" \u2713 authenticated"));
17622
- console.log(import_chalk18.default.dim(` email: ${auth.user?.email || "unknown"}`));
17689
+ console.log(import_chalk19.default.green(" \u2713 authenticated"));
17690
+ console.log(import_chalk19.default.dim(` email: ${auth.user?.email || "unknown"}`));
17623
17691
  const session = await checkSession();
17624
17692
  if (session.valid) {
17625
- console.log(import_chalk18.default.green(" \u2713 session valid"));
17626
- console.log(import_chalk18.default.dim(` plan: ${session.plan || "none"}`));
17693
+ console.log(import_chalk19.default.green(" \u2713 session valid"));
17694
+ console.log(import_chalk19.default.dim(` plan: ${session.plan || "none"}`));
17627
17695
  } else {
17628
- console.log(import_chalk18.default.red(" \u2717 session expired"));
17629
- console.log(import_chalk18.default.dim(" run: hyv init"));
17696
+ console.log(import_chalk19.default.red(" \u2717 session expired"));
17697
+ console.log(import_chalk19.default.dim(" run: hyv init"));
17630
17698
  issues++;
17631
17699
  }
17632
17700
  } else {
17633
- console.log(import_chalk18.default.red(" \u2717 auth data missing"));
17701
+ console.log(import_chalk19.default.red(" \u2717 auth data missing"));
17634
17702
  issues++;
17635
17703
  }
17636
17704
  } else {
17637
- console.log(import_chalk18.default.yellow(" ! not authenticated (free local scan works)"));
17638
- console.log(import_chalk18.default.dim(" run: hyv init for profiles + learning"));
17705
+ console.log(import_chalk19.default.yellow(" ! not authenticated (free local scan works)"));
17706
+ console.log(import_chalk19.default.dim(" run: hyv init for profiles + learning"));
17639
17707
  }
17640
- console.log(import_chalk18.default.dim("checking voice profile..."));
17708
+ console.log(import_chalk19.default.dim("checking voice profile..."));
17641
17709
  const voiceMd = path18.join(HYV_DIR, "voice.md");
17642
17710
  const hasVoiceMd = fs19.existsSync(voiceMd) && fs19.readFileSync(voiceMd, "utf-8").trim().length > 50;
17643
17711
  const profileFiles = fs19.existsSync(PROFILES_DIR) ? fs19.readdirSync(PROFILES_DIR).filter((f) => f.endsWith(".md") && f !== "voice.md") : [];
17644
17712
  if (hasVoiceMd || profileFiles.length > 0 || diskProfiles.length > 0) {
17645
17713
  if (hasVoiceMd)
17646
- console.log(import_chalk18.default.green(" \u2713 voice.md exists"));
17714
+ console.log(import_chalk19.default.green(" \u2713 voice.md exists"));
17647
17715
  if (profileFiles.length > 0)
17648
- console.log(import_chalk18.default.green(` \u2713 ${profileFiles.length} markdown profile(s)`));
17716
+ console.log(import_chalk19.default.green(` \u2713 ${profileFiles.length} markdown profile(s)`));
17649
17717
  if (diskProfiles.length > 0)
17650
- console.log(import_chalk18.default.green(` \u2713 ${diskProfiles.length} full cached profile(s)`));
17718
+ console.log(import_chalk19.default.green(` \u2713 ${diskProfiles.length} full cached profile(s)`));
17651
17719
  } else {
17652
- console.log(import_chalk18.default.yellow(" ! no voice profile (optional for free scan)"));
17653
- console.log(import_chalk18.default.dim(" run: hyv new <name> or hyv init"));
17720
+ console.log(import_chalk19.default.yellow(" ! no voice profile (optional for free scan)"));
17721
+ console.log(import_chalk19.default.dim(" run: hyv new <name> or hyv init"));
17654
17722
  }
17655
- console.log(import_chalk18.default.dim("checking agent configurations..."));
17723
+ console.log(import_chalk19.default.dim("checking agent configurations..."));
17656
17724
  const cursorLegacyRule = path18.join(HOME, ".cursor", "rules", "hyv.md");
17657
17725
  const cursorRule = path18.join(HOME, ".cursor", "rules", "hyv.mdc");
17658
17726
  if (fs19.existsSync(cursorLegacyRule) && fs19.existsSync(cursorRule)) {
17659
- console.log(import_chalk18.default.yellow(" ! stale cursor rule ~/.cursor/rules/hyv.md (use hyv.mdc)"));
17660
- console.log(import_chalk18.default.dim(" run: rm ~/.cursor/rules/hyv.md (or hyv doctor --fix-agents)"));
17727
+ console.log(import_chalk19.default.yellow(" ! stale cursor rule ~/.cursor/rules/hyv.md (use hyv.mdc)"));
17728
+ console.log(import_chalk19.default.dim(" run: rm ~/.cursor/rules/hyv.md (or hyv doctor --fix-agents)"));
17661
17729
  issues++;
17662
17730
  }
17731
+ const agMcpFile = path18.join(HOME, ".gemini", "config", "mcp_config.json");
17663
17732
  const agentChecks = [
17664
17733
  { name: "claude desktop mcp", ok: readMcpHyv(path18.join(claudeDesktopDir(), "claude_desktop_config.json")) },
17665
17734
  { name: "cursor mcp", ok: readMcpHyv(path18.join(HOME, ".cursor", "mcp.json")) },
17666
17735
  { name: "cursor rule", ok: fs19.existsSync(cursorRule) },
17736
+ { name: "antigravity mcp", ok: readMcpHyv(agMcpFile) },
17737
+ { name: "opencode mcp", ok: readOpencodeHyv() },
17738
+ { name: "opencode agents", ok: fs19.existsSync(opencodeAgentsPath()) && fs19.readFileSync(opencodeAgentsPath(), "utf-8").includes("hyv") },
17739
+ { name: "windsurf rule", ok: Boolean(windsurfRulePath()) },
17667
17740
  { name: "claude code command", ok: fs19.existsSync(path18.join(HOME, ".claude", "commands", "hyv.md")) },
17668
17741
  { name: "claude code skill", ok: fs19.existsSync(path18.join(HOME, ".claude", "skills", "hold-your-voice", "SKILL.md")) },
17669
17742
  { name: "codex agents", ok: fs19.existsSync(path18.join(HOME, ".codex", "AGENTS.md")) && fs19.readFileSync(path18.join(HOME, ".codex", "AGENTS.md"), "utf-8").includes("hyv") },
17670
- { name: "command code skill", ok: fs19.existsSync(path18.join(HOME, ".commandcode", "skills", "hyv", "SKILL.md")) }
17743
+ { name: "command code skill", ok: fs19.existsSync(path18.join(HOME, ".commandcode", "skills", "hyv", "SKILL.md")) },
17744
+ { name: "chatgpt connector guide", ok: fs19.existsSync(path18.join(HOME, ".chatgpt", "hyv-mcp-connector.txt")) }
17671
17745
  ];
17672
17746
  for (const agent of agentChecks) {
17673
17747
  if (agent.ok) {
17674
- console.log(import_chalk18.default.green(` \u2713 ${agent.name}`));
17748
+ console.log(import_chalk19.default.green(` \u2713 ${agent.name}`));
17675
17749
  } else {
17676
- console.log(import_chalk18.default.dim(` - ${agent.name} not configured`));
17750
+ console.log(import_chalk19.default.dim(` - ${agent.name} not configured`));
17677
17751
  }
17678
17752
  }
17679
17753
  if (opts.fixAgents) {
@@ -17681,59 +17755,84 @@ function registerDoctorCommand(program3) {
17681
17755
  const pkgDir = path18.resolve(__dirname, "..");
17682
17756
  const { setupAgents } = require(path18.join(pkgDir, "scripts", "postinstall-lib.js"));
17683
17757
  const result = setupAgents({ pkgDir, quiet: true });
17684
- console.log(import_chalk18.default.green(` \u2713 re-ran agent setup (${result.configured.join(", ") || "no changes"})`));
17758
+ console.log(import_chalk19.default.green(` \u2713 re-ran agent setup (${result.configured.join(", ") || "no changes"})`));
17685
17759
  if (result.warnings.length) {
17686
- console.log(import_chalk18.default.yellow(` notes: ${result.warnings.join("; ")}`));
17760
+ console.log(import_chalk19.default.yellow(` notes: ${result.warnings.join("; ")}`));
17687
17761
  }
17688
17762
  fixed++;
17689
17763
  } catch (err) {
17690
- console.log(import_chalk18.default.yellow(` ! could not re-run agent setup: ${err.message}`));
17764
+ console.log(import_chalk19.default.yellow(` ! could not re-run agent setup: ${err.message}`));
17691
17765
  }
17692
17766
  }
17693
- console.log(import_chalk18.default.dim("checking mcp server..."));
17767
+ console.log(import_chalk19.default.dim("checking mcp server..."));
17694
17768
  const claudeMcp = readMcpHyv(path18.join(claudeDesktopDir(), "claude_desktop_config.json"));
17695
17769
  const cursorMcp = readMcpHyv(path18.join(HOME, ".cursor", "mcp.json"));
17696
17770
  if (claudeMcp || cursorMcp) {
17697
17771
  if (claudeMcp)
17698
- console.log(import_chalk18.default.green(" \u2713 mcp configured for claude desktop"));
17772
+ console.log(import_chalk19.default.green(" \u2713 mcp configured for claude desktop"));
17699
17773
  if (cursorMcp)
17700
- console.log(import_chalk18.default.green(" \u2713 mcp configured for cursor"));
17774
+ console.log(import_chalk19.default.green(" \u2713 mcp configured for cursor"));
17701
17775
  } else {
17702
- console.log(import_chalk18.default.yellow(" ! mcp not configured \u2014 run: hyv doctor --fix-agents or hyv mcp --setup"));
17776
+ console.log(import_chalk19.default.yellow(" ! mcp not configured \u2014 run: hyv doctor --fix-agents or hyv mcp --setup"));
17703
17777
  issues++;
17704
17778
  }
17705
17779
  try {
17706
17780
  const stdio = await testMcpStdioSubprocess();
17707
17781
  if (stdio.ok && (stdio.toolCount || 0) >= 10) {
17708
- console.log(import_chalk18.default.green(` \u2713 mcp stdio subprocess healthy (${stdio.toolCount} tools)`));
17782
+ console.log(import_chalk19.default.green(` \u2713 mcp stdio subprocess healthy (${stdio.toolCount} tools)`));
17709
17783
  } else if (stdio.ok) {
17710
- console.log(import_chalk18.default.yellow(` ! mcp stdio ok but only ${stdio.toolCount || 0} tools`));
17784
+ console.log(import_chalk19.default.yellow(` ! mcp stdio ok but only ${stdio.toolCount || 0} tools`));
17711
17785
  issues++;
17712
17786
  } else {
17713
- console.log(import_chalk18.default.red(" \u2717 mcp stdio subprocess failed"));
17714
- console.log(import_chalk18.default.dim(" run: hyv mcp --test"));
17787
+ console.log(import_chalk19.default.red(" \u2717 mcp stdio subprocess failed"));
17788
+ console.log(import_chalk19.default.dim(" run: hyv mcp --test"));
17715
17789
  issues++;
17716
17790
  }
17717
17791
  } catch (err) {
17718
- console.log(import_chalk18.default.red(` \u2717 mcp stdio probe failed: ${err.message}`));
17792
+ console.log(import_chalk19.default.red(` \u2717 mcp stdio probe failed: ${err.message}`));
17719
17793
  issues++;
17720
17794
  }
17795
+ if (opts.verifyHosts) {
17796
+ console.log(import_chalk19.default.dim("verifying mcp hosts (spawns subprocess per config)..."));
17797
+ try {
17798
+ const pkgDir = path18.resolve(__dirname, "..");
17799
+ const { verifyAgentHosts } = require(path18.join(pkgDir, "scripts", "verify-agent-hosts.js"));
17800
+ const hosts = await verifyAgentHosts();
17801
+ for (const host of hosts) {
17802
+ if (host.kind === "manual") {
17803
+ console.log(import_chalk19.default.yellow(` \u25CB ${host.label} \u2014 ${host.detail}`));
17804
+ continue;
17805
+ }
17806
+ if (host.ok) {
17807
+ console.log(import_chalk19.default.green(` \u2713 ${host.label}${host.detail ? ` (${host.detail})` : ""}`));
17808
+ } else if (host.kind === "file") {
17809
+ console.log(import_chalk19.default.dim(` - ${host.label} \u2014 ${host.detail || "missing"}`));
17810
+ } else {
17811
+ console.log(import_chalk19.default.red(` \u2717 ${host.label} \u2014 ${host.detail || "failed"}`));
17812
+ issues++;
17813
+ }
17814
+ }
17815
+ } catch (err) {
17816
+ console.log(import_chalk19.default.red(` \u2717 host verification failed: ${err.message}`));
17817
+ issues++;
17818
+ }
17819
+ }
17721
17820
  console.log("");
17722
17821
  if (issues === 0 && fixed === 0) {
17723
- console.log(import_chalk18.default.green("\u2713 everything looks good!"));
17822
+ console.log(import_chalk19.default.green("\u2713 everything looks good!"));
17724
17823
  } else if (fixed > 0) {
17725
- console.log(import_chalk18.default.green(`\u2713 fixed ${fixed} issue(s)`));
17824
+ console.log(import_chalk19.default.green(`\u2713 fixed ${fixed} issue(s)`));
17726
17825
  if (issues > 0)
17727
- console.log(import_chalk18.default.yellow(`! ${issues} issue(s) remaining`));
17826
+ console.log(import_chalk19.default.yellow(`! ${issues} issue(s) remaining`));
17728
17827
  } else {
17729
- console.log(import_chalk18.default.yellow(`! ${issues} issue(s) found`));
17828
+ console.log(import_chalk19.default.yellow(`! ${issues} issue(s) found`));
17730
17829
  }
17731
- console.log(import_chalk18.default.dim("\nfree scan: hyv scan draft.md | full tour: hyv welcome\n"));
17830
+ console.log(import_chalk19.default.dim("\nfree scan: hyv scan draft.md | full tour: hyv welcome\n"));
17732
17831
  });
17733
17832
  }
17734
17833
 
17735
17834
  // src/commands/rename.ts
17736
- var import_chalk19 = __toESM(require_source());
17835
+ var import_chalk20 = __toESM(require_source());
17737
17836
  init_config();
17738
17837
  init_auth();
17739
17838
  function registerRenameCommand(program3) {
@@ -17741,26 +17840,26 @@ function registerRenameCommand(program3) {
17741
17840
  try {
17742
17841
  const trimmedName = newName.trim();
17743
17842
  if (!trimmedName) {
17744
- console.log(import_chalk19.default.red("\nerror: what do you want to name your profile?\n"));
17745
- console.log(import_chalk19.default.dim(' example: hyv rename "my brand voice"\n'));
17843
+ console.log(import_chalk20.default.red("\nerror: what do you want to name your profile?\n"));
17844
+ console.log(import_chalk20.default.dim(' example: hyv rename "my brand voice"\n'));
17746
17845
  process.exit(1);
17747
17846
  return;
17748
17847
  }
17749
17848
  if (trimmedName.length > 100) {
17750
- console.log(import_chalk19.default.red("\nerror: name is too long \u2014 keep it under 100 characters\n"));
17849
+ console.log(import_chalk20.default.red("\nerror: name is too long \u2014 keep it under 100 characters\n"));
17751
17850
  process.exit(1);
17752
17851
  return;
17753
17852
  }
17754
17853
  if (!/^[a-zA-Z0-9\s\-_'&.]+$/.test(trimmedName)) {
17755
- console.log(import_chalk19.default.red("\nerror: name contains invalid characters\n"));
17756
- console.log(import_chalk19.default.dim(" allowed: letters, numbers, spaces, hyphens, underscores, apostrophes\n"));
17854
+ console.log(import_chalk20.default.red("\nerror: name contains invalid characters\n"));
17855
+ console.log(import_chalk20.default.dim(" allowed: letters, numbers, spaces, hyphens, underscores, apostrophes\n"));
17757
17856
  process.exit(1);
17758
17857
  return;
17759
17858
  }
17760
17859
  const token = getToken();
17761
17860
  if (!token) {
17762
- console.log(import_chalk19.default.red("\nerror: you're not signed in yet\n"));
17763
- console.log(import_chalk19.default.dim(" run: hyv init\n"));
17861
+ console.log(import_chalk20.default.red("\nerror: you're not signed in yet\n"));
17862
+ console.log(import_chalk20.default.dim(" run: hyv init\n"));
17764
17863
  process.exit(1);
17765
17864
  return;
17766
17865
  }
@@ -17776,16 +17875,16 @@ function registerRenameCommand(program3) {
17776
17875
  );
17777
17876
  if (response.status === 200) {
17778
17877
  const data = response.data;
17779
- console.log(import_chalk19.default.green(`
17878
+ console.log(import_chalk20.default.green(`
17780
17879
  \u2713 profile renamed to ${data.profile?.name || trimmedName}
17781
17880
  `));
17782
17881
  } else {
17783
- console.log(import_chalk19.default.red(`
17882
+ console.log(import_chalk20.default.red(`
17784
17883
  error: server returned ${response.status}
17785
17884
  `));
17786
17885
  }
17787
17886
  } catch (error) {
17788
- console.error(import_chalk19.default.red(`
17887
+ console.error(import_chalk20.default.red(`
17789
17888
  error: ${error.message}
17790
17889
  `));
17791
17890
  process.exit(1);
@@ -17794,7 +17893,7 @@ error: ${error.message}
17794
17893
  }
17795
17894
 
17796
17895
  // src/commands/fix.ts
17797
- var import_chalk21 = __toESM(require_source());
17896
+ var import_chalk22 = __toESM(require_source());
17798
17897
  init_pipeline();
17799
17898
  init_local_profile();
17800
17899
  init_access();
@@ -17804,14 +17903,14 @@ init_config();
17804
17903
  var fs20 = __toESM(require("fs"));
17805
17904
  var path19 = __toESM(require("path"));
17806
17905
  var readline2 = __toESM(require("readline"));
17807
- var import_chalk20 = __toESM(require_source());
17906
+ var import_chalk21 = __toESM(require_source());
17808
17907
  async function confirmDestructiveWrite(options) {
17809
17908
  if (options.yes)
17810
17909
  return true;
17811
17910
  const label = options.target ? `${options.action} (${options.target})` : options.action;
17812
17911
  if (!process.stdin.isTTY) {
17813
- console.error(import_chalk20.default.red("\nRefusing destructive write without confirmation (non-interactive)."));
17814
- console.error(import_chalk20.default.dim(" Re-run with --yes to create .bak backups and proceed.\n"));
17912
+ console.error(import_chalk21.default.red("\nRefusing destructive write without confirmation (non-interactive)."));
17913
+ console.error(import_chalk21.default.dim(" Re-run with --yes to create .bak backups and proceed.\n"));
17815
17914
  return false;
17816
17915
  }
17817
17916
  const question = `
@@ -17847,9 +17946,9 @@ function registerFixCommand(program3) {
17847
17946
  if (options.format === "json") {
17848
17947
  console.log(JSON.stringify({ file: filePath, autoFixes: 0, llmIssues: result.stats.needsLLM, changes: [] }));
17849
17948
  } else {
17850
- console.log(import_chalk21.default.green("\n\u2713 No auto-fixable issues found."));
17949
+ console.log(import_chalk22.default.green("\n\u2713 No auto-fixable issues found."));
17851
17950
  if (result.stats.needsLLM > 0) {
17852
- console.log(import_chalk21.default.dim(` ${result.stats.needsLLM} issues need LLM rewrite \u2014 run: hyv rewrite ${file}`));
17951
+ console.log(import_chalk22.default.dim(` ${result.stats.needsLLM} issues need LLM rewrite \u2014 run: hyv rewrite ${file}`));
17853
17952
  }
17854
17953
  }
17855
17954
  return;
@@ -17863,16 +17962,16 @@ function registerFixCommand(program3) {
17863
17962
  fixed: options.dryRun ? void 0 : result.fixed
17864
17963
  }, null, 2));
17865
17964
  } else {
17866
- console.log(import_chalk21.default.dim(`
17965
+ console.log(import_chalk22.default.dim(`
17867
17966
  hyv fix ${filePath}
17868
17967
  `));
17869
17968
  for (const change of result.changes) {
17870
- console.log(import_chalk21.default.dim(` Line ${change.line}: `) + import_chalk21.default.red(change.before) + import_chalk21.default.dim(" \u2192 ") + import_chalk21.default.green(change.after));
17969
+ console.log(import_chalk22.default.dim(` Line ${change.line}: `) + import_chalk22.default.red(change.before) + import_chalk22.default.dim(" \u2192 ") + import_chalk22.default.green(change.after));
17871
17970
  }
17872
- console.log(import_chalk21.default.green(`
17971
+ console.log(import_chalk22.default.green(`
17873
17972
  \u2713 ${result.changes.length} auto-fix${result.changes.length === 1 ? "" : "es"} applied`));
17874
17973
  if (result.stats.needsLLM > 0) {
17875
- console.log(import_chalk21.default.dim(` ${result.stats.needsLLM} issues need LLM rewrite \u2014 run: hyv rewrite ${file}`));
17974
+ console.log(import_chalk22.default.dim(` ${result.stats.needsLLM} issues need LLM rewrite \u2014 run: hyv rewrite ${file}`));
17876
17975
  }
17877
17976
  }
17878
17977
  if (!options.dryRun) {
@@ -17886,7 +17985,7 @@ hyv fix ${filePath}
17886
17985
  process.exit(1);
17887
17986
  }
17888
17987
  const backupPath = writeInPlaceWithBackup(filePath, result.fixed);
17889
- console.log(import_chalk21.default.dim(` Written to ${filePath} (backup: ${backupBasename(filePath)})`));
17988
+ console.log(import_chalk22.default.dim(` Written to ${filePath} (backup: ${backupBasename(filePath)})`));
17890
17989
  saveLastEditSession({
17891
17990
  original_path: filePath,
17892
17991
  edited_path: filePath,
@@ -17894,7 +17993,7 @@ hyv fix ${filePath}
17894
17993
  edited_text: result.fixed,
17895
17994
  profile: options.profile
17896
17995
  });
17897
- console.log(import_chalk21.default.dim(" Tip: hyv reinforce --last to teach your profile from this edit"));
17996
+ console.log(import_chalk22.default.dim(" Tip: hyv reinforce --last to teach your profile from this edit"));
17898
17997
  } else if (filePath === "stdin" || !options.inPlace) {
17899
17998
  process.stdout.write("\n" + result.fixed + "\n");
17900
17999
  if (filePath !== "stdin") {
@@ -17910,14 +18009,14 @@ hyv fix ${filePath}
17910
18009
  }
17911
18010
  await maybeShowLimitedModeHint(!!profile);
17912
18011
  } catch (error) {
17913
- console.error(import_chalk21.default.red(`Error: ${error.message}`));
18012
+ console.error(import_chalk22.default.red(`Error: ${error.message}`));
17914
18013
  process.exit(1);
17915
18014
  }
17916
18015
  });
17917
18016
  }
17918
18017
 
17919
18018
  // src/commands/check.ts
17920
- var import_chalk22 = __toESM(require_source());
18019
+ var import_chalk23 = __toESM(require_source());
17921
18020
  init_pipeline();
17922
18021
  init_local_profile();
17923
18022
  init_access();
@@ -17929,18 +18028,18 @@ function registerCheckCommand(program3) {
17929
18028
  if (text === "-") {
17930
18029
  const fs31 = require("fs");
17931
18030
  if (process.stdin.isTTY) {
17932
- console.error(import_chalk22.default.red("No input provided. Pipe content or pass text as argument."));
18031
+ console.error(import_chalk23.default.red("No input provided. Pipe content or pass text as argument."));
17933
18032
  process.exit(1);
17934
18033
  }
17935
18034
  inputText = fs31.readFileSync(0, "utf-8");
17936
18035
  }
17937
18036
  if (!inputText.trim()) {
17938
- console.error(import_chalk22.default.red("No text provided."));
18037
+ console.error(import_chalk23.default.red("No text provided."));
17939
18038
  process.exit(1);
17940
18039
  }
17941
18040
  const fs30 = require("fs");
17942
18041
  if (text !== "-" && fs30.existsSync(text)) {
17943
- console.log(import_chalk22.default.yellow(`"${text}" looks like a file. Did you mean: hyv scan ${text}`));
18042
+ console.log(import_chalk23.default.yellow(`"${text}" looks like a file. Did you mean: hyv scan ${text}`));
17944
18043
  process.exit(1);
17945
18044
  }
17946
18045
  const result = runPipeline(inputText, profile, false);
@@ -17964,30 +18063,30 @@ function registerCheckCommand(program3) {
17964
18063
  }, null, 2));
17965
18064
  } else {
17966
18065
  if (result.stats.totalSignals === 0) {
17967
- console.log(import_chalk22.default.green("\n\u2713 Clean \u2014 no AI patterns found."));
17968
- console.log(import_chalk22.default.dim(` score: ${result.score}/100`));
18066
+ console.log(import_chalk23.default.green("\n\u2713 Clean \u2014 no AI patterns found."));
18067
+ console.log(import_chalk23.default.dim(` score: ${result.score}/100`));
17969
18068
  } else {
17970
18069
  console.log("");
17971
18070
  printGroupedSignals(result.signalMap.signals.slice(0, 15), profile);
17972
18071
  if (result.signalMap.signals.length > 15) {
17973
- console.log(import_chalk22.default.dim(` ... and ${result.signalMap.signals.length - 15} more`));
18072
+ console.log(import_chalk23.default.dim(` ... and ${result.signalMap.signals.length - 15} more`));
17974
18073
  }
17975
- console.log(import_chalk22.default.yellow(`
18074
+ console.log(import_chalk23.default.yellow(`
17976
18075
  ${result.stats.totalSignals} issues (${result.stats.red} red, ${result.stats.yellow} yellow)`));
17977
- console.log(import_chalk22.default.dim(` score: ${result.score}/100`));
18076
+ console.log(import_chalk23.default.dim(` score: ${result.score}/100`));
17978
18077
  }
17979
18078
  await maybeShowLimitedModeHint(!!profile);
17980
18079
  }
17981
18080
  process.exit(result.stats.totalSignals > 0 ? 1 : 0);
17982
18081
  } catch (error) {
17983
- console.error(import_chalk22.default.red(`Error: ${error.message}`));
18082
+ console.error(import_chalk23.default.red(`Error: ${error.message}`));
17984
18083
  process.exit(1);
17985
18084
  }
17986
18085
  });
17987
18086
  }
17988
18087
 
17989
18088
  // src/commands/score.ts
17990
- var import_chalk23 = __toESM(require_source());
18089
+ var import_chalk24 = __toESM(require_source());
17991
18090
  init_pipeline();
17992
18091
  init_local_profile();
17993
18092
  function registerScoreCommand(program3) {
@@ -18012,14 +18111,14 @@ function registerScoreCommand(program3) {
18012
18111
  process.exit(1);
18013
18112
  }
18014
18113
  } catch (error) {
18015
- console.error(import_chalk23.default.red(`Error: ${error.message}`));
18114
+ console.error(import_chalk24.default.red(`Error: ${error.message}`));
18016
18115
  process.exit(1);
18017
18116
  }
18018
18117
  });
18019
18118
  }
18020
18119
 
18021
18120
  // src/commands/diff.ts
18022
- var import_chalk24 = __toESM(require_source());
18121
+ var import_chalk25 = __toESM(require_source());
18023
18122
  init_pipeline();
18024
18123
  init_local_profile();
18025
18124
  function registerDiffCommand(program3) {
@@ -18029,9 +18128,9 @@ function registerDiffCommand(program3) {
18029
18128
  const { text, path: filePath } = readText(file);
18030
18129
  const result = runPipeline(text, profile, true);
18031
18130
  if (result.changes.length === 0) {
18032
- console.log(import_chalk24.default.green("\n\u2713 No auto-fixable changes."));
18131
+ console.log(import_chalk25.default.green("\n\u2713 No auto-fixable changes."));
18033
18132
  if (result.stats.needsLLM > 0) {
18034
- console.log(import_chalk24.default.dim(` ${result.stats.needsLLM} issues need LLM rewrite`));
18133
+ console.log(import_chalk25.default.dim(` ${result.stats.needsLLM} issues need LLM rewrite`));
18035
18134
  }
18036
18135
  return;
18037
18136
  }
@@ -18046,42 +18145,42 @@ function registerDiffCommand(program3) {
18046
18145
  const originalLines = text.split("\n");
18047
18146
  const fixedLines = result.fixed.split("\n");
18048
18147
  const contextN = parseInt(options.context, 10);
18049
- console.log(import_chalk24.default.dim(`--- ${filePath}`));
18050
- console.log(import_chalk24.default.dim(`+++ ${filePath} (fixed)`));
18148
+ console.log(import_chalk25.default.dim(`--- ${filePath}`));
18149
+ console.log(import_chalk25.default.dim(`+++ ${filePath} (fixed)`));
18051
18150
  for (const change of result.changes) {
18052
18151
  const lineIdx = change.line - 1;
18053
18152
  const start = Math.max(0, lineIdx - contextN);
18054
18153
  const end = Math.min(originalLines.length, lineIdx + contextN + 1);
18055
- console.log(import_chalk24.default.dim(`@@ -${start + 1},${end - start} +${start + 1},${end - start} @@`));
18154
+ console.log(import_chalk25.default.dim(`@@ -${start + 1},${end - start} +${start + 1},${end - start} @@`));
18056
18155
  for (let i = start; i < end; i++) {
18057
18156
  if (i === lineIdx) {
18058
- console.log(import_chalk24.default.red(`-${originalLines[i]}`));
18059
- console.log(import_chalk24.default.green(`+${fixedLines[i]}`));
18157
+ console.log(import_chalk25.default.red(`-${originalLines[i]}`));
18158
+ console.log(import_chalk25.default.green(`+${fixedLines[i]}`));
18060
18159
  } else {
18061
- console.log(import_chalk24.default.dim(` ${originalLines[i]}`));
18160
+ console.log(import_chalk25.default.dim(` ${originalLines[i]}`));
18062
18161
  }
18063
18162
  }
18064
18163
  }
18065
- console.log(import_chalk24.default.green(`
18164
+ console.log(import_chalk25.default.green(`
18066
18165
  ${result.changes.length} auto-fix${result.changes.length === 1 ? "" : "es"} available`));
18067
- console.log(import_chalk24.default.dim(` run: hyv fix ${file} -i to apply`));
18166
+ console.log(import_chalk25.default.dim(` run: hyv fix ${file} -i to apply`));
18068
18167
  if (options.apply && filePath !== "stdin") {
18069
18168
  const fs30 = require("fs");
18070
18169
  const path27 = require("path");
18071
18170
  const backupPath = filePath + ".bak";
18072
18171
  fs30.copyFileSync(filePath, backupPath);
18073
18172
  fs30.writeFileSync(filePath, result.fixed);
18074
- console.log(import_chalk24.default.green(` \u2713 Applied. Backup: ${path27.basename(backupPath)}`));
18173
+ console.log(import_chalk25.default.green(` \u2713 Applied. Backup: ${path27.basename(backupPath)}`));
18075
18174
  }
18076
18175
  } catch (error) {
18077
- console.error(import_chalk24.default.red(`Error: ${error.message}`));
18176
+ console.error(import_chalk25.default.red(`Error: ${error.message}`));
18078
18177
  process.exit(1);
18079
18178
  }
18080
18179
  });
18081
18180
  }
18082
18181
 
18083
18182
  // src/commands/rules.ts
18084
- var import_chalk25 = __toESM(require_source());
18183
+ var import_chalk26 = __toESM(require_source());
18085
18184
  init_config();
18086
18185
  var RULE_CATALOG = [
18087
18186
  // AI Overused Words
@@ -18175,7 +18274,7 @@ function registerRulesCommand(program3) {
18175
18274
  for (const id of ids)
18176
18275
  disabledRules.delete(id);
18177
18276
  writeConfig({ ...config, disabled_rules: [...disabledRules] });
18178
- console.log(import_chalk25.default.green(`
18277
+ console.log(import_chalk26.default.green(`
18179
18278
  \u2713 Enabled: ${ids.join(", ")}`));
18180
18279
  return;
18181
18280
  }
@@ -18184,13 +18283,13 @@ function registerRulesCommand(program3) {
18184
18283
  for (const id of ids)
18185
18284
  disabledRules.add(id);
18186
18285
  writeConfig({ ...config, disabled_rules: [...disabledRules] });
18187
- console.log(import_chalk25.default.green(`
18286
+ console.log(import_chalk26.default.green(`
18188
18287
  \u2713 Disabled: ${ids.join(", ")}`));
18189
18288
  return;
18190
18289
  }
18191
18290
  if (options.reset) {
18192
18291
  writeConfig({ ...config, disabled_rules: [] });
18193
- console.log(import_chalk25.default.green("\n\u2713 All rules reset to default (enabled)"));
18292
+ console.log(import_chalk26.default.green("\n\u2713 All rules reset to default (enabled)"));
18194
18293
  return;
18195
18294
  }
18196
18295
  let rules = [...RULE_CATALOG];
@@ -18218,34 +18317,34 @@ function registerRulesCommand(program3) {
18218
18317
  }
18219
18318
  console.log("");
18220
18319
  for (const [cat, catRules] of categories) {
18221
- console.log(import_chalk25.default.bold(` ${cat} rules (${catRules.length})
18320
+ console.log(import_chalk26.default.bold(` ${cat} rules (${catRules.length})
18222
18321
  `));
18223
- console.log(import_chalk25.default.dim(" ID Sev AutoFix Status"));
18224
- console.log(import_chalk25.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
18322
+ console.log(import_chalk26.default.dim(" ID Sev AutoFix Status"));
18323
+ console.log(import_chalk26.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
18225
18324
  for (const rule of catRules) {
18226
- const sev = rule.severity === "red" ? import_chalk25.default.red("red") : import_chalk25.default.yellow("yel");
18227
- const fix = rule.autoFixable ? import_chalk25.default.green(" \u2713") : import_chalk25.default.dim(" \u2717");
18228
- const enabled2 = disabledRules.has(rule.id) ? import_chalk25.default.red(" \u2717 disabled") : import_chalk25.default.green(" \u2713 enabled");
18325
+ const sev = rule.severity === "red" ? import_chalk26.default.red("red") : import_chalk26.default.yellow("yel");
18326
+ const fix = rule.autoFixable ? import_chalk26.default.green(" \u2713") : import_chalk26.default.dim(" \u2717");
18327
+ const enabled2 = disabledRules.has(rule.id) ? import_chalk26.default.red(" \u2717 disabled") : import_chalk26.default.green(" \u2713 enabled");
18229
18328
  const id = rule.id.padEnd(24);
18230
- console.log(` ${import_chalk25.default.dim(id)} ${sev} ${fix} ${enabled2}`);
18329
+ console.log(` ${import_chalk26.default.dim(id)} ${sev} ${fix} ${enabled2}`);
18231
18330
  }
18232
18331
  console.log("");
18233
18332
  }
18234
18333
  const enabled = rules.filter((r) => !disabledRules.has(r.id)).length;
18235
18334
  const disabled = rules.length - enabled;
18236
- console.log(import_chalk25.default.dim(` ${rules.length} rules, ${enabled} enabled, ${disabled} disabled`));
18237
- console.log(import_chalk25.default.dim(` toggle: hyv rules --disable <id>`));
18238
- console.log(import_chalk25.default.dim(` reset: hyv rules --reset
18335
+ console.log(import_chalk26.default.dim(` ${rules.length} rules, ${enabled} enabled, ${disabled} disabled`));
18336
+ console.log(import_chalk26.default.dim(` toggle: hyv rules --disable <id>`));
18337
+ console.log(import_chalk26.default.dim(` reset: hyv rules --reset
18239
18338
  `));
18240
18339
  } catch (error) {
18241
- console.error(import_chalk25.default.red(`Error: ${error.message}`));
18340
+ console.error(import_chalk26.default.red(`Error: ${error.message}`));
18242
18341
  process.exit(1);
18243
18342
  }
18244
18343
  });
18245
18344
  }
18246
18345
 
18247
18346
  // src/commands/batch.ts
18248
- var import_chalk26 = __toESM(require_source());
18347
+ var import_chalk27 = __toESM(require_source());
18249
18348
  var fs21 = __toESM(require("fs"));
18250
18349
  var path20 = __toESM(require("path"));
18251
18350
  init_pipeline();
@@ -18260,7 +18359,7 @@ function registerBatchCommand(program3) {
18260
18359
  nodir: true
18261
18360
  });
18262
18361
  if (files.length === 0) {
18263
- console.log(import_chalk26.default.yellow(`
18362
+ console.log(import_chalk27.default.yellow(`
18264
18363
  No files matching: ${pattern}`));
18265
18364
  return;
18266
18365
  }
@@ -18274,7 +18373,7 @@ No files matching: ${pattern}`));
18274
18373
  process.exit(1);
18275
18374
  }
18276
18375
  if (options.format === "text") {
18277
- console.log(import_chalk26.default.dim(`
18376
+ console.log(import_chalk27.default.dim(`
18278
18377
  scanning ${files.length} file${files.length === 1 ? "" : "s"}...
18279
18378
  `));
18280
18379
  }
@@ -18313,23 +18412,23 @@ No files matching: ${pattern}`));
18313
18412
  }
18314
18413
  } else {
18315
18414
  for (const r of results) {
18316
- const icon = r.issues > 0 ? import_chalk26.default.red("\u25CF") : import_chalk26.default.green("\u25CB");
18317
- const score = r.score < 60 ? import_chalk26.default.red(r.score) : r.score < 80 ? import_chalk26.default.yellow(r.score) : import_chalk26.default.green(r.score);
18318
- const issueStr = r.issues > 0 ? import_chalk26.default.red(`${r.issues} issues`) : import_chalk26.default.green("clean");
18415
+ const icon = r.issues > 0 ? import_chalk27.default.red("\u25CF") : import_chalk27.default.green("\u25CB");
18416
+ const score = r.score < 60 ? import_chalk27.default.red(r.score) : r.score < 80 ? import_chalk27.default.yellow(r.score) : import_chalk27.default.green(r.score);
18417
+ const issueStr = r.issues > 0 ? import_chalk27.default.red(`${r.issues} issues`) : import_chalk27.default.green("clean");
18319
18418
  console.log(` ${icon} ${r.file.padEnd(40)} ${issueStr.padEnd(20)} score: ${score}`);
18320
18419
  }
18321
18420
  const withIssues = results.filter((r) => r.issues > 0).length;
18322
18421
  const totalIssues = results.reduce((sum, r) => sum + r.issues, 0);
18323
18422
  const worst = results.reduce((min, r) => r.score < min.score ? r : min, results[0]);
18324
- console.log(import_chalk26.default.dim(`
18423
+ console.log(import_chalk27.default.dim(`
18325
18424
  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`));
18326
- console.log(import_chalk26.default.dim(` ${results.length} files, ${withIssues} with issues, ${totalIssues} total issues`));
18425
+ console.log(import_chalk27.default.dim(` ${results.length} files, ${withIssues} with issues, ${totalIssues} total issues`));
18327
18426
  if (withIssues > 0) {
18328
- console.log(import_chalk26.default.dim(` worst: ${worst.file} (${worst.score}/100)`));
18427
+ console.log(import_chalk27.default.dim(` worst: ${worst.file} (${worst.score}/100)`));
18329
18428
  }
18330
18429
  if (options.fix && options.inPlace) {
18331
18430
  const fixed = results.filter((r) => r.autoFixes > 0);
18332
- console.log(import_chalk26.default.green(`
18431
+ console.log(import_chalk27.default.green(`
18333
18432
  \u2713 ${fixed.reduce((sum, r) => sum + r.autoFixes, 0)} auto-fixes applied across ${fixed.length} files`));
18334
18433
  }
18335
18434
  }
@@ -18341,14 +18440,14 @@ No files matching: ${pattern}`));
18341
18440
  if (belowThreshold)
18342
18441
  process.exit(1);
18343
18442
  } catch (error) {
18344
- console.error(import_chalk26.default.red(`Error: ${error.message}`));
18443
+ console.error(import_chalk27.default.red(`Error: ${error.message}`));
18345
18444
  process.exit(1);
18346
18445
  }
18347
18446
  });
18348
18447
  }
18349
18448
 
18350
18449
  // src/commands/watch.ts
18351
- var import_chalk27 = __toESM(require_source());
18450
+ var import_chalk28 = __toESM(require_source());
18352
18451
  var fs22 = __toESM(require("fs"));
18353
18452
  var path21 = __toESM(require("path"));
18354
18453
  init_pipeline();
@@ -18359,7 +18458,7 @@ function registerWatchCommand(program3) {
18359
18458
  const profile = await loadProfileForCommand(options.profile);
18360
18459
  const absPath = path21.resolve(file);
18361
18460
  if (!fs22.existsSync(absPath)) {
18362
- console.error(import_chalk27.default.red(`File not found: ${absPath}`));
18461
+ console.error(import_chalk28.default.red(`File not found: ${absPath}`));
18363
18462
  process.exit(1);
18364
18463
  }
18365
18464
  if (options.command === "fix") {
@@ -18371,10 +18470,10 @@ function registerWatchCommand(program3) {
18371
18470
  if (!confirmed)
18372
18471
  process.exit(1);
18373
18472
  }
18374
- console.log(import_chalk27.default.dim(`
18473
+ console.log(import_chalk28.default.dim(`
18375
18474
  watching ${absPath}`));
18376
- console.log(import_chalk27.default.dim(`command: ${options.command} debounce: ${options.debounce}ms`));
18377
- console.log(import_chalk27.default.dim("ctrl+c to stop\n"));
18475
+ console.log(import_chalk28.default.dim(`command: ${options.command} debounce: ${options.debounce}ms`));
18476
+ console.log(import_chalk28.default.dim("ctrl+c to stop\n"));
18378
18477
  let debounceTimer = null;
18379
18478
  const debounceMs = parseInt(options.debounce, 10);
18380
18479
  let scanCount = 0;
@@ -18385,38 +18484,38 @@ watching ${absPath}`));
18385
18484
  const result = runPipeline(text, profile, options.command === "fix");
18386
18485
  scanCount++;
18387
18486
  const now = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
18388
- console.log(import_chalk27.default.dim(`[${now}] saved \u2014 ${options.command}ing...`));
18487
+ console.log(import_chalk28.default.dim(`[${now}] saved \u2014 ${options.command}ing...`));
18389
18488
  if (options.command === "score") {
18390
18489
  const score = result.score;
18391
- const color = score < 60 ? import_chalk27.default.red : score < 80 ? import_chalk27.default.yellow : import_chalk27.default.green;
18490
+ const color = score < 60 ? import_chalk28.default.red : score < 80 ? import_chalk28.default.yellow : import_chalk28.default.green;
18392
18491
  console.log(` ${color(score + "/100")}`);
18393
18492
  if (lastScore > 0 && score !== lastScore) {
18394
18493
  const delta = score - lastScore;
18395
- console.log(import_chalk27.default.dim(` ${delta > 0 ? "\u2191" : "\u2193"} ${Math.abs(delta)} from last scan`));
18494
+ console.log(import_chalk28.default.dim(` ${delta > 0 ? "\u2191" : "\u2193"} ${Math.abs(delta)} from last scan`));
18396
18495
  }
18397
18496
  lastScore = score;
18398
18497
  } else if (options.command === "fix") {
18399
18498
  if (result.changes.length > 0) {
18400
18499
  for (const change of result.changes) {
18401
- console.log(import_chalk27.default.dim(` Line ${change.line}: `) + import_chalk27.default.red(change.before) + import_chalk27.default.dim(" \u2192 ") + import_chalk27.default.green(change.after));
18500
+ console.log(import_chalk28.default.dim(` Line ${change.line}: `) + import_chalk28.default.red(change.before) + import_chalk28.default.dim(" \u2192 ") + import_chalk28.default.green(change.after));
18402
18501
  }
18403
18502
  ignoreWatchUntil = Date.now() + debounceMs + 200;
18404
18503
  writeInPlaceWithBackup(absPath, result.fixed);
18405
- console.log(import_chalk27.default.green(` \u2713 ${result.changes.length} auto-fixes applied`));
18504
+ console.log(import_chalk28.default.green(` \u2713 ${result.changes.length} auto-fixes applied`));
18406
18505
  } else {
18407
- console.log(import_chalk27.default.green(" \u2713 no auto-fixable issues"));
18506
+ console.log(import_chalk28.default.green(" \u2713 no auto-fixable issues"));
18408
18507
  }
18409
18508
  } else {
18410
18509
  if (result.stats.totalSignals === 0) {
18411
- console.log(import_chalk27.default.green(` \u2713 clean \u2014 score: ${result.score}/100`));
18510
+ console.log(import_chalk28.default.green(` \u2713 clean \u2014 score: ${result.score}/100`));
18412
18511
  } else {
18413
- console.log(import_chalk27.default.yellow(` ${result.stats.totalSignals} issues (${result.stats.red} red, ${result.stats.yellow} yellow) score: ${result.score}/100`));
18512
+ console.log(import_chalk28.default.yellow(` ${result.stats.totalSignals} issues (${result.stats.red} red, ${result.stats.yellow} yellow) score: ${result.score}/100`));
18414
18513
  for (const signal of result.signalMap.signals.slice(0, 3)) {
18415
- const sev = signal.severity === "red" ? import_chalk27.default.red("\u25CF") : import_chalk27.default.yellow("\u25CB");
18514
+ const sev = signal.severity === "red" ? import_chalk28.default.red("\u25CF") : import_chalk28.default.yellow("\u25CB");
18416
18515
  console.log(` ${sev} line ${signal.line}: ${signal.id} \u2014 ${signal.suggestion}`);
18417
18516
  }
18418
18517
  if (result.signalMap.signals.length > 3) {
18419
- console.log(import_chalk27.default.dim(` ... and ${result.signalMap.signals.length - 3} more`));
18518
+ console.log(import_chalk28.default.dim(` ... and ${result.signalMap.signals.length - 3} more`));
18420
18519
  }
18421
18520
  }
18422
18521
  }
@@ -18433,21 +18532,21 @@ watching ${absPath}`));
18433
18532
  debounceTimer = setTimeout(runScan, debounceMs);
18434
18533
  });
18435
18534
  process.on("SIGINT", () => {
18436
- console.log(import_chalk27.default.dim(`
18535
+ console.log(import_chalk28.default.dim(`
18437
18536
  ${scanCount} scans completed. exiting.`));
18438
18537
  process.exit(0);
18439
18538
  });
18440
18539
  await new Promise(() => {
18441
18540
  });
18442
18541
  } catch (error) {
18443
- console.error(import_chalk27.default.red(`Error: ${error.message}`));
18542
+ console.error(import_chalk28.default.red(`Error: ${error.message}`));
18444
18543
  process.exit(1);
18445
18544
  }
18446
18545
  });
18447
18546
  }
18448
18547
 
18449
18548
  // src/commands/demo.ts
18450
- var import_chalk28 = __toESM(require_source());
18549
+ var import_chalk29 = __toESM(require_source());
18451
18550
  var fs23 = __toESM(require("fs"));
18452
18551
  var SAMPLES = {
18453
18552
  linkedin: {
@@ -18538,52 +18637,52 @@ function registerDemoCommand(program3) {
18538
18637
  const style = options.clean ? "clean" : options.style;
18539
18638
  const sample = SAMPLES[style];
18540
18639
  if (!sample) {
18541
- console.error(import_chalk28.default.red(`Unknown style: ${options.style}. Valid: ${Object.keys(SAMPLES).filter((k2) => k2 !== "clean").join(", ")}`));
18640
+ console.error(import_chalk29.default.red(`Unknown style: ${options.style}. Valid: ${Object.keys(SAMPLES).filter((k2) => k2 !== "clean").join(", ")}`));
18542
18641
  process.exit(1);
18543
18642
  }
18544
18643
  if (options.output) {
18545
18644
  const outputPath = require("path").resolve(options.output);
18546
18645
  fs23.writeFileSync(outputPath, sample.text);
18547
- console.log(import_chalk28.default.green(`
18646
+ console.log(import_chalk29.default.green(`
18548
18647
  \u2713 Sample written to ${outputPath}`));
18549
18648
  if (sample.patterns.length > 0) {
18550
- console.log(import_chalk28.default.dim(` Contains ${sample.patterns.length} AI patterns: ${sample.patterns.slice(0, 5).join(", ")}...`));
18649
+ console.log(import_chalk29.default.dim(` Contains ${sample.patterns.length} AI patterns: ${sample.patterns.slice(0, 5).join(", ")}...`));
18551
18650
  }
18552
- console.log(import_chalk28.default.dim(`
18651
+ console.log(import_chalk29.default.dim(`
18553
18652
  Scan it: hyv scan ${options.output}`));
18554
- console.log(import_chalk28.default.dim(` Fix it: hyv fix ${options.output}`));
18653
+ console.log(import_chalk29.default.dim(` Fix it: hyv fix ${options.output}`));
18555
18654
  } else {
18556
- console.log(import_chalk28.default.bold(`
18655
+ console.log(import_chalk29.default.bold(`
18557
18656
  \u2500\u2500\u2500 sample (${style}) \u2500\u2500\u2500
18558
18657
  `));
18559
18658
  console.log(sample.text);
18560
- console.log(import_chalk28.default.dim(`
18659
+ console.log(import_chalk29.default.dim(`
18561
18660
  \u2500\u2500\u2500 end \u2500\u2500\u2500`));
18562
18661
  if (sample.patterns.length > 0) {
18563
- console.log(import_chalk28.default.dim(`
18662
+ console.log(import_chalk29.default.dim(`
18564
18663
  ${sample.patterns.length} AI patterns embedded: ${sample.patterns.slice(0, 8).join(", ")}...`));
18565
18664
  }
18566
- console.log(import_chalk28.default.dim(`
18665
+ console.log(import_chalk29.default.dim(`
18567
18666
  Save to file: hyv demo --output demo.md`));
18568
- console.log(import_chalk28.default.dim(` Scan it: hyv scan demo.md`));
18569
- console.log(import_chalk28.default.dim(` Fix it: hyv fix demo.md
18667
+ console.log(import_chalk29.default.dim(` Scan it: hyv scan demo.md`));
18668
+ console.log(import_chalk29.default.dim(` Fix it: hyv fix demo.md
18570
18669
  `));
18571
18670
  }
18572
18671
  } catch (error) {
18573
- console.error(import_chalk28.default.red(`Error: ${error.message}`));
18672
+ console.error(import_chalk29.default.red(`Error: ${error.message}`));
18574
18673
  process.exit(1);
18575
18674
  }
18576
18675
  });
18577
18676
  }
18578
18677
 
18579
18678
  // src/commands/open.ts
18580
- var import_chalk29 = __toESM(require_source());
18679
+ var import_chalk30 = __toESM(require_source());
18581
18680
  var PAGES = {
18582
- dashboard: "https://holdyourvoice.com/app",
18583
- profiles: "https://holdyourvoice.com/app",
18584
- pricing: "https://holdyourvoice.com/app/billing",
18585
- settings: "https://holdyourvoice.com/app/settings",
18586
- billing: "https://holdyourvoice.com/app/billing"
18681
+ dashboard: "https://holdyourvoice.com/dashboard",
18682
+ profiles: "https://holdyourvoice.com/dashboard?tab=profiles",
18683
+ pricing: "https://holdyourvoice.com/dashboard?tab=billing",
18684
+ settings: "https://holdyourvoice.com/dashboard",
18685
+ billing: "https://holdyourvoice.com/dashboard?tab=billing"
18587
18686
  };
18588
18687
  function registerOpenCommand(program3) {
18589
18688
  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) => {
@@ -18595,12 +18694,12 @@ function registerOpenCommand(program3) {
18595
18694
  return;
18596
18695
  }
18597
18696
  const open3 = (await Promise.resolve().then(() => __toESM(require_open()))).default;
18598
- console.log(import_chalk29.default.dim(`
18697
+ console.log(import_chalk30.default.dim(`
18599
18698
  Opening ${url}...`));
18600
18699
  await open3(url);
18601
- console.log(import_chalk29.default.green(" \u2713 Opened in browser\n"));
18700
+ console.log(import_chalk30.default.green(" \u2713 Opened in browser\n"));
18602
18701
  } catch (error) {
18603
- console.error(import_chalk29.default.red(`Error: ${error.message}`));
18702
+ console.error(import_chalk30.default.red(`Error: ${error.message}`));
18604
18703
  process.exit(1);
18605
18704
  }
18606
18705
  });
@@ -18686,7 +18785,7 @@ function getWelcomeText(args2) {
18686
18785
  }
18687
18786
 
18688
18787
  // src/commands/content.ts
18689
- var import_chalk30 = __toESM(require_source());
18788
+ var import_chalk31 = __toESM(require_source());
18690
18789
  init_free_paid();
18691
18790
  var TEMPLATES = {
18692
18791
  cursor: {
@@ -18760,62 +18859,28 @@ ${COMMUNITY_URL}`
18760
18859
  function registerContentCommand(program3) {
18761
18860
  program3.command("content").description("Blog outlines, CI snippets, and share templates").argument("[topic]", "cursor | agents | ci | share", "cursor").option("--list", "List available templates").action((topic, opts) => {
18762
18861
  if (opts.list) {
18763
- console.log(import_chalk30.default.bold("\nhyv content templates\n"));
18862
+ console.log(import_chalk31.default.bold("\nhyv content templates\n"));
18764
18863
  for (const [key, t2] of Object.entries(TEMPLATES)) {
18765
- console.log(import_chalk30.default.dim(` ${key}`) + ` \u2014 ${t2.title}`);
18864
+ console.log(import_chalk31.default.dim(` ${key}`) + ` \u2014 ${t2.title}`);
18766
18865
  }
18767
18866
  console.log("");
18768
18867
  return;
18769
18868
  }
18770
18869
  const t = TEMPLATES[topic] || TEMPLATES.cursor;
18771
- console.log(import_chalk30.default.bold(`
18870
+ console.log(import_chalk31.default.bold(`
18772
18871
  ${t.title}
18773
18872
  `));
18774
18873
  console.log(t.body);
18775
- console.log(import_chalk30.default.dim("\nBlog: https://holdyourvoice.com/blog\n"));
18874
+ console.log(import_chalk31.default.dim("\nBlog: https://holdyourvoice.com/blog\n"));
18776
18875
  });
18777
18876
  }
18778
18877
 
18779
18878
  // src/commands/upgrade.ts
18780
- var import_chalk31 = __toESM(require_source());
18781
- var import_child_process4 = require("child_process");
18782
- init_version();
18879
+ init_billing_upgrade();
18783
18880
  function registerUpgradeCommand(program3) {
18784
- program3.command("upgrade").description("Upgrade to the latest @holdyourvoice/hyv").option("--check", "Only check if an update is available").action(async (opts) => {
18785
- const current = getCliVersion();
18786
- console.log(import_chalk31.default.dim(`
18787
- Current: ${getEngineLabel()}
18788
- `));
18789
- let latest = current;
18790
- try {
18791
- const out = (0, import_child_process4.execSync)("npm view @holdyourvoice/hyv version", { encoding: "utf-8", timeout: 15e3 });
18792
- latest = out.trim();
18793
- } catch {
18794
- console.log(import_chalk31.default.yellow("Could not reach npm registry. Try: npm i -g @holdyourvoice/hyv@latest"));
18795
- return;
18796
- }
18797
- const cmp = compareSemver(current, latest);
18798
- if (cmp === 0) {
18799
- console.log(import_chalk31.default.green("\u2713 You are on the latest version."));
18800
- return;
18801
- }
18802
- if (cmp > 0) {
18803
- console.log(import_chalk31.default.green(`\u2713 You are ahead of npm (published: ${latest}).`));
18804
- return;
18805
- }
18806
- console.log(import_chalk31.default.cyan(`Update available: ${current} \u2192 ${latest}`));
18807
- if (opts.check) {
18808
- console.log(import_chalk31.default.dim("\nRun: hyv upgrade or npm i -g @holdyourvoice/hyv@latest\n"));
18809
- return;
18810
- }
18811
- console.log(import_chalk31.default.dim("Installing..."));
18812
- try {
18813
- (0, import_child_process4.execSync)("npm i -g @holdyourvoice/hyv@latest", { stdio: "inherit" });
18814
- console.log(import_chalk31.default.green("\n\u2713 Upgraded successfully. Restart your terminal.\n"));
18815
- } catch {
18816
- console.log(import_chalk31.default.red("\nUpgrade failed. Run manually: npm i -g @holdyourvoice/hyv@latest\n"));
18817
- process.exit(1);
18818
- }
18881
+ program3.command("upgrade").description("Upgrade to a paid plan (opens billing in your browser)").option("--plan <plan>", "Plan to checkout: individual or multiple", "individual").action(async (opts) => {
18882
+ const plan = opts.plan === "multiple" ? "multiple" : "individual";
18883
+ await openBillingUpgrade({ plan });
18819
18884
  });
18820
18885
  }
18821
18886
 
@@ -19506,8 +19571,16 @@ function printMcpSetup() {
19506
19571
  console.log(import_chalk32.default.dim(" Instructions: ~/.codex/AGENTS.md (merged on install)\n"));
19507
19572
  console.log(import_chalk32.default.bold("Command Code"));
19508
19573
  console.log(import_chalk32.default.dim(" Skill: ~/.commandcode/skills/hyv/SKILL.md\n"));
19509
- console.log(import_chalk32.default.bold("ChatGPT"));
19574
+ console.log(import_chalk32.default.bold("ChatGPT Desktop (manual connector)"));
19575
+ console.log(import_chalk32.default.dim(" Settings \u2192 Connectors \u2192 add connector"));
19576
+ console.log(import_chalk32.default.dim(" Name: hold your voice | Command: hyv | Arguments: mcp"));
19577
+ console.log(import_chalk32.default.dim(" Guide: ~/.chatgpt/hyv-mcp-connector.txt (after hyv doctor --fix-agents)"));
19510
19578
  console.log(import_chalk32.default.dim(" hyv mcp --setup-chatgpt\n"));
19579
+ console.log(import_chalk32.default.bold("Antigravity"));
19580
+ console.log(import_chalk32.default.dim(" MCP: ~/.gemini/config/mcp_config.json \u2192 mcpServers.hyv (auto via postinstall)\n"));
19581
+ console.log(import_chalk32.default.bold("OpenCode"));
19582
+ console.log(import_chalk32.default.dim(" MCP: ~/.config/opencode/opencode.jsonc \u2192 mcp.hyv (auto via postinstall)"));
19583
+ console.log(import_chalk32.default.dim(" Rules: ~/.config/opencode/AGENTS.md\n"));
19511
19584
  console.log(import_chalk32.default.bold("Auto-configure"));
19512
19585
  console.log(import_chalk32.default.dim(" hyv doctor --fix-agents"));
19513
19586
  console.log(import_chalk32.default.dim(" HYV_AUTO_CONFIGURE_AGENTS=0 npm i -g @holdyourvoice/hyv (skip)\n"));
@@ -19680,7 +19753,7 @@ async function exportCommand(format, opts) {
19680
19753
  } else {
19681
19754
  console.log(`
19682
19755
  ${c.red("\u2717")} no voice profiles found`);
19683
- console.log(` ${c.dim("create one at")} ${c.cyan("https://holdyourvoice.com/app")}`);
19756
+ console.log(` ${c.dim("create one at")} ${c.cyan("https://holdyourvoice.com/dashboard")}`);
19684
19757
  }
19685
19758
  process.exit(1);
19686
19759
  return;
@@ -19780,15 +19853,24 @@ program2.command("mcp").description("Start MCP server (for Claude Desktop and ot
19780
19853
  return;
19781
19854
  }
19782
19855
  if (opts.setupChatgpt) {
19783
- console.log(import_chalk33.default.bold("\nhold your voice \u2014 chatgpt setup\n"));
19784
- console.log("To connect HYV to ChatGPT:");
19785
- console.log(import_chalk33.default.dim(" 1. Go to ") + import_chalk33.default.cyan("https://chatgpt.com/#settings/Connectors"));
19786
- console.log(import_chalk33.default.dim(" 2. Add a new connector"));
19787
- console.log(import_chalk33.default.dim(" 3. For local MCP, use: ") + import_chalk33.default.cyan("hyv mcp"));
19788
- console.log(import_chalk33.default.dim(" 4. ChatGPT Desktop supports stdio MCP servers"));
19856
+ const home = require("os").homedir();
19857
+ const guide = require("path").join(home, ".chatgpt", "hyv-mcp-connector.txt");
19858
+ console.log(import_chalk33.default.bold("\nhold your voice \u2014 chatgpt desktop mcp setup\n"));
19859
+ console.log("ChatGPT has no auto-config file. Add this connector once in the desktop app:\n");
19860
+ console.log(import_chalk33.default.dim(" 1. Install hyv: ") + import_chalk33.default.cyan("npm i -g @holdyourvoice/hyv@latest && hyv welcome"));
19861
+ console.log(import_chalk33.default.dim(" 2. Open ") + import_chalk33.default.cyan("https://chatgpt.com/#settings/Connectors"));
19862
+ console.log(import_chalk33.default.dim(" 3. Add connector"));
19863
+ console.log(import_chalk33.default.dim(" 4. Name: ") + import_chalk33.default.cyan("hold your voice"));
19864
+ console.log(import_chalk33.default.dim(" 5. Command: ") + import_chalk33.default.cyan("hyv"));
19865
+ console.log(import_chalk33.default.dim(" 6. Arguments: ") + import_chalk33.default.cyan("mcp"));
19866
+ console.log(import_chalk33.default.dim(" 7. Save, restart ChatGPT Desktop, ask: scan this with hold your voice"));
19789
19867
  console.log("");
19790
- console.log(import_chalk33.default.dim("Note: The remote HTTP MCP endpoint is not yet available."));
19791
- console.log(import_chalk33.default.dim("Use the local stdio MCP server with Claude Desktop or Claude Code instead."));
19868
+ if (require("fs").existsSync(guide)) {
19869
+ console.log(import_chalk33.default.dim(`Full guide written to: ${guide}`));
19870
+ } else {
19871
+ console.log(import_chalk33.default.dim("Run hyv doctor --fix-agents to write ~/.chatgpt/hyv-mcp-connector.txt"));
19872
+ }
19873
+ console.log(import_chalk33.default.dim("\nBrowser chatgpt cannot use local MCP \u2014 desktop app only."));
19792
19874
  return;
19793
19875
  }
19794
19876
  startMcpServer();