@holdyourvoice/hyv 2.9.23 → 2.9.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +395 -232
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -973,7 +973,7 @@ 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 path28 = require("node:path");
976
+ var path29 = require("node:path");
977
977
  var fs31 = require("node:fs");
978
978
  var process2 = require("node:process");
979
979
  var { Argument: Argument2, humanReadableArgName } = require_argument();
@@ -1916,10 +1916,10 @@ 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 = path28.resolve(baseDir, baseName);
1919
+ const localBin = path29.resolve(baseDir, baseName);
1920
1920
  if (fs31.existsSync(localBin))
1921
1921
  return localBin;
1922
- if (sourceExt.includes(path28.extname(baseName)))
1922
+ if (sourceExt.includes(path29.extname(baseName)))
1923
1923
  return void 0;
1924
1924
  const foundExt = sourceExt.find(
1925
1925
  (ext) => fs31.existsSync(`${localBin}${ext}`)
@@ -1939,17 +1939,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
1939
1939
  } catch (err) {
1940
1940
  resolvedScriptPath = this._scriptPath;
1941
1941
  }
1942
- executableDir = path28.resolve(
1943
- path28.dirname(resolvedScriptPath),
1942
+ executableDir = path29.resolve(
1943
+ path29.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 = path28.basename(
1950
+ const legacyName = path29.basename(
1951
1951
  this._scriptPath,
1952
- path28.extname(this._scriptPath)
1952
+ path29.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(path28.extname(executableFile));
1963
+ launchWithNode = sourceExt.includes(path29.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 = path28.basename(filename, path28.extname(filename));
2820
+ this._name = path29.basename(filename, path29.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(path29) {
2835
- if (path29 === void 0)
2834
+ executableDir(path30) {
2835
+ if (path30 === void 0)
2836
2836
  return this._executableDir;
2837
- this._executableDir = path29;
2837
+ this._executableDir = path30;
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 path28 = [graph[toModel].parent, toModel];
3937
+ const path29 = [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
- path28.unshift(graph[cur].parent);
3941
+ path29.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 = path28;
3945
+ fn.conversion = path29;
3946
3946
  return fn;
3947
3947
  }
3948
3948
  module2.exports = function(fromModel) {
@@ -4381,14 +4381,14 @@ var require_templates = __commonJS({
4381
4381
  }
4382
4382
  return results;
4383
4383
  }
4384
- function buildStyle(chalk36, styles) {
4384
+ function buildStyle(chalk37, 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 = chalk36;
4391
+ let current = chalk37;
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 = (chalk36, temporary) => {
4403
+ module2.exports = (chalk37, 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(chalk36, styles)(string));
4413
+ chunks.push(styles.length === 0 ? string : buildStyle(chalk37, 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(chalk36, styles)(chunk.join("")));
4419
+ chunks.push(buildStyle(chalk37, 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 chalk37 = {};
4468
- applyOptions(chalk37, options);
4469
- chalk37.template = (...arguments_) => chalkTag(chalk37.template, ...arguments_);
4470
- Object.setPrototypeOf(chalk37, Chalk.prototype);
4471
- Object.setPrototypeOf(chalk37.template, chalk37);
4472
- chalk37.template.constructor = () => {
4467
+ const chalk38 = {};
4468
+ applyOptions(chalk38, options);
4469
+ chalk38.template = (...arguments_) => chalkTag(chalk38.template, ...arguments_);
4470
+ Object.setPrototypeOf(chalk38, Chalk.prototype);
4471
+ Object.setPrototypeOf(chalk38.template, chalk38);
4472
+ chalk38.template.constructor = () => {
4473
4473
  throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.");
4474
4474
  };
4475
- chalk37.template.Instance = ChalkClass;
4476
- return chalk37.template;
4475
+ chalk38.template.Instance = ChalkClass;
4476
+ return chalk38.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 = (chalk37, ...strings) => {
4587
+ var chalkTag = (chalk38, ...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(chalk37, parts.join(""));
4603
+ return template(chalk38, parts.join(""));
4604
4604
  };
4605
4605
  Object.defineProperties(Chalk.prototype, styles);
4606
- var chalk36 = Chalk();
4607
- chalk36.supportsColor = stdoutColor;
4608
- chalk36.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 });
4609
- chalk36.stderr.supportsColor = stderrColor;
4610
- module2.exports = chalk36;
4606
+ var chalk37 = Chalk();
4607
+ chalk37.supportsColor = stdoutColor;
4608
+ chalk37.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 });
4609
+ chalk37.stderr.supportsColor = stderrColor;
4610
+ module2.exports = chalk37;
4611
4611
  }
4612
4612
  });
4613
4613
 
@@ -5128,13 +5128,13 @@ var require_define_lazy_prop = __commonJS({
5128
5128
  // node_modules/open/index.js
5129
5129
  var require_open = __commonJS({
5130
5130
  "node_modules/open/index.js"(exports2, module2) {
5131
- var path28 = require("path");
5131
+ var path29 = require("path");
5132
5132
  var childProcess = require("child_process");
5133
5133
  var { promises: fs31, constants: fsConstants } = require("fs");
5134
5134
  var isWsl = require_is_wsl();
5135
5135
  var isDocker = require_is_docker();
5136
5136
  var defineLazyProperty = require_define_lazy_prop();
5137
- var localXdgOpenPath = path28.join(__dirname, "xdg-open");
5137
+ var localXdgOpenPath = path29.join(__dirname, "xdg-open");
5138
5138
  var { platform, arch } = process;
5139
5139
  var hasContainerEnv = () => {
5140
5140
  try {
@@ -5291,14 +5291,14 @@ var require_open = __commonJS({
5291
5291
  }
5292
5292
  const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
5293
5293
  if (options.wait) {
5294
- return new Promise((resolve17, reject) => {
5294
+ return new Promise((resolve18, reject) => {
5295
5295
  subprocess.once("error", reject);
5296
5296
  subprocess.once("close", (exitCode) => {
5297
5297
  if (!options.allowNonzeroExitCode && exitCode > 0) {
5298
5298
  reject(new Error(`Exited with code ${exitCode}`));
5299
5299
  return;
5300
5300
  }
5301
- resolve17(subprocess);
5301
+ resolve18(subprocess);
5302
5302
  });
5303
5303
  });
5304
5304
  }
@@ -5514,16 +5514,16 @@ function compareSemver(a, b) {
5514
5514
  return 0;
5515
5515
  }
5516
5516
  function fetchLatestNpmVersion(timeoutMs = 8e3) {
5517
- return new Promise((resolve17) => {
5517
+ return new Promise((resolve18) => {
5518
5518
  (0, import_child_process.execFile)(
5519
5519
  "npm",
5520
5520
  ["view", "@holdyourvoice/hyv", "version"],
5521
5521
  { timeout: timeoutMs, encoding: "utf-8" },
5522
5522
  (err, stdout) => {
5523
5523
  if (err || !stdout?.trim())
5524
- resolve17(null);
5524
+ resolve18(null);
5525
5525
  else
5526
- resolve17(stdout.trim());
5526
+ resolve18(stdout.trim());
5527
5527
  }
5528
5528
  );
5529
5529
  });
@@ -5588,7 +5588,7 @@ function escapeHtml(value) {
5588
5588
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
5589
5589
  }
5590
5590
  function request(url, options = {}) {
5591
- return new Promise((resolve17, reject) => {
5591
+ return new Promise((resolve18, reject) => {
5592
5592
  const urlObj = new URL(url);
5593
5593
  const isHttps = urlObj.protocol === "https:";
5594
5594
  const client = isHttps ? https : http;
@@ -5609,9 +5609,9 @@ function request(url, options = {}) {
5609
5609
  res.on("data", (chunk) => data += chunk);
5610
5610
  res.on("end", () => {
5611
5611
  try {
5612
- resolve17({ status: res.statusCode || 0, data: JSON.parse(data) });
5612
+ resolve18({ status: res.statusCode || 0, data: JSON.parse(data) });
5613
5613
  } catch {
5614
- resolve17({ status: res.statusCode || 0, data });
5614
+ resolve18({ status: res.statusCode || 0, data });
5615
5615
  }
5616
5616
  });
5617
5617
  });
@@ -5669,9 +5669,9 @@ async function authenticateWithLicense(licenseKey) {
5669
5669
  }
5670
5670
  async function authenticateWithBrowser() {
5671
5671
  const server = http.createServer();
5672
- const port = await new Promise((resolve17) => {
5672
+ const port = await new Promise((resolve18) => {
5673
5673
  server.listen(0, "127.0.0.1", () => {
5674
- resolve17(server.address().port);
5674
+ resolve18(server.address().port);
5675
5675
  });
5676
5676
  });
5677
5677
  const redirectUri = `http://127.0.0.1:${port}/callback`;
@@ -5690,7 +5690,7 @@ async function authenticateWithBrowser() {
5690
5690
  }
5691
5691
  console.log(import_chalk2.default.cyan("\nOpening browser for authentication..."));
5692
5692
  await (0, import_open.default)(assertSafeOAuthUrl(auth_url));
5693
- const authData = await new Promise((resolve17, reject) => {
5693
+ const authData = await new Promise((resolve18, reject) => {
5694
5694
  const timeout = setTimeout(() => {
5695
5695
  server.close();
5696
5696
  reject(new Error(
@@ -5749,7 +5749,7 @@ async function authenticateWithBrowser() {
5749
5749
  `);
5750
5750
  clearTimeout(timeout);
5751
5751
  server.close();
5752
- resolve17(data);
5752
+ resolve18(data);
5753
5753
  } catch (error) {
5754
5754
  res.writeHead(500, { "Content-Type": "text/html" });
5755
5755
  res.end(`<h1>Authentication failed</h1><p>${escapeHtml(error.message)}</p>`);
@@ -5911,11 +5911,11 @@ var init_telemetry = __esm({
5911
5911
  });
5912
5912
 
5913
5913
  // src/lib/api.ts
5914
- async function request2(method, path28, body) {
5914
+ async function request2(method, path29, body) {
5915
5915
  const token = await getValidToken();
5916
5916
  if (!token)
5917
5917
  throw new Error("you're not signed in yet. run: hyv init");
5918
- const url = `${API_BASE}${path28}`;
5918
+ const url = `${API_BASE}${path29}`;
5919
5919
  const opts = {
5920
5920
  method,
5921
5921
  headers: {
@@ -5940,11 +5940,11 @@ async function request2(method, path28, body) {
5940
5940
  }
5941
5941
  return res.json();
5942
5942
  }
5943
- function apiGet(path28) {
5944
- return request2("GET", path28);
5943
+ function apiGet(path29) {
5944
+ return request2("GET", path29);
5945
5945
  }
5946
- function apiPost(path28, body) {
5947
- return request2("POST", path28, body);
5946
+ function apiPost(path29, body) {
5947
+ return request2("POST", path29, body);
5948
5948
  }
5949
5949
  var init_api = __esm({
5950
5950
  "src/lib/api.ts"() {
@@ -6419,6 +6419,19 @@ async function requirePaidFeature(feature) {
6419
6419
  throw new Error(FEATURE_MESSAGES[feature]);
6420
6420
  }
6421
6421
  }
6422
+ async function maybeShowScanAttribution(jsonMode) {
6423
+ if (jsonMode)
6424
+ return;
6425
+ if (process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true")
6426
+ return;
6427
+ if (isLocalOnlyMode())
6428
+ return;
6429
+ const access = await getAccessState();
6430
+ if (access.hasPaidPlan)
6431
+ return;
6432
+ console.log(import_chalk5.default.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
6433
+ console.log(import_chalk5.default.dim("powered by holdyourvoice.com \xB7 remove this with a profile \u2192 hyv init"));
6434
+ }
6422
6435
  async function maybeShowLimitedModeHint(hasProfile) {
6423
6436
  if (isLocalOnlyMode())
6424
6437
  return;
@@ -11167,7 +11180,7 @@ function runPipeline(text, profile, applyFixes = false) {
11167
11180
  }
11168
11181
  function readText(source) {
11169
11182
  const fs31 = require("fs");
11170
- const path28 = require("path");
11183
+ const path29 = require("path");
11171
11184
  if (source === "-") {
11172
11185
  if (process.stdin.isTTY) {
11173
11186
  console.error("No input provided. Pipe content or specify a file.");
@@ -11175,7 +11188,7 @@ function readText(source) {
11175
11188
  }
11176
11189
  return { text: fs31.readFileSync(0, "utf-8"), path: "stdin" };
11177
11190
  }
11178
- const resolved = path28.resolve(source);
11191
+ const resolved = path29.resolve(source);
11179
11192
  if (!fs31.existsSync(resolved)) {
11180
11193
  console.error(`File not found: ${resolved}`);
11181
11194
  process.exit(1);
@@ -11580,7 +11593,7 @@ function isInteractiveTTY() {
11580
11593
  return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
11581
11594
  }
11582
11595
  function briefPause(ms2 = 280) {
11583
- return new Promise((resolve17) => setTimeout(resolve17, ms2));
11596
+ return new Promise((resolve18) => setTimeout(resolve18, ms2));
11584
11597
  }
11585
11598
  async function withSpinner(label, fn, opts = {}) {
11586
11599
  const minMs = opts.minMs ?? 450;
@@ -11900,7 +11913,7 @@ function saveLocalProfile(name, content) {
11900
11913
  return path14.join(os9.homedir(), ".hyv", "profiles", `${safe}.md`);
11901
11914
  }
11902
11915
  function fetchUrlText(url) {
11903
- return new Promise((resolve17, reject) => {
11916
+ return new Promise((resolve18, reject) => {
11904
11917
  let parsed;
11905
11918
  try {
11906
11919
  parsed = new URL(url);
@@ -11929,7 +11942,7 @@ function fetchUrlText(url) {
11929
11942
  });
11930
11943
  res.on("end", () => {
11931
11944
  const text = data.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
11932
- resolve17(text.slice(0, 12e3));
11945
+ resolve18(text.slice(0, 12e3));
11933
11946
  });
11934
11947
  }
11935
11948
  );
@@ -11949,10 +11962,10 @@ async function collectSamplesFromLink(url) {
11949
11962
  }
11950
11963
  function askLine(prompt) {
11951
11964
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
11952
- return new Promise((resolve17) => {
11965
+ return new Promise((resolve18) => {
11953
11966
  rl.question(prompt, (answer) => {
11954
11967
  rl.close();
11955
- resolve17(answer.trim());
11968
+ resolve18(answer.trim());
11956
11969
  });
11957
11970
  });
11958
11971
  }
@@ -11961,11 +11974,11 @@ async function askMultiline(intro) {
11961
11974
  console.log(import_chalk12.default.dim(" paste below, then type --- on its own line when done\n"));
11962
11975
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
11963
11976
  const lines = [];
11964
- return new Promise((resolve17) => {
11977
+ return new Promise((resolve18) => {
11965
11978
  rl.on("line", (line) => {
11966
11979
  if (line.trim() === "---") {
11967
11980
  rl.close();
11968
- resolve17(lines.join("\n").trim());
11981
+ resolve18(lines.join("\n").trim());
11969
11982
  return;
11970
11983
  }
11971
11984
  lines.push(line);
@@ -15819,7 +15832,7 @@ var {
15819
15832
  } = import_index.default;
15820
15833
 
15821
15834
  // src/index.ts
15822
- var import_chalk35 = __toESM(require_source());
15835
+ var import_chalk36 = __toESM(require_source());
15823
15836
 
15824
15837
  // src/commands/init.ts
15825
15838
  var import_chalk4 = __toESM(require_source());
@@ -17171,7 +17184,7 @@ function registerImportCommand(program3) {
17171
17184
  });
17172
17185
  }
17173
17186
  function askQuestion(question) {
17174
- return new Promise((resolve17) => {
17187
+ return new Promise((resolve18) => {
17175
17188
  const readline3 = require("readline");
17176
17189
  const rl = readline3.createInterface({
17177
17190
  input: process.stdin,
@@ -17180,7 +17193,7 @@ function askQuestion(question) {
17180
17193
  rl.question(import_chalk13.default.cyan(` ${question}
17181
17194
  > `), (answer) => {
17182
17195
  rl.close();
17183
- resolve17(answer.trim());
17196
+ resolve18(answer.trim());
17184
17197
  });
17185
17198
  });
17186
17199
  }
@@ -17719,6 +17732,7 @@ hyv scan ${filePath}`));
17719
17732
  if (options.format !== "json") {
17720
17733
  printScanShareHint(score, signals.length);
17721
17734
  }
17735
+ await maybeShowScanAttribution(options.format === "json");
17722
17736
  recordEvent("scan_complete", {
17723
17737
  score,
17724
17738
  issues: signals.length,
@@ -17777,7 +17791,7 @@ async function testMcpStdioSubprocess() {
17777
17791
  const entry = resolveCliEntry();
17778
17792
  if (!entry)
17779
17793
  return { ok: false };
17780
- return new Promise((resolve17) => {
17794
+ return new Promise((resolve18) => {
17781
17795
  const child = (0, import_child_process4.spawn)(process.execPath, [entry, "mcp"], {
17782
17796
  stdio: ["pipe", "pipe", "pipe"],
17783
17797
  env: { ...process.env, HYV_POSTINSTALL_QUIET: "1" }
@@ -17793,7 +17807,7 @@ async function testMcpStdioSubprocess() {
17793
17807
  child.kill();
17794
17808
  } catch {
17795
17809
  }
17796
- resolve17({ ok, toolCount });
17810
+ resolve18({ ok, toolCount });
17797
17811
  };
17798
17812
  const timeout = setTimeout(() => finish(false), 1e4);
17799
17813
  const handleLine = (line) => {
@@ -18198,11 +18212,11 @@ async function confirmDestructiveWrite(options) {
18198
18212
  const question = `
18199
18213
  ${label}
18200
18214
  A .bak backup will be created. Proceed? [y/N] `;
18201
- const answer = await new Promise((resolve17) => {
18215
+ const answer = await new Promise((resolve18) => {
18202
18216
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
18203
18217
  rl.question(question, (value) => {
18204
18218
  rl.close();
18205
- resolve17(value.trim().toLowerCase());
18219
+ resolve18(value.trim().toLowerCase());
18206
18220
  });
18207
18221
  });
18208
18222
  return answer === "y" || answer === "yes";
@@ -18448,11 +18462,11 @@ function registerDiffCommand(program3) {
18448
18462
  console.log(import_chalk25.default.dim(` run: hyv fix ${file} -i to apply`));
18449
18463
  if (options.apply && filePath !== "stdin") {
18450
18464
  const fs31 = require("fs");
18451
- const path28 = require("path");
18465
+ const path29 = require("path");
18452
18466
  const backupPath = filePath + ".bak";
18453
18467
  fs31.copyFileSync(filePath, backupPath);
18454
18468
  fs31.writeFileSync(filePath, result.fixed);
18455
- console.log(import_chalk25.default.green(` \u2713 Applied. Backup: ${path28.basename(backupPath)}`));
18469
+ console.log(import_chalk25.default.green(` \u2713 Applied. Backup: ${path29.basename(backupPath)}`));
18456
18470
  }
18457
18471
  } catch (error) {
18458
18472
  console.error(import_chalk25.default.red(`Error: ${error.message}`));
@@ -19186,9 +19200,148 @@ function registerUpgradeCommand(program3) {
19186
19200
  });
19187
19201
  }
19188
19202
 
19203
+ // src/commands/share.ts
19204
+ var import_chalk33 = __toESM(require_source());
19205
+ var path24 = __toESM(require("path"));
19206
+ init_pipeline();
19207
+ init_local_profile();
19208
+ init_telemetry();
19209
+ init_signals();
19210
+ var { createCanvas, registerFont } = (() => {
19211
+ try {
19212
+ return require("canvas");
19213
+ } catch {
19214
+ console.error(import_chalk33.default.red("canvas package is required. install it: npm install canvas"));
19215
+ process.exit(1);
19216
+ }
19217
+ })();
19218
+ var CARD_W = 1200;
19219
+ var CARD_H = 630;
19220
+ function scoreColor(score) {
19221
+ if (score < 50)
19222
+ return "#ef4444";
19223
+ if (score < 75)
19224
+ return "#f59e0b";
19225
+ return "#22c55e";
19226
+ }
19227
+ function topPatternPills(signals) {
19228
+ const counts = /* @__PURE__ */ new Map();
19229
+ for (const s of signals) {
19230
+ counts.set(s.id, (counts.get(s.id) || 0) + 1);
19231
+ }
19232
+ return [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([id, count]) => ({ id, count }));
19233
+ }
19234
+ function drawCard(ctx, rawScore, fixedScore, topPatterns, fileName, hasFixes) {
19235
+ const w = CARD_W, h = CARD_H;
19236
+ ctx.fillStyle = "#0a0a0a";
19237
+ ctx.fillRect(0, 0, w, h);
19238
+ ctx.fillStyle = "#888";
19239
+ ctx.font = '14px "Menlo", "Courier New", monospace';
19240
+ ctx.fillText("hold your voice", 40, 50);
19241
+ const scoreMain = hasFixes ? `${rawScore} \u2192 ${fixedScore}` : `${rawScore}/100`;
19242
+ ctx.fillStyle = scoreColor(rawScore);
19243
+ ctx.font = 'bold 80px "Menlo", "Courier New", monospace';
19244
+ ctx.textAlign = "center";
19245
+ ctx.fillText(scoreMain, w / 2, h / 2 - 20);
19246
+ ctx.fillStyle = "#888";
19247
+ ctx.font = '16px "Menlo", "Courier New", monospace';
19248
+ ctx.fillText(hasFixes ? "raw \u2192 after local fixes" : "voice score", w / 2, h / 2 + 30);
19249
+ if (topPatterns.length > 0) {
19250
+ let pillX = w / 2 - topPatterns.length * 90 / 2;
19251
+ if (topPatterns.length === 1)
19252
+ pillX = w / 2 - 80;
19253
+ else if (topPatterns.length === 2)
19254
+ pillX = w / 2 - 130;
19255
+ for (const p of topPatterns) {
19256
+ const label = `[${p.id}]`;
19257
+ ctx.fillStyle = "#222";
19258
+ const tw = ctx.measureText ? ctx.measureText(label).width + 24 : 160;
19259
+ const pillW = Math.max(tw, 100);
19260
+ roundRect(ctx, pillX - 4, h / 2 + 60, pillW, 32, 6);
19261
+ ctx.fillStyle = "#222";
19262
+ ctx.fill();
19263
+ ctx.fillStyle = "#ccc";
19264
+ ctx.font = '13px "Menlo", "Courier New", monospace';
19265
+ ctx.textAlign = "left";
19266
+ ctx.fillText(label, pillX + 12, h / 2 + 82);
19267
+ pillX += pillW + 12;
19268
+ }
19269
+ }
19270
+ ctx.fillStyle = "#555";
19271
+ ctx.font = '13px "Menlo", "Courier New", monospace';
19272
+ ctx.textAlign = "left";
19273
+ ctx.fillText(fileName, 40, h - 30);
19274
+ ctx.fillStyle = "#555";
19275
+ ctx.font = '13px "Menlo", "Courier New", monospace';
19276
+ ctx.textAlign = "right";
19277
+ ctx.fillText("holdyourvoice.com", w - 40, h - 30);
19278
+ }
19279
+ function roundRect(ctx, x2, y, w, h, r) {
19280
+ ctx.beginPath();
19281
+ ctx.moveTo(x2 + r, y);
19282
+ ctx.lineTo(x2 + w - r, y);
19283
+ ctx.quadraticCurveTo(x2 + w, y, x2 + w, y + r);
19284
+ ctx.lineTo(x2 + w, y + h - r);
19285
+ ctx.quadraticCurveTo(x2 + w, y + h, x2 + w - r, y + h);
19286
+ ctx.lineTo(x2 + r, y + h);
19287
+ ctx.quadraticCurveTo(x2, y + h, x2, y + h - r);
19288
+ ctx.lineTo(x2, y + r);
19289
+ ctx.quadraticCurveTo(x2, y, x2 + r, y);
19290
+ ctx.closePath();
19291
+ }
19292
+ function registerShareCommand(program3) {
19293
+ program3.command("share").description("Generate a shareable score card PNG from a scan").argument("<file>", "File to scan (or - for stdin)").option("--open", "Open the image after generation").option("--profile <name>", "Voice profile for scan context").action(async (file, options) => {
19294
+ try {
19295
+ const profile = await loadProfileForCommand(options.profile);
19296
+ const { text, path: filePath } = readText(file);
19297
+ if (!text.trim()) {
19298
+ console.warn(import_chalk33.default.yellow("File is empty or contains only whitespace."));
19299
+ process.exit(0);
19300
+ }
19301
+ const analysis = await runHybridAnalysis(text, profile, {
19302
+ profileSlug: options.profile || profile?.slug
19303
+ });
19304
+ const rawScore = analysis.mode === "hybrid" ? analysis.score : calculateScore(text, analysis.signalMap.signals);
19305
+ const pipelineResult = runPipeline(text, profile, true);
19306
+ const fixedScore = pipelineResult.autoFixResult.changed ? (() => {
19307
+ const fixedSignalMap = extractSignals(pipelineResult.autoFixResult.fixed, profile);
19308
+ return calculateScore(pipelineResult.autoFixResult.fixed, fixedSignalMap.signals);
19309
+ })() : null;
19310
+ const topPatterns = topPatternPills(analysis.signalMap.signals);
19311
+ const canvas = createCanvas(CARD_W, CARD_H);
19312
+ const ctx = canvas.getContext("2d");
19313
+ const displayName = filePath === "stdin" ? "unnamed draft" : path24.basename(filePath);
19314
+ drawCard(ctx, rawScore, fixedScore, topPatterns, displayName, pipelineResult.autoFixResult.changed);
19315
+ const ts2 = Date.now();
19316
+ const outName = `hyv-score-${ts2}.png`;
19317
+ const outPath = path24.resolve(process.cwd(), outName);
19318
+ const buf = canvas.toBuffer("image/png");
19319
+ require("fs").writeFileSync(outPath, buf);
19320
+ console.log(import_chalk33.default.green(`
19321
+ score card saved \u2192 ./${outName}`));
19322
+ const rawStr = String(rawScore);
19323
+ const afterStr = pipelineResult.autoFixResult.changed ? ` after hyv. ${fixedScore}` : ".";
19324
+ const tweetText = `my ai draft scored ${rawStr}${afterStr} holdyourvoice.com`;
19325
+ const tweetUrl = `https://x.com/intent/tweet?text=${encodeURIComponent(tweetText)}`;
19326
+ console.log(import_chalk33.default.dim(`share it: ${tweetUrl}`));
19327
+ if (options.open) {
19328
+ try {
19329
+ const open3 = require_open();
19330
+ await open3(outPath);
19331
+ } catch {
19332
+ }
19333
+ }
19334
+ recordEvent("share_complete", { score: rawScore, fileName: displayName });
19335
+ } catch (error) {
19336
+ console.error(import_chalk33.default.red(`Error: ${error.message}`));
19337
+ process.exit(1);
19338
+ }
19339
+ });
19340
+ }
19341
+
19189
19342
  // src/mcp.ts
19190
19343
  var fs27 = __toESM(require("fs"));
19191
- var path25 = __toESM(require("path"));
19344
+ var path26 = __toESM(require("path"));
19192
19345
  var os13 = __toESM(require("os"));
19193
19346
  init_classifier();
19194
19347
  init_autofix();
@@ -19201,28 +19354,28 @@ init_telemetry();
19201
19354
  init_access();
19202
19355
 
19203
19356
  // src/lib/mcp-integrate.ts
19204
- var import_chalk33 = __toESM(require_source());
19357
+ var import_chalk34 = __toESM(require_source());
19205
19358
  var fs26 = __toESM(require("fs"));
19206
19359
  var os12 = __toESM(require("os"));
19207
- var path24 = __toESM(require("path"));
19360
+ var path25 = __toESM(require("path"));
19208
19361
  init_version();
19209
19362
  init_welcome_flow();
19210
19363
  init_config();
19211
19364
  init_local_profile();
19212
19365
  function resolveCliRoot() {
19213
19366
  const candidates = [
19214
- path24.resolve(__dirname, ".."),
19215
- path24.resolve(__dirname, "..", "..")
19367
+ path25.resolve(__dirname, ".."),
19368
+ path25.resolve(__dirname, "..", "..")
19216
19369
  ];
19217
19370
  for (const root of candidates) {
19218
- if (fs26.existsSync(path24.join(root, "scripts", "postinstall-lib.js"))) {
19371
+ if (fs26.existsSync(path25.join(root, "scripts", "postinstall-lib.js"))) {
19219
19372
  return root;
19220
19373
  }
19221
19374
  }
19222
19375
  return candidates[0];
19223
19376
  }
19224
19377
  function loadPostinstallLib() {
19225
- return require(path24.join(resolveCliRoot(), "scripts", "postinstall-lib.js"));
19378
+ return require(path25.join(resolveCliRoot(), "scripts", "postinstall-lib.js"));
19226
19379
  }
19227
19380
  function runMcpAutoIntegrate(opts = {}) {
19228
19381
  const { integrateDetectedAgents } = loadPostinstallLib();
@@ -19265,7 +19418,7 @@ function buildOnboardingStatusLines() {
19265
19418
  function formatChatGptConnectorGuide() {
19266
19419
  const lib = loadPostinstallLib();
19267
19420
  const mcpCmd = lib.resolveHyvMcpCommand(resolveCliRoot());
19268
- const guidePath = path24.join(os12.homedir(), ".chatgpt", "hyv-mcp-connector.txt");
19421
+ const guidePath = path25.join(os12.homedir(), ".chatgpt", "hyv-mcp-connector.txt");
19269
19422
  const lines = [
19270
19423
  "### ChatGPT Desktop \u2014 RECOMMENDED: Path A (remote OAuth)",
19271
19424
  "",
@@ -19400,75 +19553,75 @@ function printMcpIntegrateReport(result, opts = {}) {
19400
19553
  const configuredIds = new Set(
19401
19554
  result.configured.map((label) => agentIdForConfiguredLabel(label)).filter(Boolean)
19402
19555
  );
19403
- console.log(import_chalk33.default.bold("\nhold your voice \u2014 mcp integration\n"));
19404
- console.log(import_chalk33.default.dim(` ${getEngineLabel()}
19556
+ console.log(import_chalk34.default.bold("\nhold your voice \u2014 mcp integration\n"));
19557
+ console.log(import_chalk34.default.dim(` ${getEngineLabel()}
19405
19558
  `));
19406
19559
  const welcome = readWelcomeState();
19407
19560
  const profiles = listLocalProfileNames2();
19408
19561
  if (profiles.length > 0) {
19409
- console.log(import_chalk33.default.dim(` voice profiles: ${profiles.join(", ")}`));
19562
+ console.log(import_chalk34.default.dim(` voice profiles: ${profiles.join(", ")}`));
19410
19563
  } else {
19411
- console.log(import_chalk33.default.yellow(" no voice profile yet \u2014 mcp still works (free scan). finish onboarding in terminal or in-chat via hyv_welcome"));
19564
+ console.log(import_chalk34.default.yellow(" no voice profile yet \u2014 mcp still works (free scan). finish onboarding in terminal or in-chat via hyv_welcome"));
19412
19565
  }
19413
19566
  if (welcome.completed_steps?.length) {
19414
- console.log(import_chalk33.default.dim(` welcome progress: ${welcome.completed_steps.join(", ")}`));
19567
+ console.log(import_chalk34.default.dim(` welcome progress: ${welcome.completed_steps.join(", ")}`));
19415
19568
  }
19416
19569
  console.log("");
19417
19570
  if (result.detected.length === 0) {
19418
- console.log(import_chalk33.default.yellow(" no supported ai apps detected on this machine."));
19419
- console.log(import_chalk33.default.dim("\n install cursor, claude desktop, chatgpt desktop, or another supported app,"));
19420
- console.log(import_chalk33.default.dim(" then run hyv mcp again \u2014 or hyv doctor --fix-agents to configure everything."));
19421
- console.log(import_chalk33.default.dim("\n in chatgpt/claude/cursor: call hyv_welcome to onboard without the terminal."));
19422
- console.log(import_chalk33.default.dim(" chatgpt desktop (paid): developer mode \u2192 new app \u2192 https://holdyourvoice.com/mcp + oauth"));
19423
- console.log(import_chalk33.default.dim(" full steps: hyv mcp --setup-chatgpt\n"));
19571
+ console.log(import_chalk34.default.yellow(" no supported ai apps detected on this machine."));
19572
+ console.log(import_chalk34.default.dim("\n install cursor, claude desktop, chatgpt desktop, or another supported app,"));
19573
+ console.log(import_chalk34.default.dim(" then run hyv mcp again \u2014 or hyv doctor --fix-agents to configure everything."));
19574
+ console.log(import_chalk34.default.dim("\n in chatgpt/claude/cursor: call hyv_welcome to onboard without the terminal."));
19575
+ console.log(import_chalk34.default.dim(" chatgpt desktop (paid): developer mode \u2192 new app \u2192 https://holdyourvoice.com/mcp + oauth"));
19576
+ console.log(import_chalk34.default.dim(" full steps: hyv mcp --setup-chatgpt\n"));
19424
19577
  return;
19425
19578
  }
19426
- console.log(import_chalk33.default.bold("detected apps"));
19579
+ console.log(import_chalk34.default.bold("detected apps"));
19427
19580
  for (const app of result.detected) {
19428
19581
  const justConfigured = configuredIds.has(app.id);
19429
19582
  const integrated = isAgentIntegrated(app.id) || justConfigured;
19430
- const mark = app.integration === "manual" ? import_chalk33.default.yellow("\u25CB") : integrated ? import_chalk33.default.green("\u2713") : import_chalk33.default.cyan("\u2192");
19583
+ const mark = app.integration === "manual" ? import_chalk34.default.yellow("\u25CB") : integrated ? import_chalk34.default.green("\u2713") : import_chalk34.default.cyan("\u2192");
19431
19584
  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";
19432
19585
  console.log(` ${mark} ${app.label} \u2014 ${status}`);
19433
- console.log(import_chalk33.default.dim(` ${app.reason} \xB7 ${app.integration}`));
19586
+ console.log(import_chalk34.default.dim(` ${app.reason} \xB7 ${app.integration}`));
19434
19587
  }
19435
19588
  if (result.configured.length > 0) {
19436
- console.log(import_chalk33.default.green(`
19589
+ console.log(import_chalk34.default.green(`
19437
19590
  wired hyv into: ${result.configured.join(", ")}`));
19438
19591
  }
19439
19592
  if (result.warnings.length > 0) {
19440
- console.log(import_chalk33.default.yellow("\n notes:"));
19593
+ console.log(import_chalk34.default.yellow("\n notes:"));
19441
19594
  for (const warning of result.warnings) {
19442
- console.log(import_chalk33.default.yellow(` ! ${warning}`));
19595
+ console.log(import_chalk34.default.yellow(` ! ${warning}`));
19443
19596
  }
19444
19597
  }
19445
19598
  const mcpApps = result.detected.filter((a) => a.integration === "mcp");
19446
19599
  const manualApps = result.detected.filter((a) => a.integration === "manual");
19447
- console.log(import_chalk33.default.bold("\nnext steps"));
19448
- console.log(import_chalk33.default.dim(" in this app: hyv_welcome (onboarding) \xB7 hyv_mcp_setup (status/refresh) \xB7 hyv_demo (try a scan)"));
19600
+ console.log(import_chalk34.default.bold("\nnext steps"));
19601
+ console.log(import_chalk34.default.dim(" in this app: hyv_welcome (onboarding) \xB7 hyv_mcp_setup (status/refresh) \xB7 hyv_demo (try a scan)"));
19449
19602
  if (mcpApps.length > 0) {
19450
- console.log(import_chalk33.default.dim(" restart apps that use mcp (cursor, claude desktop, antigravity, opencode)"));
19603
+ console.log(import_chalk34.default.dim(" restart apps that use mcp (cursor, claude desktop, antigravity, opencode)"));
19451
19604
  }
19452
19605
  if (manualApps.length > 0) {
19453
- console.log(import_chalk33.default.dim(" chatgpt (recommended): developer mode \u2192 new app \u2192 https://holdyourvoice.com/mcp + oauth"));
19454
- console.log(import_chalk33.default.dim(" chatgpt (free fallback): settings \u2192 connectors \u2192 command hyv, arguments mcp"));
19455
- console.log(import_chalk33.default.dim(" full steps: hyv mcp --setup-chatgpt"));
19606
+ console.log(import_chalk34.default.dim(" chatgpt (recommended): developer mode \u2192 new app \u2192 https://holdyourvoice.com/mcp + oauth"));
19607
+ console.log(import_chalk34.default.dim(" chatgpt (free fallback): settings \u2192 connectors \u2192 command hyv, arguments mcp"));
19608
+ console.log(import_chalk34.default.dim(" full steps: hyv mcp --setup-chatgpt"));
19456
19609
  }
19457
- console.log(import_chalk33.default.dim(" refresh stale configs after upgrade: hyv mcp --force"));
19458
- console.log(import_chalk33.default.dim(" verify: hyv mcp --test"));
19459
- console.log(import_chalk33.default.dim(" all hosts: hyv doctor --verify-hosts\n"));
19610
+ console.log(import_chalk34.default.dim(" refresh stale configs after upgrade: hyv mcp --force"));
19611
+ console.log(import_chalk34.default.dim(" verify: hyv mcp --test"));
19612
+ console.log(import_chalk34.default.dim(" all hosts: hyv doctor --verify-hosts\n"));
19460
19613
  }
19461
19614
 
19462
19615
  // src/mcp.ts
19463
19616
  init_mcp_profile_hydrate();
19464
19617
  init_profile();
19465
- var VOICE_MD = path25.join(os13.homedir(), ".hyv", "voice.md");
19618
+ var VOICE_MD = path26.join(os13.homedir(), ".hyv", "voice.md");
19466
19619
  var MAX_RESPONSE_CHARS = 12e4;
19467
19620
  var MAX_SCAN_FILE_BYTES = 2 * 1024 * 1024;
19468
19621
  function readScanFile(filePath) {
19469
19622
  const cwdReal = fs27.realpathSync(process.cwd());
19470
- const resolved = fs27.realpathSync(path25.resolve(filePath));
19471
- if (!resolved.startsWith(cwdReal + path25.sep) && resolved !== cwdReal) {
19623
+ const resolved = fs27.realpathSync(path26.resolve(filePath));
19624
+ if (!resolved.startsWith(cwdReal + path26.sep) && resolved !== cwdReal) {
19472
19625
  throw new Error(`file must be in the current working directory (${cwdReal})`);
19473
19626
  }
19474
19627
  const stat = fs27.statSync(resolved);
@@ -19484,7 +19637,7 @@ function toolResultPayload(result) {
19484
19637
  ...isError ? { isError: true } : {}
19485
19638
  };
19486
19639
  }
19487
- var pkgPath = path25.resolve(__dirname, "..", "package.json");
19640
+ var pkgPath = path26.resolve(__dirname, "..", "package.json");
19488
19641
  var pkgVersion = (() => {
19489
19642
  try {
19490
19643
  return JSON.parse(fs27.readFileSync(pkgPath, "utf-8")).version;
@@ -20087,7 +20240,7 @@ async function startMcpServer() {
20087
20240
  const access = await getAccessState().catch(() => null);
20088
20241
  const config = (() => {
20089
20242
  try {
20090
- return JSON.parse(fs27.readFileSync(path25.join(os13.homedir(), ".hyv", "config.json"), "utf-8"));
20243
+ return JSON.parse(fs27.readFileSync(path26.join(os13.homedir(), ".hyv", "config.json"), "utf-8"));
20091
20244
  } catch {
20092
20245
  return {};
20093
20246
  }
@@ -20144,83 +20297,83 @@ async function startMcpServer() {
20144
20297
  }
20145
20298
 
20146
20299
  // src/lib/mcp-setup.ts
20147
- var import_chalk34 = __toESM(require_source());
20300
+ var import_chalk35 = __toESM(require_source());
20148
20301
  var fs28 = __toESM(require("fs"));
20149
- var path26 = __toESM(require("path"));
20302
+ var path27 = __toESM(require("path"));
20150
20303
  var os14 = __toESM(require("os"));
20151
20304
  init_version();
20152
20305
  var HOME2 = os14.homedir();
20153
20306
  var IS_WIN2 = process.platform === "win32";
20154
20307
  function claudeDesktopConfigPath() {
20155
20308
  if (IS_WIN2)
20156
- return path26.join(HOME2, "AppData", "Roaming", "Claude", "claude_desktop_config.json");
20309
+ return path27.join(HOME2, "AppData", "Roaming", "Claude", "claude_desktop_config.json");
20157
20310
  if (process.platform === "linux")
20158
- return path26.join(HOME2, ".config", "Claude", "claude_desktop_config.json");
20159
- return path26.join(HOME2, "Library", "Application Support", "Claude", "claude_desktop_config.json");
20311
+ return path27.join(HOME2, ".config", "Claude", "claude_desktop_config.json");
20312
+ return path27.join(HOME2, "Library", "Application Support", "Claude", "claude_desktop_config.json");
20160
20313
  }
20161
20314
  function printMcpSetup() {
20162
- console.log(import_chalk34.default.bold("\nhold your voice \u2014 mcp setup\n"));
20163
- console.log(import_chalk34.default.dim(` ${getEngineLabel()}
20315
+ console.log(import_chalk35.default.bold("\nhold your voice \u2014 mcp setup\n"));
20316
+ console.log(import_chalk35.default.dim(` ${getEngineLabel()}
20164
20317
  `));
20165
- console.log(import_chalk34.default.bold("Claude Desktop"));
20166
- console.log(import_chalk34.default.dim(" Add to claude_desktop_config.json \u2192 mcpServers.hyv:"));
20167
- console.log(import_chalk34.default.cyan(` ${mcpServerSnippet().split("\n").join("\n ")}`));
20168
- console.log(import_chalk34.default.dim(` Config: ${claudeDesktopConfigPath()}
20318
+ console.log(import_chalk35.default.bold("Claude Desktop"));
20319
+ console.log(import_chalk35.default.dim(" Add to claude_desktop_config.json \u2192 mcpServers.hyv:"));
20320
+ console.log(import_chalk35.default.cyan(` ${mcpServerSnippet().split("\n").join("\n ")}`));
20321
+ console.log(import_chalk35.default.dim(` Config: ${claudeDesktopConfigPath()}
20169
20322
  `));
20170
- console.log(import_chalk34.default.bold("Cursor"));
20171
- console.log(import_chalk34.default.dim(" MCP: ~/.cursor/mcp.json \u2192 mcpServers.hyv (same JSON as above)"));
20172
- console.log(import_chalk34.default.dim(" Rule: ~/.cursor/rules/hyv.mdc (alwaysApply \u2014 auto via postinstall)\n"));
20173
- console.log(import_chalk34.default.bold("Claude Code"));
20174
- console.log(import_chalk34.default.dim(" Command: ~/.claude/commands/hyv.md"));
20175
- console.log(import_chalk34.default.dim(" Skill: ~/.claude/skills/hold-your-voice/SKILL.md\n"));
20176
- console.log(import_chalk34.default.bold("Windsurf"));
20177
- console.log(import_chalk34.default.dim(" Rule: ~/.windsurf/rules/hyv.md (trigger: always_on)\n"));
20178
- console.log(import_chalk34.default.bold("Codex"));
20179
- console.log(import_chalk34.default.dim(" Instructions: ~/.codex/AGENTS.md (merged on install)\n"));
20180
- console.log(import_chalk34.default.bold("Command Code"));
20181
- console.log(import_chalk34.default.dim(" Skill: ~/.commandcode/skills/hyv/SKILL.md\n"));
20182
- console.log(import_chalk34.default.bold("ChatGPT Desktop (manual connector)"));
20183
- console.log(import_chalk34.default.dim(" Settings \u2192 Connectors \u2192 add connector"));
20184
- console.log(import_chalk34.default.dim(" Name: hold your voice | Command: hyv | Arguments: mcp"));
20185
- console.log(import_chalk34.default.dim(" Guide: ~/.chatgpt/hyv-mcp-connector.txt (after hyv doctor --fix-agents)"));
20186
- console.log(import_chalk34.default.dim(" hyv mcp --setup-chatgpt"));
20323
+ console.log(import_chalk35.default.bold("Cursor"));
20324
+ console.log(import_chalk35.default.dim(" MCP: ~/.cursor/mcp.json \u2192 mcpServers.hyv (same JSON as above)"));
20325
+ console.log(import_chalk35.default.dim(" Rule: ~/.cursor/rules/hyv.mdc (alwaysApply \u2014 auto via postinstall)\n"));
20326
+ console.log(import_chalk35.default.bold("Claude Code"));
20327
+ console.log(import_chalk35.default.dim(" Command: ~/.claude/commands/hyv.md"));
20328
+ console.log(import_chalk35.default.dim(" Skill: ~/.claude/skills/hold-your-voice/SKILL.md\n"));
20329
+ console.log(import_chalk35.default.bold("Windsurf"));
20330
+ console.log(import_chalk35.default.dim(" Rule: ~/.windsurf/rules/hyv.md (trigger: always_on)\n"));
20331
+ console.log(import_chalk35.default.bold("Codex"));
20332
+ console.log(import_chalk35.default.dim(" Instructions: ~/.codex/AGENTS.md (merged on install)\n"));
20333
+ console.log(import_chalk35.default.bold("Command Code"));
20334
+ console.log(import_chalk35.default.dim(" Skill: ~/.commandcode/skills/hyv/SKILL.md\n"));
20335
+ console.log(import_chalk35.default.bold("ChatGPT Desktop (manual connector)"));
20336
+ console.log(import_chalk35.default.dim(" Settings \u2192 Connectors \u2192 add connector"));
20337
+ console.log(import_chalk35.default.dim(" Name: hold your voice | Command: hyv | Arguments: mcp"));
20338
+ console.log(import_chalk35.default.dim(" Guide: ~/.chatgpt/hyv-mcp-connector.txt (after hyv doctor --fix-agents)"));
20339
+ console.log(import_chalk35.default.dim(" hyv mcp --setup-chatgpt"));
20187
20340
  if (IS_WIN2) {
20188
- console.log(import_chalk34.default.dim(" Windows (Lenovo/Win11 often Restricted): if blocked use:"));
20189
- console.log(import_chalk34.default.cyan(' powershell -ExecutionPolicy Bypass -Command "hyv ..."'));
20190
- console.log(import_chalk34.default.dim(" Diagnose: Get-ExecutionPolicy -List"));
20191
- console.log(import_chalk34.default.dim(" Permanent fix: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force"));
20192
- console.log(import_chalk34.default.dim(" For connectors: use full path printed in the .txt (node + .js)"));
20341
+ console.log(import_chalk35.default.dim(" Windows (Lenovo/Win11 often Restricted): if blocked use:"));
20342
+ console.log(import_chalk35.default.cyan(' powershell -ExecutionPolicy Bypass -Command "hyv ..."'));
20343
+ console.log(import_chalk35.default.dim(" Diagnose: Get-ExecutionPolicy -List"));
20344
+ console.log(import_chalk35.default.dim(" Permanent fix: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force"));
20345
+ console.log(import_chalk35.default.dim(" For connectors: use full path printed in the .txt (node + .js)"));
20193
20346
  }
20194
20347
  console.log("");
20195
- console.log(import_chalk34.default.bold("Antigravity"));
20196
- console.log(import_chalk34.default.dim(" MCP: ~/.gemini/config/mcp_config.json \u2192 mcpServers.hyv (auto via postinstall)\n"));
20197
- console.log(import_chalk34.default.bold("OpenCode"));
20198
- console.log(import_chalk34.default.dim(" MCP: ~/.config/opencode/opencode.jsonc \u2192 mcp.hyv (auto via postinstall)"));
20199
- console.log(import_chalk34.default.dim(" Rules: ~/.config/opencode/AGENTS.md\n"));
20200
- console.log(import_chalk34.default.bold("Auto-configure"));
20201
- console.log(import_chalk34.default.dim(" hyv mcp (detect installed apps + wire mcp into them)"));
20202
- console.log(import_chalk34.default.dim(" hyv mcp --force (refresh configs after hyv upgrade)"));
20203
- console.log(import_chalk34.default.dim(" hyv doctor --fix-agents (configure all apps, not just detected)"));
20204
- console.log(import_chalk34.default.dim(" HYV_AUTO_CONFIGURE_AGENTS=0 npm i -g @holdyourvoice/hyv (skip)\n"));
20205
- console.log(import_chalk34.default.bold("In-chat (no terminal)"));
20206
- console.log(import_chalk34.default.dim(" hyv_mcp_setup \u2014 status, integrate, or chatgpt connector steps"));
20207
- console.log(import_chalk34.default.dim(" hyv_welcome \u2014 finish onboarding inside Cursor/Claude/ChatGPT\n"));
20208
- console.log(import_chalk34.default.bold("Verify"));
20209
- console.log(import_chalk34.default.dim(" hyv mcp --test"));
20210
- console.log(import_chalk34.default.dim(" HYV_TELEMETRY=1 hyv mcp (optional usage logging to ~/.hyv/telemetry/)\n"));
20348
+ console.log(import_chalk35.default.bold("Antigravity"));
20349
+ console.log(import_chalk35.default.dim(" MCP: ~/.gemini/config/mcp_config.json \u2192 mcpServers.hyv (auto via postinstall)\n"));
20350
+ console.log(import_chalk35.default.bold("OpenCode"));
20351
+ console.log(import_chalk35.default.dim(" MCP: ~/.config/opencode/opencode.jsonc \u2192 mcp.hyv (auto via postinstall)"));
20352
+ console.log(import_chalk35.default.dim(" Rules: ~/.config/opencode/AGENTS.md\n"));
20353
+ console.log(import_chalk35.default.bold("Auto-configure"));
20354
+ console.log(import_chalk35.default.dim(" hyv mcp (detect installed apps + wire mcp into them)"));
20355
+ console.log(import_chalk35.default.dim(" hyv mcp --force (refresh configs after hyv upgrade)"));
20356
+ console.log(import_chalk35.default.dim(" hyv doctor --fix-agents (configure all apps, not just detected)"));
20357
+ console.log(import_chalk35.default.dim(" HYV_AUTO_CONFIGURE_AGENTS=0 npm i -g @holdyourvoice/hyv (skip)\n"));
20358
+ console.log(import_chalk35.default.bold("In-chat (no terminal)"));
20359
+ console.log(import_chalk35.default.dim(" hyv_mcp_setup \u2014 status, integrate, or chatgpt connector steps"));
20360
+ console.log(import_chalk35.default.dim(" hyv_welcome \u2014 finish onboarding inside Cursor/Claude/ChatGPT\n"));
20361
+ console.log(import_chalk35.default.bold("Verify"));
20362
+ console.log(import_chalk35.default.dim(" hyv mcp --test"));
20363
+ console.log(import_chalk35.default.dim(" HYV_TELEMETRY=1 hyv mcp (optional usage logging to ~/.hyv/telemetry/)\n"));
20211
20364
  }
20212
20365
  async function runMcpSelfTest() {
20213
- console.log(import_chalk34.default.bold("\nhold your voice \u2014 mcp self-test\n"));
20214
- console.log(import_chalk34.default.dim(` ${getEngineLabel()}
20366
+ console.log(import_chalk35.default.bold("\nhold your voice \u2014 mcp self-test\n"));
20367
+ console.log(import_chalk35.default.dim(` ${getEngineLabel()}
20215
20368
  `));
20216
20369
  let passed = 0;
20217
20370
  let failed = 0;
20218
20371
  const tools = getMcpToolNames();
20219
20372
  if (tools.length >= 10) {
20220
- console.log(import_chalk34.default.green(` \u2713 ${tools.length} MCP tools registered`));
20373
+ console.log(import_chalk35.default.green(` \u2713 ${tools.length} MCP tools registered`));
20221
20374
  passed++;
20222
20375
  } else {
20223
- console.log(import_chalk34.default.red(` \u2717 expected 10+ tools, got ${tools.length}`));
20376
+ console.log(import_chalk35.default.red(` \u2717 expected 10+ tools, got ${tools.length}`));
20224
20377
  failed++;
20225
20378
  }
20226
20379
  const required = [
@@ -20234,89 +20387,89 @@ async function runMcpSelfTest() {
20234
20387
  ];
20235
20388
  for (const name of required) {
20236
20389
  if (tools.includes(name)) {
20237
- console.log(import_chalk34.default.green(` \u2713 tool: ${name}`));
20390
+ console.log(import_chalk35.default.green(` \u2713 tool: ${name}`));
20238
20391
  passed++;
20239
20392
  } else {
20240
- console.log(import_chalk34.default.red(` \u2717 missing tool: ${name}`));
20393
+ console.log(import_chalk35.default.red(` \u2717 missing tool: ${name}`));
20241
20394
  failed++;
20242
20395
  }
20243
20396
  }
20244
20397
  try {
20245
20398
  const welcome = await invokeMcpTool("hyv_welcome", {});
20246
20399
  if (welcome.includes("Hold Your Voice") || welcome.includes("hold your voice")) {
20247
- console.log(import_chalk34.default.green(" \u2713 hyv_welcome responds"));
20400
+ console.log(import_chalk35.default.green(" \u2713 hyv_welcome responds"));
20248
20401
  passed++;
20249
20402
  } else {
20250
- console.log(import_chalk34.default.red(" \u2717 hyv_welcome unexpected output"));
20403
+ console.log(import_chalk35.default.red(" \u2717 hyv_welcome unexpected output"));
20251
20404
  failed++;
20252
20405
  }
20253
20406
  } catch (e) {
20254
- console.log(import_chalk34.default.red(` \u2717 hyv_welcome failed: ${e.message}`));
20407
+ console.log(import_chalk35.default.red(` \u2717 hyv_welcome failed: ${e.message}`));
20255
20408
  failed++;
20256
20409
  }
20257
20410
  try {
20258
20411
  const setup = await invokeMcpTool("hyv_mcp_setup", { action: "status" });
20259
20412
  if (setup.includes("HYV MCP status") && setup.includes("hyv_welcome")) {
20260
- console.log(import_chalk34.default.green(" \u2713 hyv_mcp_setup responds"));
20413
+ console.log(import_chalk35.default.green(" \u2713 hyv_mcp_setup responds"));
20261
20414
  passed++;
20262
20415
  } else {
20263
- console.log(import_chalk34.default.red(" \u2717 hyv_mcp_setup unexpected output"));
20416
+ console.log(import_chalk35.default.red(" \u2717 hyv_mcp_setup unexpected output"));
20264
20417
  failed++;
20265
20418
  }
20266
20419
  } catch (e) {
20267
- console.log(import_chalk34.default.red(` \u2717 hyv_mcp_setup failed: ${e.message}`));
20420
+ console.log(import_chalk35.default.red(` \u2717 hyv_mcp_setup failed: ${e.message}`));
20268
20421
  failed++;
20269
20422
  }
20270
20423
  try {
20271
20424
  const demo = await invokeMcpTool("hyv_demo", {});
20272
20425
  if (demo.includes("Score") || demo.includes("issues")) {
20273
- console.log(import_chalk34.default.green(" \u2713 hyv_demo pipeline works"));
20426
+ console.log(import_chalk35.default.green(" \u2713 hyv_demo pipeline works"));
20274
20427
  passed++;
20275
20428
  } else {
20276
- console.log(import_chalk34.default.red(" \u2717 hyv_demo unexpected output"));
20429
+ console.log(import_chalk35.default.red(" \u2717 hyv_demo unexpected output"));
20277
20430
  failed++;
20278
20431
  }
20279
20432
  } catch (e) {
20280
- console.log(import_chalk34.default.red(` \u2717 hyv_demo failed: ${e.message}`));
20433
+ console.log(import_chalk35.default.red(` \u2717 hyv_demo failed: ${e.message}`));
20281
20434
  failed++;
20282
20435
  }
20283
- const voiceMd = path26.join(HOME2, ".hyv", "voice.md");
20436
+ const voiceMd = path27.join(HOME2, ".hyv", "voice.md");
20284
20437
  if (fs28.existsSync(voiceMd)) {
20285
- console.log(import_chalk34.default.green(" \u2713 voice profile found"));
20438
+ console.log(import_chalk35.default.green(" \u2713 voice profile found"));
20286
20439
  passed++;
20287
20440
  } else {
20288
- console.log(import_chalk34.default.dim(" - no voice.md (free local engine still works)"));
20441
+ console.log(import_chalk35.default.dim(" - no voice.md (free local engine still works)"));
20289
20442
  }
20290
20443
  if (getDemoText().length > 100) {
20291
- console.log(import_chalk34.default.green(" \u2713 demo content available"));
20444
+ console.log(import_chalk35.default.green(" \u2713 demo content available"));
20292
20445
  passed++;
20293
20446
  } else {
20294
- console.log(import_chalk34.default.red(" \u2717 demo content missing"));
20447
+ console.log(import_chalk35.default.red(" \u2717 demo content missing"));
20295
20448
  failed++;
20296
20449
  }
20297
20450
  try {
20298
20451
  const stdio = await testMcpStdioSubprocess();
20299
20452
  if (stdio.ok && (stdio.toolCount || 0) >= 10) {
20300
- console.log(import_chalk34.default.green(` \u2713 stdio MCP subprocess responds (${stdio.toolCount} tools)`));
20453
+ console.log(import_chalk35.default.green(` \u2713 stdio MCP subprocess responds (${stdio.toolCount} tools)`));
20301
20454
  passed++;
20302
20455
  } else if (stdio.ok) {
20303
- console.log(import_chalk34.default.yellow(` ! stdio MCP subprocess ok but only ${stdio.toolCount || 0} tools`));
20456
+ console.log(import_chalk35.default.yellow(` ! stdio MCP subprocess ok but only ${stdio.toolCount || 0} tools`));
20304
20457
  failed++;
20305
20458
  } else {
20306
- console.log(import_chalk34.default.red(" \u2717 stdio MCP subprocess failed"));
20459
+ console.log(import_chalk35.default.red(" \u2717 stdio MCP subprocess failed"));
20307
20460
  failed++;
20308
20461
  }
20309
20462
  } catch (e) {
20310
- console.log(import_chalk34.default.red(` \u2717 stdio MCP subprocess failed: ${e.message}`));
20463
+ console.log(import_chalk35.default.red(` \u2717 stdio MCP subprocess failed: ${e.message}`));
20311
20464
  failed++;
20312
20465
  }
20313
20466
  console.log("");
20314
20467
  if (failed === 0) {
20315
- console.log(import_chalk34.default.green(`\u2713 all checks passed (${passed})`));
20316
- console.log(import_chalk34.default.dim("\nStart server: hyv mcp\n"));
20468
+ console.log(import_chalk35.default.green(`\u2713 all checks passed (${passed})`));
20469
+ console.log(import_chalk35.default.dim("\nStart server: hyv mcp\n"));
20317
20470
  return true;
20318
20471
  }
20319
- console.log(import_chalk34.default.yellow(`! ${failed} check(s) failed, ${passed} passed`));
20472
+ console.log(import_chalk35.default.yellow(`! ${failed} check(s) failed, ${passed} passed`));
20320
20473
  return false;
20321
20474
  }
20322
20475
 
@@ -20446,9 +20599,9 @@ async function exportCommand(format, opts) {
20446
20599
  init_access();
20447
20600
  init_welcome();
20448
20601
  var fs30 = __toESM(require("fs"));
20449
- var path27 = __toESM(require("path"));
20602
+ var path28 = __toESM(require("path"));
20450
20603
  var program2 = new Command();
20451
- var pkgPath2 = path27.resolve(__dirname, "..", "package.json");
20604
+ var pkgPath2 = path28.resolve(__dirname, "..", "package.json");
20452
20605
  var pkgVersion2 = (() => {
20453
20606
  try {
20454
20607
  return JSON.parse(fs30.readFileSync(pkgPath2, "utf-8")).version;
@@ -20484,6 +20637,7 @@ registerOpenCommand(program2);
20484
20637
  registerWelcomeCommand(program2);
20485
20638
  registerContentCommand(program2);
20486
20639
  registerUpgradeCommand(program2);
20640
+ registerShareCommand(program2);
20487
20641
  program2.command("mcp").description("Detect installed apps, configure MCP, and start the MCP server").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", "Force re-configure MCP even if already integrated").action(async (opts) => {
20488
20642
  if (opts.setup) {
20489
20643
  printMcpSetup();
@@ -20497,56 +20651,65 @@ program2.command("mcp").description("Detect installed apps, configure MCP, and s
20497
20651
  if (opts.setupChatgpt) {
20498
20652
  const home = require("os").homedir();
20499
20653
  const guide = require("path").join(home, ".chatgpt", "hyv-mcp-connector.txt");
20500
- console.log(import_chalk35.default.bold("\nhold your voice \u2014 chatgpt desktop setup\n"));
20501
- console.log(import_chalk35.default.bold("=== RECOMMENDED \u2014 PATH A: remote oauth (paid hyv users) ==="));
20502
- console.log(import_chalk35.default.dim(" No local install. OAuth runs in ChatGPT's browser \u2014 no Windows firewall issues.\n"));
20503
- console.log(import_chalk35.default.dim(" Requires: paid HYV plan + ChatGPT Desktop\n"));
20504
- console.log(import_chalk35.default.dim(" 1. In ChatGPT: Settings \u2192 turn ") + import_chalk35.default.cyan("Developer mode") + import_chalk35.default.dim(" ON"));
20505
- console.log(import_chalk35.default.dim(" (Accept the elevated risk warning \u2014 expected, not a HYV bug)"));
20506
- console.log(import_chalk35.default.dim(" 2. Settings \u2192 Apps \u2192 ") + import_chalk35.default.cyan("New App"));
20507
- console.log(import_chalk35.default.dim(" 3. Fill in:"));
20508
- console.log(import_chalk35.default.dim(" Name: ") + import_chalk35.default.cyan("hold your voice"));
20509
- console.log(import_chalk35.default.dim(" Description: ") + import_chalk35.default.cyan("Scans writing for AI patterns and voice drift"));
20510
- console.log(import_chalk35.default.dim(" Connection: ") + import_chalk35.default.cyan("Server URL") + import_chalk35.default.dim(" \u2192 ") + import_chalk35.default.cyan("https://holdyourvoice.com/mcp"));
20511
- console.log(import_chalk35.default.dim(" Authentication: ") + import_chalk35.default.cyan("OAuth"));
20512
- console.log(import_chalk35.default.dim(" Checkbox: ") + import_chalk35.default.cyan('"I understand and want to continue"'));
20513
- console.log(import_chalk35.default.dim(" 4. Save \u2192 complete OAuth sign-in to holdyourvoice.com"));
20514
- console.log(import_chalk35.default.dim(' 5. Test: "scan this with hold your voice"\n'));
20515
- console.log(import_chalk35.default.dim(" Cloud app setup: ") + import_chalk35.default.cyan("https://holdyourvoice.com/app/api/mcp"));
20516
- console.log(import_chalk35.default.dim(" Wiki guide: ") + import_chalk35.default.cyan("https://holdyourvoice.com/wiki/use-hyv-in-chatgpt\n"));
20517
- console.log(import_chalk35.default.bold("=== FALLBACK \u2014 PATH B: local connector (free users only) ==="));
20518
- console.log(import_chalk35.default.dim(" Only if you do not have a paid HYV plan. Requires Node.js 18+.\n"));
20519
- console.log(import_chalk35.default.dim(" 1. Install hyv: ") + import_chalk35.default.cyan("npm i -g @holdyourvoice/hyv@latest && hyv welcome"));
20520
- console.log(import_chalk35.default.dim(" 2. In ChatGPT: ") + import_chalk35.default.cyan("Settings \u2192 Connectors") + import_chalk35.default.dim(" (or https://chatgpt.com/#settings/Connectors)"));
20521
- console.log(import_chalk35.default.dim(" 3. Add connector:"));
20522
- console.log(import_chalk35.default.dim(" Name: ") + import_chalk35.default.cyan("hold your voice"));
20523
- console.log(import_chalk35.default.dim(" Command: ") + import_chalk35.default.cyan("hyv") + import_chalk35.default.dim(" (full path on Windows if needed)"));
20524
- console.log(import_chalk35.default.dim(" Arguments: ") + import_chalk35.default.cyan("mcp"));
20525
- console.log(import_chalk35.default.dim(" 4. Save, restart ChatGPT Desktop"));
20526
- console.log(import_chalk35.default.dim(' 5. Test: "scan this with hold your voice"\n'));
20527
- console.log(import_chalk35.default.dim(" If connector fails to start, use full paths from:"));
20528
- console.log(import_chalk35.default.cyan(" " + guide));
20529
- console.log(import_chalk35.default.dim(""));
20530
- console.log(import_chalk35.default.dim('Windows tip: If you get "running scripts is disabled", use:'));
20531
- console.log(import_chalk35.default.cyan(' powershell -ExecutionPolicy Bypass -Command "hyv mcp --setup-chatgpt"'));
20532
- console.log(import_chalk35.default.dim(" Fix once: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force"));
20533
- console.log(import_chalk35.default.dim(" In ChatGPT connector use the FULL path from the connector .txt file\n"));
20534
- console.log(import_chalk35.default.bold('=== not seeing "New App"? ==='));
20535
- console.log(import_chalk35.default.dim(" \u2022 Turn Developer mode ON in ChatGPT settings \u2014 Path A needs it"));
20536
- console.log(import_chalk35.default.dim(" \u2022 If you only see Connectors, you are on Path B (free fallback)"));
20537
- console.log(import_chalk35.default.dim(" \u2022 Browser ChatGPT cannot use MCP \u2014 desktop app only\n"));
20654
+ console.log(import_chalk36.default.bold("\nhold your voice \u2014 chatgpt desktop setup\n"));
20655
+ console.log(import_chalk36.default.bold("=== RECOMMENDED \u2014 PATH A: remote oauth (paid hyv users) ==="));
20656
+ console.log(import_chalk36.default.dim(" No local install. OAuth runs in ChatGPT's browser \u2014 no Windows firewall issues.\n"));
20657
+ console.log(import_chalk36.default.dim(" Requires: paid HYV plan + ChatGPT Desktop\n"));
20658
+ console.log(import_chalk36.default.dim(" 1. In ChatGPT: Settings \u2192 turn ") + import_chalk36.default.cyan("Developer mode") + import_chalk36.default.dim(" ON"));
20659
+ console.log(import_chalk36.default.dim(" (Accept the elevated risk warning \u2014 expected, not a HYV bug)"));
20660
+ console.log(import_chalk36.default.dim(" 2. Settings \u2192 Apps \u2192 ") + import_chalk36.default.cyan("New App"));
20661
+ console.log(import_chalk36.default.dim(" 3. Fill in:"));
20662
+ console.log(import_chalk36.default.dim(" Name: ") + import_chalk36.default.cyan("hold your voice"));
20663
+ console.log(import_chalk36.default.dim(" Description: ") + import_chalk36.default.cyan("Scans writing for AI patterns and voice drift"));
20664
+ console.log(import_chalk36.default.dim(" Connection: ") + import_chalk36.default.cyan("Server URL") + import_chalk36.default.dim(" \u2192 ") + import_chalk36.default.cyan("https://holdyourvoice.com/mcp"));
20665
+ console.log(import_chalk36.default.dim(" Authentication: ") + import_chalk36.default.cyan("OAuth"));
20666
+ console.log(import_chalk36.default.dim(" Checkbox: ") + import_chalk36.default.cyan('"I understand and want to continue"'));
20667
+ console.log(import_chalk36.default.dim(" 4. Save \u2192 complete OAuth sign-in to holdyourvoice.com"));
20668
+ console.log(import_chalk36.default.dim(' 5. Test: "scan this with hold your voice"\n'));
20669
+ console.log(import_chalk36.default.dim(" Cloud app setup: ") + import_chalk36.default.cyan("https://holdyourvoice.com/app/api/mcp"));
20670
+ console.log(import_chalk36.default.dim(" Wiki guide: ") + import_chalk36.default.cyan("https://holdyourvoice.com/wiki/use-hyv-in-chatgpt\n"));
20671
+ console.log(import_chalk36.default.bold("=== FALLBACK \u2014 PATH B: local connector (free users only) ==="));
20672
+ console.log(import_chalk36.default.dim(" Only if you do not have a paid HYV plan. Requires Node.js 18+.\n"));
20673
+ console.log(import_chalk36.default.dim(" 1. Install hyv: ") + import_chalk36.default.cyan("npm i -g @holdyourvoice/hyv@latest && hyv welcome"));
20674
+ console.log(import_chalk36.default.dim(" 2. In ChatGPT: ") + import_chalk36.default.cyan("Settings \u2192 Connectors") + import_chalk36.default.dim(" (or https://chatgpt.com/#settings/Connectors)"));
20675
+ console.log(import_chalk36.default.dim(" 3. Add connector:"));
20676
+ console.log(import_chalk36.default.dim(" Name: ") + import_chalk36.default.cyan("hold your voice"));
20677
+ console.log(import_chalk36.default.dim(" Command: ") + import_chalk36.default.cyan("hyv") + import_chalk36.default.dim(" (full path on Windows if needed)"));
20678
+ console.log(import_chalk36.default.dim(" Arguments: ") + import_chalk36.default.cyan("mcp"));
20679
+ console.log(import_chalk36.default.dim(" 4. Save, restart ChatGPT Desktop"));
20680
+ console.log(import_chalk36.default.dim(' 5. Test: "scan this with hold your voice"\n'));
20681
+ console.log(import_chalk36.default.dim(" If connector fails to start, use full paths from:"));
20682
+ console.log(import_chalk36.default.cyan(" " + guide));
20683
+ console.log(import_chalk36.default.dim(""));
20684
+ console.log(import_chalk36.default.dim('Windows tip: If you get "running scripts is disabled", use:'));
20685
+ console.log(import_chalk36.default.cyan(' powershell -ExecutionPolicy Bypass -Command "hyv mcp --setup-chatgpt"'));
20686
+ console.log(import_chalk36.default.dim(" Fix once: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force"));
20687
+ console.log(import_chalk36.default.dim(" In ChatGPT connector use the FULL path from the connector .txt file\n"));
20688
+ console.log(import_chalk36.default.bold('=== not seeing "New App"? ==='));
20689
+ console.log(import_chalk36.default.dim(" \u2022 Turn Developer mode ON in ChatGPT settings \u2014 Path A needs it"));
20690
+ console.log(import_chalk36.default.dim(" \u2022 If you only see Connectors, you are on Path B (free fallback)"));
20691
+ console.log(import_chalk36.default.dim(" \u2022 Browser ChatGPT cannot use MCP \u2014 desktop app only\n"));
20538
20692
  if (require("fs").existsSync(guide)) {
20539
- console.log(import_chalk35.default.dim(` Full connector paths written to: ${guide}`));
20693
+ console.log(import_chalk36.default.dim(` Full connector paths written to: ${guide}`));
20540
20694
  } else {
20541
- console.log(import_chalk35.default.dim(" Run hyv doctor --fix-agents to write " + guide));
20695
+ console.log(import_chalk36.default.dim(" Run hyv doctor --fix-agents to write " + guide));
20542
20696
  }
20543
20697
  console.log("");
20544
20698
  return;
20545
20699
  }
20546
- console.log(import_chalk35.default.bold("\nhold your voice \u2014 detecting and configuring mcp...\n"));
20700
+ console.log(import_chalk36.default.bold("\nhold your voice \u2014 detecting and configuring mcp...\n"));
20547
20701
  const result = runMcpAutoIntegrate({ force: Boolean(opts.force) });
20548
20702
  printMcpIntegrateReport(result, { force: Boolean(opts.force) });
20549
- console.log(import_chalk35.default.dim("\nstarting MCP server (press Ctrl+C to stop)...\n"));
20703
+ console.log(import_chalk36.default.green.bold("\n\u2713 hold your voice \u2014 mcp setup complete\n"));
20704
+ console.log(import_chalk36.default.dim(" " + import_chalk36.default.bold("To integrate HYV with all MCP-compatible apps on your machine")));
20705
+ console.log(import_chalk36.default.dim(" (Cursor, Claude Desktop, Windsurf, Antigravity, OpenCode, ChatGPT, Codex,"));
20706
+ console.log(import_chalk36.default.dim(" Command Code, and more) \u2014 simply run:"));
20707
+ console.log("");
20708
+ console.log(import_chalk36.default.cyan(" hyv mcp"));
20709
+ console.log("");
20710
+ console.log(import_chalk36.default.dim(" It auto-detects installed apps, configures MCP servers, and is ready"));
20711
+ console.log(import_chalk36.default.dim(" for scanning, rewriting, and voice-profile validation in any tool.\n"));
20712
+ console.log(import_chalk36.default.dim("\nstarting MCP server (press Ctrl+C to stop)...\n"));
20550
20713
  startMcpServer();
20551
20714
  });
20552
20715
  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) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holdyourvoice/hyv",
3
- "version": "2.9.23",
3
+ "version": "2.9.24",
4
4
  "description": "Free local AI writing scan for cursor & claude. MCP server, 220+ pattern detection, voice profiles. npx @holdyourvoice/hyv welcome",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -8,7 +8,7 @@
8
8
  "hyvoice": "dist/index.js"
9
9
  },
10
10
  "scripts": {
11
- "build": "esbuild src/index.ts --bundle --platform=node --target=node18 --outfile=dist/index.js --format=cjs --banner:js='#!/usr/bin/env node'",
11
+ "build": "esbuild src/index.ts --bundle --platform=node --target=node18 --outfile=dist/index.js --format=cjs --external:canvas --banner:js='#!/usr/bin/env node'",
12
12
  "build:debug": "esbuild src/index.ts --bundle --platform=node --target=node18 --outfile=dist/index.js --format=cjs --sourcemap --banner:js='#!/usr/bin/env node'",
13
13
  "dev": "npm run build && node dist/index.js",
14
14
  "validate:publish": "npm run build && node scripts/validate-publish.js",
@@ -41,6 +41,7 @@
41
41
  "license": "UNLICENSED",
42
42
  "private": false,
43
43
  "dependencies": {
44
+ "canvas": "^3.2.3",
44
45
  "chalk": "^4.1.2",
45
46
  "commander": "^12.1.0",
46
47
  "glob": "^13.0.6",