@holdyourvoice/hyv 2.9.14 → 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
  }
@@ -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>`);
@@ -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: {
@@ -5889,15 +5883,11 @@ async function request2(method, path27, body) {
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,130 +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 subStatus = String(session.subscription_status || "").toLowerCase();
5947
- const activeSubscription = !subStatus || ["active", "past_due", "trialing"].includes(subStatus);
5948
- const hasPaidPlan = session.valid && activeSubscription && plan !== "none" && plan !== "free" && plan !== "expired" && plan !== "unknown" && plan !== "pending";
5949
- const state = {
5950
- authenticated: session.valid,
5951
- hasPaidPlan,
5952
- plan: session.plan || "none",
5953
- localOnly: false
5954
- };
5955
- cachedAccess = { state, at: now };
5956
- return state;
5957
- } catch {
5958
- const state = { authenticated: !!token, hasPaidPlan: false, plan: "unknown", localOnly: false };
5959
- cachedAccess = { state, at: now };
5960
- return state;
5961
- }
5962
- }
5963
- async function requirePaidFeature(feature) {
5964
- if (isLocalOnlyMode()) {
5965
- throw new Error(
5966
- `${FEATURE_MESSAGES[feature]} (local-only mode is on \u2014 unset HYV_LOCAL_ONLY or remove --local-only)`
5967
- );
5968
- }
5969
- const token = getToken();
5970
- if (!token) {
5971
- throw new Error(`you're not signed in yet. run: hyv init \u2014 then ${FEATURE_MESSAGES[feature]}`);
5972
- }
5973
- let data;
5974
- try {
5975
- data = await apiGet("/cli/heartbeat");
5976
- } catch (err) {
5977
- const msg = err.message || "";
5978
- if (msg.includes("not signed in") || msg.includes("session expired") || msg.includes("don't have access")) {
5979
- throw err;
5980
- }
5981
- throw new Error("can't reach the server. check your internet connection and try again.");
5982
- }
5983
- const plan = (data.plan || "none").toLowerCase();
5984
- const subStatus = String(data.subscription_status || data.status || "").toLowerCase();
5985
- if (!data.plan || plan === "none" || plan === "free" || plan === "expired" || subStatus === "trialing" || subStatus === "none") {
5986
- throw new Error(FEATURE_MESSAGES[feature]);
5987
- }
5988
- }
5989
- async function maybeShowLimitedModeHint(hasProfile) {
5990
- if (isLocalOnlyMode())
5991
- return;
5992
- const access = await getAccessState();
5993
- if (access.hasPaidPlan)
5994
- return;
5995
- if (hasProfile) {
5996
- console.log(import_chalk5.default.dim("\n using cached profile (local). sync for latest: hyv sync"));
5997
- } else if (!access.authenticated) {
5998
- console.log(import_chalk5.default.dim("\n local mode \u2014 free scan engine. profiles + learning: hyv init"));
5999
- } else {
6000
- console.log(import_chalk5.default.dim("\n local mode \u2014 upgrade for full profiles + learning: hyv upgrade"));
6001
- }
6002
- }
6003
- function formatModeLabel(access, hasFullProfile) {
6004
- if (access.localOnly)
6005
- return "local-only (forced)";
6006
- if (access.hasPaidPlan && hasFullProfile)
6007
- return "full profile (paid)";
6008
- if (hasFullProfile)
6009
- return "cached profile (local)";
6010
- if (access.authenticated)
6011
- return "local engine (free)";
6012
- return "local engine (free, not signed in)";
6013
- }
6014
- var import_chalk5, FEATURE_MESSAGES, localOnlyOverride, cachedAccess, ACCESS_CACHE_MS;
6015
- var init_access = __esm({
6016
- "src/lib/access.ts"() {
6017
- "use strict";
6018
- import_chalk5 = __toESM(require_source());
6019
- init_config();
6020
- init_auth();
6021
- init_api();
6022
- FEATURE_MESSAGES = {
6023
- profiles: "syncing voice profiles from your account requires a paid plan. run: hyv upgrade",
6024
- learning: "the learning loop (reinforce, add) requires a paid plan. run: hyv upgrade",
6025
- premiumPrompts: "rich profile-aware rewrite prompts require a paid plan. run: hyv upgrade",
6026
- serverAnalysis: "server-assisted analysis requires a paid plan. run: hyv upgrade"
6027
- };
6028
- localOnlyOverride = false;
6029
- cachedAccess = null;
6030
- ACCESS_CACHE_MS = 3e4;
6031
- }
6032
- });
6033
-
6034
5900
  // src/lib/profile.ts
6035
5901
  async function loadFullProfile(slug, opts = {}) {
6036
5902
  const includeSamples = opts.includeSamples !== false;
@@ -6242,8 +6108,12 @@ function countLearnedPatterns(slug) {
6242
6108
  async function loadProfileForCommand(name, opts = {}) {
6243
6109
  const config = readConfig();
6244
6110
  const candidates = [];
6245
- if (name)
6111
+ if (name) {
6246
6112
  candidates.push(name);
6113
+ const normalized = toSafeProfileCacheKey(name);
6114
+ if (normalized !== name)
6115
+ candidates.push(normalized);
6116
+ }
6247
6117
  if (config.default_profile)
6248
6118
  candidates.push(config.default_profile);
6249
6119
  if (config.profile)
@@ -6294,6 +6164,250 @@ var init_local_profile = __esm({
6294
6164
  }
6295
6165
  });
6296
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
+
6297
6411
  // src/lib/profile-parse.ts
6298
6412
  function parseAnchorsFromBody(body) {
6299
6413
  const anchors = [];
@@ -7432,7 +7546,7 @@ function ps(n7) {
7432
7546
  return n7.replace(as, fe).replace(ls, ue).replace(cs, qt).replace(fs10, de).replace(us, pe);
7433
7547
  }
7434
7548
  function ms(n7) {
7435
- 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, ".");
7436
7550
  }
7437
7551
  function me(n7) {
7438
7552
  if (!n7)
@@ -7532,7 +7646,7 @@ function Ut(n7, t = {}) {
7532
7646
  function es(n7, t = {}) {
7533
7647
  return new I(n7, t).iterate();
7534
7648
  }
7535
- 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;
7536
7650
  var init_index_min = __esm({
7537
7651
  "node_modules/glob/dist/esm/index.min.js"() {
7538
7652
  import_node_url = require("node:url");
@@ -7579,7 +7693,7 @@ var init_index_min = __esm({
7579
7693
  is = new RegExp(fe, "g");
7580
7694
  rs = new RegExp(ue, "g");
7581
7695
  ns = new RegExp(qt, "g");
7582
- os6 = new RegExp(de, "g");
7696
+ os7 = new RegExp(de, "g");
7583
7697
  hs = new RegExp(pe, "g");
7584
7698
  as = /\\\\/g;
7585
7699
  ls = /\\{/g;
@@ -10740,18 +10854,18 @@ function stripXmlText(xml) {
10740
10854
  }
10741
10855
  function commandExists(cmd) {
10742
10856
  try {
10743
- (0, import_child_process2.execFileSync)("which", [cmd], { stdio: "ignore" });
10857
+ (0, import_child_process3.execFileSync)("which", [cmd], { stdio: "ignore" });
10744
10858
  return true;
10745
10859
  } catch {
10746
10860
  return false;
10747
10861
  }
10748
10862
  }
10749
10863
  function unzipList(filePath) {
10750
- 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 });
10751
10865
  return out.split("\n").map((l) => l.trim()).filter(Boolean);
10752
10866
  }
10753
10867
  function unzipExtract(filePath, entry) {
10754
- return (0, import_child_process2.execFileSync)("unzip", ["-p", filePath, entry], {
10868
+ return (0, import_child_process3.execFileSync)("unzip", ["-p", filePath, entry], {
10755
10869
  encoding: "utf-8",
10756
10870
  maxBuffer: 1e7
10757
10871
  });
@@ -10759,7 +10873,7 @@ function unzipExtract(filePath, entry) {
10759
10873
  function extractDocx(filePath) {
10760
10874
  if (process.platform === "darwin") {
10761
10875
  try {
10762
- 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], {
10763
10877
  encoding: "utf-8",
10764
10878
  maxBuffer: 1e7
10765
10879
  });
@@ -10802,7 +10916,7 @@ function extractPdfRaw(buffer) {
10802
10916
  function extractPdf(filePath) {
10803
10917
  if (process.platform === "darwin") {
10804
10918
  try {
10805
- 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], {
10806
10920
  encoding: "utf-8",
10807
10921
  maxBuffer: 1e7
10808
10922
  });
@@ -10812,7 +10926,7 @@ function extractPdf(filePath) {
10812
10926
  }
10813
10927
  }
10814
10928
  if (commandExists("pdftotext")) {
10815
- 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, "-"], {
10816
10930
  encoding: "utf-8",
10817
10931
  maxBuffer: 1e7
10818
10932
  });
@@ -10877,7 +10991,7 @@ function listDocumentsInDir(dirPath) {
10877
10991
  }).filter(isSupportedDocument);
10878
10992
  }
10879
10993
  function collectDocumentsFromPath(inputPath) {
10880
- const resolved = path10.resolve(inputPath.trim().replace(/^~(?=$|\/)/, os7.homedir()));
10994
+ const resolved = path10.resolve(inputPath.trim().replace(/^~(?=$|\/)/, os8.homedir()));
10881
10995
  if (!fs11.existsSync(resolved)) {
10882
10996
  throw new Error(`path not found: ${resolved}`);
10883
10997
  }
@@ -10908,19 +11022,19 @@ function readDraftInput(input) {
10908
11022
  const trimmed = input.trim();
10909
11023
  if (!trimmed)
10910
11024
  throw new Error("empty draft");
10911
- const maybePath = path10.resolve(trimmed.replace(/^~(?=$|\/)/, os7.homedir()));
11025
+ const maybePath = path10.resolve(trimmed.replace(/^~(?=$|\/)/, os8.homedir()));
10912
11026
  if (fs11.existsSync(maybePath) && fs11.statSync(maybePath).isFile()) {
10913
11027
  return { text: extractTextFromFile(maybePath), source: maybePath };
10914
11028
  }
10915
11029
  return { text: trimmed, source: "paste" };
10916
11030
  }
10917
- 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;
10918
11032
  var init_document_text = __esm({
10919
11033
  "src/lib/document-text.ts"() {
10920
11034
  "use strict";
10921
- import_child_process2 = require("child_process");
11035
+ import_child_process3 = require("child_process");
10922
11036
  fs11 = __toESM(require("fs"));
10923
- os7 = __toESM(require("os"));
11037
+ os8 = __toESM(require("os"));
10924
11038
  path10 = __toESM(require("path"));
10925
11039
  init_index_min();
10926
11040
  SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
@@ -10996,21 +11110,21 @@ function runPipeline(text, profile, applyFixes = false) {
10996
11110
  };
10997
11111
  }
10998
11112
  function readText(source) {
10999
- const fs30 = require("fs");
11000
- const path27 = require("path");
11113
+ const fs31 = require("fs");
11114
+ const path28 = require("path");
11001
11115
  if (source === "-") {
11002
11116
  if (process.stdin.isTTY) {
11003
11117
  console.error("No input provided. Pipe content or specify a file.");
11004
11118
  process.exit(1);
11005
11119
  }
11006
- return { text: fs30.readFileSync(0, "utf-8"), path: "stdin" };
11120
+ return { text: fs31.readFileSync(0, "utf-8"), path: "stdin" };
11007
11121
  }
11008
- const resolved = path27.resolve(source);
11009
- if (!fs30.existsSync(resolved)) {
11122
+ const resolved = path28.resolve(source);
11123
+ if (!fs31.existsSync(resolved)) {
11010
11124
  console.error(`File not found: ${resolved}`);
11011
11125
  process.exit(1);
11012
11126
  }
11013
- const stat = fs30.statSync(resolved);
11127
+ const stat = fs31.statSync(resolved);
11014
11128
  if (stat.isDirectory()) {
11015
11129
  console.error(`${resolved} is a directory, not a file.`);
11016
11130
  process.exit(1);
@@ -11410,7 +11524,7 @@ function isInteractiveTTY() {
11410
11524
  return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
11411
11525
  }
11412
11526
  function briefPause(ms2 = 280) {
11413
- return new Promise((resolve15) => setTimeout(resolve15, ms2));
11527
+ return new Promise((resolve16) => setTimeout(resolve16, ms2));
11414
11528
  }
11415
11529
  async function withSpinner(label, fn, opts = {}) {
11416
11530
  const minMs = opts.minMs ?? 450;
@@ -11461,10 +11575,10 @@ var init_terminal_ui = __esm({
11461
11575
 
11462
11576
  // src/lib/welcome-flow.ts
11463
11577
  function localProfilePath(name) {
11464
- return path14.join(os8.homedir(), ".hyv", "profiles", `${name}.md`);
11578
+ return path14.join(os9.homedir(), ".hyv", "profiles", `${name}.md`);
11465
11579
  }
11466
11580
  function listLocalProfileNames() {
11467
- const profilesDir = path14.join(os8.homedir(), ".hyv", "profiles");
11581
+ const profilesDir = path14.join(os9.homedir(), ".hyv", "profiles");
11468
11582
  if (!fs15.existsSync(profilesDir))
11469
11583
  return [];
11470
11584
  return fs15.readdirSync(profilesDir).filter((entry) => entry.endsWith(".md")).map((entry) => entry.slice(0, -3));
@@ -11725,10 +11839,10 @@ function saveLocalProfile(name, content) {
11725
11839
  writeWelcomeState({ profile_name: safe });
11726
11840
  markStepComplete("name");
11727
11841
  markStepComplete("samples");
11728
- return path14.join(os8.homedir(), ".hyv", "profiles", `${safe}.md`);
11842
+ return path14.join(os9.homedir(), ".hyv", "profiles", `${safe}.md`);
11729
11843
  }
11730
11844
  function fetchUrlText(url) {
11731
- return new Promise((resolve15, reject) => {
11845
+ return new Promise((resolve16, reject) => {
11732
11846
  let parsed;
11733
11847
  try {
11734
11848
  parsed = new URL(url);
@@ -11757,7 +11871,7 @@ function fetchUrlText(url) {
11757
11871
  });
11758
11872
  res.on("end", () => {
11759
11873
  const text = data.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
11760
- resolve15(text.slice(0, 12e3));
11874
+ resolve16(text.slice(0, 12e3));
11761
11875
  });
11762
11876
  }
11763
11877
  );
@@ -11777,10 +11891,10 @@ async function collectSamplesFromLink(url) {
11777
11891
  }
11778
11892
  function askLine(prompt) {
11779
11893
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
11780
- return new Promise((resolve15) => {
11894
+ return new Promise((resolve16) => {
11781
11895
  rl.question(prompt, (answer) => {
11782
11896
  rl.close();
11783
- resolve15(answer.trim());
11897
+ resolve16(answer.trim());
11784
11898
  });
11785
11899
  });
11786
11900
  }
@@ -11789,11 +11903,11 @@ async function askMultiline(intro) {
11789
11903
  console.log(import_chalk12.default.dim(" paste below, then type --- on its own line when done\n"));
11790
11904
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
11791
11905
  const lines = [];
11792
- return new Promise((resolve15) => {
11906
+ return new Promise((resolve16) => {
11793
11907
  rl.on("line", (line) => {
11794
11908
  if (line.trim() === "---") {
11795
11909
  rl.close();
11796
- resolve15(lines.join("\n").trim());
11910
+ resolve16(lines.join("\n").trim());
11797
11911
  return;
11798
11912
  }
11799
11913
  lines.push(line);
@@ -12091,7 +12205,7 @@ function getMcpWelcomeResponse(args2) {
12091
12205
  }
12092
12206
  return buildWelcomeGuide({ profileName: args2.profile, forLlm: true });
12093
12207
  }
12094
- var import_chalk12, fs15, http2, https2, os8, path14, readline, PROFILE_SYNC_TIMEOUT_MS, 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;
12095
12209
  var init_welcome_flow = __esm({
12096
12210
  "src/lib/welcome-flow.ts"() {
12097
12211
  "use strict";
@@ -12099,7 +12213,7 @@ var init_welcome_flow = __esm({
12099
12213
  fs15 = __toESM(require("fs"));
12100
12214
  http2 = __toESM(require("http"));
12101
12215
  https2 = __toESM(require("https"));
12102
- os8 = __toESM(require("os"));
12216
+ os9 = __toESM(require("os"));
12103
12217
  path14 = __toESM(require("path"));
12104
12218
  readline = __toESM(require("readline"));
12105
12219
  init_pipeline();
@@ -12121,7 +12235,7 @@ var init_welcome_flow = __esm({
12121
12235
  { n: 3, key: "test", title: "test on a draft", hint: "optional \u2014 scan or rewrite a draft" },
12122
12236
  { n: 4, key: "signup", title: "save & unlock", hint: "signup syncs your profile and unlocks learning" }
12123
12237
  ];
12124
- STATE_FILE = path14.join(os8.homedir(), ".hyv", "welcome-state.json");
12238
+ STATE_FILE = path14.join(os9.homedir(), ".hyv", "welcome-state.json");
12125
12239
  }
12126
12240
  });
12127
12241
 
@@ -13157,15 +13271,15 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
13157
13271
  g.minimatch.escape = vi2.escape;
13158
13272
  g.minimatch.unescape = Ei2.unescape;
13159
13273
  });
13160
- var fs30 = R2((Wt2) => {
13274
+ var fs31 = R2((Wt2) => {
13161
13275
  "use strict";
13162
13276
  Object.defineProperty(Wt2, "__esModule", { value: true });
13163
13277
  Wt2.LRUCache = void 0;
13164
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) => {
13165
13279
  typeof ge2.emitWarning == "function" ? ge2.emitWarning(n7, t, e, s) : console.error(`[${e}] ${t}: ${n7}`);
13166
- }, Lt2 = globalThis.AbortController, os13 = globalThis.AbortSignal;
13280
+ }, Lt2 = globalThis.AbortController, os15 = globalThis.AbortSignal;
13167
13281
  if (typeof Lt2 > "u") {
13168
- os13 = class {
13282
+ os15 = class {
13169
13283
  onabort;
13170
13284
  _onabort = [];
13171
13285
  reason;
@@ -13177,7 +13291,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
13177
13291
  constructor() {
13178
13292
  t();
13179
13293
  }
13180
- signal = new os13();
13294
+ signal = new os15();
13181
13295
  abort(e) {
13182
13296
  if (!this.signal.aborted) {
13183
13297
  this.signal.reason = e, this.signal.aborted = true;
@@ -14126,7 +14240,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
14126
14240
  };
14127
14241
  Object.defineProperty(_2, "__esModule", { value: true });
14128
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;
14129
- 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) => {
14130
14244
  let t = vs2.get(n7);
14131
14245
  if (t)
14132
14246
  return t;
@@ -15645,7 +15759,7 @@ var {
15645
15759
  } = import_index.default;
15646
15760
 
15647
15761
  // src/index.ts
15648
- var import_chalk33 = __toESM(require_source());
15762
+ var import_chalk34 = __toESM(require_source());
15649
15763
 
15650
15764
  // src/commands/init.ts
15651
15765
  var import_chalk4 = __toESM(require_source());
@@ -15791,10 +15905,19 @@ function registerInitCommand(program3) {
15791
15905
  if (authData.license_key) {
15792
15906
  console.log(import_chalk4.default.dim(` License: ${authData.license_key.slice(0, 12)}...`));
15793
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
+ }
15794
15917
  const mcpResults = configureMcpForDesktop();
15795
15918
  const { printPaidUnlockReminder: printPaidUnlockReminder2 } = await Promise.resolve().then(() => (init_marketing_hints(), marketing_hints_exports));
15796
15919
  console.log("\nNext steps:");
15797
- 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)"));
15798
15921
  console.log(import_chalk4.default.dim(" 2. Scan a draft: hyv scan draft.md"));
15799
15922
  console.log(import_chalk4.default.dim(" 3. Rewrite with voice: hyv rewrite draft.md"));
15800
15923
  printPaidUnlockReminder2();
@@ -16018,6 +16141,8 @@ init_profile();
16018
16141
  init_profile_meta();
16019
16142
  var fs8 = __toESM(require("fs"));
16020
16143
  var path8 = __toESM(require("path"));
16144
+ var os6 = __toESM(require("os"));
16145
+ var import_child_process2 = require("child_process");
16021
16146
  function registerSyncCommand(program3) {
16022
16147
  program3.command("sync").description("Sync profiles and rules from server").option("--force", "Force re-download even if cache is fresh").action(async (options) => {
16023
16148
  try {
@@ -16105,7 +16230,15 @@ function registerSyncCommand(program3) {
16105
16230
  process.exit(1);
16106
16231
  }
16107
16232
  });
16108
- 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
+ }
16109
16242
  if (options.history) {
16110
16243
  await showProfileHistory(options.history);
16111
16244
  return;
@@ -16151,6 +16284,58 @@ ${profiles.length} profile(s) cached.`));
16151
16284
  await program3.parseAsync(["node", "hyv", "sync", "--force"]);
16152
16285
  });
16153
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
+ }
16154
16339
  async function showProfileHistory(slug) {
16155
16340
  const { authenticatedRequest: authenticatedRequest2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
16156
16341
  const token = getToken();
@@ -16990,7 +17175,7 @@ function registerImportCommand(program3) {
16990
17175
  });
16991
17176
  }
16992
17177
  function askQuestion(question) {
16993
- return new Promise((resolve15) => {
17178
+ return new Promise((resolve16) => {
16994
17179
  const readline3 = require("readline");
16995
17180
  const rl = readline3.createInterface({
16996
17181
  input: process.stdin,
@@ -16999,7 +17184,7 @@ function askQuestion(question) {
16999
17184
  rl.question(import_chalk13.default.cyan(` ${question}
17000
17185
  > `), (answer) => {
17001
17186
  rl.close();
17002
- resolve15(answer.trim());
17187
+ resolve16(answer.trim());
17003
17188
  });
17004
17189
  });
17005
17190
  }
@@ -17558,7 +17743,7 @@ hyv scan ${filePath}`));
17558
17743
  var import_chalk19 = __toESM(require_source());
17559
17744
  var fs19 = __toESM(require("fs"));
17560
17745
  var path18 = __toESM(require("path"));
17561
- var os9 = __toESM(require("os"));
17746
+ var os10 = __toESM(require("os"));
17562
17747
  init_config();
17563
17748
  init_auth();
17564
17749
  init_access();
@@ -17566,7 +17751,7 @@ init_local_profile();
17566
17751
  init_version();
17567
17752
 
17568
17753
  // src/lib/mcp-stdio-test.ts
17569
- var import_child_process3 = require("child_process");
17754
+ var import_child_process4 = require("child_process");
17570
17755
 
17571
17756
  // src/lib/cli-entry.ts
17572
17757
  var fs18 = __toESM(require("fs"));
@@ -17596,8 +17781,8 @@ async function testMcpStdioSubprocess() {
17596
17781
  const entry = resolveCliEntry();
17597
17782
  if (!entry)
17598
17783
  return { ok: false };
17599
- return new Promise((resolve15) => {
17600
- 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"], {
17601
17786
  stdio: ["pipe", "pipe", "pipe"],
17602
17787
  env: { ...process.env, HYV_POSTINSTALL_QUIET: "1" }
17603
17788
  });
@@ -17612,7 +17797,7 @@ async function testMcpStdioSubprocess() {
17612
17797
  child.kill();
17613
17798
  } catch {
17614
17799
  }
17615
- resolve15({ ok, toolCount });
17800
+ resolve16({ ok, toolCount });
17616
17801
  };
17617
17802
  const timeout = setTimeout(() => finish(false), 1e4);
17618
17803
  const handleLine = (line) => {
@@ -17663,7 +17848,7 @@ async function testMcpStdioSubprocess() {
17663
17848
  }
17664
17849
 
17665
17850
  // src/commands/doctor.ts
17666
- var HOME = os9.homedir();
17851
+ var HOME = os10.homedir();
17667
17852
  var IS_WIN = process.platform === "win32";
17668
17853
  function claudeDesktopDir() {
17669
17854
  if (IS_WIN)
@@ -17874,7 +18059,7 @@ function registerDoctorCommand(program3) {
17874
18059
  if (cursorMcp)
17875
18060
  console.log(import_chalk19.default.green(" \u2713 mcp configured for cursor"));
17876
18061
  } else {
17877
- 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"));
17878
18063
  issues++;
17879
18064
  }
17880
18065
  try {
@@ -18017,11 +18202,11 @@ async function confirmDestructiveWrite(options) {
18017
18202
  const question = `
18018
18203
  ${label}
18019
18204
  A .bak backup will be created. Proceed? [y/N] `;
18020
- const answer = await new Promise((resolve15) => {
18205
+ const answer = await new Promise((resolve16) => {
18021
18206
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
18022
18207
  rl.question(question, (value) => {
18023
18208
  rl.close();
18024
- resolve15(value.trim().toLowerCase());
18209
+ resolve16(value.trim().toLowerCase());
18025
18210
  });
18026
18211
  });
18027
18212
  return answer === "y" || answer === "yes";
@@ -18127,19 +18312,19 @@ function registerCheckCommand(program3) {
18127
18312
  const profile = await loadProfileForCommand(options.profile);
18128
18313
  let inputText = text;
18129
18314
  if (text === "-") {
18130
- const fs31 = require("fs");
18315
+ const fs32 = require("fs");
18131
18316
  if (process.stdin.isTTY) {
18132
18317
  console.error(import_chalk23.default.red("No input provided. Pipe content or pass text as argument."));
18133
18318
  process.exit(1);
18134
18319
  }
18135
- inputText = fs31.readFileSync(0, "utf-8");
18320
+ inputText = fs32.readFileSync(0, "utf-8");
18136
18321
  }
18137
18322
  if (!inputText.trim()) {
18138
18323
  console.error(import_chalk23.default.red("No text provided."));
18139
18324
  process.exit(1);
18140
18325
  }
18141
- const fs30 = require("fs");
18142
- if (text !== "-" && fs30.existsSync(text)) {
18326
+ const fs31 = require("fs");
18327
+ if (text !== "-" && fs31.existsSync(text)) {
18143
18328
  console.log(import_chalk23.default.yellow(`"${text}" looks like a file. Did you mean: hyv scan ${text}`));
18144
18329
  process.exit(1);
18145
18330
  }
@@ -18266,12 +18451,12 @@ function registerDiffCommand(program3) {
18266
18451
  ${result.changes.length} auto-fix${result.changes.length === 1 ? "" : "es"} available`));
18267
18452
  console.log(import_chalk25.default.dim(` run: hyv fix ${file} -i to apply`));
18268
18453
  if (options.apply && filePath !== "stdin") {
18269
- const fs30 = require("fs");
18270
- const path27 = require("path");
18454
+ const fs31 = require("fs");
18455
+ const path28 = require("path");
18271
18456
  const backupPath = filePath + ".bak";
18272
- fs30.copyFileSync(filePath, backupPath);
18273
- fs30.writeFileSync(filePath, result.fixed);
18274
- 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)}`));
18275
18460
  }
18276
18461
  } catch (error) {
18277
18462
  console.error(import_chalk25.default.red(`Error: ${error.message}`));
@@ -18812,8 +18997,8 @@ init_welcome();
18812
18997
  // src/lib/onboarding.ts
18813
18998
  var fs24 = __toESM(require("fs"));
18814
18999
  var path22 = __toESM(require("path"));
18815
- var os10 = __toESM(require("os"));
18816
- var hyvDir = path22.join(os10.homedir(), ".hyv");
19000
+ var os11 = __toESM(require("os"));
19001
+ var hyvDir = path22.join(os11.homedir(), ".hyv");
18817
19002
  var onboardingFile = path22.join(hyvDir, "onboarding-complete.json");
18818
19003
  function hasCompletedOnboarding() {
18819
19004
  try {
@@ -18986,9 +19171,9 @@ function registerUpgradeCommand(program3) {
18986
19171
  }
18987
19172
 
18988
19173
  // src/mcp.ts
18989
- var fs26 = __toESM(require("fs"));
18990
- var path24 = __toESM(require("path"));
18991
- var os11 = __toESM(require("os"));
19174
+ var fs27 = __toESM(require("fs"));
19175
+ var path25 = __toESM(require("path"));
19176
+ var os13 = __toESM(require("os"));
18992
19177
  init_classifier();
18993
19178
  init_autofix();
18994
19179
  init_validator();
@@ -18996,23 +19181,262 @@ init_pipeline();
18996
19181
  init_signals();
18997
19182
  init_local_profile();
18998
19183
  init_welcome();
18999
- init_config();
19000
19184
  init_telemetry();
19001
19185
  init_access();
19002
- 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");
19003
19427
  var MAX_RESPONSE_CHARS = 12e4;
19004
19428
  var MAX_SCAN_FILE_BYTES = 2 * 1024 * 1024;
19005
19429
  function readScanFile(filePath) {
19006
- const cwdReal = fs26.realpathSync(process.cwd());
19007
- const resolved = fs26.realpathSync(path24.resolve(filePath));
19008
- 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) {
19009
19433
  throw new Error(`file must be in the current working directory (${cwdReal})`);
19010
19434
  }
19011
- const stat = fs26.statSync(resolved);
19435
+ const stat = fs27.statSync(resolved);
19012
19436
  if (stat.size > MAX_SCAN_FILE_BYTES) {
19013
19437
  throw new Error(`file too large (max ${MAX_SCAN_FILE_BYTES} bytes)`);
19014
19438
  }
19015
- return fs26.readFileSync(resolved, "utf-8");
19439
+ return fs27.readFileSync(resolved, "utf-8");
19016
19440
  }
19017
19441
  function toolResultPayload(result) {
19018
19442
  const isError = result.startsWith("Error:") || result.startsWith("Unknown tool:");
@@ -19021,20 +19445,22 @@ function toolResultPayload(result) {
19021
19445
  ...isError ? { isError: true } : {}
19022
19446
  };
19023
19447
  }
19024
- var pkgPath = path24.resolve(__dirname, "..", "package.json");
19448
+ var pkgPath = path25.resolve(__dirname, "..", "package.json");
19025
19449
  var pkgVersion = (() => {
19026
19450
  try {
19027
- return JSON.parse(fs26.readFileSync(pkgPath, "utf-8")).version;
19451
+ return JSON.parse(fs27.readFileSync(pkgPath, "utf-8")).version;
19028
19452
  } catch {
19029
19453
  return "2.7.1";
19030
19454
  }
19031
19455
  })();
19032
- async function resolveProfile(slug, allowServerFetch = false) {
19033
- const profile = await loadProfileForCommand(slug, { allowServerFetch });
19034
- if (slug && !profile) {
19035
- const { requirePaidFeature: requirePaidFeature2 } = await Promise.resolve().then(() => (init_access(), access_exports));
19036
- await requirePaidFeature2("premiumPrompts");
19037
- 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
+ }
19038
19464
  }
19039
19465
  return profile;
19040
19466
  }
@@ -19134,27 +19560,8 @@ async function toolScan(args2) {
19134
19560
  }
19135
19561
  }
19136
19562
  async function toolProfiles(_args) {
19137
- const local = [.../* @__PURE__ */ new Set([...listCachedProfiles(), ...listDiskCachedProfiles()])];
19138
- if (local.length > 0) {
19139
- return "Cached profiles (local):\n" + local.map((p) => ` \u2022 ${p}`).join("\n");
19140
- }
19141
- try {
19142
- const { apiGet: apiGet2 } = await Promise.resolve().then(() => (init_api(), api_exports));
19143
- const data = await apiGet2("/cli/profiles");
19144
- const profiles = data.profiles || [];
19145
- if (profiles.length === 0) {
19146
- return "No voice profiles found. Free local scan works without a profile. Run: hyv init";
19147
- }
19148
- return profiles.map(
19149
- (p) => `${p.name}${p.is_default ? " (default)" : ""}${p.keywords?.length ? " \u2014 " + p.keywords.slice(0, 3).join(", ") : ""}`
19150
- ).join("\n");
19151
- } catch (err) {
19152
- const msg = err.message || "";
19153
- if (msg.includes("session expired") || msg.includes("not signed in")) {
19154
- return "Not signed in. Free local scan/fix/check work offline. Run `hyv init` for profiles.";
19155
- }
19156
- return `Cached profiles: none. Free local engine ready. (${msg})`;
19157
- }
19563
+ const hydrate = await ensureMcpProfilesHydrated();
19564
+ return formatMcpProfilesList(hydrate);
19158
19565
  }
19159
19566
  async function toolValidate(args2) {
19160
19567
  const text = args2.text || "";
@@ -19262,6 +19669,22 @@ function toolListFreeTools() {
19262
19669
  function toolDemo() {
19263
19670
  return getDemoText();
19264
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
+ }
19265
19688
  async function toolAnalyze(args2) {
19266
19689
  const text = args2.text || "";
19267
19690
  if (!text.trim())
@@ -19356,6 +19779,23 @@ async function toolClean(args2) {
19356
19779
  }
19357
19780
  }
19358
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
+ },
19359
19799
  {
19360
19800
  name: "hyv_welcome",
19361
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.",
@@ -19478,7 +19918,7 @@ var TOOLS = [
19478
19918
  },
19479
19919
  {
19480
19920
  name: "hyv_profiles",
19481
- 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.",
19482
19922
  inputSchema: { type: "object", properties: {} }
19483
19923
  },
19484
19924
  {
@@ -19503,14 +19943,15 @@ var PROMPTS = [
19503
19943
  ];
19504
19944
  var HYV_STATUS_PROMPT = `Use hold your voice MCP tools:
19505
19945
 
19506
- 1. New user \u2192 hyv_welcome (or step 1\u20134). Step 2: hyv_welcome mode=extract_prompt to build profile from chat.
19507
- 2. Save profile \u2192 user runs hyv import <name> file.md (or you draft markdown for them).
19508
- 3. hyv_profiles \u2014 list local/account profiles.
19509
- 4. Writing: hyv_scan \u2192 hyv_fix / hyv_rewrite \u2192 hyv_validate.
19510
- 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).
19511
19951
 
19512
19952
  Keep the answer compact.`;
19513
19953
  var TOOL_HANDLERS = {
19954
+ hyv_mcp_setup: toolMcpSetup,
19514
19955
  hyv_welcome: toolWelcome,
19515
19956
  hyv_list_free_tools: () => toolListFreeTools(),
19516
19957
  hyv_demo: () => toolDemo(),
@@ -19605,14 +20046,31 @@ async function handleRequest(line) {
19605
20046
  }
19606
20047
  async function startMcpServer() {
19607
20048
  const access = await getAccessState().catch(() => null);
19608
- 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)) {
19609
20060
  mcpLog("info", `voice profile: ${VOICE_MD}`);
19610
20061
  } else {
19611
- 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)");
19612
20063
  }
19613
20064
  if (access) {
19614
20065
  mcpLog("info", `mode: ${access.hasPaidPlan ? "paid" : "free local"}${access.authenticated ? "" : " (not signed in)"}`);
19615
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
+ });
19616
20074
  let buffer = "";
19617
20075
  process.stdin.setEncoding("utf-8");
19618
20076
  let requestChain = Promise.resolve();
@@ -19637,150 +20095,176 @@ async function startMcpServer() {
19637
20095
  }
19638
20096
 
19639
20097
  // src/lib/mcp-setup.ts
19640
- var import_chalk32 = __toESM(require_source());
19641
- var fs27 = __toESM(require("fs"));
19642
- var path25 = __toESM(require("path"));
19643
- 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"));
19644
20102
  init_version();
19645
- var HOME2 = os12.homedir();
20103
+ var HOME2 = os14.homedir();
19646
20104
  var IS_WIN2 = process.platform === "win32";
19647
20105
  function claudeDesktopConfigPath() {
19648
20106
  if (IS_WIN2)
19649
- return path25.join(HOME2, "AppData", "Roaming", "Claude", "claude_desktop_config.json");
20107
+ return path26.join(HOME2, "AppData", "Roaming", "Claude", "claude_desktop_config.json");
19650
20108
  if (process.platform === "linux")
19651
- return path25.join(HOME2, ".config", "Claude", "claude_desktop_config.json");
19652
- 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");
19653
20111
  }
19654
20112
  function printMcpSetup() {
19655
- console.log(import_chalk32.default.bold("\nhold your voice \u2014 mcp setup\n"));
19656
- 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()}
19657
20115
  `));
19658
- console.log(import_chalk32.default.bold("Claude Desktop"));
19659
- console.log(import_chalk32.default.dim(" Add to claude_desktop_config.json \u2192 mcpServers.hyv:"));
19660
- console.log(import_chalk32.default.cyan(` ${mcpServerSnippet().split("\n").join("\n ")}`));
19661
- 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()}
19662
20120
  `));
19663
- console.log(import_chalk32.default.bold("Cursor"));
19664
- console.log(import_chalk32.default.dim(" MCP: ~/.cursor/mcp.json \u2192 mcpServers.hyv (same JSON as above)"));
19665
- console.log(import_chalk32.default.dim(" Rule: ~/.cursor/rules/hyv.mdc (alwaysApply \u2014 auto via postinstall)\n"));
19666
- console.log(import_chalk32.default.bold("Claude Code"));
19667
- console.log(import_chalk32.default.dim(" Command: ~/.claude/commands/hyv.md"));
19668
- console.log(import_chalk32.default.dim(" Skill: ~/.claude/skills/hold-your-voice/SKILL.md\n"));
19669
- console.log(import_chalk32.default.bold("Windsurf"));
19670
- console.log(import_chalk32.default.dim(" Rule: ~/.windsurf/rules/hyv.md (trigger: always_on)\n"));
19671
- console.log(import_chalk32.default.bold("Codex"));
19672
- console.log(import_chalk32.default.dim(" Instructions: ~/.codex/AGENTS.md (merged on install)\n"));
19673
- console.log(import_chalk32.default.bold("Command Code"));
19674
- console.log(import_chalk32.default.dim(" Skill: ~/.commandcode/skills/hyv/SKILL.md\n"));
19675
- console.log(import_chalk32.default.bold("ChatGPT Desktop (manual connector)"));
19676
- console.log(import_chalk32.default.dim(" Settings \u2192 Connectors \u2192 add connector"));
19677
- console.log(import_chalk32.default.dim(" Name: hold your voice | Command: hyv | Arguments: mcp"));
19678
- console.log(import_chalk32.default.dim(" Guide: ~/.chatgpt/hyv-mcp-connector.txt (after hyv doctor --fix-agents)"));
19679
- console.log(import_chalk32.default.dim(" hyv mcp --setup-chatgpt\n"));
19680
- console.log(import_chalk32.default.bold("Antigravity"));
19681
- console.log(import_chalk32.default.dim(" MCP: ~/.gemini/config/mcp_config.json \u2192 mcpServers.hyv (auto via postinstall)\n"));
19682
- console.log(import_chalk32.default.bold("OpenCode"));
19683
- console.log(import_chalk32.default.dim(" MCP: ~/.config/opencode/opencode.jsonc \u2192 mcp.hyv (auto via postinstall)"));
19684
- console.log(import_chalk32.default.dim(" Rules: ~/.config/opencode/AGENTS.md\n"));
19685
- console.log(import_chalk32.default.bold("Auto-configure"));
19686
- console.log(import_chalk32.default.dim(" hyv doctor --fix-agents"));
19687
- console.log(import_chalk32.default.dim(" HYV_AUTO_CONFIGURE_AGENTS=0 npm i -g @holdyourvoice/hyv (skip)\n"));
19688
- console.log(import_chalk32.default.bold("Verify"));
19689
- console.log(import_chalk32.default.dim(" hyv mcp --test"));
19690
- 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"));
19691
20154
  }
19692
20155
  async function runMcpSelfTest() {
19693
- console.log(import_chalk32.default.bold("\nhold your voice \u2014 mcp self-test\n"));
19694
- 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()}
19695
20158
  `));
19696
20159
  let passed = 0;
19697
20160
  let failed = 0;
19698
20161
  const tools = getMcpToolNames();
19699
20162
  if (tools.length >= 10) {
19700
- 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`));
19701
20164
  passed++;
19702
20165
  } else {
19703
- 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}`));
19704
20167
  failed++;
19705
20168
  }
19706
- 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
+ ];
19707
20178
  for (const name of required) {
19708
20179
  if (tools.includes(name)) {
19709
- console.log(import_chalk32.default.green(` \u2713 tool: ${name}`));
20180
+ console.log(import_chalk33.default.green(` \u2713 tool: ${name}`));
19710
20181
  passed++;
19711
20182
  } else {
19712
- console.log(import_chalk32.default.red(` \u2717 missing tool: ${name}`));
20183
+ console.log(import_chalk33.default.red(` \u2717 missing tool: ${name}`));
19713
20184
  failed++;
19714
20185
  }
19715
20186
  }
19716
20187
  try {
19717
20188
  const welcome = await invokeMcpTool("hyv_welcome", {});
19718
20189
  if (welcome.includes("Hold Your Voice") || welcome.includes("hold your voice")) {
19719
- console.log(import_chalk32.default.green(" \u2713 hyv_welcome responds"));
20190
+ console.log(import_chalk33.default.green(" \u2713 hyv_welcome responds"));
19720
20191
  passed++;
19721
20192
  } else {
19722
- console.log(import_chalk32.default.red(" \u2717 hyv_welcome unexpected output"));
20193
+ console.log(import_chalk33.default.red(" \u2717 hyv_welcome unexpected output"));
19723
20194
  failed++;
19724
20195
  }
19725
20196
  } catch (e) {
19726
- console.log(import_chalk32.default.red(` \u2717 hyv_welcome failed: ${e.message}`));
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"));
20204
+ passed++;
20205
+ } else {
20206
+ console.log(import_chalk33.default.red(" \u2717 hyv_mcp_setup unexpected output"));
20207
+ failed++;
20208
+ }
20209
+ } catch (e) {
20210
+ console.log(import_chalk33.default.red(` \u2717 hyv_mcp_setup failed: ${e.message}`));
19727
20211
  failed++;
19728
20212
  }
19729
20213
  try {
19730
20214
  const demo = await invokeMcpTool("hyv_demo", {});
19731
20215
  if (demo.includes("Score") || demo.includes("issues")) {
19732
- console.log(import_chalk32.default.green(" \u2713 hyv_demo pipeline works"));
20216
+ console.log(import_chalk33.default.green(" \u2713 hyv_demo pipeline works"));
19733
20217
  passed++;
19734
20218
  } else {
19735
- console.log(import_chalk32.default.red(" \u2717 hyv_demo unexpected output"));
20219
+ console.log(import_chalk33.default.red(" \u2717 hyv_demo unexpected output"));
19736
20220
  failed++;
19737
20221
  }
19738
20222
  } catch (e) {
19739
- 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}`));
19740
20224
  failed++;
19741
20225
  }
19742
- const voiceMd = path25.join(HOME2, ".hyv", "voice.md");
19743
- if (fs27.existsSync(voiceMd)) {
19744
- 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"));
19745
20229
  passed++;
19746
20230
  } else {
19747
- 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)"));
19748
20232
  }
19749
20233
  if (getDemoText().length > 100) {
19750
- console.log(import_chalk32.default.green(" \u2713 demo content available"));
20234
+ console.log(import_chalk33.default.green(" \u2713 demo content available"));
19751
20235
  passed++;
19752
20236
  } else {
19753
- console.log(import_chalk32.default.red(" \u2717 demo content missing"));
20237
+ console.log(import_chalk33.default.red(" \u2717 demo content missing"));
19754
20238
  failed++;
19755
20239
  }
19756
20240
  try {
19757
20241
  const stdio = await testMcpStdioSubprocess();
19758
20242
  if (stdio.ok && (stdio.toolCount || 0) >= 10) {
19759
- 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)`));
19760
20244
  passed++;
19761
20245
  } else if (stdio.ok) {
19762
- 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`));
19763
20247
  failed++;
19764
20248
  } else {
19765
- console.log(import_chalk32.default.red(" \u2717 stdio MCP subprocess failed"));
20249
+ console.log(import_chalk33.default.red(" \u2717 stdio MCP subprocess failed"));
19766
20250
  failed++;
19767
20251
  }
19768
20252
  } catch (e) {
19769
- 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}`));
19770
20254
  failed++;
19771
20255
  }
19772
20256
  console.log("");
19773
20257
  if (failed === 0) {
19774
- console.log(import_chalk32.default.green(`\u2713 all checks passed (${passed})`));
19775
- 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"));
19776
20260
  return true;
19777
20261
  }
19778
- 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`));
19779
20263
  return false;
19780
20264
  }
19781
20265
 
19782
20266
  // src/commands/export.ts
19783
- var fs28 = __toESM(require("fs"));
20267
+ var fs29 = __toESM(require("fs"));
19784
20268
  init_api();
19785
20269
  var FORMATS = {
19786
20270
  claude: {
@@ -19867,7 +20351,7 @@ async function exportCommand(format, opts) {
19867
20351
  const prompt = fmt.wrap(detail.profile, detail.body);
19868
20352
  if (opts.output) {
19869
20353
  const outFile = opts.output.replace("{name}", profile.slug || profile.name);
19870
- fs28.writeFileSync(outFile, prompt);
20354
+ fs29.writeFileSync(outFile, prompt);
19871
20355
  results.push({ profile: profile.name, file: outFile });
19872
20356
  } else {
19873
20357
  results.push({ profile: profile.name, prompt });
@@ -19904,13 +20388,13 @@ async function exportCommand(format, opts) {
19904
20388
  // src/index.ts
19905
20389
  init_access();
19906
20390
  init_welcome();
19907
- var fs29 = __toESM(require("fs"));
19908
- var path26 = __toESM(require("path"));
20391
+ var fs30 = __toESM(require("fs"));
20392
+ var path27 = __toESM(require("path"));
19909
20393
  var program2 = new Command();
19910
- var pkgPath2 = path26.resolve(__dirname, "..", "package.json");
20394
+ var pkgPath2 = path27.resolve(__dirname, "..", "package.json");
19911
20395
  var pkgVersion2 = (() => {
19912
20396
  try {
19913
- return JSON.parse(fs29.readFileSync(pkgPath2, "utf-8")).version;
20397
+ return JSON.parse(fs30.readFileSync(pkgPath2, "utf-8")).version;
19914
20398
  } catch {
19915
20399
  return "2.7.1";
19916
20400
  }
@@ -19943,7 +20427,7 @@ registerOpenCommand(program2);
19943
20427
  registerWelcomeCommand(program2);
19944
20428
  registerContentCommand(program2);
19945
20429
  registerUpgradeCommand(program2);
19946
- 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) => {
19947
20431
  if (opts.setup) {
19948
20432
  printMcpSetup();
19949
20433
  return;
@@ -19954,26 +20438,21 @@ program2.command("mcp").description("Start MCP server (for Claude Desktop and ot
19954
20438
  return;
19955
20439
  }
19956
20440
  if (opts.setupChatgpt) {
19957
- const home = require("os").homedir();
19958
- const guide = require("path").join(home, ".chatgpt", "hyv-mcp-connector.txt");
19959
- console.log(import_chalk33.default.bold("\nhold your voice \u2014 chatgpt desktop mcp setup\n"));
19960
- console.log("ChatGPT has no auto-config file. Add this connector once in the desktop app:\n");
19961
- console.log(import_chalk33.default.dim(" 1. Install hyv: ") + import_chalk33.default.cyan("npm i -g @holdyourvoice/hyv@latest && hyv welcome"));
19962
- console.log(import_chalk33.default.dim(" 2. Open ") + import_chalk33.default.cyan("https://chatgpt.com/#settings/Connectors"));
19963
- console.log(import_chalk33.default.dim(" 3. Add connector"));
19964
- console.log(import_chalk33.default.dim(" 4. Name: ") + import_chalk33.default.cyan("hold your voice"));
19965
- console.log(import_chalk33.default.dim(" 5. Command: ") + import_chalk33.default.cyan("hyv"));
19966
- console.log(import_chalk33.default.dim(" 6. Arguments: ") + import_chalk33.default.cyan("mcp"));
19967
- console.log(import_chalk33.default.dim(" 7. Save, restart ChatGPT Desktop, ask: scan this with hold your voice"));
19968
- console.log("");
19969
- if (require("fs").existsSync(guide)) {
19970
- console.log(import_chalk33.default.dim(`Full guide written to: ${guide}`));
19971
- } else {
19972
- console.log(import_chalk33.default.dim("Run hyv doctor --fix-agents to write ~/.chatgpt/hyv-mcp-connector.txt"));
19973
- }
19974
- 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"));
19975
20445
  return;
19976
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
+ }
19977
20456
  startMcpServer();
19978
20457
  });
19979
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) => {