@holdyourvoice/hyv 2.9.13 → 2.9.15

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
@@ -973,8 +973,8 @@ var require_command = __commonJS({
973
973
  "node_modules/commander/lib/command.js"(exports2) {
974
974
  var EventEmitter = require("node:events").EventEmitter;
975
975
  var childProcess = require("node:child_process");
976
- var path27 = require("node:path");
977
- var fs30 = require("node:fs");
976
+ var path28 = require("node:path");
977
+ var fs31 = require("node:fs");
978
978
  var process2 = require("node:process");
979
979
  var { Argument: Argument2, humanReadableArgName } = require_argument();
980
980
  var { CommanderError: CommanderError2 } = require_error();
@@ -1916,13 +1916,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
1916
1916
  let launchWithNode = false;
1917
1917
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1918
1918
  function findFile(baseDir, baseName) {
1919
- const localBin = path27.resolve(baseDir, baseName);
1920
- if (fs30.existsSync(localBin))
1919
+ const localBin = path28.resolve(baseDir, baseName);
1920
+ if (fs31.existsSync(localBin))
1921
1921
  return localBin;
1922
- if (sourceExt.includes(path27.extname(baseName)))
1922
+ if (sourceExt.includes(path28.extname(baseName)))
1923
1923
  return void 0;
1924
1924
  const foundExt = sourceExt.find(
1925
- (ext) => fs30.existsSync(`${localBin}${ext}`)
1925
+ (ext) => fs31.existsSync(`${localBin}${ext}`)
1926
1926
  );
1927
1927
  if (foundExt)
1928
1928
  return `${localBin}${foundExt}`;
@@ -1935,21 +1935,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
1935
1935
  if (this._scriptPath) {
1936
1936
  let resolvedScriptPath;
1937
1937
  try {
1938
- resolvedScriptPath = fs30.realpathSync(this._scriptPath);
1938
+ resolvedScriptPath = fs31.realpathSync(this._scriptPath);
1939
1939
  } catch (err) {
1940
1940
  resolvedScriptPath = this._scriptPath;
1941
1941
  }
1942
- executableDir = path27.resolve(
1943
- path27.dirname(resolvedScriptPath),
1942
+ executableDir = path28.resolve(
1943
+ path28.dirname(resolvedScriptPath),
1944
1944
  executableDir
1945
1945
  );
1946
1946
  }
1947
1947
  if (executableDir) {
1948
1948
  let localFile = findFile(executableDir, executableFile);
1949
1949
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1950
- const legacyName = path27.basename(
1950
+ const legacyName = path28.basename(
1951
1951
  this._scriptPath,
1952
- path27.extname(this._scriptPath)
1952
+ path28.extname(this._scriptPath)
1953
1953
  );
1954
1954
  if (legacyName !== this._name) {
1955
1955
  localFile = findFile(
@@ -1960,7 +1960,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1960
1960
  }
1961
1961
  executableFile = localFile || executableFile;
1962
1962
  }
1963
- launchWithNode = sourceExt.includes(path27.extname(executableFile));
1963
+ launchWithNode = sourceExt.includes(path28.extname(executableFile));
1964
1964
  let proc;
1965
1965
  if (process2.platform !== "win32") {
1966
1966
  if (launchWithNode) {
@@ -2817,7 +2817,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2817
2817
  * @return {Command}
2818
2818
  */
2819
2819
  nameFromFilename(filename) {
2820
- this._name = path27.basename(filename, path27.extname(filename));
2820
+ this._name = path28.basename(filename, path28.extname(filename));
2821
2821
  return this;
2822
2822
  }
2823
2823
  /**
@@ -2831,10 +2831,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
2831
2831
  * @param {string} [path]
2832
2832
  * @return {(string|null|Command)}
2833
2833
  */
2834
- executableDir(path28) {
2835
- if (path28 === void 0)
2834
+ executableDir(path29) {
2835
+ if (path29 === void 0)
2836
2836
  return this._executableDir;
2837
- this._executableDir = path28;
2837
+ this._executableDir = path29;
2838
2838
  return this;
2839
2839
  }
2840
2840
  /**
@@ -3934,15 +3934,15 @@ var require_route = __commonJS({
3934
3934
  };
3935
3935
  }
3936
3936
  function wrapConversion(toModel, graph) {
3937
- const path27 = [graph[toModel].parent, toModel];
3937
+ const path28 = [graph[toModel].parent, toModel];
3938
3938
  let fn = conversions[graph[toModel].parent][toModel];
3939
3939
  let cur = graph[toModel].parent;
3940
3940
  while (graph[cur].parent) {
3941
- path27.unshift(graph[cur].parent);
3941
+ path28.unshift(graph[cur].parent);
3942
3942
  fn = link(conversions[graph[cur].parent][cur], fn);
3943
3943
  cur = graph[cur].parent;
3944
3944
  }
3945
- fn.conversion = path27;
3945
+ fn.conversion = path28;
3946
3946
  return fn;
3947
3947
  }
3948
3948
  module2.exports = function(fromModel) {
@@ -4182,7 +4182,7 @@ var require_has_flag = __commonJS({
4182
4182
  var require_supports_color = __commonJS({
4183
4183
  "node_modules/supports-color/index.js"(exports2, module2) {
4184
4184
  "use strict";
4185
- var os13 = require("os");
4185
+ var os15 = require("os");
4186
4186
  var tty = require("tty");
4187
4187
  var hasFlag = require_has_flag();
4188
4188
  var { env } = process;
@@ -4230,7 +4230,7 @@ var require_supports_color = __commonJS({
4230
4230
  return min;
4231
4231
  }
4232
4232
  if (process.platform === "win32") {
4233
- const osRelease = os13.release().split(".");
4233
+ const osRelease = os15.release().split(".");
4234
4234
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
4235
4235
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
4236
4236
  }
@@ -4381,14 +4381,14 @@ var require_templates = __commonJS({
4381
4381
  }
4382
4382
  return results;
4383
4383
  }
4384
- function buildStyle(chalk34, styles) {
4384
+ function buildStyle(chalk35, styles) {
4385
4385
  const enabled = {};
4386
4386
  for (const layer of styles) {
4387
4387
  for (const style of layer.styles) {
4388
4388
  enabled[style[0]] = layer.inverse ? null : style.slice(1);
4389
4389
  }
4390
4390
  }
4391
- let current = chalk34;
4391
+ let current = chalk35;
4392
4392
  for (const [styleName, styles2] of Object.entries(enabled)) {
4393
4393
  if (!Array.isArray(styles2)) {
4394
4394
  continue;
@@ -4400,7 +4400,7 @@ var require_templates = __commonJS({
4400
4400
  }
4401
4401
  return current;
4402
4402
  }
4403
- module2.exports = (chalk34, temporary) => {
4403
+ module2.exports = (chalk35, temporary) => {
4404
4404
  const styles = [];
4405
4405
  const chunks = [];
4406
4406
  let chunk = [];
@@ -4410,13 +4410,13 @@ var require_templates = __commonJS({
4410
4410
  } else if (style) {
4411
4411
  const string = chunk.join("");
4412
4412
  chunk = [];
4413
- chunks.push(styles.length === 0 ? string : buildStyle(chalk34, styles)(string));
4413
+ chunks.push(styles.length === 0 ? string : buildStyle(chalk35, styles)(string));
4414
4414
  styles.push({ inverse, styles: parseStyle(style) });
4415
4415
  } else if (close) {
4416
4416
  if (styles.length === 0) {
4417
4417
  throw new Error("Found extraneous } in Chalk template literal");
4418
4418
  }
4419
- chunks.push(buildStyle(chalk34, styles)(chunk.join("")));
4419
+ chunks.push(buildStyle(chalk35, styles)(chunk.join("")));
4420
4420
  chunk = [];
4421
4421
  styles.pop();
4422
4422
  } else {
@@ -4464,16 +4464,16 @@ var require_source = __commonJS({
4464
4464
  }
4465
4465
  };
4466
4466
  var chalkFactory = (options) => {
4467
- const chalk35 = {};
4468
- applyOptions(chalk35, options);
4469
- chalk35.template = (...arguments_) => chalkTag(chalk35.template, ...arguments_);
4470
- Object.setPrototypeOf(chalk35, Chalk.prototype);
4471
- Object.setPrototypeOf(chalk35.template, chalk35);
4472
- chalk35.template.constructor = () => {
4467
+ const chalk36 = {};
4468
+ applyOptions(chalk36, options);
4469
+ chalk36.template = (...arguments_) => chalkTag(chalk36.template, ...arguments_);
4470
+ Object.setPrototypeOf(chalk36, Chalk.prototype);
4471
+ Object.setPrototypeOf(chalk36.template, chalk36);
4472
+ chalk36.template.constructor = () => {
4473
4473
  throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.");
4474
4474
  };
4475
- chalk35.template.Instance = ChalkClass;
4476
- return chalk35.template;
4475
+ chalk36.template.Instance = ChalkClass;
4476
+ return chalk36.template;
4477
4477
  };
4478
4478
  function Chalk(options) {
4479
4479
  return chalkFactory(options);
@@ -4584,7 +4584,7 @@ var require_source = __commonJS({
4584
4584
  return openAll + string + closeAll;
4585
4585
  };
4586
4586
  var template;
4587
- var chalkTag = (chalk35, ...strings) => {
4587
+ var chalkTag = (chalk36, ...strings) => {
4588
4588
  const [firstString] = strings;
4589
4589
  if (!isArray(firstString) || !isArray(firstString.raw)) {
4590
4590
  return strings.join(" ");
@@ -4600,14 +4600,14 @@ var require_source = __commonJS({
4600
4600
  if (template === void 0) {
4601
4601
  template = require_templates();
4602
4602
  }
4603
- return template(chalk35, parts.join(""));
4603
+ return template(chalk36, parts.join(""));
4604
4604
  };
4605
4605
  Object.defineProperties(Chalk.prototype, styles);
4606
- var chalk34 = Chalk();
4607
- chalk34.supportsColor = stdoutColor;
4608
- chalk34.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 });
4609
- chalk34.stderr.supportsColor = stderrColor;
4610
- module2.exports = chalk34;
4606
+ var chalk35 = Chalk();
4607
+ chalk35.supportsColor = stdoutColor;
4608
+ chalk35.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 });
4609
+ chalk35.stderr.supportsColor = stderrColor;
4610
+ module2.exports = chalk35;
4611
4611
  }
4612
4612
  });
4613
4613
 
@@ -4990,11 +4990,11 @@ var init_config = __esm({
4990
4990
  var require_is_docker = __commonJS({
4991
4991
  "node_modules/is-docker/index.js"(exports2, module2) {
4992
4992
  "use strict";
4993
- var fs30 = require("fs");
4993
+ var fs31 = require("fs");
4994
4994
  var isDocker;
4995
4995
  function hasDockerEnv() {
4996
4996
  try {
4997
- fs30.statSync("/.dockerenv");
4997
+ fs31.statSync("/.dockerenv");
4998
4998
  return true;
4999
4999
  } catch (_2) {
5000
5000
  return false;
@@ -5002,7 +5002,7 @@ var require_is_docker = __commonJS({
5002
5002
  }
5003
5003
  function hasDockerCGroup() {
5004
5004
  try {
5005
- return fs30.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
5005
+ return fs31.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
5006
5006
  } catch (_2) {
5007
5007
  return false;
5008
5008
  }
@@ -5020,21 +5020,21 @@ var require_is_docker = __commonJS({
5020
5020
  var require_is_wsl = __commonJS({
5021
5021
  "node_modules/is-wsl/index.js"(exports2, module2) {
5022
5022
  "use strict";
5023
- var os13 = require("os");
5024
- var fs30 = require("fs");
5023
+ var os15 = require("os");
5024
+ var fs31 = require("fs");
5025
5025
  var isDocker = require_is_docker();
5026
5026
  var isWsl = () => {
5027
5027
  if (process.platform !== "linux") {
5028
5028
  return false;
5029
5029
  }
5030
- if (os13.release().toLowerCase().includes("microsoft")) {
5030
+ if (os15.release().toLowerCase().includes("microsoft")) {
5031
5031
  if (isDocker()) {
5032
5032
  return false;
5033
5033
  }
5034
5034
  return true;
5035
5035
  }
5036
5036
  try {
5037
- return fs30.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isDocker() : false;
5037
+ return fs31.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isDocker() : false;
5038
5038
  } catch (_2) {
5039
5039
  return false;
5040
5040
  }
@@ -5073,17 +5073,17 @@ var require_define_lazy_prop = __commonJS({
5073
5073
  // node_modules/open/index.js
5074
5074
  var require_open = __commonJS({
5075
5075
  "node_modules/open/index.js"(exports2, module2) {
5076
- var path27 = require("path");
5076
+ var path28 = require("path");
5077
5077
  var childProcess = require("child_process");
5078
- var { promises: fs30, constants: fsConstants } = require("fs");
5078
+ var { promises: fs31, constants: fsConstants } = require("fs");
5079
5079
  var isWsl = require_is_wsl();
5080
5080
  var isDocker = require_is_docker();
5081
5081
  var defineLazyProperty = require_define_lazy_prop();
5082
- var localXdgOpenPath = path27.join(__dirname, "xdg-open");
5082
+ var localXdgOpenPath = path28.join(__dirname, "xdg-open");
5083
5083
  var { platform, arch } = process;
5084
5084
  var hasContainerEnv = () => {
5085
5085
  try {
5086
- fs30.statSync("/run/.containerenv");
5086
+ fs31.statSync("/run/.containerenv");
5087
5087
  return true;
5088
5088
  } catch {
5089
5089
  return false;
@@ -5106,14 +5106,14 @@ var require_open = __commonJS({
5106
5106
  const configFilePath = "/etc/wsl.conf";
5107
5107
  let isConfigFileExists = false;
5108
5108
  try {
5109
- await fs30.access(configFilePath, fsConstants.F_OK);
5109
+ await fs31.access(configFilePath, fsConstants.F_OK);
5110
5110
  isConfigFileExists = true;
5111
5111
  } catch {
5112
5112
  }
5113
5113
  if (!isConfigFileExists) {
5114
5114
  return defaultMountPoint;
5115
5115
  }
5116
- const configContent = await fs30.readFile(configFilePath, { encoding: "utf8" });
5116
+ const configContent = await fs31.readFile(configFilePath, { encoding: "utf8" });
5117
5117
  const configMountPoint = /(?<!#.*)root\s*=\s*(?<mountPoint>.*)/g.exec(configContent);
5118
5118
  if (!configMountPoint) {
5119
5119
  return defaultMountPoint;
@@ -5213,7 +5213,7 @@ var require_open = __commonJS({
5213
5213
  const isBundled = !__dirname || __dirname === "/";
5214
5214
  let exeLocalXdgOpen = false;
5215
5215
  try {
5216
- await fs30.access(localXdgOpenPath, fsConstants.X_OK);
5216
+ await fs31.access(localXdgOpenPath, fsConstants.X_OK);
5217
5217
  exeLocalXdgOpen = true;
5218
5218
  } catch {
5219
5219
  }
@@ -5236,14 +5236,14 @@ var require_open = __commonJS({
5236
5236
  }
5237
5237
  const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
5238
5238
  if (options.wait) {
5239
- return new Promise((resolve15, reject) => {
5239
+ return new Promise((resolve16, reject) => {
5240
5240
  subprocess.once("error", reject);
5241
5241
  subprocess.once("close", (exitCode) => {
5242
5242
  if (!options.allowNonzeroExitCode && exitCode > 0) {
5243
5243
  reject(new Error(`Exited with code ${exitCode}`));
5244
5244
  return;
5245
5245
  }
5246
- resolve15(subprocess);
5246
+ resolve16(subprocess);
5247
5247
  });
5248
5248
  });
5249
5249
  }
@@ -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/dashboard?tab=billing";
5409
+ DASHBOARD_BILLING_URL = "https://holdyourvoice.com/app/billing";
5410
5410
  }
5411
5411
  });
5412
5412
 
@@ -5459,16 +5459,16 @@ function compareSemver(a, b) {
5459
5459
  return 0;
5460
5460
  }
5461
5461
  function fetchLatestNpmVersion(timeoutMs = 8e3) {
5462
- return new Promise((resolve15) => {
5462
+ return new Promise((resolve16) => {
5463
5463
  (0, import_child_process.execFile)(
5464
5464
  "npm",
5465
5465
  ["view", "@holdyourvoice/hyv", "version"],
5466
5466
  { timeout: timeoutMs, encoding: "utf-8" },
5467
5467
  (err, stdout) => {
5468
5468
  if (err || !stdout?.trim())
5469
- resolve15(null);
5469
+ resolve16(null);
5470
5470
  else
5471
- resolve15(stdout.trim());
5471
+ resolve16(stdout.trim());
5472
5472
  }
5473
5473
  );
5474
5474
  });
@@ -5533,7 +5533,7 @@ function escapeHtml(value) {
5533
5533
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
5534
5534
  }
5535
5535
  function request(url, options = {}) {
5536
- return new Promise((resolve15, reject) => {
5536
+ return new Promise((resolve16, reject) => {
5537
5537
  const urlObj = new URL(url);
5538
5538
  const isHttps = urlObj.protocol === "https:";
5539
5539
  const client = isHttps ? https : http;
@@ -5554,9 +5554,9 @@ function request(url, options = {}) {
5554
5554
  res.on("data", (chunk) => data += chunk);
5555
5555
  res.on("end", () => {
5556
5556
  try {
5557
- resolve15({ status: res.statusCode || 0, data: JSON.parse(data) });
5557
+ resolve16({ status: res.statusCode || 0, data: JSON.parse(data) });
5558
5558
  } catch {
5559
- resolve15({ status: res.statusCode || 0, data });
5559
+ resolve16({ status: res.statusCode || 0, data });
5560
5560
  }
5561
5561
  });
5562
5562
  });
@@ -5614,9 +5614,9 @@ async function authenticateWithLicense(licenseKey) {
5614
5614
  }
5615
5615
  async function authenticateWithBrowser() {
5616
5616
  const server = http.createServer();
5617
- const port = await new Promise((resolve15) => {
5617
+ const port = await new Promise((resolve16) => {
5618
5618
  server.listen(0, "127.0.0.1", () => {
5619
- resolve15(server.address().port);
5619
+ resolve16(server.address().port);
5620
5620
  });
5621
5621
  });
5622
5622
  const redirectUri = `http://127.0.0.1:${port}/callback`;
@@ -5635,7 +5635,7 @@ async function authenticateWithBrowser() {
5635
5635
  }
5636
5636
  console.log(import_chalk2.default.cyan("\nOpening browser for authentication..."));
5637
5637
  await (0, import_open.default)(assertSafeOAuthUrl(auth_url));
5638
- const authData = await new Promise((resolve15, reject) => {
5638
+ const authData = await new Promise((resolve16, reject) => {
5639
5639
  const timeout = setTimeout(() => {
5640
5640
  server.close();
5641
5641
  reject(new Error("Authentication timeout. Please try again."));
@@ -5692,7 +5692,7 @@ async function authenticateWithBrowser() {
5692
5692
  `);
5693
5693
  clearTimeout(timeout);
5694
5694
  server.close();
5695
- resolve15(data);
5695
+ resolve16(data);
5696
5696
  } catch (error) {
5697
5697
  res.writeHead(500, { "Content-Type": "text/html" });
5698
5698
  res.end(`<h1>Authentication failed</h1><p>${escapeHtml(error.message)}</p>`);
@@ -5710,7 +5710,7 @@ async function authenticateWithBrowser() {
5710
5710
  return authData;
5711
5711
  }
5712
5712
  async function openAuthenticatedDashboard(opts = {}) {
5713
- const nextPath = opts.next || "/dashboard?tab=billing";
5713
+ const nextPath = opts.next || "/app/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 === "/dashboard?tab=billing" || nextPath === "/app/billing" ? DASHBOARD_BILLING_URL : assertSafeOpenUrl(`https://holdyourvoice.com${nextPath}`);
5728
+ const billingUrl = 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) {
@@ -5854,17 +5854,11 @@ var init_telemetry = __esm({
5854
5854
  });
5855
5855
 
5856
5856
  // src/lib/api.ts
5857
- var api_exports = {};
5858
- __export(api_exports, {
5859
- apiGet: () => apiGet,
5860
- apiPost: () => apiPost,
5861
- requireSubscription: () => requireSubscription
5862
- });
5863
- async function request2(method, path27, body) {
5857
+ async function request2(method, path28, body) {
5864
5858
  const token = await getValidToken();
5865
5859
  if (!token)
5866
5860
  throw new Error("you're not signed in yet. run: hyv init");
5867
- const url = `${API_BASE}${path27}`;
5861
+ const url = `${API_BASE}${path28}`;
5868
5862
  const opts = {
5869
5863
  method,
5870
5864
  headers: {
@@ -5883,21 +5877,17 @@ async function request2(method, path27, body) {
5883
5877
  if (res.status === 401)
5884
5878
  throw new Error("your session expired. run: hyv init to sign in again.");
5885
5879
  if (res.status === 403)
5886
- throw new Error("you don't have access to this feature. check your plan at holdyourvoice.com/dashboard?tab=billing");
5880
+ throw new Error("you don't have access to this feature. check your plan at holdyourvoice.com/app/billing");
5887
5881
  if (!res.ok) {
5888
5882
  throw new Error(`something went wrong (${res.status}). try again or contact support.`);
5889
5883
  }
5890
5884
  return res.json();
5891
5885
  }
5892
- function apiGet(path27) {
5893
- return request2("GET", path27);
5894
- }
5895
- function apiPost(path27, body) {
5896
- return request2("POST", path27, body);
5886
+ function apiGet(path28) {
5887
+ return request2("GET", path28);
5897
5888
  }
5898
- async function requireSubscription() {
5899
- const { requirePaidFeature: requirePaidFeature2 } = await Promise.resolve().then(() => (init_access(), access_exports));
5900
- await requirePaidFeature2("profiles");
5889
+ function apiPost(path28, body) {
5890
+ return request2("POST", path28, body);
5901
5891
  }
5902
5892
  var init_api = __esm({
5903
5893
  "src/lib/api.ts"() {
@@ -5907,128 +5897,6 @@ var init_api = __esm({
5907
5897
  }
5908
5898
  });
5909
5899
 
5910
- // src/lib/access.ts
5911
- var access_exports = {};
5912
- __export(access_exports, {
5913
- formatModeLabel: () => formatModeLabel,
5914
- getAccessState: () => getAccessState,
5915
- isLocalOnlyMode: () => isLocalOnlyMode,
5916
- maybeShowLimitedModeHint: () => maybeShowLimitedModeHint,
5917
- requirePaidFeature: () => requirePaidFeature,
5918
- setLocalOnlyMode: () => setLocalOnlyMode
5919
- });
5920
- function setLocalOnlyMode(enabled) {
5921
- localOnlyOverride = enabled;
5922
- }
5923
- function isLocalOnlyMode() {
5924
- if (localOnlyOverride)
5925
- return true;
5926
- const env = process.env.HYV_LOCAL_ONLY;
5927
- return env === "1" || env === "true";
5928
- }
5929
- async function getAccessState() {
5930
- if (isLocalOnlyMode()) {
5931
- return { authenticated: false, hasPaidPlan: false, plan: "local", localOnly: true };
5932
- }
5933
- const now = Date.now();
5934
- if (cachedAccess && now - cachedAccess.at < ACCESS_CACHE_MS) {
5935
- return cachedAccess.state;
5936
- }
5937
- const token = getToken();
5938
- if (!token) {
5939
- const state = { authenticated: false, hasPaidPlan: false, plan: "none", localOnly: false };
5940
- cachedAccess = { state, at: now };
5941
- return state;
5942
- }
5943
- try {
5944
- const session = await checkSession();
5945
- const plan = (session.plan || "none").toLowerCase();
5946
- const hasPaidPlan = session.valid && plan !== "none" && plan !== "free" && plan !== "expired" && plan !== "unknown";
5947
- const state = {
5948
- authenticated: session.valid,
5949
- hasPaidPlan,
5950
- plan: session.plan || "none",
5951
- localOnly: false
5952
- };
5953
- cachedAccess = { state, at: now };
5954
- return state;
5955
- } catch {
5956
- const state = { authenticated: !!token, hasPaidPlan: false, plan: "unknown", localOnly: false };
5957
- cachedAccess = { state, at: now };
5958
- return state;
5959
- }
5960
- }
5961
- async function requirePaidFeature(feature) {
5962
- if (isLocalOnlyMode()) {
5963
- throw new Error(
5964
- `${FEATURE_MESSAGES[feature]} (local-only mode is on \u2014 unset HYV_LOCAL_ONLY or remove --local-only)`
5965
- );
5966
- }
5967
- const token = getToken();
5968
- if (!token) {
5969
- throw new Error(`you're not signed in yet. run: hyv init \u2014 then ${FEATURE_MESSAGES[feature]}`);
5970
- }
5971
- let data;
5972
- try {
5973
- data = await apiGet("/cli/heartbeat");
5974
- } catch (err) {
5975
- const msg = err.message || "";
5976
- if (msg.includes("not signed in") || msg.includes("session expired") || msg.includes("don't have access")) {
5977
- throw err;
5978
- }
5979
- throw new Error("can't reach the server. check your internet connection and try again.");
5980
- }
5981
- const plan = (data.plan || "none").toLowerCase();
5982
- const subStatus = String(data.subscription_status || data.status || "").toLowerCase();
5983
- if (!data.plan || plan === "none" || plan === "free" || plan === "expired" || subStatus === "trialing" || subStatus === "none") {
5984
- throw new Error(FEATURE_MESSAGES[feature]);
5985
- }
5986
- }
5987
- async function maybeShowLimitedModeHint(hasProfile) {
5988
- if (isLocalOnlyMode())
5989
- return;
5990
- const access = await getAccessState();
5991
- if (access.hasPaidPlan)
5992
- return;
5993
- if (hasProfile) {
5994
- console.log(import_chalk5.default.dim("\n using cached profile (local). sync for latest: hyv sync"));
5995
- } else if (!access.authenticated) {
5996
- console.log(import_chalk5.default.dim("\n local mode \u2014 free scan engine. profiles + learning: hyv init"));
5997
- } else {
5998
- console.log(import_chalk5.default.dim("\n local mode \u2014 upgrade for full profiles + learning: hyv upgrade"));
5999
- }
6000
- }
6001
- function formatModeLabel(access, hasFullProfile) {
6002
- if (access.localOnly)
6003
- return "local-only (forced)";
6004
- if (access.hasPaidPlan && hasFullProfile)
6005
- return "full profile (paid)";
6006
- if (hasFullProfile)
6007
- return "cached profile (local)";
6008
- if (access.authenticated)
6009
- return "local engine (free)";
6010
- return "local engine (free, not signed in)";
6011
- }
6012
- var import_chalk5, FEATURE_MESSAGES, localOnlyOverride, cachedAccess, ACCESS_CACHE_MS;
6013
- var init_access = __esm({
6014
- "src/lib/access.ts"() {
6015
- "use strict";
6016
- import_chalk5 = __toESM(require_source());
6017
- init_config();
6018
- init_auth();
6019
- init_api();
6020
- FEATURE_MESSAGES = {
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"
6025
- };
6026
- localOnlyOverride = false;
6027
- cachedAccess = null;
6028
- ACCESS_CACHE_MS = 3e4;
6029
- }
6030
- });
6031
-
6032
5900
  // src/lib/profile.ts
6033
5901
  async function loadFullProfile(slug, opts = {}) {
6034
5902
  const includeSamples = opts.includeSamples !== false;
@@ -6240,8 +6108,12 @@ function countLearnedPatterns(slug) {
6240
6108
  async function loadProfileForCommand(name, opts = {}) {
6241
6109
  const config = readConfig();
6242
6110
  const candidates = [];
6243
- if (name)
6111
+ if (name) {
6244
6112
  candidates.push(name);
6113
+ const normalized = toSafeProfileCacheKey(name);
6114
+ if (normalized !== name)
6115
+ candidates.push(normalized);
6116
+ }
6245
6117
  if (config.default_profile)
6246
6118
  candidates.push(config.default_profile);
6247
6119
  if (config.profile)
@@ -6292,6 +6164,250 @@ var init_local_profile = __esm({
6292
6164
  }
6293
6165
  });
6294
6166
 
6167
+ // src/lib/mcp-profile-hydrate.ts
6168
+ var mcp_profile_hydrate_exports = {};
6169
+ __export(mcp_profile_hydrate_exports, {
6170
+ ensureMcpProfilesHydrated: () => ensureMcpProfilesHydrated,
6171
+ formatMcpProfilesList: () => formatMcpProfilesList,
6172
+ normalizeProfileSlug: () => normalizeProfileSlug
6173
+ });
6174
+ function normalizeProfileSlug(name) {
6175
+ return toSafeProfileCacheKey(name);
6176
+ }
6177
+ async function ensureMcpProfilesHydrated(opts = {}) {
6178
+ if (process.env.VITEST) {
6179
+ return { ok: true, synced: [], skipped: true };
6180
+ }
6181
+ if (!getToken()) {
6182
+ return { ok: true, synced: [], skipped: true };
6183
+ }
6184
+ const now = Date.now();
6185
+ if (!opts.force && now - lastHydrateAt < HYDRATE_TTL_MS) {
6186
+ return { ok: true, synced: [], skipped: true };
6187
+ }
6188
+ if (hydrateInFlight && !opts.force) {
6189
+ return hydrateInFlight;
6190
+ }
6191
+ hydrateInFlight = runHydrate().then((result) => {
6192
+ lastHydrateAt = Date.now();
6193
+ return result;
6194
+ }).finally(() => {
6195
+ hydrateInFlight = null;
6196
+ });
6197
+ return hydrateInFlight;
6198
+ }
6199
+ async function runHydrate() {
6200
+ const synced = [];
6201
+ try {
6202
+ const data = await apiGet("/cli/profiles");
6203
+ const profiles = data.profiles || [];
6204
+ if (profiles.length === 0) {
6205
+ return { ok: true, synced: [] };
6206
+ }
6207
+ let defaultSlug;
6208
+ for (const row of profiles) {
6209
+ const slug = normalizeProfileSlug(row.slug || row.name);
6210
+ if (row.is_default)
6211
+ defaultSlug = slug;
6212
+ try {
6213
+ const detail = await apiGet(`/cli/profiles/${encodeURIComponent(slug)}`);
6214
+ const content = (detail.content || "").trim();
6215
+ if (content) {
6216
+ writeCachedProfile(slug, content);
6217
+ if (!synced.includes(slug))
6218
+ synced.push(slug);
6219
+ }
6220
+ await loadFullProfile(slug, {
6221
+ forceRefresh: true,
6222
+ serverUpdatedAt: row.updated_at || detail.updated_at
6223
+ });
6224
+ } catch {
6225
+ }
6226
+ }
6227
+ const config = readConfig();
6228
+ const localNames = /* @__PURE__ */ new Set([...listCachedProfiles(), ...listDiskCachedProfiles()]);
6229
+ const shouldSetDefault = defaultSlug && (!config.default_profile || !localNames.has(config.default_profile));
6230
+ if (shouldSetDefault && defaultSlug) {
6231
+ writeConfig({ ...config, default_profile: defaultSlug, profile: defaultSlug });
6232
+ }
6233
+ return { ok: true, synced, defaultProfile: defaultSlug || config.default_profile };
6234
+ } catch (err) {
6235
+ const message = err instanceof Error ? err.message : "profile sync failed";
6236
+ return { ok: false, synced, error: message };
6237
+ }
6238
+ }
6239
+ function formatMcpProfilesList(hydrate) {
6240
+ const config = readConfig();
6241
+ const local = [.../* @__PURE__ */ new Set([...listCachedProfiles(), ...listDiskCachedProfiles()])].sort();
6242
+ const active = config.default_profile || config.profile;
6243
+ const lines = ["### Voice profiles (MCP-ready)"];
6244
+ if (active && local.includes(active)) {
6245
+ lines.push(`Active default: **${active}** \u2014 hyv_scan / hyv_rewrite / hyv_clean use this unless you pass \`profile\`.`);
6246
+ } else if (local.length === 1) {
6247
+ lines.push(`Active default: **${local[0]}** (only local profile).`);
6248
+ } else if (local.length > 1) {
6249
+ lines.push("No default set \u2014 pass `profile` on tools, or run `hyv init` + create a default in the dashboard.");
6250
+ }
6251
+ if (local.length > 0) {
6252
+ lines.push("");
6253
+ lines.push("Local (ready for MCP tools now):");
6254
+ for (const name of local) {
6255
+ const mark = name === active ? " (default)" : "";
6256
+ lines.push(` \u2022 ${name}${mark}`);
6257
+ }
6258
+ } else {
6259
+ lines.push("");
6260
+ lines.push("No local profiles yet.");
6261
+ }
6262
+ if (!getToken()) {
6263
+ lines.push("");
6264
+ lines.push("Account profiles (dashboard / web): run **`hyv init`** once on this machine \u2014 MCP will auto-download them here.");
6265
+ lines.push("Terminal welcome (`hyv welcome`) saves locally immediately; no init needed for that path.");
6266
+ return lines.join("\n");
6267
+ }
6268
+ if (hydrate?.synced?.length) {
6269
+ lines.push("");
6270
+ lines.push(`Just synced from your account: ${hydrate.synced.join(", ")}`);
6271
+ } else if (hydrate?.error) {
6272
+ lines.push("");
6273
+ lines.push(`Account sync note: ${hydrate.error}`);
6274
+ } else if (local.length === 0 && hydrate?.skipped) {
6275
+ lines.push("");
6276
+ lines.push("Signed in \u2014 checking account\u2026 if profiles exist on holdyourvoice.com, they load automatically.");
6277
+ }
6278
+ lines.push("");
6279
+ lines.push("Same profile everywhere: build in **dashboard** or **`hyv welcome`**, then use MCP tools with no extra setup (after `hyv init` for dashboard-only profiles).");
6280
+ return lines.join("\n");
6281
+ }
6282
+ var lastHydrateAt, hydrateInFlight, HYDRATE_TTL_MS;
6283
+ var init_mcp_profile_hydrate = __esm({
6284
+ "src/lib/mcp-profile-hydrate.ts"() {
6285
+ "use strict";
6286
+ init_config();
6287
+ init_api();
6288
+ init_profile();
6289
+ init_local_profile();
6290
+ lastHydrateAt = 0;
6291
+ hydrateInFlight = null;
6292
+ HYDRATE_TTL_MS = 5 * 60 * 1e3;
6293
+ }
6294
+ });
6295
+
6296
+ // src/lib/access.ts
6297
+ function setLocalOnlyMode(enabled) {
6298
+ localOnlyOverride = enabled;
6299
+ }
6300
+ function isLocalOnlyMode() {
6301
+ if (localOnlyOverride)
6302
+ return true;
6303
+ const env = process.env.HYV_LOCAL_ONLY;
6304
+ return env === "1" || env === "true";
6305
+ }
6306
+ async function getAccessState() {
6307
+ if (isLocalOnlyMode()) {
6308
+ return { authenticated: false, hasPaidPlan: false, plan: "local", localOnly: true };
6309
+ }
6310
+ const now = Date.now();
6311
+ if (cachedAccess && now - cachedAccess.at < ACCESS_CACHE_MS) {
6312
+ return cachedAccess.state;
6313
+ }
6314
+ const token = getToken();
6315
+ if (!token) {
6316
+ const state = { authenticated: false, hasPaidPlan: false, plan: "none", localOnly: false };
6317
+ cachedAccess = { state, at: now };
6318
+ return state;
6319
+ }
6320
+ try {
6321
+ const session = await checkSession();
6322
+ const plan = (session.plan || "none").toLowerCase();
6323
+ const subStatus = String(session.subscription_status || "").toLowerCase();
6324
+ const activeSubscription = !subStatus || ["active", "past_due", "trialing"].includes(subStatus);
6325
+ const hasPaidPlan = session.valid && activeSubscription && plan !== "none" && plan !== "free" && plan !== "expired" && plan !== "unknown" && plan !== "pending";
6326
+ const state = {
6327
+ authenticated: session.valid,
6328
+ hasPaidPlan,
6329
+ plan: session.plan || "none",
6330
+ localOnly: false
6331
+ };
6332
+ cachedAccess = { state, at: now };
6333
+ return state;
6334
+ } catch {
6335
+ const state = { authenticated: !!token, hasPaidPlan: false, plan: "unknown", localOnly: false };
6336
+ cachedAccess = { state, at: now };
6337
+ return state;
6338
+ }
6339
+ }
6340
+ async function requirePaidFeature(feature) {
6341
+ if (isLocalOnlyMode()) {
6342
+ throw new Error(
6343
+ `${FEATURE_MESSAGES[feature]} (local-only mode is on \u2014 unset HYV_LOCAL_ONLY or remove --local-only)`
6344
+ );
6345
+ }
6346
+ const token = getToken();
6347
+ if (!token) {
6348
+ throw new Error(`you're not signed in yet. run: hyv init \u2014 then ${FEATURE_MESSAGES[feature]}`);
6349
+ }
6350
+ let data;
6351
+ try {
6352
+ data = await apiGet("/cli/heartbeat");
6353
+ } catch (err) {
6354
+ const msg = err.message || "";
6355
+ if (msg.includes("not signed in") || msg.includes("session expired") || msg.includes("don't have access")) {
6356
+ throw err;
6357
+ }
6358
+ throw new Error("can't reach the server. check your internet connection and try again.");
6359
+ }
6360
+ const plan = (data.plan || "none").toLowerCase();
6361
+ const subStatus = String(data.subscription_status || data.status || "").toLowerCase();
6362
+ if (!data.plan || plan === "none" || plan === "free" || plan === "expired" || subStatus === "trialing" || subStatus === "none") {
6363
+ throw new Error(FEATURE_MESSAGES[feature]);
6364
+ }
6365
+ }
6366
+ async function maybeShowLimitedModeHint(hasProfile) {
6367
+ if (isLocalOnlyMode())
6368
+ return;
6369
+ const access = await getAccessState();
6370
+ if (access.hasPaidPlan)
6371
+ return;
6372
+ if (hasProfile) {
6373
+ console.log(import_chalk5.default.dim("\n using cached profile (local). sync for latest: hyv sync"));
6374
+ } else if (!access.authenticated) {
6375
+ console.log(import_chalk5.default.dim("\n local mode \u2014 free scan engine. profiles + learning: hyv init"));
6376
+ } else {
6377
+ console.log(import_chalk5.default.dim("\n local mode \u2014 upgrade for full profiles + learning: hyv upgrade"));
6378
+ }
6379
+ }
6380
+ function formatModeLabel(access, hasFullProfile) {
6381
+ if (access.localOnly)
6382
+ return "local-only (forced)";
6383
+ if (access.hasPaidPlan && hasFullProfile)
6384
+ return "full profile (paid)";
6385
+ if (hasFullProfile)
6386
+ return "cached profile (local)";
6387
+ if (access.authenticated)
6388
+ return "local engine (free)";
6389
+ return "local engine (free, not signed in)";
6390
+ }
6391
+ var import_chalk5, FEATURE_MESSAGES, localOnlyOverride, cachedAccess, ACCESS_CACHE_MS;
6392
+ var init_access = __esm({
6393
+ "src/lib/access.ts"() {
6394
+ "use strict";
6395
+ import_chalk5 = __toESM(require_source());
6396
+ init_config();
6397
+ init_auth();
6398
+ init_api();
6399
+ FEATURE_MESSAGES = {
6400
+ profiles: "syncing voice profiles from your account requires a paid plan. run: hyv upgrade",
6401
+ learning: "the learning loop (reinforce, add) requires a paid plan. run: hyv upgrade",
6402
+ premiumPrompts: "rich profile-aware rewrite prompts require a paid plan. run: hyv upgrade",
6403
+ serverAnalysis: "server-assisted analysis requires a paid plan. run: hyv upgrade"
6404
+ };
6405
+ localOnlyOverride = false;
6406
+ cachedAccess = null;
6407
+ ACCESS_CACHE_MS = 3e4;
6408
+ }
6409
+ });
6410
+
6295
6411
  // src/lib/profile-parse.ts
6296
6412
  function parseAnchorsFromBody(body) {
6297
6413
  const anchors = [];
@@ -7430,7 +7546,7 @@ function ps(n7) {
7430
7546
  return n7.replace(as, fe).replace(ls, ue).replace(cs, qt).replace(fs10, de).replace(us, pe);
7431
7547
  }
7432
7548
  function ms(n7) {
7433
- return n7.replace(is, "\\").replace(rs, "{").replace(ns, "}").replace(os6, ",").replace(hs, ".");
7549
+ return n7.replace(is, "\\").replace(rs, "{").replace(ns, "}").replace(os7, ",").replace(hs, ".");
7434
7550
  }
7435
7551
  function me(n7) {
7436
7552
  if (!n7)
@@ -7530,7 +7646,7 @@ function Ut(n7, t = {}) {
7530
7646
  function es(n7, t = {}) {
7531
7647
  return new I(n7, t).iterate();
7532
7648
  }
7533
- var import_node_url, import_node_path, import_node_url2, import_fs, xi, import_promises, import_node_events, import_node_stream, import_node_string_decoder, Gt, ce, ss, fe, ue, qt, de, pe, is, rs, ns, os6, hs, as, ls, cs, fs10, us, ds, at, Ss, lt, Es, we, ye, W, xs, be, vs, Ct, Cs, Ts, As, ks, Kt, Se, Ee, Q, tt, O, Rs, Os, Fs, Ds, Ms, Ns, _s, Ls, Ws, Ps, js, Is, zs, Bs, Us, $s, Gs, Hs, Ce, Te, Ae, xe, qs, A, Ks, Vs, Ys, Xs, Js, N, Zs, ke, Qs, ti, ve, ei, D, si, Oe, Vt, Fe, At, Re, ii, q, De, Tt, ri, ft, Ne, oi, hi, ai, G, H, K, kt, ut, Rt, _e, Ot, Le, P, et, v, dt, st, C, F, T, Yt, Ft, k, x, Xt, Jt, We, Zt, B, Qt, Dt, pt, Y, M, mt, li, ci, fi, ui, Mt, te, di, pi, V, vi, wt, Ue, $e, Ri, Oi, L, Ge, He, U, qe, Ke, X, Ve, _, gt, se, je, yt, j, Nt, Lt, Ie, Fi, ie, ze, bt, Be, _t, Wt, ne, Ye, R, Pt, jt, It, it, rt, St, Cr, Xe, Di, Mi, Ni, nt, _i, ot, oe, he, ae, Et, Li, zt, xt, vt, Pi, I, le, ji, Ii, zi, Bi, Ui, Ze;
7649
+ var import_node_url, import_node_path, import_node_url2, import_fs, xi, import_promises, import_node_events, import_node_stream, import_node_string_decoder, Gt, ce, ss, fe, ue, qt, de, pe, is, rs, ns, os7, hs, as, ls, cs, fs10, us, ds, at, Ss, lt, Es, we, ye, W, xs, be, vs, Ct, Cs, Ts, As, ks, Kt, Se, Ee, Q, tt, O, Rs, Os, Fs, Ds, Ms, Ns, _s, Ls, Ws, Ps, js, Is, zs, Bs, Us, $s, Gs, Hs, Ce, Te, Ae, xe, qs, A, Ks, Vs, Ys, Xs, Js, N, Zs, ke, Qs, ti, ve, ei, D, si, Oe, Vt, Fe, At, Re, ii, q, De, Tt, ri, ft, Ne, oi, hi, ai, G, H, K, kt, ut, Rt, _e, Ot, Le, P, et, v, dt, st, C, F, T, Yt, Ft, k, x, Xt, Jt, We, Zt, B, Qt, Dt, pt, Y, M, mt, li, ci, fi, ui, Mt, te, di, pi, V, vi, wt, Ue, $e, Ri, Oi, L, Ge, He, U, qe, Ke, X, Ve, _, gt, se, je, yt, j, Nt, Lt, Ie, Fi, ie, ze, bt, Be, _t, Wt, ne, Ye, R, Pt, jt, It, it, rt, St, Cr, Xe, Di, Mi, Ni, nt, _i, ot, oe, he, ae, Et, Li, zt, xt, vt, Pi, I, le, ji, Ii, zi, Bi, Ui, Ze;
7534
7650
  var init_index_min = __esm({
7535
7651
  "node_modules/glob/dist/esm/index.min.js"() {
7536
7652
  import_node_url = require("node:url");
@@ -7577,7 +7693,7 @@ var init_index_min = __esm({
7577
7693
  is = new RegExp(fe, "g");
7578
7694
  rs = new RegExp(ue, "g");
7579
7695
  ns = new RegExp(qt, "g");
7580
- os6 = new RegExp(de, "g");
7696
+ os7 = new RegExp(de, "g");
7581
7697
  hs = new RegExp(pe, "g");
7582
7698
  as = /\\\\/g;
7583
7699
  ls = /\\{/g;
@@ -10738,18 +10854,18 @@ function stripXmlText(xml) {
10738
10854
  }
10739
10855
  function commandExists(cmd) {
10740
10856
  try {
10741
- (0, import_child_process2.execFileSync)("which", [cmd], { stdio: "ignore" });
10857
+ (0, import_child_process3.execFileSync)("which", [cmd], { stdio: "ignore" });
10742
10858
  return true;
10743
10859
  } catch {
10744
10860
  return false;
10745
10861
  }
10746
10862
  }
10747
10863
  function unzipList(filePath) {
10748
- const out = (0, import_child_process2.execFileSync)("unzip", ["-Z1", filePath], { encoding: "utf-8", maxBuffer: 5e6 });
10864
+ const out = (0, import_child_process3.execFileSync)("unzip", ["-Z1", filePath], { encoding: "utf-8", maxBuffer: 5e6 });
10749
10865
  return out.split("\n").map((l) => l.trim()).filter(Boolean);
10750
10866
  }
10751
10867
  function unzipExtract(filePath, entry) {
10752
- return (0, import_child_process2.execFileSync)("unzip", ["-p", filePath, entry], {
10868
+ return (0, import_child_process3.execFileSync)("unzip", ["-p", filePath, entry], {
10753
10869
  encoding: "utf-8",
10754
10870
  maxBuffer: 1e7
10755
10871
  });
@@ -10757,7 +10873,7 @@ function unzipExtract(filePath, entry) {
10757
10873
  function extractDocx(filePath) {
10758
10874
  if (process.platform === "darwin") {
10759
10875
  try {
10760
- const out = (0, import_child_process2.execFileSync)("textutil", ["-convert", "txt", "-stdout", filePath], {
10876
+ const out = (0, import_child_process3.execFileSync)("textutil", ["-convert", "txt", "-stdout", filePath], {
10761
10877
  encoding: "utf-8",
10762
10878
  maxBuffer: 1e7
10763
10879
  });
@@ -10800,7 +10916,7 @@ function extractPdfRaw(buffer) {
10800
10916
  function extractPdf(filePath) {
10801
10917
  if (process.platform === "darwin") {
10802
10918
  try {
10803
- const out = (0, import_child_process2.execFileSync)("textutil", ["-convert", "txt", "-stdout", filePath], {
10919
+ const out = (0, import_child_process3.execFileSync)("textutil", ["-convert", "txt", "-stdout", filePath], {
10804
10920
  encoding: "utf-8",
10805
10921
  maxBuffer: 1e7
10806
10922
  });
@@ -10810,7 +10926,7 @@ function extractPdf(filePath) {
10810
10926
  }
10811
10927
  }
10812
10928
  if (commandExists("pdftotext")) {
10813
- const out = (0, import_child_process2.execFileSync)("pdftotext", ["-layout", "-enc", "UTF-8", filePath, "-"], {
10929
+ const out = (0, import_child_process3.execFileSync)("pdftotext", ["-layout", "-enc", "UTF-8", filePath, "-"], {
10814
10930
  encoding: "utf-8",
10815
10931
  maxBuffer: 1e7
10816
10932
  });
@@ -10875,7 +10991,7 @@ function listDocumentsInDir(dirPath) {
10875
10991
  }).filter(isSupportedDocument);
10876
10992
  }
10877
10993
  function collectDocumentsFromPath(inputPath) {
10878
- const resolved = path10.resolve(inputPath.trim().replace(/^~(?=$|\/)/, os7.homedir()));
10994
+ const resolved = path10.resolve(inputPath.trim().replace(/^~(?=$|\/)/, os8.homedir()));
10879
10995
  if (!fs11.existsSync(resolved)) {
10880
10996
  throw new Error(`path not found: ${resolved}`);
10881
10997
  }
@@ -10906,19 +11022,19 @@ function readDraftInput(input) {
10906
11022
  const trimmed = input.trim();
10907
11023
  if (!trimmed)
10908
11024
  throw new Error("empty draft");
10909
- const maybePath = path10.resolve(trimmed.replace(/^~(?=$|\/)/, os7.homedir()));
11025
+ const maybePath = path10.resolve(trimmed.replace(/^~(?=$|\/)/, os8.homedir()));
10910
11026
  if (fs11.existsSync(maybePath) && fs11.statSync(maybePath).isFile()) {
10911
11027
  return { text: extractTextFromFile(maybePath), source: maybePath };
10912
11028
  }
10913
11029
  return { text: trimmed, source: "paste" };
10914
11030
  }
10915
- var import_child_process2, fs11, os7, path10, SUPPORTED_EXTENSIONS, SAMPLE_GLOB, GLOB_IGNORE;
11031
+ var import_child_process3, fs11, os8, path10, SUPPORTED_EXTENSIONS, SAMPLE_GLOB, GLOB_IGNORE;
10916
11032
  var init_document_text = __esm({
10917
11033
  "src/lib/document-text.ts"() {
10918
11034
  "use strict";
10919
- import_child_process2 = require("child_process");
11035
+ import_child_process3 = require("child_process");
10920
11036
  fs11 = __toESM(require("fs"));
10921
- os7 = __toESM(require("os"));
11037
+ os8 = __toESM(require("os"));
10922
11038
  path10 = __toESM(require("path"));
10923
11039
  init_index_min();
10924
11040
  SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
@@ -10994,21 +11110,21 @@ function runPipeline(text, profile, applyFixes = false) {
10994
11110
  };
10995
11111
  }
10996
11112
  function readText(source) {
10997
- const fs30 = require("fs");
10998
- const path27 = require("path");
11113
+ const fs31 = require("fs");
11114
+ const path28 = require("path");
10999
11115
  if (source === "-") {
11000
11116
  if (process.stdin.isTTY) {
11001
11117
  console.error("No input provided. Pipe content or specify a file.");
11002
11118
  process.exit(1);
11003
11119
  }
11004
- return { text: fs30.readFileSync(0, "utf-8"), path: "stdin" };
11120
+ return { text: fs31.readFileSync(0, "utf-8"), path: "stdin" };
11005
11121
  }
11006
- const resolved = path27.resolve(source);
11007
- if (!fs30.existsSync(resolved)) {
11122
+ const resolved = path28.resolve(source);
11123
+ if (!fs31.existsSync(resolved)) {
11008
11124
  console.error(`File not found: ${resolved}`);
11009
11125
  process.exit(1);
11010
11126
  }
11011
- const stat = fs30.statSync(resolved);
11127
+ const stat = fs31.statSync(resolved);
11012
11128
  if (stat.isDirectory()) {
11013
11129
  console.error(`${resolved} is a directory, not a file.`);
11014
11130
  process.exit(1);
@@ -11408,7 +11524,7 @@ function isInteractiveTTY() {
11408
11524
  return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
11409
11525
  }
11410
11526
  function briefPause(ms2 = 280) {
11411
- return new Promise((resolve15) => setTimeout(resolve15, ms2));
11527
+ return new Promise((resolve16) => setTimeout(resolve16, ms2));
11412
11528
  }
11413
11529
  async function withSpinner(label, fn, opts = {}) {
11414
11530
  const minMs = opts.minMs ?? 450;
@@ -11458,6 +11574,25 @@ var init_terminal_ui = __esm({
11458
11574
  });
11459
11575
 
11460
11576
  // src/lib/welcome-flow.ts
11577
+ function localProfilePath(name) {
11578
+ return path14.join(os9.homedir(), ".hyv", "profiles", `${name}.md`);
11579
+ }
11580
+ function listLocalProfileNames() {
11581
+ const profilesDir = path14.join(os9.homedir(), ".hyv", "profiles");
11582
+ if (!fs15.existsSync(profilesDir))
11583
+ return [];
11584
+ return fs15.readdirSync(profilesDir).filter((entry) => entry.endsWith(".md")).map((entry) => entry.slice(0, -3));
11585
+ }
11586
+ function formatPlanLabel(plan) {
11587
+ const labels = {
11588
+ individual: "Individual",
11589
+ multiple: "Multiple",
11590
+ solo: "Solo",
11591
+ team: "Team",
11592
+ agency: "Agency"
11593
+ };
11594
+ return labels[plan.toLowerCase()] || plan;
11595
+ }
11461
11596
  function readWelcomeState() {
11462
11597
  try {
11463
11598
  if (!fs15.existsSync(STATE_FILE)) {
@@ -11704,10 +11839,10 @@ function saveLocalProfile(name, content) {
11704
11839
  writeWelcomeState({ profile_name: safe });
11705
11840
  markStepComplete("name");
11706
11841
  markStepComplete("samples");
11707
- return path14.join(os8.homedir(), ".hyv", "profiles", `${safe}.md`);
11842
+ return path14.join(os9.homedir(), ".hyv", "profiles", `${safe}.md`);
11708
11843
  }
11709
11844
  function fetchUrlText(url) {
11710
- return new Promise((resolve15, reject) => {
11845
+ return new Promise((resolve16, reject) => {
11711
11846
  let parsed;
11712
11847
  try {
11713
11848
  parsed = new URL(url);
@@ -11736,7 +11871,7 @@ function fetchUrlText(url) {
11736
11871
  });
11737
11872
  res.on("end", () => {
11738
11873
  const text = data.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
11739
- resolve15(text.slice(0, 12e3));
11874
+ resolve16(text.slice(0, 12e3));
11740
11875
  });
11741
11876
  }
11742
11877
  );
@@ -11756,10 +11891,10 @@ async function collectSamplesFromLink(url) {
11756
11891
  }
11757
11892
  function askLine(prompt) {
11758
11893
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
11759
- return new Promise((resolve15) => {
11894
+ return new Promise((resolve16) => {
11760
11895
  rl.question(prompt, (answer) => {
11761
11896
  rl.close();
11762
- resolve15(answer.trim());
11897
+ resolve16(answer.trim());
11763
11898
  });
11764
11899
  });
11765
11900
  }
@@ -11768,11 +11903,11 @@ async function askMultiline(intro) {
11768
11903
  console.log(import_chalk12.default.dim(" paste below, then type --- on its own line when done\n"));
11769
11904
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
11770
11905
  const lines = [];
11771
- return new Promise((resolve15) => {
11906
+ return new Promise((resolve16) => {
11772
11907
  rl.on("line", (line) => {
11773
11908
  if (line.trim() === "---") {
11774
11909
  rl.close();
11775
- resolve15(lines.join("\n").trim());
11910
+ resolve16(lines.join("\n").trim());
11776
11911
  return;
11777
11912
  }
11778
11913
  lines.push(line);
@@ -11794,8 +11929,28 @@ function formatScanResult(text, profile) {
11794
11929
  }
11795
11930
  async function stepName() {
11796
11931
  console.log(import_chalk12.default.bold("\nstep 1 \xB7 name your profile\n"));
11932
+ const state = readWelcomeState();
11933
+ const existing = listLocalProfileNames();
11934
+ if (state.profile_name && existing.includes(state.profile_name)) {
11935
+ const reuse = await askYesNo(` reuse profile "${state.profile_name}"?`, true);
11936
+ if (reuse) {
11937
+ markStepComplete("name");
11938
+ return state.profile_name;
11939
+ }
11940
+ } else if (existing.length === 1) {
11941
+ const only = existing[0];
11942
+ const reuse = await askYesNo(` reuse existing profile "${only}"?`, true);
11943
+ if (reuse) {
11944
+ writeWelcomeState({ profile_name: only });
11945
+ markStepComplete("name");
11946
+ return only;
11947
+ }
11948
+ }
11797
11949
  const name = await askLine(import_chalk12.default.cyan(" profile name (e.g. my-voice): "));
11798
- return assertSafeProfileName(name);
11950
+ const safe = assertSafeProfileName(name);
11951
+ writeWelcomeState({ profile_name: safe });
11952
+ markStepComplete("name");
11953
+ return safe;
11799
11954
  }
11800
11955
  async function stepSamples(profileName) {
11801
11956
  console.log(import_chalk12.default.bold("\nstep 2 \xB7 add writing samples\n"));
@@ -11859,6 +12014,8 @@ _Add pasted samples to train this profile._
11859
12014
  console.log(import_chalk12.default.green(`
11860
12015
  \u2713 profile saved`));
11861
12016
  console.log(import_chalk12.default.dim(` ${saved}`));
12017
+ writeWelcomeState({ profile_name: profileName });
12018
+ markStepComplete("samples");
11862
12019
  }
11863
12020
  async function stepTest(profileName) {
11864
12021
  console.log(import_chalk12.default.bold("\nstep 3 \xB7 test on a draft"));
@@ -11899,42 +12056,25 @@ async function stepTest(profileName) {
11899
12056
  console.log(import_chalk12.default.dim(` try: hyv rewrite ${rewriteTarget} --profile ${profileName}`));
11900
12057
  markStepComplete("test");
11901
12058
  }
11902
- async function stepSignup(profileName) {
11903
- console.log(import_chalk12.default.bold("\nstep 4 \xB7 save & unlock\n"));
11904
- console.log(" your profile works on this machine. scan anything, anytime \u2014 free forever.");
11905
- console.log("");
11906
- console.log(" create a free account to back it up and sync everywhere.");
11907
- console.log(" then unlock learning for " + import_chalk12.default.bold("$1 your first month") + " \u2014 profiles that");
11908
- console.log(" get sharper every rewrite, hybrid rewrites, and your dashboard.\n");
11909
- console.log(import_chalk12.default.dim(" free forever (no account): scan, fix, check, mcp"));
11910
- console.log(import_chalk12.default.dim(" $1 first month: learning loop, rich rewrites, sync across devices\n"));
11911
- const ready = await askYesNo(" create your free account now? ($1 first month to unlock everything)");
11912
- if (!ready) {
11913
- console.log(import_chalk12.default.dim("\n no rush \u2014 your profile stays on this machine."));
11914
- console.log(import_chalk12.default.dim(" whenever you want backup + learning:"));
11915
- console.log(import_chalk12.default.dim(" hyv init"));
11916
- console.log(import_chalk12.default.dim(" hyv plan --upgrade ($1 first month)"));
11917
- console.log(import_chalk12.default.dim(` ${PRICING_URL}
11918
- `));
11919
- return;
12059
+ async function syncProfileToAccount(profileName) {
12060
+ const profilePath = localProfilePath(profileName);
12061
+ if (!fs15.existsSync(profilePath)) {
12062
+ console.log(import_chalk12.default.yellow(` no local profile at ${profilePath}`));
12063
+ return false;
11920
12064
  }
11921
12065
  if (!isInitialized() || !getToken()) {
11922
- console.log(import_chalk12.default.cyan("\n opening browser for signup (one sign-in)...\n"));
11923
- await withSpinner("creating your account\u2026", () => authenticateWithBrowser());
12066
+ console.log(import_chalk12.default.cyan("\n opening browser for sign-in...\n"));
12067
+ await withSpinner("signing in\u2026", () => authenticateWithBrowser());
11924
12068
  await briefPause();
11925
- console.log(import_chalk12.default.green(" \u2713 account created"));
11926
- } else {
11927
- console.log(import_chalk12.default.dim("\n already signed in \u2014 syncing profile..."));
12069
+ console.log(import_chalk12.default.green(" \u2713 signed in"));
11928
12070
  }
11929
- const content = fs15.readFileSync(
11930
- path14.join(os8.homedir(), ".hyv", "profiles", `${profileName}.md`),
11931
- "utf-8"
11932
- );
12071
+ const content = fs15.readFileSync(profilePath, "utf-8");
11933
12072
  try {
11934
12073
  const response = await withSpinner(
11935
12074
  "syncing profile\u2026",
11936
12075
  () => authenticatedRequest(cliApiUrl("/cli/profiles/new"), {
11937
12076
  method: "POST",
12077
+ timeout: PROFILE_SYNC_TIMEOUT_MS,
11938
12078
  body: { name: profileName, content, source: "welcome" }
11939
12079
  })
11940
12080
  );
@@ -11945,27 +12085,100 @@ async function stepSignup(profileName) {
11945
12085
  } else {
11946
12086
  console.log(import_chalk12.default.green(" \u2713 profile synced to your account"));
11947
12087
  }
11948
- } else {
11949
- const detail = response.data?.error;
11950
- console.log(import_chalk12.default.yellow(
11951
- ` profile saved locally \u2014 retry \`hyv welcome\` when online${detail ? ` (${detail})` : ` (HTTP ${response.status})`}`
11952
- ));
12088
+ return true;
11953
12089
  }
12090
+ const detail = response.data?.error;
12091
+ console.log(import_chalk12.default.yellow(
12092
+ ` profile saved locally \u2014 retry \`hyv sync\`${detail ? ` (${detail})` : ` (HTTP ${response.status})`}`
12093
+ ));
11954
12094
  } catch (err) {
11955
12095
  console.log(import_chalk12.default.yellow(
11956
- ` profile saved locally \u2014 retry \`hyv welcome\` (${err?.message || "sync failed"})`
12096
+ ` profile saved locally \u2014 retry \`hyv sync\` (${err?.message || "sync failed"})`
11957
12097
  ));
11958
12098
  }
12099
+ return false;
12100
+ }
12101
+ async function stepSignup(profileName) {
12102
+ console.log(import_chalk12.default.bold("\nstep 4 \xB7 save & unlock\n"));
12103
+ const access = await getAccessState();
12104
+ if (access.hasPaidPlan) {
12105
+ console.log(` you're on ${import_chalk12.default.bold(formatPlanLabel(access.plan))} \u2014 learning, sync, and dashboard are unlocked.`);
12106
+ console.log(import_chalk12.default.dim("\n syncing your local profile to your account..."));
12107
+ await syncProfileToAccount(profileName);
12108
+ markStepComplete("signup");
12109
+ console.log(import_chalk12.default.dim("\n run `hyv scan draft.md` or `hyv sync` anytime.\n"));
12110
+ return;
12111
+ }
12112
+ console.log(" your profile works on this machine. scan anything, anytime \u2014 free forever.");
12113
+ console.log("");
12114
+ if (access.authenticated) {
12115
+ console.log(" you're signed in. sync this profile, or upgrade for learning + rich rewrites.");
12116
+ console.log(import_chalk12.default.dim("\n free forever: scan, fix, check, mcp"));
12117
+ console.log(import_chalk12.default.dim(" paid: learning loop, hybrid rewrites, sync across devices\n"));
12118
+ const syncNow = await askYesNo(" sync profile to your account now?", true);
12119
+ if (syncNow) {
12120
+ await syncProfileToAccount(profileName);
12121
+ }
12122
+ const upgrade = await askYesNo(" open billing to upgrade?", false);
12123
+ if (upgrade) {
12124
+ await withSpinner("opening billing\u2026", () => openAuthenticatedDashboard({ next: "/app/billing" }));
12125
+ await briefPause();
12126
+ }
12127
+ markStepComplete("signup");
12128
+ console.log(import_chalk12.default.dim("\n upgrade anytime: `hyv plan --upgrade`\n"));
12129
+ return;
12130
+ }
12131
+ console.log(" create a free account to back it up and sync everywhere.");
12132
+ console.log(" then unlock learning for " + import_chalk12.default.bold("$1 your first month") + " \u2014 profiles that");
12133
+ console.log(" get sharper every rewrite, hybrid rewrites, and your dashboard.\n");
12134
+ console.log(import_chalk12.default.dim(" free forever (no account): scan, fix, check, mcp"));
12135
+ console.log(import_chalk12.default.dim(" $1 first month: learning loop, rich rewrites, sync across devices\n"));
12136
+ const ready = await askYesNo(" create your free account now? ($1 first month to unlock everything)");
12137
+ if (!ready) {
12138
+ console.log(import_chalk12.default.dim("\n no rush \u2014 your profile stays on this machine."));
12139
+ console.log(import_chalk12.default.dim(" whenever you want backup + learning:"));
12140
+ console.log(import_chalk12.default.dim(" hyv init"));
12141
+ console.log(import_chalk12.default.dim(" hyv plan --upgrade ($1 first month)"));
12142
+ console.log(import_chalk12.default.dim(` ${PRICING_URL}
12143
+ `));
12144
+ return;
12145
+ }
12146
+ await syncProfileToAccount(profileName);
11959
12147
  console.log(import_chalk12.default.cyan("\n opening billing in your dashboard ($1 first month)..."));
11960
- await withSpinner("opening billing\u2026", () => openAuthenticatedDashboard({ next: "/dashboard?tab=billing" }));
12148
+ await withSpinner("opening billing\u2026", () => openAuthenticatedDashboard({ next: "/app/billing" }));
11961
12149
  await briefPause();
11962
12150
  markStepComplete("signup");
11963
12151
  console.log(import_chalk12.default.dim("\n you're signed in \u2014 pick a plan in billing, no second login.\n"));
11964
12152
  }
12153
+ async function maybeRunPaidWelcomeShortcut() {
12154
+ const access = await getAccessState();
12155
+ if (!access.authenticated || !access.hasPaidPlan)
12156
+ return null;
12157
+ const state = readWelcomeState();
12158
+ const profiles = listLocalProfileNames();
12159
+ const profileName = state.profile_name && profiles.includes(state.profile_name) ? state.profile_name : profiles[0];
12160
+ if (!profileName)
12161
+ return null;
12162
+ console.log(import_chalk12.default.green(`
12163
+ ${formatPlanLabel(access.plan)} plan active \u2014 profile "${profileName}" ready.`));
12164
+ const resync = await askYesNo(" sync profile to your account now?", true);
12165
+ if (resync) {
12166
+ await syncProfileToAccount(profileName);
12167
+ }
12168
+ markStepComplete("signup");
12169
+ console.log(import_chalk12.default.green("\ndone \u2014 your voice profile is ready.\n"));
12170
+ console.log(import_chalk12.default.dim(" hyv scan draft.md"));
12171
+ console.log(import_chalk12.default.dim(` hyv rewrite draft.md --profile ${profileName}`));
12172
+ console.log(import_chalk12.default.dim(" hyv mcp --setup\n"));
12173
+ return profileName;
12174
+ }
11965
12175
  async function runInteractiveWelcome() {
11966
12176
  recordEvent("welcome_interactive");
11967
12177
  console.log("\n" + buildWelcomeHeader());
11968
12178
  try {
12179
+ const shortcut = await maybeRunPaidWelcomeShortcut();
12180
+ if (shortcut)
12181
+ return;
11969
12182
  const profileName = await stepName();
11970
12183
  await stepSamples(profileName);
11971
12184
  await stepTest(profileName);
@@ -11992,7 +12205,7 @@ function getMcpWelcomeResponse(args2) {
11992
12205
  }
11993
12206
  return buildWelcomeGuide({ profileName: args2.profile, forLlm: true });
11994
12207
  }
11995
- var import_chalk12, fs15, http2, https2, os8, path14, readline, WELCOME_TAGLINE, FLOW_STEPS, STATE_FILE;
12208
+ var import_chalk12, fs15, http2, https2, os9, path14, readline, PROFILE_SYNC_TIMEOUT_MS, WELCOME_TAGLINE, FLOW_STEPS, STATE_FILE;
11996
12209
  var init_welcome_flow = __esm({
11997
12210
  "src/lib/welcome-flow.ts"() {
11998
12211
  "use strict";
@@ -12000,7 +12213,7 @@ var init_welcome_flow = __esm({
12000
12213
  fs15 = __toESM(require("fs"));
12001
12214
  http2 = __toESM(require("http"));
12002
12215
  https2 = __toESM(require("https"));
12003
- os8 = __toESM(require("os"));
12216
+ os9 = __toESM(require("os"));
12004
12217
  path14 = __toESM(require("path"));
12005
12218
  readline = __toESM(require("readline"));
12006
12219
  init_pipeline();
@@ -12009,10 +12222,12 @@ var init_welcome_flow = __esm({
12009
12222
  init_terminal_ui();
12010
12223
  init_config();
12011
12224
  init_auth();
12225
+ init_access();
12012
12226
  init_scan();
12013
12227
  init_free_paid();
12014
12228
  init_telemetry();
12015
12229
  init_document_text();
12230
+ PROFILE_SYNC_TIMEOUT_MS = 9e4;
12016
12231
  WELCOME_TAGLINE = "Hold Your Voice \u2014 make your AI agents sound exactly like you.";
12017
12232
  FLOW_STEPS = [
12018
12233
  { n: 1, key: "name", title: "name your profile", hint: "pick a short name \u2014 e.g. my-voice" },
@@ -12020,7 +12235,7 @@ var init_welcome_flow = __esm({
12020
12235
  { n: 3, key: "test", title: "test on a draft", hint: "optional \u2014 scan or rewrite a draft" },
12021
12236
  { n: 4, key: "signup", title: "save & unlock", hint: "signup syncs your profile and unlocks learning" }
12022
12237
  ];
12023
- STATE_FILE = path14.join(os8.homedir(), ".hyv", "welcome-state.json");
12238
+ STATE_FILE = path14.join(os9.homedir(), ".hyv", "welcome-state.json");
12024
12239
  }
12025
12240
  });
12026
12241
 
@@ -12144,7 +12359,7 @@ __export(billing_upgrade_exports, {
12144
12359
  });
12145
12360
  async function openBillingUpgrade(opts = {}) {
12146
12361
  const plan = opts.plan || "individual";
12147
- const next = `/dashboard?tab=billing&checkout=${plan}`;
12362
+ const next = `/app/billing?checkout=${plan}`;
12148
12363
  const token = getToken();
12149
12364
  if (!token) {
12150
12365
  console.log(import_chalk14.default.cyan("\nSign in to upgrade \u2014 opening browser...\n"));
@@ -13056,15 +13271,15 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
13056
13271
  g.minimatch.escape = vi2.escape;
13057
13272
  g.minimatch.unescape = Ei2.unescape;
13058
13273
  });
13059
- var fs30 = R2((Wt2) => {
13274
+ var fs31 = R2((Wt2) => {
13060
13275
  "use strict";
13061
13276
  Object.defineProperty(Wt2, "__esModule", { value: true });
13062
13277
  Wt2.LRUCache = void 0;
13063
13278
  var er = typeof performance == "object" && performance && typeof performance.now == "function" ? performance : Date, as2 = /* @__PURE__ */ new Set(), ge2 = typeof process == "object" && process ? process : {}, ls2 = (n7, t, e, s) => {
13064
13279
  typeof ge2.emitWarning == "function" ? ge2.emitWarning(n7, t, e, s) : console.error(`[${e}] ${t}: ${n7}`);
13065
- }, Lt2 = globalThis.AbortController, os13 = globalThis.AbortSignal;
13280
+ }, Lt2 = globalThis.AbortController, os15 = globalThis.AbortSignal;
13066
13281
  if (typeof Lt2 > "u") {
13067
- os13 = class {
13282
+ os15 = class {
13068
13283
  onabort;
13069
13284
  _onabort = [];
13070
13285
  reason;
@@ -13076,7 +13291,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
13076
13291
  constructor() {
13077
13292
  t();
13078
13293
  }
13079
- signal = new os13();
13294
+ signal = new os15();
13080
13295
  abort(e) {
13081
13296
  if (!this.signal.aborted) {
13082
13297
  this.signal.reason = e, this.signal.aborted = true;
@@ -14025,7 +14240,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
14025
14240
  };
14026
14241
  Object.defineProperty(_2, "__esModule", { value: true });
14027
14242
  _2.PathScurry = _2.Path = _2.PathScurryDarwin = _2.PathScurryPosix = _2.PathScurryWin32 = _2.PathScurryBase = _2.PathPosix = _2.PathWin32 = _2.PathBase = _2.ChildrenCache = _2.ResolveCache = void 0;
14028
- var Qt2 = fs30(), Yt2 = require("node:path"), yr = require("node:url"), pt2 = require("fs"), Sr = br(require("node:fs")), vr = pt2.realpathSync.native, Ht2 = require("node:fs/promises"), bs2 = Oe2(), mt2 = { lstatSync: pt2.lstatSync, readdir: pt2.readdir, readdirSync: pt2.readdirSync, readlinkSync: pt2.readlinkSync, realpathSync: vr, promises: { lstat: Ht2.lstat, readdir: Ht2.readdir, readlink: Ht2.readlink, realpath: Ht2.realpath } }, _s2 = (n7) => !n7 || n7 === mt2 || n7 === Sr ? mt2 : { ...mt2, ...n7, promises: { ...mt2.promises, ...n7.promises || {} } }, Os2 = /^\\\\\?\\([a-z]:)\\?$/i, Er = (n7) => n7.replace(/\//g, "\\").replace(Os2, "$1\\"), _r = /[\\\/]/, N2 = 0, xs2 = 1, Ts2 = 2, G2 = 4, Cs2 = 6, Rs2 = 8, Q2 = 10, As2 = 12, j2 = 15, dt2 = ~j2, xe2 = 16, ys2 = 32, gt2 = 64, W2 = 128, Vt2 = 256, Xt2 = 512, Ss2 = gt2 | W2 | Xt2, Or = 1023, Te2 = (n7) => n7.isFile() ? Rs2 : n7.isDirectory() ? G2 : n7.isSymbolicLink() ? Q2 : n7.isCharacterDevice() ? Ts2 : n7.isBlockDevice() ? Cs2 : n7.isSocket() ? As2 : n7.isFIFO() ? xs2 : N2, vs2 = new Qt2.LRUCache({ max: 2 ** 12 }), wt2 = (n7) => {
14243
+ var Qt2 = fs31(), Yt2 = require("node:path"), yr = require("node:url"), pt2 = require("fs"), Sr = br(require("node:fs")), vr = pt2.realpathSync.native, Ht2 = require("node:fs/promises"), bs2 = Oe2(), mt2 = { lstatSync: pt2.lstatSync, readdir: pt2.readdir, readdirSync: pt2.readdirSync, readlinkSync: pt2.readlinkSync, realpathSync: vr, promises: { lstat: Ht2.lstat, readdir: Ht2.readdir, readlink: Ht2.readlink, realpath: Ht2.realpath } }, _s2 = (n7) => !n7 || n7 === mt2 || n7 === Sr ? mt2 : { ...mt2, ...n7, promises: { ...mt2.promises, ...n7.promises || {} } }, Os2 = /^\\\\\?\\([a-z]:)\\?$/i, Er = (n7) => n7.replace(/\//g, "\\").replace(Os2, "$1\\"), _r = /[\\\/]/, N2 = 0, xs2 = 1, Ts2 = 2, G2 = 4, Cs2 = 6, Rs2 = 8, Q2 = 10, As2 = 12, j2 = 15, dt2 = ~j2, xe2 = 16, ys2 = 32, gt2 = 64, W2 = 128, Vt2 = 256, Xt2 = 512, Ss2 = gt2 | W2 | Xt2, Or = 1023, Te2 = (n7) => n7.isFile() ? Rs2 : n7.isDirectory() ? G2 : n7.isSymbolicLink() ? Q2 : n7.isCharacterDevice() ? Ts2 : n7.isBlockDevice() ? Cs2 : n7.isSocket() ? As2 : n7.isFIFO() ? xs2 : N2, vs2 = new Qt2.LRUCache({ max: 2 ** 12 }), wt2 = (n7) => {
14029
14244
  let t = vs2.get(n7);
14030
14245
  if (t)
14031
14246
  return t;
@@ -15544,7 +15759,7 @@ var {
15544
15759
  } = import_index.default;
15545
15760
 
15546
15761
  // src/index.ts
15547
- var import_chalk33 = __toESM(require_source());
15762
+ var import_chalk34 = __toESM(require_source());
15548
15763
 
15549
15764
  // src/commands/init.ts
15550
15765
  var import_chalk4 = __toESM(require_source());
@@ -15690,10 +15905,19 @@ function registerInitCommand(program3) {
15690
15905
  if (authData.license_key) {
15691
15906
  console.log(import_chalk4.default.dim(` License: ${authData.license_key.slice(0, 12)}...`));
15692
15907
  }
15908
+ try {
15909
+ const { ensureMcpProfilesHydrated: ensureMcpProfilesHydrated2 } = await Promise.resolve().then(() => (init_mcp_profile_hydrate(), mcp_profile_hydrate_exports));
15910
+ const hydrated = await ensureMcpProfilesHydrated2({ force: true });
15911
+ if (hydrated.synced?.length) {
15912
+ console.log(import_chalk4.default.green(`
15913
+ \u2713 MCP profiles ready: ${hydrated.synced.join(", ")}`));
15914
+ }
15915
+ } catch {
15916
+ }
15693
15917
  const mcpResults = configureMcpForDesktop();
15694
15918
  const { printPaidUnlockReminder: printPaidUnlockReminder2 } = await Promise.resolve().then(() => (init_marketing_hints(), marketing_hints_exports));
15695
15919
  console.log("\nNext steps:");
15696
- console.log(import_chalk4.default.dim(" 1. Set up your voice: hyv welcome"));
15920
+ console.log(import_chalk4.default.dim(" 1. Voice profile: hyv welcome (or use dashboard \u2014 MCP syncs after init)"));
15697
15921
  console.log(import_chalk4.default.dim(" 2. Scan a draft: hyv scan draft.md"));
15698
15922
  console.log(import_chalk4.default.dim(" 3. Rewrite with voice: hyv rewrite draft.md"));
15699
15923
  printPaidUnlockReminder2();
@@ -15917,6 +16141,8 @@ init_profile();
15917
16141
  init_profile_meta();
15918
16142
  var fs8 = __toESM(require("fs"));
15919
16143
  var path8 = __toESM(require("path"));
16144
+ var os6 = __toESM(require("os"));
16145
+ var import_child_process2 = require("child_process");
15920
16146
  function registerSyncCommand(program3) {
15921
16147
  program3.command("sync").description("Sync profiles and rules from server").option("--force", "Force re-download even if cache is fresh").action(async (options) => {
15922
16148
  try {
@@ -16004,7 +16230,15 @@ function registerSyncCommand(program3) {
16004
16230
  process.exit(1);
16005
16231
  }
16006
16232
  });
16007
- program3.command("profiles").description("List voice profiles").option("--verbose", "Show learned patterns, drift, anchors").option("--history <name>", "Show profile evolution for a slug").action(async (options) => {
16233
+ program3.command("profiles").description("List, edit, or delete voice profiles").option("--verbose", "Show learned patterns, drift, anchors").option("--history <name>", "Show profile evolution for a slug").option("--delete <name>", "Delete a profile (server + local cache)").option("--edit <name>", "Open a local profile in your $EDITOR").action(async (options) => {
16234
+ if (options.delete) {
16235
+ await deleteProfileByName(options.delete);
16236
+ return;
16237
+ }
16238
+ if (options.edit) {
16239
+ await editLocalProfile(options.edit);
16240
+ return;
16241
+ }
16008
16242
  if (options.history) {
16009
16243
  await showProfileHistory(options.history);
16010
16244
  return;
@@ -16050,6 +16284,58 @@ ${profiles.length} profile(s) cached.`));
16050
16284
  await program3.parseAsync(["node", "hyv", "sync", "--force"]);
16051
16285
  });
16052
16286
  }
16287
+ async function deleteProfileByName(name) {
16288
+ const token = getToken();
16289
+ const localKey = toSafeProfileCacheKey(name);
16290
+ const localPath = path8.join(os6.homedir(), ".hyv", "profiles", `${localKey}.md`);
16291
+ if (token) {
16292
+ try {
16293
+ const res = await authenticatedRequest(cliApiUrl("/cli/profiles/delete"), {
16294
+ method: "POST",
16295
+ body: { slug_or_id: name }
16296
+ });
16297
+ if (res.status !== 200) {
16298
+ const err = res.data?.error || `delete failed (HTTP ${res.status})`;
16299
+ console.log(import_chalk8.default.red(`
16300
+ ${err}
16301
+ `));
16302
+ process.exit(1);
16303
+ }
16304
+ console.log(import_chalk8.default.green(`
16305
+ \u2713 deleted "${name}" from your account
16306
+ `));
16307
+ } catch (err) {
16308
+ console.log(import_chalk8.default.red(`
16309
+ ${err.message || "delete failed"}
16310
+ `));
16311
+ process.exit(1);
16312
+ }
16313
+ } else {
16314
+ console.log(import_chalk8.default.yellow("\n not signed in \u2014 deleting local profile only\n"));
16315
+ }
16316
+ if (fs8.existsSync(localPath)) {
16317
+ fs8.unlinkSync(localPath);
16318
+ console.log(import_chalk8.default.dim(` removed ${localPath}`));
16319
+ }
16320
+ }
16321
+ async function editLocalProfile(name) {
16322
+ const localKey = toSafeProfileCacheKey(name);
16323
+ const localPath = path8.join(os6.homedir(), ".hyv", "profiles", `${localKey}.md`);
16324
+ if (!fs8.existsSync(localPath)) {
16325
+ console.log(import_chalk8.default.yellow(`
16326
+ no local profile at ${localPath}`));
16327
+ console.log(import_chalk8.default.dim(" run `hyv sync` or `hyv welcome` first\n"));
16328
+ process.exit(1);
16329
+ }
16330
+ const editor = process.env.EDITOR || process.env.VISUAL || (process.platform === "win32" ? "notepad" : "nano");
16331
+ const result = (0, import_child_process2.spawnSync)(editor, [localPath], { stdio: "inherit", shell: process.platform === "win32" });
16332
+ if (result.status !== 0) {
16333
+ process.exit(result.status || 1);
16334
+ }
16335
+ console.log(import_chalk8.default.green(`
16336
+ \u2713 saved ${localPath}`));
16337
+ console.log(import_chalk8.default.dim(" sync to account: hyv sync\n"));
16338
+ }
16053
16339
  async function showProfileHistory(slug) {
16054
16340
  const { authenticatedRequest: authenticatedRequest2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
16055
16341
  const token = getToken();
@@ -16889,7 +17175,7 @@ function registerImportCommand(program3) {
16889
17175
  });
16890
17176
  }
16891
17177
  function askQuestion(question) {
16892
- return new Promise((resolve15) => {
17178
+ return new Promise((resolve16) => {
16893
17179
  const readline3 = require("readline");
16894
17180
  const rl = readline3.createInterface({
16895
17181
  input: process.stdin,
@@ -16898,7 +17184,7 @@ function askQuestion(question) {
16898
17184
  rl.question(import_chalk13.default.cyan(` ${question}
16899
17185
  > `), (answer) => {
16900
17186
  rl.close();
16901
- resolve15(answer.trim());
17187
+ resolve16(answer.trim());
16902
17188
  });
16903
17189
  });
16904
17190
  }
@@ -17457,7 +17743,7 @@ hyv scan ${filePath}`));
17457
17743
  var import_chalk19 = __toESM(require_source());
17458
17744
  var fs19 = __toESM(require("fs"));
17459
17745
  var path18 = __toESM(require("path"));
17460
- var os9 = __toESM(require("os"));
17746
+ var os10 = __toESM(require("os"));
17461
17747
  init_config();
17462
17748
  init_auth();
17463
17749
  init_access();
@@ -17465,7 +17751,7 @@ init_local_profile();
17465
17751
  init_version();
17466
17752
 
17467
17753
  // src/lib/mcp-stdio-test.ts
17468
- var import_child_process3 = require("child_process");
17754
+ var import_child_process4 = require("child_process");
17469
17755
 
17470
17756
  // src/lib/cli-entry.ts
17471
17757
  var fs18 = __toESM(require("fs"));
@@ -17495,8 +17781,8 @@ async function testMcpStdioSubprocess() {
17495
17781
  const entry = resolveCliEntry();
17496
17782
  if (!entry)
17497
17783
  return { ok: false };
17498
- return new Promise((resolve15) => {
17499
- const child = (0, import_child_process3.spawn)(process.execPath, [entry, "mcp"], {
17784
+ return new Promise((resolve16) => {
17785
+ const child = (0, import_child_process4.spawn)(process.execPath, [entry, "mcp"], {
17500
17786
  stdio: ["pipe", "pipe", "pipe"],
17501
17787
  env: { ...process.env, HYV_POSTINSTALL_QUIET: "1" }
17502
17788
  });
@@ -17511,7 +17797,7 @@ async function testMcpStdioSubprocess() {
17511
17797
  child.kill();
17512
17798
  } catch {
17513
17799
  }
17514
- resolve15({ ok, toolCount });
17800
+ resolve16({ ok, toolCount });
17515
17801
  };
17516
17802
  const timeout = setTimeout(() => finish(false), 1e4);
17517
17803
  const handleLine = (line) => {
@@ -17562,7 +17848,7 @@ async function testMcpStdioSubprocess() {
17562
17848
  }
17563
17849
 
17564
17850
  // src/commands/doctor.ts
17565
- var HOME = os9.homedir();
17851
+ var HOME = os10.homedir();
17566
17852
  var IS_WIN = process.platform === "win32";
17567
17853
  function claudeDesktopDir() {
17568
17854
  if (IS_WIN)
@@ -17773,7 +18059,7 @@ function registerDoctorCommand(program3) {
17773
18059
  if (cursorMcp)
17774
18060
  console.log(import_chalk19.default.green(" \u2713 mcp configured for cursor"));
17775
18061
  } else {
17776
- console.log(import_chalk19.default.yellow(" ! mcp not configured \u2014 run: hyv doctor --fix-agents or hyv mcp --setup"));
18062
+ console.log(import_chalk19.default.yellow(" ! mcp not configured \u2014 run: hyv mcp (auto-detect) or hyv doctor --fix-agents"));
17777
18063
  issues++;
17778
18064
  }
17779
18065
  try {
@@ -17916,11 +18202,11 @@ async function confirmDestructiveWrite(options) {
17916
18202
  const question = `
17917
18203
  ${label}
17918
18204
  A .bak backup will be created. Proceed? [y/N] `;
17919
- const answer = await new Promise((resolve15) => {
18205
+ const answer = await new Promise((resolve16) => {
17920
18206
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
17921
18207
  rl.question(question, (value) => {
17922
18208
  rl.close();
17923
- resolve15(value.trim().toLowerCase());
18209
+ resolve16(value.trim().toLowerCase());
17924
18210
  });
17925
18211
  });
17926
18212
  return answer === "y" || answer === "yes";
@@ -18026,19 +18312,19 @@ function registerCheckCommand(program3) {
18026
18312
  const profile = await loadProfileForCommand(options.profile);
18027
18313
  let inputText = text;
18028
18314
  if (text === "-") {
18029
- const fs31 = require("fs");
18315
+ const fs32 = require("fs");
18030
18316
  if (process.stdin.isTTY) {
18031
18317
  console.error(import_chalk23.default.red("No input provided. Pipe content or pass text as argument."));
18032
18318
  process.exit(1);
18033
18319
  }
18034
- inputText = fs31.readFileSync(0, "utf-8");
18320
+ inputText = fs32.readFileSync(0, "utf-8");
18035
18321
  }
18036
18322
  if (!inputText.trim()) {
18037
18323
  console.error(import_chalk23.default.red("No text provided."));
18038
18324
  process.exit(1);
18039
18325
  }
18040
- const fs30 = require("fs");
18041
- if (text !== "-" && fs30.existsSync(text)) {
18326
+ const fs31 = require("fs");
18327
+ if (text !== "-" && fs31.existsSync(text)) {
18042
18328
  console.log(import_chalk23.default.yellow(`"${text}" looks like a file. Did you mean: hyv scan ${text}`));
18043
18329
  process.exit(1);
18044
18330
  }
@@ -18165,12 +18451,12 @@ function registerDiffCommand(program3) {
18165
18451
  ${result.changes.length} auto-fix${result.changes.length === 1 ? "" : "es"} available`));
18166
18452
  console.log(import_chalk25.default.dim(` run: hyv fix ${file} -i to apply`));
18167
18453
  if (options.apply && filePath !== "stdin") {
18168
- const fs30 = require("fs");
18169
- const path27 = require("path");
18454
+ const fs31 = require("fs");
18455
+ const path28 = require("path");
18170
18456
  const backupPath = filePath + ".bak";
18171
- fs30.copyFileSync(filePath, backupPath);
18172
- fs30.writeFileSync(filePath, result.fixed);
18173
- console.log(import_chalk25.default.green(` \u2713 Applied. Backup: ${path27.basename(backupPath)}`));
18457
+ fs31.copyFileSync(filePath, backupPath);
18458
+ fs31.writeFileSync(filePath, result.fixed);
18459
+ console.log(import_chalk25.default.green(` \u2713 Applied. Backup: ${path28.basename(backupPath)}`));
18174
18460
  }
18175
18461
  } catch (error) {
18176
18462
  console.error(import_chalk25.default.red(`Error: ${error.message}`));
@@ -18353,8 +18639,8 @@ function registerBatchCommand(program3) {
18353
18639
  program3.command("batch").description("Scan or fix multiple files matching a glob").argument("<pattern>", 'Glob pattern (e.g., "posts/**/*.md")').option("--fix", "Apply auto-fixes (default: scan only)").option("-i, --in-place", "Write fixes back to files").option("-y, --yes", "Confirm destructive in-place fixes without prompting").option("--threshold <n>", "Fail if any file score < threshold").option("--fail-on-hit", "Exit with code 2 if any file has issues").option("--sort <field>", "Sort by: issues, score, name", "issues").option("--format <type>", "Output format (text, json, csv)", "text").option("--profile <name>", "Voice profile").option("--ignore <patterns>", "Comma-separated glob ignores").action(async (pattern, options) => {
18354
18640
  try {
18355
18641
  const profile = await loadProfileForCommand(options.profile);
18356
- const glob = require_index_min();
18357
- const files = glob.sync(pattern, {
18642
+ const { globSync } = require_index_min();
18643
+ const files = globSync(pattern, {
18358
18644
  ignore: options.ignore ? options.ignore.split(",") : void 0,
18359
18645
  nodir: true
18360
18646
  });
@@ -18680,9 +18966,9 @@ var import_chalk30 = __toESM(require_source());
18680
18966
  var PAGES = {
18681
18967
  dashboard: "https://holdyourvoice.com/dashboard",
18682
18968
  profiles: "https://holdyourvoice.com/dashboard?tab=profiles",
18683
- pricing: "https://holdyourvoice.com/dashboard?tab=billing",
18969
+ pricing: "https://holdyourvoice.com/app/billing",
18684
18970
  settings: "https://holdyourvoice.com/dashboard",
18685
- billing: "https://holdyourvoice.com/dashboard?tab=billing"
18971
+ billing: "https://holdyourvoice.com/app/billing"
18686
18972
  };
18687
18973
  function registerOpenCommand(program3) {
18688
18974
  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) => {
@@ -18711,8 +18997,8 @@ init_welcome();
18711
18997
  // src/lib/onboarding.ts
18712
18998
  var fs24 = __toESM(require("fs"));
18713
18999
  var path22 = __toESM(require("path"));
18714
- var os10 = __toESM(require("os"));
18715
- var hyvDir = path22.join(os10.homedir(), ".hyv");
19000
+ var os11 = __toESM(require("os"));
19001
+ var hyvDir = path22.join(os11.homedir(), ".hyv");
18716
19002
  var onboardingFile = path22.join(hyvDir, "onboarding-complete.json");
18717
19003
  function hasCompletedOnboarding() {
18718
19004
  try {
@@ -18885,9 +19171,9 @@ function registerUpgradeCommand(program3) {
18885
19171
  }
18886
19172
 
18887
19173
  // src/mcp.ts
18888
- var fs26 = __toESM(require("fs"));
18889
- var path24 = __toESM(require("path"));
18890
- var os11 = __toESM(require("os"));
19174
+ var fs27 = __toESM(require("fs"));
19175
+ var path25 = __toESM(require("path"));
19176
+ var os13 = __toESM(require("os"));
18891
19177
  init_classifier();
18892
19178
  init_autofix();
18893
19179
  init_validator();
@@ -18895,23 +19181,262 @@ init_pipeline();
18895
19181
  init_signals();
18896
19182
  init_local_profile();
18897
19183
  init_welcome();
18898
- init_config();
18899
19184
  init_telemetry();
18900
19185
  init_access();
18901
- var VOICE_MD = path24.join(os11.homedir(), ".hyv", "voice.md");
19186
+
19187
+ // src/lib/mcp-integrate.ts
19188
+ var import_chalk32 = __toESM(require_source());
19189
+ var fs26 = __toESM(require("fs"));
19190
+ var os12 = __toESM(require("os"));
19191
+ var path24 = __toESM(require("path"));
19192
+ init_version();
19193
+ init_welcome_flow();
19194
+ init_config();
19195
+ init_local_profile();
19196
+ function resolveCliRoot() {
19197
+ const candidates = [
19198
+ path24.resolve(__dirname, ".."),
19199
+ path24.resolve(__dirname, "..", "..")
19200
+ ];
19201
+ for (const root of candidates) {
19202
+ if (fs26.existsSync(path24.join(root, "scripts", "postinstall-lib.js"))) {
19203
+ return root;
19204
+ }
19205
+ }
19206
+ return candidates[0];
19207
+ }
19208
+ function loadPostinstallLib() {
19209
+ return require(path24.join(resolveCliRoot(), "scripts", "postinstall-lib.js"));
19210
+ }
19211
+ function runMcpAutoIntegrate(opts = {}) {
19212
+ const { integrateDetectedAgents } = loadPostinstallLib();
19213
+ return integrateDetectedAgents({
19214
+ pkgDir: resolveCliRoot(),
19215
+ quiet: true,
19216
+ force: Boolean(opts.force)
19217
+ });
19218
+ }
19219
+ function listLocalProfileNames2() {
19220
+ return [.../* @__PURE__ */ new Set([...listCachedProfiles(), ...listDiskCachedProfiles()])].sort();
19221
+ }
19222
+ function buildOnboardingStatusLines() {
19223
+ const lines = [];
19224
+ const welcome = readWelcomeState();
19225
+ const profiles = listLocalProfileNames2();
19226
+ const onboarded = hasCompletedOnboarding();
19227
+ const config = readConfig();
19228
+ const active = config.default_profile || config.profile;
19229
+ if (profiles.length > 0) {
19230
+ const activeNote = active && profiles.includes(active) ? ` (default: ${active})` : "";
19231
+ lines.push(`voice profiles (MCP-ready): ${profiles.join(", ")}${activeNote}`);
19232
+ } else {
19233
+ lines.push("voice profiles: none on this machine yet");
19234
+ lines.push("dashboard profile \u2192 run `hyv init` once; terminal `hyv welcome` \u2192 saved locally automatically");
19235
+ }
19236
+ if (welcome.profile_name) {
19237
+ lines.push(`welcome progress: profile name "${welcome.profile_name}"`);
19238
+ }
19239
+ if (welcome.completed_steps?.length) {
19240
+ const done = welcome.completed_steps.map((key) => FLOW_STEPS.find((s) => s.key === key)?.title || key).join(", ");
19241
+ lines.push(`welcome steps done: ${done}`);
19242
+ } else if (!onboarded) {
19243
+ lines.push("welcome steps: not started (or only partial)");
19244
+ }
19245
+ lines.push("free without profile: hyv_scan, hyv_demo, hyv_fix, hyv_check work offline");
19246
+ lines.push("with profile: hyv_rewrite, hyv_validate, hyv_clean use your voice rules");
19247
+ return lines;
19248
+ }
19249
+ function formatChatGptConnectorGuide() {
19250
+ const lib = loadPostinstallLib();
19251
+ const mcpCmd = lib.resolveHyvMcpCommand(resolveCliRoot());
19252
+ const guidePath = path24.join(os12.homedir(), ".chatgpt", "hyv-mcp-connector.txt");
19253
+ const lines = [
19254
+ "### ChatGPT Desktop connector (manual \u2014 no auto-config file)",
19255
+ "",
19256
+ "1. Open ChatGPT **desktop** app (browser chat cannot use local MCP)",
19257
+ "2. Settings \u2192 Connectors \u2192 Add connector",
19258
+ "3. Name: **hold your voice**",
19259
+ "4. Command: **hyv**",
19260
+ "5. Arguments: **mcp**",
19261
+ "",
19262
+ "If the connector fails to start, use absolute paths:",
19263
+ ` command: ${mcpCmd.command}`,
19264
+ ` arguments: ${mcpCmd.args.join(" ")}`,
19265
+ "",
19266
+ "6. Save, restart ChatGPT Desktop",
19267
+ '7. Ask: "run hyv_welcome" or "scan this draft with hold your voice"',
19268
+ ""
19269
+ ];
19270
+ if (fs26.existsSync(guidePath)) {
19271
+ lines.push(`Full guide on disk: ${guidePath}`);
19272
+ } else {
19273
+ lines.push("Run `hyv mcp` or `hyv doctor --fix-agents` to write the guide file.");
19274
+ }
19275
+ return lines.join("\n");
19276
+ }
19277
+ function buildMcpAgentStatus() {
19278
+ const {
19279
+ detectInstalledAgents,
19280
+ isAgentIntegrated,
19281
+ resolveHyvMcpCommand
19282
+ } = loadPostinstallLib();
19283
+ const home = os12.homedir();
19284
+ const detected = detectInstalledAgents(home);
19285
+ const mcpCmd = resolveHyvMcpCommand(resolveCliRoot());
19286
+ const lines = [
19287
+ "### HYV MCP status",
19288
+ "",
19289
+ `mcp server command: ${mcpCmd.command} ${mcpCmd.args.join(" ")}`,
19290
+ "",
19291
+ ...buildOnboardingStatusLines().map((l) => `- ${l}`),
19292
+ ""
19293
+ ];
19294
+ if (detected.length === 0) {
19295
+ lines.push("### Installed apps");
19296
+ lines.push("- none detected \u2014 install Cursor, Claude Desktop, ChatGPT Desktop, etc.");
19297
+ lines.push("- then run `hyv mcp` in terminal or call hyv_mcp_setup with action=integrate");
19298
+ lines.push("");
19299
+ lines.push(formatChatGptConnectorGuide());
19300
+ return lines.join("\n");
19301
+ }
19302
+ lines.push("### Installed apps");
19303
+ for (const app of detected) {
19304
+ const integrated = isAgentIntegrated(app.id, home);
19305
+ const status = app.integration === "manual" ? integrated ? "guide written" : "add connector manually" : integrated ? "integrated" : "needs setup";
19306
+ lines.push(`- ${app.label}: ${status} (${app.integration})`);
19307
+ }
19308
+ lines.push("");
19309
+ lines.push("### In this chat (no terminal needed)");
19310
+ lines.push("- Which profile is active \u2192 hyv_profiles");
19311
+ lines.push("- New or partial setup \u2192 hyv_welcome (steps 1\u20134, or mode=extract_prompt for voice from chat)");
19312
+ lines.push("- Refresh app configs \u2192 hyv_mcp_setup with action=integrate (force=true after hyv upgrade)");
19313
+ lines.push("- ChatGPT connector steps \u2192 hyv_mcp_setup with action=chatgpt");
19314
+ lines.push("- Test free scan \u2192 hyv_demo or hyv_scan on any draft");
19315
+ return lines.join("\n");
19316
+ }
19317
+ function formatMcpIntegrateReportText(result, opts = {}) {
19318
+ const { agentIdForConfiguredLabel, isAgentIntegrated } = loadPostinstallLib();
19319
+ const configuredIds = new Set(
19320
+ result.configured.map((label) => agentIdForConfiguredLabel(label)).filter(Boolean)
19321
+ );
19322
+ const lines = [
19323
+ "### HYV MCP integration",
19324
+ "",
19325
+ ...buildOnboardingStatusLines().map((l) => `- ${l}`),
19326
+ ""
19327
+ ];
19328
+ if (result.detected.length === 0) {
19329
+ lines.push("No supported AI apps detected on this machine.");
19330
+ lines.push("Install Cursor, Claude Desktop, Windsurf, or ChatGPT Desktop, then run integrate again.");
19331
+ lines.push("");
19332
+ lines.push(formatChatGptConnectorGuide());
19333
+ return lines.join("\n");
19334
+ }
19335
+ lines.push("### Apps");
19336
+ for (const app of result.detected) {
19337
+ const justConfigured = configuredIds.has(app.id);
19338
+ const integrated = isAgentIntegrated(app.id) || justConfigured;
19339
+ const status = app.integration === "manual" ? "manual connector" : justConfigured ? opts.force ? "updated now" : "configured now" : integrated ? "integrated" : "needs setup";
19340
+ lines.push(`- ${app.label}: ${status}`);
19341
+ }
19342
+ if (result.configured.length > 0) {
19343
+ lines.push("");
19344
+ lines.push(`Wired: ${result.configured.join(", ")}`);
19345
+ }
19346
+ if (result.warnings.length > 0) {
19347
+ lines.push("");
19348
+ lines.push("Notes:");
19349
+ for (const warning of result.warnings) {
19350
+ lines.push(`- ${warning}`);
19351
+ }
19352
+ }
19353
+ lines.push("");
19354
+ lines.push("Restart MCP hosts (Cursor, Claude Desktop, Antigravity, OpenCode) after config changes.");
19355
+ if (result.detected.some((a) => a.integration === "manual")) {
19356
+ lines.push("");
19357
+ lines.push(formatChatGptConnectorGuide());
19358
+ }
19359
+ return lines.join("\n");
19360
+ }
19361
+ function printMcpIntegrateReport(result, opts = {}) {
19362
+ const { agentIdForConfiguredLabel, isAgentIntegrated } = loadPostinstallLib();
19363
+ const configuredIds = new Set(
19364
+ result.configured.map((label) => agentIdForConfiguredLabel(label)).filter(Boolean)
19365
+ );
19366
+ console.log(import_chalk32.default.bold("\nhold your voice \u2014 mcp integration\n"));
19367
+ console.log(import_chalk32.default.dim(` ${getEngineLabel()}
19368
+ `));
19369
+ const welcome = readWelcomeState();
19370
+ const profiles = listLocalProfileNames2();
19371
+ if (profiles.length > 0) {
19372
+ console.log(import_chalk32.default.dim(` voice profiles: ${profiles.join(", ")}`));
19373
+ } else {
19374
+ console.log(import_chalk32.default.yellow(" no voice profile yet \u2014 mcp still works (free scan). finish onboarding in terminal or in-chat via hyv_welcome"));
19375
+ }
19376
+ if (welcome.completed_steps?.length) {
19377
+ console.log(import_chalk32.default.dim(` welcome progress: ${welcome.completed_steps.join(", ")}`));
19378
+ }
19379
+ console.log("");
19380
+ if (result.detected.length === 0) {
19381
+ console.log(import_chalk32.default.yellow(" no supported ai apps detected on this machine."));
19382
+ console.log(import_chalk32.default.dim("\n install cursor, claude desktop, chatgpt desktop, or another supported app,"));
19383
+ console.log(import_chalk32.default.dim(" then run hyv mcp again \u2014 or hyv doctor --fix-agents to configure everything."));
19384
+ console.log(import_chalk32.default.dim("\n in chatgpt/claude/cursor: call hyv_welcome to onboard without the terminal."));
19385
+ console.log(import_chalk32.default.dim(" chatgpt desktop: hyv mcp --setup-chatgpt\n"));
19386
+ return;
19387
+ }
19388
+ console.log(import_chalk32.default.bold("detected apps"));
19389
+ for (const app of result.detected) {
19390
+ const justConfigured = configuredIds.has(app.id);
19391
+ const integrated = isAgentIntegrated(app.id) || justConfigured;
19392
+ const mark = app.integration === "manual" ? import_chalk32.default.yellow("\u25CB") : integrated ? import_chalk32.default.green("\u2713") : import_chalk32.default.cyan("\u2192");
19393
+ const status = app.integration === "manual" ? "manual connector \u2014 see ~/.chatgpt/hyv-mcp-connector.txt" : justConfigured ? opts.force ? "updated now" : "configured now" : integrated ? "integrated" : "needs setup";
19394
+ console.log(` ${mark} ${app.label} \u2014 ${status}`);
19395
+ console.log(import_chalk32.default.dim(` ${app.reason} \xB7 ${app.integration}`));
19396
+ }
19397
+ if (result.configured.length > 0) {
19398
+ console.log(import_chalk32.default.green(`
19399
+ wired hyv into: ${result.configured.join(", ")}`));
19400
+ }
19401
+ if (result.warnings.length > 0) {
19402
+ console.log(import_chalk32.default.yellow("\n notes:"));
19403
+ for (const warning of result.warnings) {
19404
+ console.log(import_chalk32.default.yellow(` ! ${warning}`));
19405
+ }
19406
+ }
19407
+ const mcpApps = result.detected.filter((a) => a.integration === "mcp");
19408
+ const manualApps = result.detected.filter((a) => a.integration === "manual");
19409
+ console.log(import_chalk32.default.bold("\nnext steps"));
19410
+ console.log(import_chalk32.default.dim(" in this app: hyv_welcome (onboarding) \xB7 hyv_mcp_setup (status/refresh) \xB7 hyv_demo (try a scan)"));
19411
+ if (mcpApps.length > 0) {
19412
+ console.log(import_chalk32.default.dim(" restart apps that use mcp (cursor, claude desktop, antigravity, opencode)"));
19413
+ }
19414
+ if (manualApps.length > 0) {
19415
+ console.log(import_chalk32.default.dim(" chatgpt: settings \u2192 connectors \u2192 command hyv, arguments mcp"));
19416
+ console.log(import_chalk32.default.dim(" full steps: hyv mcp --setup-chatgpt"));
19417
+ }
19418
+ console.log(import_chalk32.default.dim(" refresh stale configs after upgrade: hyv mcp --force"));
19419
+ console.log(import_chalk32.default.dim(" verify: hyv mcp --test"));
19420
+ console.log(import_chalk32.default.dim(" all hosts: hyv doctor --verify-hosts\n"));
19421
+ }
19422
+
19423
+ // src/mcp.ts
19424
+ init_mcp_profile_hydrate();
19425
+ init_profile();
19426
+ var VOICE_MD = path25.join(os13.homedir(), ".hyv", "voice.md");
18902
19427
  var MAX_RESPONSE_CHARS = 12e4;
18903
19428
  var MAX_SCAN_FILE_BYTES = 2 * 1024 * 1024;
18904
19429
  function readScanFile(filePath) {
18905
- const cwdReal = fs26.realpathSync(process.cwd());
18906
- const resolved = fs26.realpathSync(path24.resolve(filePath));
18907
- if (!resolved.startsWith(cwdReal + path24.sep) && resolved !== cwdReal) {
19430
+ const cwdReal = fs27.realpathSync(process.cwd());
19431
+ const resolved = fs27.realpathSync(path25.resolve(filePath));
19432
+ if (!resolved.startsWith(cwdReal + path25.sep) && resolved !== cwdReal) {
18908
19433
  throw new Error(`file must be in the current working directory (${cwdReal})`);
18909
19434
  }
18910
- const stat = fs26.statSync(resolved);
19435
+ const stat = fs27.statSync(resolved);
18911
19436
  if (stat.size > MAX_SCAN_FILE_BYTES) {
18912
19437
  throw new Error(`file too large (max ${MAX_SCAN_FILE_BYTES} bytes)`);
18913
19438
  }
18914
- return fs26.readFileSync(resolved, "utf-8");
19439
+ return fs27.readFileSync(resolved, "utf-8");
18915
19440
  }
18916
19441
  function toolResultPayload(result) {
18917
19442
  const isError = result.startsWith("Error:") || result.startsWith("Unknown tool:");
@@ -18920,20 +19445,22 @@ function toolResultPayload(result) {
18920
19445
  ...isError ? { isError: true } : {}
18921
19446
  };
18922
19447
  }
18923
- var pkgPath = path24.resolve(__dirname, "..", "package.json");
19448
+ var pkgPath = path25.resolve(__dirname, "..", "package.json");
18924
19449
  var pkgVersion = (() => {
18925
19450
  try {
18926
- return JSON.parse(fs26.readFileSync(pkgPath, "utf-8")).version;
19451
+ return JSON.parse(fs27.readFileSync(pkgPath, "utf-8")).version;
18927
19452
  } catch {
18928
19453
  return "2.7.1";
18929
19454
  }
18930
19455
  })();
18931
- async function resolveProfile(slug, allowServerFetch = false) {
18932
- const profile = await loadProfileForCommand(slug, { allowServerFetch });
18933
- if (slug && !profile) {
18934
- const { requirePaidFeature: requirePaidFeature2 } = await Promise.resolve().then(() => (init_access(), access_exports));
18935
- await requirePaidFeature2("premiumPrompts");
18936
- return loadProfileForCommand(slug, { allowServerFetch: true });
19456
+ async function resolveProfile(slug) {
19457
+ await ensureMcpProfilesHydrated();
19458
+ let profile = await loadProfileForCommand(slug, { allowServerFetch: true });
19459
+ if (!profile && slug) {
19460
+ try {
19461
+ profile = await loadFullProfile(normalizeProfileSlug(slug), { forceRefresh: true });
19462
+ } catch {
19463
+ }
18937
19464
  }
18938
19465
  return profile;
18939
19466
  }
@@ -19033,27 +19560,8 @@ async function toolScan(args2) {
19033
19560
  }
19034
19561
  }
19035
19562
  async function toolProfiles(_args) {
19036
- const local = [.../* @__PURE__ */ new Set([...listCachedProfiles(), ...listDiskCachedProfiles()])];
19037
- if (local.length > 0) {
19038
- return "Cached profiles (local):\n" + local.map((p) => ` \u2022 ${p}`).join("\n");
19039
- }
19040
- try {
19041
- const { apiGet: apiGet2 } = await Promise.resolve().then(() => (init_api(), api_exports));
19042
- const data = await apiGet2("/cli/profiles");
19043
- const profiles = data.profiles || [];
19044
- if (profiles.length === 0) {
19045
- return "No voice profiles found. Free local scan works without a profile. Run: hyv init";
19046
- }
19047
- return profiles.map(
19048
- (p) => `${p.name}${p.is_default ? " (default)" : ""}${p.keywords?.length ? " \u2014 " + p.keywords.slice(0, 3).join(", ") : ""}`
19049
- ).join("\n");
19050
- } catch (err) {
19051
- const msg = err.message || "";
19052
- if (msg.includes("session expired") || msg.includes("not signed in")) {
19053
- return "Not signed in. Free local scan/fix/check work offline. Run `hyv init` for profiles.";
19054
- }
19055
- return `Cached profiles: none. Free local engine ready. (${msg})`;
19056
- }
19563
+ const hydrate = await ensureMcpProfilesHydrated();
19564
+ return formatMcpProfilesList(hydrate);
19057
19565
  }
19058
19566
  async function toolValidate(args2) {
19059
19567
  const text = args2.text || "";
@@ -19161,6 +19669,22 @@ function toolListFreeTools() {
19161
19669
  function toolDemo() {
19162
19670
  return getDemoText();
19163
19671
  }
19672
+ function toolMcpSetup(args2 = {}) {
19673
+ const action = (args2.action || "status").toLowerCase();
19674
+ const force = Boolean(args2.force);
19675
+ switch (action) {
19676
+ case "status":
19677
+ return buildMcpAgentStatus();
19678
+ case "integrate": {
19679
+ const result = runMcpAutoIntegrate({ force });
19680
+ return formatMcpIntegrateReportText(result, { force });
19681
+ }
19682
+ case "chatgpt":
19683
+ return formatChatGptConnectorGuide();
19684
+ default:
19685
+ return `Error: unknown action "${args2.action}". Use status, integrate, or chatgpt.`;
19686
+ }
19687
+ }
19164
19688
  async function toolAnalyze(args2) {
19165
19689
  const text = args2.text || "";
19166
19690
  if (!text.trim())
@@ -19255,6 +19779,23 @@ async function toolClean(args2) {
19255
19779
  }
19256
19780
  }
19257
19781
  var TOOLS = [
19782
+ {
19783
+ name: "hyv_mcp_setup",
19784
+ description: "MCP host setup without terminal: status of installed apps, auto-integrate configs, or ChatGPT Desktop connector steps. Works with or without a voice profile \u2014 use hyv_welcome for onboarding.",
19785
+ inputSchema: {
19786
+ type: "object",
19787
+ properties: {
19788
+ action: {
19789
+ type: "string",
19790
+ description: "status (default) | integrate (wire hyv into Cursor/Claude/etc.) | chatgpt (desktop connector steps)"
19791
+ },
19792
+ force: {
19793
+ type: "boolean",
19794
+ description: "Refresh MCP configs even when already integrated (e.g. after hyv upgrade)"
19795
+ }
19796
+ }
19797
+ }
19798
+ },
19258
19799
  {
19259
19800
  name: "hyv_welcome",
19260
19801
  description: "Profile-first onboarding: name \u2192 samples \u2192 test draft \u2192 signup. Call when the user is new. Use step (1-4) for one step, mode extract_prompt for chat voice extraction.",
@@ -19377,7 +19918,7 @@ var TOOLS = [
19377
19918
  },
19378
19919
  {
19379
19920
  name: "hyv_profiles",
19380
- description: "List cached or account voice profiles. Falls back gracefully when not signed in.",
19921
+ description: "List voice profiles ready for MCP tools (local + account after hyv init). Shows active default. Call before hyv_rewrite/hyv_clean if unsure which profile to use.",
19381
19922
  inputSchema: { type: "object", properties: {} }
19382
19923
  },
19383
19924
  {
@@ -19402,14 +19943,15 @@ var PROMPTS = [
19402
19943
  ];
19403
19944
  var HYV_STATUS_PROMPT = `Use hold your voice MCP tools:
19404
19945
 
19405
- 1. New user \u2192 hyv_welcome (or step 1\u20134). Step 2: hyv_welcome mode=extract_prompt to build profile from chat.
19406
- 2. Save profile \u2192 user runs hyv import <name> file.md (or you draft markdown for them).
19407
- 3. hyv_profiles \u2014 list local/account profiles.
19408
- 4. Writing: hyv_scan \u2192 hyv_fix / hyv_rewrite \u2192 hyv_validate.
19409
- 5. Ready to pay \u2192 hyv init + hyv plan --upgrade (signup last, not first).
19946
+ 0. MCP setup \u2192 hyv_mcp_setup (status | integrate | chatgpt). Profiles \u2192 hyv_profiles (lists MCP-ready profiles).
19947
+ 1. Profiles work automatically: terminal \`hyv welcome\` saves locally; dashboard profiles need \`hyv init\` once on this machine (MCP auto-syncs).
19948
+ 2. New onboarding in chat \u2192 hyv_welcome. Step 2: mode=extract_prompt. Save markdown \u2192 hyv import or dashboard.
19949
+ 3. Writing (use active profile from hyv_profiles): hyv_scan \u2192 hyv_fix / hyv_rewrite \u2192 hyv_validate. Optional profile= slug.
19950
+ 4. Paid extras \u2192 hyv init + hyv plan --upgrade (signup last).
19410
19951
 
19411
19952
  Keep the answer compact.`;
19412
19953
  var TOOL_HANDLERS = {
19954
+ hyv_mcp_setup: toolMcpSetup,
19413
19955
  hyv_welcome: toolWelcome,
19414
19956
  hyv_list_free_tools: () => toolListFreeTools(),
19415
19957
  hyv_demo: () => toolDemo(),
@@ -19504,14 +20046,31 @@ async function handleRequest(line) {
19504
20046
  }
19505
20047
  async function startMcpServer() {
19506
20048
  const access = await getAccessState().catch(() => null);
19507
- if (fs26.existsSync(VOICE_MD)) {
20049
+ const config = (() => {
20050
+ try {
20051
+ return JSON.parse(fs27.readFileSync(path25.join(os13.homedir(), ".hyv", "config.json"), "utf-8"));
20052
+ } catch {
20053
+ return {};
20054
+ }
20055
+ })();
20056
+ const defaultProfile = config.default_profile || config.profile;
20057
+ if (defaultProfile) {
20058
+ mcpLog("info", `default profile: ${defaultProfile}`);
20059
+ } else if (fs27.existsSync(VOICE_MD)) {
19508
20060
  mcpLog("info", `voice profile: ${VOICE_MD}`);
19509
20061
  } else {
19510
- mcpLog("info", "free local engine ready \u2014 no voice profile yet");
20062
+ mcpLog("info", "free local engine ready \u2014 no voice profile yet (hyv_profiles / hyv init)");
19511
20063
  }
19512
20064
  if (access) {
19513
20065
  mcpLog("info", `mode: ${access.hasPaidPlan ? "paid" : "free local"}${access.authenticated ? "" : " (not signed in)"}`);
19514
20066
  }
20067
+ ensureMcpProfilesHydrated().then((r) => {
20068
+ if (r.synced?.length)
20069
+ mcpLog("info", `synced account profiles: ${r.synced.join(", ")}`);
20070
+ else if (r.error)
20071
+ mcpLog("info", `account profile sync skipped: ${r.error}`);
20072
+ }).catch(() => {
20073
+ });
19515
20074
  let buffer = "";
19516
20075
  process.stdin.setEncoding("utf-8");
19517
20076
  let requestChain = Promise.resolve();
@@ -19536,150 +20095,176 @@ async function startMcpServer() {
19536
20095
  }
19537
20096
 
19538
20097
  // src/lib/mcp-setup.ts
19539
- var import_chalk32 = __toESM(require_source());
19540
- var fs27 = __toESM(require("fs"));
19541
- var path25 = __toESM(require("path"));
19542
- var os12 = __toESM(require("os"));
20098
+ var import_chalk33 = __toESM(require_source());
20099
+ var fs28 = __toESM(require("fs"));
20100
+ var path26 = __toESM(require("path"));
20101
+ var os14 = __toESM(require("os"));
19543
20102
  init_version();
19544
- var HOME2 = os12.homedir();
20103
+ var HOME2 = os14.homedir();
19545
20104
  var IS_WIN2 = process.platform === "win32";
19546
20105
  function claudeDesktopConfigPath() {
19547
20106
  if (IS_WIN2)
19548
- return path25.join(HOME2, "AppData", "Roaming", "Claude", "claude_desktop_config.json");
20107
+ return path26.join(HOME2, "AppData", "Roaming", "Claude", "claude_desktop_config.json");
19549
20108
  if (process.platform === "linux")
19550
- return path25.join(HOME2, ".config", "Claude", "claude_desktop_config.json");
19551
- return path25.join(HOME2, "Library", "Application Support", "Claude", "claude_desktop_config.json");
20109
+ return path26.join(HOME2, ".config", "Claude", "claude_desktop_config.json");
20110
+ return path26.join(HOME2, "Library", "Application Support", "Claude", "claude_desktop_config.json");
19552
20111
  }
19553
20112
  function printMcpSetup() {
19554
- console.log(import_chalk32.default.bold("\nhold your voice \u2014 mcp setup\n"));
19555
- console.log(import_chalk32.default.dim(` ${getEngineLabel()}
20113
+ console.log(import_chalk33.default.bold("\nhold your voice \u2014 mcp setup\n"));
20114
+ console.log(import_chalk33.default.dim(` ${getEngineLabel()}
19556
20115
  `));
19557
- console.log(import_chalk32.default.bold("Claude Desktop"));
19558
- console.log(import_chalk32.default.dim(" Add to claude_desktop_config.json \u2192 mcpServers.hyv:"));
19559
- console.log(import_chalk32.default.cyan(` ${mcpServerSnippet().split("\n").join("\n ")}`));
19560
- console.log(import_chalk32.default.dim(` Config: ${claudeDesktopConfigPath()}
20116
+ console.log(import_chalk33.default.bold("Claude Desktop"));
20117
+ console.log(import_chalk33.default.dim(" Add to claude_desktop_config.json \u2192 mcpServers.hyv:"));
20118
+ console.log(import_chalk33.default.cyan(` ${mcpServerSnippet().split("\n").join("\n ")}`));
20119
+ console.log(import_chalk33.default.dim(` Config: ${claudeDesktopConfigPath()}
19561
20120
  `));
19562
- console.log(import_chalk32.default.bold("Cursor"));
19563
- console.log(import_chalk32.default.dim(" MCP: ~/.cursor/mcp.json \u2192 mcpServers.hyv (same JSON as above)"));
19564
- console.log(import_chalk32.default.dim(" Rule: ~/.cursor/rules/hyv.mdc (alwaysApply \u2014 auto via postinstall)\n"));
19565
- console.log(import_chalk32.default.bold("Claude Code"));
19566
- console.log(import_chalk32.default.dim(" Command: ~/.claude/commands/hyv.md"));
19567
- console.log(import_chalk32.default.dim(" Skill: ~/.claude/skills/hold-your-voice/SKILL.md\n"));
19568
- console.log(import_chalk32.default.bold("Windsurf"));
19569
- console.log(import_chalk32.default.dim(" Rule: ~/.windsurf/rules/hyv.md (trigger: always_on)\n"));
19570
- console.log(import_chalk32.default.bold("Codex"));
19571
- console.log(import_chalk32.default.dim(" Instructions: ~/.codex/AGENTS.md (merged on install)\n"));
19572
- console.log(import_chalk32.default.bold("Command Code"));
19573
- console.log(import_chalk32.default.dim(" Skill: ~/.commandcode/skills/hyv/SKILL.md\n"));
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)"));
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"));
19584
- console.log(import_chalk32.default.bold("Auto-configure"));
19585
- console.log(import_chalk32.default.dim(" hyv doctor --fix-agents"));
19586
- console.log(import_chalk32.default.dim(" HYV_AUTO_CONFIGURE_AGENTS=0 npm i -g @holdyourvoice/hyv (skip)\n"));
19587
- console.log(import_chalk32.default.bold("Verify"));
19588
- console.log(import_chalk32.default.dim(" hyv mcp --test"));
19589
- console.log(import_chalk32.default.dim(" HYV_TELEMETRY=1 hyv mcp (optional usage logging to ~/.hyv/telemetry/)\n"));
20121
+ console.log(import_chalk33.default.bold("Cursor"));
20122
+ console.log(import_chalk33.default.dim(" MCP: ~/.cursor/mcp.json \u2192 mcpServers.hyv (same JSON as above)"));
20123
+ console.log(import_chalk33.default.dim(" Rule: ~/.cursor/rules/hyv.mdc (alwaysApply \u2014 auto via postinstall)\n"));
20124
+ console.log(import_chalk33.default.bold("Claude Code"));
20125
+ console.log(import_chalk33.default.dim(" Command: ~/.claude/commands/hyv.md"));
20126
+ console.log(import_chalk33.default.dim(" Skill: ~/.claude/skills/hold-your-voice/SKILL.md\n"));
20127
+ console.log(import_chalk33.default.bold("Windsurf"));
20128
+ console.log(import_chalk33.default.dim(" Rule: ~/.windsurf/rules/hyv.md (trigger: always_on)\n"));
20129
+ console.log(import_chalk33.default.bold("Codex"));
20130
+ console.log(import_chalk33.default.dim(" Instructions: ~/.codex/AGENTS.md (merged on install)\n"));
20131
+ console.log(import_chalk33.default.bold("Command Code"));
20132
+ console.log(import_chalk33.default.dim(" Skill: ~/.commandcode/skills/hyv/SKILL.md\n"));
20133
+ console.log(import_chalk33.default.bold("ChatGPT Desktop (manual connector)"));
20134
+ console.log(import_chalk33.default.dim(" Settings \u2192 Connectors \u2192 add connector"));
20135
+ console.log(import_chalk33.default.dim(" Name: hold your voice | Command: hyv | Arguments: mcp"));
20136
+ console.log(import_chalk33.default.dim(" Guide: ~/.chatgpt/hyv-mcp-connector.txt (after hyv doctor --fix-agents)"));
20137
+ console.log(import_chalk33.default.dim(" hyv mcp --setup-chatgpt\n"));
20138
+ console.log(import_chalk33.default.bold("Antigravity"));
20139
+ console.log(import_chalk33.default.dim(" MCP: ~/.gemini/config/mcp_config.json \u2192 mcpServers.hyv (auto via postinstall)\n"));
20140
+ console.log(import_chalk33.default.bold("OpenCode"));
20141
+ console.log(import_chalk33.default.dim(" MCP: ~/.config/opencode/opencode.jsonc \u2192 mcp.hyv (auto via postinstall)"));
20142
+ console.log(import_chalk33.default.dim(" Rules: ~/.config/opencode/AGENTS.md\n"));
20143
+ console.log(import_chalk33.default.bold("Auto-configure"));
20144
+ console.log(import_chalk33.default.dim(" hyv mcp (detect installed apps + wire mcp into them)"));
20145
+ console.log(import_chalk33.default.dim(" hyv mcp --force (refresh configs after hyv upgrade)"));
20146
+ console.log(import_chalk33.default.dim(" hyv doctor --fix-agents (configure all apps, not just detected)"));
20147
+ console.log(import_chalk33.default.dim(" HYV_AUTO_CONFIGURE_AGENTS=0 npm i -g @holdyourvoice/hyv (skip)\n"));
20148
+ console.log(import_chalk33.default.bold("In-chat (no terminal)"));
20149
+ console.log(import_chalk33.default.dim(" hyv_mcp_setup \u2014 status, integrate, or chatgpt connector steps"));
20150
+ console.log(import_chalk33.default.dim(" hyv_welcome \u2014 finish onboarding inside Cursor/Claude/ChatGPT\n"));
20151
+ console.log(import_chalk33.default.bold("Verify"));
20152
+ console.log(import_chalk33.default.dim(" hyv mcp --test"));
20153
+ console.log(import_chalk33.default.dim(" HYV_TELEMETRY=1 hyv mcp (optional usage logging to ~/.hyv/telemetry/)\n"));
19590
20154
  }
19591
20155
  async function runMcpSelfTest() {
19592
- console.log(import_chalk32.default.bold("\nhold your voice \u2014 mcp self-test\n"));
19593
- console.log(import_chalk32.default.dim(` ${getEngineLabel()}
20156
+ console.log(import_chalk33.default.bold("\nhold your voice \u2014 mcp self-test\n"));
20157
+ console.log(import_chalk33.default.dim(` ${getEngineLabel()}
19594
20158
  `));
19595
20159
  let passed = 0;
19596
20160
  let failed = 0;
19597
20161
  const tools = getMcpToolNames();
19598
20162
  if (tools.length >= 10) {
19599
- console.log(import_chalk32.default.green(` \u2713 ${tools.length} MCP tools registered`));
20163
+ console.log(import_chalk33.default.green(` \u2713 ${tools.length} MCP tools registered`));
19600
20164
  passed++;
19601
20165
  } else {
19602
- console.log(import_chalk32.default.red(` \u2717 expected 10+ tools, got ${tools.length}`));
20166
+ console.log(import_chalk33.default.red(` \u2717 expected 10+ tools, got ${tools.length}`));
19603
20167
  failed++;
19604
20168
  }
19605
- const required = ["hyv_welcome", "hyv_scan", "hyv_analyze", "hyv_clean", "hyv_validate", "hyv_list_free_tools"];
20169
+ const required = [
20170
+ "hyv_mcp_setup",
20171
+ "hyv_welcome",
20172
+ "hyv_scan",
20173
+ "hyv_analyze",
20174
+ "hyv_clean",
20175
+ "hyv_validate",
20176
+ "hyv_list_free_tools"
20177
+ ];
19606
20178
  for (const name of required) {
19607
20179
  if (tools.includes(name)) {
19608
- console.log(import_chalk32.default.green(` \u2713 tool: ${name}`));
20180
+ console.log(import_chalk33.default.green(` \u2713 tool: ${name}`));
19609
20181
  passed++;
19610
20182
  } else {
19611
- console.log(import_chalk32.default.red(` \u2717 missing tool: ${name}`));
20183
+ console.log(import_chalk33.default.red(` \u2717 missing tool: ${name}`));
19612
20184
  failed++;
19613
20185
  }
19614
20186
  }
19615
20187
  try {
19616
20188
  const welcome = await invokeMcpTool("hyv_welcome", {});
19617
20189
  if (welcome.includes("Hold Your Voice") || welcome.includes("hold your voice")) {
19618
- console.log(import_chalk32.default.green(" \u2713 hyv_welcome responds"));
20190
+ console.log(import_chalk33.default.green(" \u2713 hyv_welcome responds"));
20191
+ passed++;
20192
+ } else {
20193
+ console.log(import_chalk33.default.red(" \u2717 hyv_welcome unexpected output"));
20194
+ failed++;
20195
+ }
20196
+ } catch (e) {
20197
+ console.log(import_chalk33.default.red(` \u2717 hyv_welcome failed: ${e.message}`));
20198
+ failed++;
20199
+ }
20200
+ try {
20201
+ const setup = await invokeMcpTool("hyv_mcp_setup", { action: "status" });
20202
+ if (setup.includes("HYV MCP status") && setup.includes("hyv_welcome")) {
20203
+ console.log(import_chalk33.default.green(" \u2713 hyv_mcp_setup responds"));
19619
20204
  passed++;
19620
20205
  } else {
19621
- console.log(import_chalk32.default.red(" \u2717 hyv_welcome unexpected output"));
20206
+ console.log(import_chalk33.default.red(" \u2717 hyv_mcp_setup unexpected output"));
19622
20207
  failed++;
19623
20208
  }
19624
20209
  } catch (e) {
19625
- console.log(import_chalk32.default.red(` \u2717 hyv_welcome failed: ${e.message}`));
20210
+ console.log(import_chalk33.default.red(` \u2717 hyv_mcp_setup failed: ${e.message}`));
19626
20211
  failed++;
19627
20212
  }
19628
20213
  try {
19629
20214
  const demo = await invokeMcpTool("hyv_demo", {});
19630
20215
  if (demo.includes("Score") || demo.includes("issues")) {
19631
- console.log(import_chalk32.default.green(" \u2713 hyv_demo pipeline works"));
20216
+ console.log(import_chalk33.default.green(" \u2713 hyv_demo pipeline works"));
19632
20217
  passed++;
19633
20218
  } else {
19634
- console.log(import_chalk32.default.red(" \u2717 hyv_demo unexpected output"));
20219
+ console.log(import_chalk33.default.red(" \u2717 hyv_demo unexpected output"));
19635
20220
  failed++;
19636
20221
  }
19637
20222
  } catch (e) {
19638
- console.log(import_chalk32.default.red(` \u2717 hyv_demo failed: ${e.message}`));
20223
+ console.log(import_chalk33.default.red(` \u2717 hyv_demo failed: ${e.message}`));
19639
20224
  failed++;
19640
20225
  }
19641
- const voiceMd = path25.join(HOME2, ".hyv", "voice.md");
19642
- if (fs27.existsSync(voiceMd)) {
19643
- console.log(import_chalk32.default.green(" \u2713 voice profile found"));
20226
+ const voiceMd = path26.join(HOME2, ".hyv", "voice.md");
20227
+ if (fs28.existsSync(voiceMd)) {
20228
+ console.log(import_chalk33.default.green(" \u2713 voice profile found"));
19644
20229
  passed++;
19645
20230
  } else {
19646
- console.log(import_chalk32.default.dim(" - no voice.md (free local engine still works)"));
20231
+ console.log(import_chalk33.default.dim(" - no voice.md (free local engine still works)"));
19647
20232
  }
19648
20233
  if (getDemoText().length > 100) {
19649
- console.log(import_chalk32.default.green(" \u2713 demo content available"));
20234
+ console.log(import_chalk33.default.green(" \u2713 demo content available"));
19650
20235
  passed++;
19651
20236
  } else {
19652
- console.log(import_chalk32.default.red(" \u2717 demo content missing"));
20237
+ console.log(import_chalk33.default.red(" \u2717 demo content missing"));
19653
20238
  failed++;
19654
20239
  }
19655
20240
  try {
19656
20241
  const stdio = await testMcpStdioSubprocess();
19657
20242
  if (stdio.ok && (stdio.toolCount || 0) >= 10) {
19658
- console.log(import_chalk32.default.green(` \u2713 stdio MCP subprocess responds (${stdio.toolCount} tools)`));
20243
+ console.log(import_chalk33.default.green(` \u2713 stdio MCP subprocess responds (${stdio.toolCount} tools)`));
19659
20244
  passed++;
19660
20245
  } else if (stdio.ok) {
19661
- console.log(import_chalk32.default.yellow(` ! stdio MCP subprocess ok but only ${stdio.toolCount || 0} tools`));
20246
+ console.log(import_chalk33.default.yellow(` ! stdio MCP subprocess ok but only ${stdio.toolCount || 0} tools`));
19662
20247
  failed++;
19663
20248
  } else {
19664
- console.log(import_chalk32.default.red(" \u2717 stdio MCP subprocess failed"));
20249
+ console.log(import_chalk33.default.red(" \u2717 stdio MCP subprocess failed"));
19665
20250
  failed++;
19666
20251
  }
19667
20252
  } catch (e) {
19668
- console.log(import_chalk32.default.red(` \u2717 stdio MCP subprocess failed: ${e.message}`));
20253
+ console.log(import_chalk33.default.red(` \u2717 stdio MCP subprocess failed: ${e.message}`));
19669
20254
  failed++;
19670
20255
  }
19671
20256
  console.log("");
19672
20257
  if (failed === 0) {
19673
- console.log(import_chalk32.default.green(`\u2713 all checks passed (${passed})`));
19674
- console.log(import_chalk32.default.dim("\nStart server: hyv mcp\n"));
20258
+ console.log(import_chalk33.default.green(`\u2713 all checks passed (${passed})`));
20259
+ console.log(import_chalk33.default.dim("\nStart server: hyv mcp\n"));
19675
20260
  return true;
19676
20261
  }
19677
- console.log(import_chalk32.default.yellow(`! ${failed} check(s) failed, ${passed} passed`));
20262
+ console.log(import_chalk33.default.yellow(`! ${failed} check(s) failed, ${passed} passed`));
19678
20263
  return false;
19679
20264
  }
19680
20265
 
19681
20266
  // src/commands/export.ts
19682
- var fs28 = __toESM(require("fs"));
20267
+ var fs29 = __toESM(require("fs"));
19683
20268
  init_api();
19684
20269
  var FORMATS = {
19685
20270
  claude: {
@@ -19766,7 +20351,7 @@ async function exportCommand(format, opts) {
19766
20351
  const prompt = fmt.wrap(detail.profile, detail.body);
19767
20352
  if (opts.output) {
19768
20353
  const outFile = opts.output.replace("{name}", profile.slug || profile.name);
19769
- fs28.writeFileSync(outFile, prompt);
20354
+ fs29.writeFileSync(outFile, prompt);
19770
20355
  results.push({ profile: profile.name, file: outFile });
19771
20356
  } else {
19772
20357
  results.push({ profile: profile.name, prompt });
@@ -19803,13 +20388,13 @@ async function exportCommand(format, opts) {
19803
20388
  // src/index.ts
19804
20389
  init_access();
19805
20390
  init_welcome();
19806
- var fs29 = __toESM(require("fs"));
19807
- var path26 = __toESM(require("path"));
20391
+ var fs30 = __toESM(require("fs"));
20392
+ var path27 = __toESM(require("path"));
19808
20393
  var program2 = new Command();
19809
- var pkgPath2 = path26.resolve(__dirname, "..", "package.json");
20394
+ var pkgPath2 = path27.resolve(__dirname, "..", "package.json");
19810
20395
  var pkgVersion2 = (() => {
19811
20396
  try {
19812
- return JSON.parse(fs29.readFileSync(pkgPath2, "utf-8")).version;
20397
+ return JSON.parse(fs30.readFileSync(pkgPath2, "utf-8")).version;
19813
20398
  } catch {
19814
20399
  return "2.7.1";
19815
20400
  }
@@ -19842,7 +20427,7 @@ registerOpenCommand(program2);
19842
20427
  registerWelcomeCommand(program2);
19843
20428
  registerContentCommand(program2);
19844
20429
  registerUpgradeCommand(program2);
19845
- program2.command("mcp").description("Start MCP server (for Claude Desktop and other MCP hosts)").option("--setup", "Show MCP setup for Claude Desktop, Cursor, Windsurf, Codex").option("--test", "Run MCP health check (tools, profile, stdio)").option("--setup-chatgpt", "Show ChatGPT connector setup instructions").action(async (opts) => {
20430
+ program2.command("mcp").description("Detect local AI apps, wire hyv MCP into them, or start stdio server for hosts").option("--setup", "Show MCP setup for Claude Desktop, Cursor, Windsurf, Codex").option("--test", "Run MCP health check (tools, profile, stdio)").option("--setup-chatgpt", "Show ChatGPT connector setup instructions").option("--force", "Refresh MCP configs even when already integrated (e.g. after hyv upgrade)").option("--stdio", "Start MCP stdio server (used by Cursor, Claude Desktop, etc.)").option("--integrate-only", "Detect and configure apps without starting stdio server").action(async (opts) => {
19846
20431
  if (opts.setup) {
19847
20432
  printMcpSetup();
19848
20433
  return;
@@ -19853,26 +20438,21 @@ program2.command("mcp").description("Start MCP server (for Claude Desktop and ot
19853
20438
  return;
19854
20439
  }
19855
20440
  if (opts.setupChatgpt) {
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"));
19867
- console.log("");
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."));
20441
+ console.log(import_chalk34.default.bold("\nhold your voice \u2014 chatgpt desktop mcp setup\n"));
20442
+ console.log(formatChatGptConnectorGuide());
20443
+ console.log(import_chalk34.default.dim("\nBrowser chatgpt cannot use local MCP \u2014 desktop app only."));
20444
+ console.log(import_chalk34.default.dim("In ChatGPT chat: call hyv_mcp_setup or hyv_welcome \u2014 no terminal needed.\n"));
19874
20445
  return;
19875
20446
  }
20447
+ const wantsIntegrate = Boolean(opts.integrateOnly || process.stdin.isTTY);
20448
+ if (wantsIntegrate) {
20449
+ const integrateOpts = { force: Boolean(opts.force) };
20450
+ const result = runMcpAutoIntegrate(integrateOpts);
20451
+ printMcpIntegrateReport(result, integrateOpts);
20452
+ if (!opts.stdio)
20453
+ return;
20454
+ console.log(import_chalk34.default.dim("starting stdio mcp server for local testing (ctrl+c to stop)\u2026\n"));
20455
+ }
19876
20456
  startMcpServer();
19877
20457
  });
19878
20458
  program2.command("export").description("Export voice profile for LLMs").argument("[format]", "Export format (claude, chatgpt, generic, cursor)", "claude").option("--output <file>", "Write to file instead of stdout").option("--json", "Output as JSON").action(async (format, opts) => {