@holdyourvoice/hyv 2.9.8 → 2.9.10

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
@@ -974,7 +974,7 @@ var require_command = __commonJS({
974
974
  var EventEmitter = require("node:events").EventEmitter;
975
975
  var childProcess = require("node:child_process");
976
976
  var path26 = require("node:path");
977
- var fs28 = require("node:fs");
977
+ var fs29 = 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();
@@ -1917,12 +1917,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
1917
1917
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1918
1918
  function findFile(baseDir, baseName) {
1919
1919
  const localBin = path26.resolve(baseDir, baseName);
1920
- if (fs28.existsSync(localBin))
1920
+ if (fs29.existsSync(localBin))
1921
1921
  return localBin;
1922
1922
  if (sourceExt.includes(path26.extname(baseName)))
1923
1923
  return void 0;
1924
1924
  const foundExt = sourceExt.find(
1925
- (ext) => fs28.existsSync(`${localBin}${ext}`)
1925
+ (ext) => fs29.existsSync(`${localBin}${ext}`)
1926
1926
  );
1927
1927
  if (foundExt)
1928
1928
  return `${localBin}${foundExt}`;
@@ -1935,7 +1935,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1935
1935
  if (this._scriptPath) {
1936
1936
  let resolvedScriptPath;
1937
1937
  try {
1938
- resolvedScriptPath = fs28.realpathSync(this._scriptPath);
1938
+ resolvedScriptPath = fs29.realpathSync(this._scriptPath);
1939
1939
  } catch (err) {
1940
1940
  resolvedScriptPath = this._scriptPath;
1941
1941
  }
@@ -4611,6 +4611,44 @@ var require_source = __commonJS({
4611
4611
  }
4612
4612
  });
4613
4613
 
4614
+ // src/lib/data-safety.ts
4615
+ function shouldReplaceCachedContent(existing, incoming) {
4616
+ const next = incoming.trim();
4617
+ if (!next) {
4618
+ return !existing?.trim();
4619
+ }
4620
+ return true;
4621
+ }
4622
+ function backupProfileFileIfExists(profilePath) {
4623
+ if (!fs.existsSync(profilePath)) {
4624
+ return false;
4625
+ }
4626
+ try {
4627
+ fs.copyFileSync(profilePath, `${profilePath}.hyv.bak`);
4628
+ return true;
4629
+ } catch {
4630
+ return false;
4631
+ }
4632
+ }
4633
+ function safeWriteProfileFile(profilePath, content, existing) {
4634
+ if (!shouldReplaceCachedContent(existing, content)) {
4635
+ return { written: false, backedUp: false, reason: "empty-would-erase" };
4636
+ }
4637
+ if (existing !== null && existing === content) {
4638
+ return { written: false, backedUp: false, reason: "unchanged" };
4639
+ }
4640
+ const backedUp = backupProfileFileIfExists(profilePath);
4641
+ fs.writeFileSync(profilePath, content, { mode: 384 });
4642
+ return { written: true, backedUp };
4643
+ }
4644
+ var fs;
4645
+ var init_data_safety = __esm({
4646
+ "src/lib/data-safety.ts"() {
4647
+ "use strict";
4648
+ fs = __toESM(require("fs"));
4649
+ }
4650
+ });
4651
+
4614
4652
  // src/lib/config.ts
4615
4653
  function validateApiBase(raw) {
4616
4654
  const trimmed = raw.replace(/\/$/, "");
@@ -4697,11 +4735,11 @@ function profilePathForName(name) {
4697
4735
  function ensureHyvDir() {
4698
4736
  const dirs = [HYV_DIR, PROFILES_DIR, CACHE_DIR, QUEUE_DIR];
4699
4737
  for (const dir of dirs) {
4700
- if (!fs.existsSync(dir)) {
4701
- fs.mkdirSync(dir, { recursive: true, mode: 448 });
4738
+ if (!fs2.existsSync(dir)) {
4739
+ fs2.mkdirSync(dir, { recursive: true, mode: 448 });
4702
4740
  } else {
4703
4741
  try {
4704
- fs.chmodSync(dir, 448);
4742
+ fs2.chmodSync(dir, 448);
4705
4743
  } catch {
4706
4744
  }
4707
4745
  }
@@ -4709,33 +4747,33 @@ function ensureHyvDir() {
4709
4747
  }
4710
4748
  function appendSecureLine(filePath, line, dir) {
4711
4749
  if (dir) {
4712
- if (!fs.existsSync(dir))
4713
- fs.mkdirSync(dir, { recursive: true, mode: 448 });
4750
+ if (!fs2.existsSync(dir))
4751
+ fs2.mkdirSync(dir, { recursive: true, mode: 448 });
4714
4752
  else {
4715
4753
  try {
4716
- fs.chmodSync(dir, 448);
4754
+ fs2.chmodSync(dir, 448);
4717
4755
  } catch {
4718
4756
  }
4719
4757
  }
4720
4758
  }
4721
- if (!fs.existsSync(filePath)) {
4722
- fs.writeFileSync(filePath, line, { mode: 384 });
4759
+ if (!fs2.existsSync(filePath)) {
4760
+ fs2.writeFileSync(filePath, line, { mode: 384 });
4723
4761
  return;
4724
4762
  }
4725
4763
  try {
4726
- fs.chmodSync(filePath, 384);
4764
+ fs2.chmodSync(filePath, 384);
4727
4765
  } catch {
4728
4766
  }
4729
- fs.appendFileSync(filePath, line);
4767
+ fs2.appendFileSync(filePath, line);
4730
4768
  }
4731
4769
  function isInitialized() {
4732
- return fs.existsSync(AUTH_FILE);
4770
+ return fs2.existsSync(AUTH_FILE);
4733
4771
  }
4734
4772
  function readAuth() {
4735
4773
  try {
4736
- if (!fs.existsSync(AUTH_FILE))
4774
+ if (!fs2.existsSync(AUTH_FILE))
4737
4775
  return null;
4738
- const data = fs.readFileSync(AUTH_FILE, "utf-8");
4776
+ const data = fs2.readFileSync(AUTH_FILE, "utf-8");
4739
4777
  return JSON.parse(data);
4740
4778
  } catch {
4741
4779
  return null;
@@ -4743,13 +4781,13 @@ function readAuth() {
4743
4781
  }
4744
4782
  function writeAuth(auth) {
4745
4783
  ensureHyvDir();
4746
- fs.writeFileSync(AUTH_FILE, JSON.stringify(auth, null, 2), { mode: 384 });
4784
+ fs2.writeFileSync(AUTH_FILE, JSON.stringify(auth, null, 2), { mode: 384 });
4747
4785
  }
4748
4786
  function readConfig() {
4749
4787
  try {
4750
- if (!fs.existsSync(CONFIG_FILE))
4788
+ if (!fs2.existsSync(CONFIG_FILE))
4751
4789
  return {};
4752
- const data = fs.readFileSync(CONFIG_FILE, "utf-8");
4790
+ const data = fs2.readFileSync(CONFIG_FILE, "utf-8");
4753
4791
  return JSON.parse(data);
4754
4792
  } catch {
4755
4793
  return {};
@@ -4757,7 +4795,7 @@ function readConfig() {
4757
4795
  }
4758
4796
  function writeConfig(config) {
4759
4797
  ensureHyvDir();
4760
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 384 });
4798
+ fs2.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 384 });
4761
4799
  }
4762
4800
  function getToken() {
4763
4801
  const auth = readAuth();
@@ -4773,9 +4811,9 @@ function getToken() {
4773
4811
  }
4774
4812
  function listCachedProfiles() {
4775
4813
  try {
4776
- if (!fs.existsSync(PROFILES_DIR))
4814
+ if (!fs2.existsSync(PROFILES_DIR))
4777
4815
  return [];
4778
- return fs.readdirSync(PROFILES_DIR).filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", ""));
4816
+ return fs2.readdirSync(PROFILES_DIR).filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", ""));
4779
4817
  } catch {
4780
4818
  return [];
4781
4819
  }
@@ -4783,9 +4821,9 @@ function listCachedProfiles() {
4783
4821
  function readCachedProfile(name) {
4784
4822
  const profilePath = profilePathForName(name);
4785
4823
  try {
4786
- if (!fs.existsSync(profilePath))
4824
+ if (!fs2.existsSync(profilePath))
4787
4825
  return null;
4788
- return fs.readFileSync(profilePath, "utf-8");
4826
+ return fs2.readFileSync(profilePath, "utf-8");
4789
4827
  } catch (err) {
4790
4828
  if (err.message?.includes("Invalid profile name"))
4791
4829
  throw err;
@@ -4794,15 +4832,19 @@ function readCachedProfile(name) {
4794
4832
  }
4795
4833
  function writeCachedProfile(name, content) {
4796
4834
  const profilePath = profilePathForName(name);
4797
- fs.writeFileSync(profilePath, content, { mode: 384 });
4835
+ const existing = fs2.existsSync(profilePath) ? fs2.readFileSync(profilePath, "utf-8") : null;
4836
+ const result = safeWriteProfileFile(profilePath, content, existing);
4837
+ if (!result.written && result.reason === "empty-would-erase") {
4838
+ throw new Error("Refusing to replace profile with empty content");
4839
+ }
4798
4840
  }
4799
4841
  function getQueuedSignals() {
4800
4842
  try {
4801
- if (!fs.existsSync(QUEUE_DIR))
4843
+ if (!fs2.existsSync(QUEUE_DIR))
4802
4844
  return [];
4803
- const files = fs.readdirSync(QUEUE_DIR).filter((f) => f.endsWith(".json"));
4845
+ const files = fs2.readdirSync(QUEUE_DIR).filter((f) => f.endsWith(".json"));
4804
4846
  return files.map((f) => {
4805
- const data = fs.readFileSync(path.join(QUEUE_DIR, f), "utf-8");
4847
+ const data = fs2.readFileSync(path.join(QUEUE_DIR, f), "utf-8");
4806
4848
  return JSON.parse(data);
4807
4849
  });
4808
4850
  } catch {
@@ -4813,29 +4855,30 @@ function queueSignal(signal) {
4813
4855
  ensureHyvDir();
4814
4856
  const id = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
4815
4857
  const filePath = path.join(QUEUE_DIR, `${id}.json`);
4816
- fs.writeFileSync(filePath, JSON.stringify(signal, null, 2), { mode: 384 });
4858
+ fs2.writeFileSync(filePath, JSON.stringify(signal, null, 2), { mode: 384 });
4817
4859
  }
4818
4860
  function saveLastEditSession(session) {
4819
4861
  ensureHyvDir();
4820
4862
  const data = { ...session, saved_at: (/* @__PURE__ */ new Date()).toISOString() };
4821
- fs.writeFileSync(LAST_SESSION_FILE, JSON.stringify(data, null, 2), { mode: 384 });
4863
+ fs2.writeFileSync(LAST_SESSION_FILE, JSON.stringify(data, null, 2), { mode: 384 });
4822
4864
  }
4823
4865
  function readLastEditSession() {
4824
4866
  try {
4825
- if (!fs.existsSync(LAST_SESSION_FILE))
4867
+ if (!fs2.existsSync(LAST_SESSION_FILE))
4826
4868
  return null;
4827
- return JSON.parse(fs.readFileSync(LAST_SESSION_FILE, "utf-8"));
4869
+ return JSON.parse(fs2.readFileSync(LAST_SESSION_FILE, "utf-8"));
4828
4870
  } catch {
4829
4871
  return null;
4830
4872
  }
4831
4873
  }
4832
- var fs, path, os, HYV_DIR, AUTH_FILE, CONFIG_FILE, PROFILES_DIR, CACHE_DIR, QUEUE_DIR, LAST_SESSION_FILE, ALLOWED_API_HOSTS, ALLOWED_OAUTH_HOSTS, API_BASE, PROFILE_NAME_RE;
4874
+ var fs2, path, os, HYV_DIR, AUTH_FILE, CONFIG_FILE, PROFILES_DIR, CACHE_DIR, QUEUE_DIR, LAST_SESSION_FILE, ALLOWED_API_HOSTS, ALLOWED_OAUTH_HOSTS, API_BASE, PROFILE_NAME_RE;
4833
4875
  var init_config = __esm({
4834
4876
  "src/lib/config.ts"() {
4835
4877
  "use strict";
4836
- fs = __toESM(require("fs"));
4878
+ fs2 = __toESM(require("fs"));
4837
4879
  path = __toESM(require("path"));
4838
4880
  os = __toESM(require("os"));
4881
+ init_data_safety();
4839
4882
  HYV_DIR = path.join(os.homedir(), ".hyv");
4840
4883
  AUTH_FILE = path.join(HYV_DIR, "auth.json");
4841
4884
  CONFIG_FILE = path.join(HYV_DIR, "config.json");
@@ -4860,11 +4903,11 @@ var init_config = __esm({
4860
4903
  var require_is_docker = __commonJS({
4861
4904
  "node_modules/is-docker/index.js"(exports2, module2) {
4862
4905
  "use strict";
4863
- var fs28 = require("fs");
4906
+ var fs29 = require("fs");
4864
4907
  var isDocker;
4865
4908
  function hasDockerEnv() {
4866
4909
  try {
4867
- fs28.statSync("/.dockerenv");
4910
+ fs29.statSync("/.dockerenv");
4868
4911
  return true;
4869
4912
  } catch (_2) {
4870
4913
  return false;
@@ -4872,7 +4915,7 @@ var require_is_docker = __commonJS({
4872
4915
  }
4873
4916
  function hasDockerCGroup() {
4874
4917
  try {
4875
- return fs28.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
4918
+ return fs29.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
4876
4919
  } catch (_2) {
4877
4920
  return false;
4878
4921
  }
@@ -4891,7 +4934,7 @@ var require_is_wsl = __commonJS({
4891
4934
  "node_modules/is-wsl/index.js"(exports2, module2) {
4892
4935
  "use strict";
4893
4936
  var os12 = require("os");
4894
- var fs28 = require("fs");
4937
+ var fs29 = require("fs");
4895
4938
  var isDocker = require_is_docker();
4896
4939
  var isWsl = () => {
4897
4940
  if (process.platform !== "linux") {
@@ -4904,7 +4947,7 @@ var require_is_wsl = __commonJS({
4904
4947
  return true;
4905
4948
  }
4906
4949
  try {
4907
- return fs28.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isDocker() : false;
4950
+ return fs29.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isDocker() : false;
4908
4951
  } catch (_2) {
4909
4952
  return false;
4910
4953
  }
@@ -4945,7 +4988,7 @@ var require_open = __commonJS({
4945
4988
  "node_modules/open/index.js"(exports2, module2) {
4946
4989
  var path26 = require("path");
4947
4990
  var childProcess = require("child_process");
4948
- var { promises: fs28, constants: fsConstants } = require("fs");
4991
+ var { promises: fs29, constants: fsConstants } = require("fs");
4949
4992
  var isWsl = require_is_wsl();
4950
4993
  var isDocker = require_is_docker();
4951
4994
  var defineLazyProperty = require_define_lazy_prop();
@@ -4953,7 +4996,7 @@ var require_open = __commonJS({
4953
4996
  var { platform, arch } = process;
4954
4997
  var hasContainerEnv = () => {
4955
4998
  try {
4956
- fs28.statSync("/run/.containerenv");
4999
+ fs29.statSync("/run/.containerenv");
4957
5000
  return true;
4958
5001
  } catch {
4959
5002
  return false;
@@ -4976,14 +5019,14 @@ var require_open = __commonJS({
4976
5019
  const configFilePath = "/etc/wsl.conf";
4977
5020
  let isConfigFileExists = false;
4978
5021
  try {
4979
- await fs28.access(configFilePath, fsConstants.F_OK);
5022
+ await fs29.access(configFilePath, fsConstants.F_OK);
4980
5023
  isConfigFileExists = true;
4981
5024
  } catch {
4982
5025
  }
4983
5026
  if (!isConfigFileExists) {
4984
5027
  return defaultMountPoint;
4985
5028
  }
4986
- const configContent = await fs28.readFile(configFilePath, { encoding: "utf8" });
5029
+ const configContent = await fs29.readFile(configFilePath, { encoding: "utf8" });
4987
5030
  const configMountPoint = /(?<!#.*)root\s*=\s*(?<mountPoint>.*)/g.exec(configContent);
4988
5031
  if (!configMountPoint) {
4989
5032
  return defaultMountPoint;
@@ -5083,7 +5126,7 @@ var require_open = __commonJS({
5083
5126
  const isBundled = !__dirname || __dirname === "/";
5084
5127
  let exeLocalXdgOpen = false;
5085
5128
  try {
5086
- await fs28.access(localXdgOpenPath, fsConstants.X_OK);
5129
+ await fs29.access(localXdgOpenPath, fsConstants.X_OK);
5087
5130
  exeLocalXdgOpen = true;
5088
5131
  } catch {
5089
5132
  }
@@ -5289,14 +5332,14 @@ function pkgRoot() {
5289
5332
  // src/lib/ → cli/
5290
5333
  ];
5291
5334
  for (const root of candidates) {
5292
- if (fs2.existsSync(path2.join(root, "package.json")))
5335
+ if (fs3.existsSync(path2.join(root, "package.json")))
5293
5336
  return root;
5294
5337
  }
5295
5338
  return path2.resolve(__dirname, "..");
5296
5339
  }
5297
5340
  function getCliVersion() {
5298
5341
  try {
5299
- const pkg = JSON.parse(fs2.readFileSync(path2.join(PKG_ROOT, "package.json"), "utf-8"));
5342
+ const pkg = JSON.parse(fs3.readFileSync(path2.join(PKG_ROOT, "package.json"), "utf-8"));
5300
5343
  return pkg.version || "unknown";
5301
5344
  } catch {
5302
5345
  return "unknown";
@@ -5304,8 +5347,8 @@ function getCliVersion() {
5304
5347
  }
5305
5348
  function getRulesVersion() {
5306
5349
  try {
5307
- if (fs2.existsSync(RULES_MANIFEST)) {
5308
- return JSON.parse(fs2.readFileSync(RULES_MANIFEST, "utf-8")).version || "unknown";
5350
+ if (fs3.existsSync(RULES_MANIFEST)) {
5351
+ return JSON.parse(fs3.readFileSync(RULES_MANIFEST, "utf-8")).version || "unknown";
5309
5352
  }
5310
5353
  } catch {
5311
5354
  }
@@ -5343,11 +5386,11 @@ function fetchLatestNpmVersion(timeoutMs = 8e3) {
5343
5386
  );
5344
5387
  });
5345
5388
  }
5346
- var fs2, path2, import_child_process, PKG_ROOT, RULES_MANIFEST;
5389
+ var fs3, path2, import_child_process, PKG_ROOT, RULES_MANIFEST;
5347
5390
  var init_version = __esm({
5348
5391
  "src/lib/version.ts"() {
5349
5392
  "use strict";
5350
- fs2 = __toESM(require("fs"));
5393
+ fs3 = __toESM(require("fs"));
5351
5394
  path2 = __toESM(require("path"));
5352
5395
  import_child_process = require("child_process");
5353
5396
  PKG_ROOT = pkgRoot();
@@ -5753,7 +5796,7 @@ async function request2(method, path26, body) {
5753
5796
  if (res.status === 401)
5754
5797
  throw new Error("your session expired. run: hyv init to sign in again.");
5755
5798
  if (res.status === 403)
5756
- throw new Error("you don't have access to this feature. check your plan at holdyourvoice.com/dashboard");
5799
+ throw new Error("you don't have access to this feature. check your plan at holdyourvoice.com/app/billing");
5757
5800
  if (!res.ok) {
5758
5801
  throw new Error(`something went wrong (${res.status}). try again or contact support.`);
5759
5802
  }
@@ -5973,9 +6016,9 @@ function getDiskCachePath(slug) {
5973
6016
  function loadFromDiskCache(slug) {
5974
6017
  try {
5975
6018
  const cachePath = getDiskCachePath(slug);
5976
- if (!fs3.existsSync(cachePath))
6019
+ if (!fs4.existsSync(cachePath))
5977
6020
  return null;
5978
- const content = fs3.readFileSync(cachePath, "utf-8");
6021
+ const content = fs4.readFileSync(cachePath, "utf-8");
5979
6022
  const entry = JSON.parse(content);
5980
6023
  if (!entry.data || !entry.timestamp)
5981
6024
  return null;
@@ -5986,10 +6029,10 @@ function loadFromDiskCache(slug) {
5986
6029
  }
5987
6030
  function saveToDiskCache(slug, entry) {
5988
6031
  try {
5989
- if (!fs3.existsSync(DISK_CACHE_DIR)) {
5990
- fs3.mkdirSync(DISK_CACHE_DIR, { recursive: true });
6032
+ if (!fs4.existsSync(DISK_CACHE_DIR)) {
6033
+ fs4.mkdirSync(DISK_CACHE_DIR, { recursive: true });
5991
6034
  }
5992
- fs3.writeFileSync(getDiskCachePath(slug), JSON.stringify(entry), "utf-8");
6035
+ fs4.writeFileSync(getDiskCachePath(slug), JSON.stringify(entry), "utf-8");
5993
6036
  } catch {
5994
6037
  }
5995
6038
  }
@@ -6007,13 +6050,13 @@ function buildMinimalProfile(slug, body) {
6007
6050
  cadence: {}
6008
6051
  };
6009
6052
  }
6010
- var fs3, path4, os3, CACHE_TTL, memoryCache, DISK_CACHE_DIR;
6053
+ var fs4, path4, os3, CACHE_TTL, memoryCache, DISK_CACHE_DIR;
6011
6054
  var init_profile = __esm({
6012
6055
  "src/lib/profile.ts"() {
6013
6056
  "use strict";
6014
6057
  init_api();
6015
6058
  init_config();
6016
- fs3 = __toESM(require("fs"));
6059
+ fs4 = __toESM(require("fs"));
6017
6060
  path4 = __toESM(require("path"));
6018
6061
  os3 = __toESM(require("os"));
6019
6062
  CACHE_TTL = 5 * 60 * 1e3;
@@ -6038,9 +6081,9 @@ function cachePathForSlug(slug) {
6038
6081
  function loadProfileFromDiskCache(slug) {
6039
6082
  try {
6040
6083
  const cachePath = cachePathForSlug(slug);
6041
- if (!fs4.existsSync(cachePath))
6084
+ if (!fs5.existsSync(cachePath))
6042
6085
  return void 0;
6043
- const entry = JSON.parse(fs4.readFileSync(cachePath, "utf-8"));
6086
+ const entry = JSON.parse(fs5.readFileSync(cachePath, "utf-8"));
6044
6087
  if (entry?.data?.body)
6045
6088
  return entry.data;
6046
6089
  } catch {
@@ -6064,9 +6107,9 @@ function profileFromMarkdown(slug, body) {
6064
6107
  function getProfileCacheAge(slug) {
6065
6108
  try {
6066
6109
  const cachePath = cachePathForSlug(slug);
6067
- if (!fs4.existsSync(cachePath))
6110
+ if (!fs5.existsSync(cachePath))
6068
6111
  return null;
6069
- const entry = JSON.parse(fs4.readFileSync(cachePath, "utf-8"));
6112
+ const entry = JSON.parse(fs5.readFileSync(cachePath, "utf-8"));
6070
6113
  return entry.timestamp || null;
6071
6114
  } catch {
6072
6115
  return null;
@@ -6074,9 +6117,9 @@ function getProfileCacheAge(slug) {
6074
6117
  }
6075
6118
  function listDiskCachedProfiles() {
6076
6119
  try {
6077
- if (!fs4.existsSync(DISK_CACHE_DIR2))
6120
+ if (!fs5.existsSync(DISK_CACHE_DIR2))
6078
6121
  return [];
6079
- return fs4.readdirSync(DISK_CACHE_DIR2).filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", ""));
6122
+ return fs5.readdirSync(DISK_CACHE_DIR2).filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", ""));
6080
6123
  } catch {
6081
6124
  return [];
6082
6125
  }
@@ -6133,11 +6176,11 @@ function hasRichProfile(profile) {
6133
6176
  return false;
6134
6177
  return (profile.never_list?.length || 0) > 0 || (profile.learned_patterns?.length || 0) > 0 || (profile.drift_snapshot?.length || 0) > 0 || (profile.voice_rules?.length || 0) > 0;
6135
6178
  }
6136
- var fs4, path5, os4, DISK_CACHE_DIR2;
6179
+ var fs5, path5, os4, DISK_CACHE_DIR2;
6137
6180
  var init_local_profile = __esm({
6138
6181
  "src/lib/local-profile.ts"() {
6139
6182
  "use strict";
6140
- fs4 = __toESM(require("fs"));
6183
+ fs5 = __toESM(require("fs"));
6141
6184
  path5 = __toESM(require("path"));
6142
6185
  os4 = __toESM(require("os"));
6143
6186
  init_config();
@@ -6235,19 +6278,19 @@ var init_profile_parse = __esm({
6235
6278
  function loadSupplementalPatterns() {
6236
6279
  const p = path8.join(CACHE_DIR, "supplemental-rules.json");
6237
6280
  try {
6238
- if (!fs7.existsSync(p))
6281
+ if (!fs8.existsSync(p))
6239
6282
  return [];
6240
- const data = JSON.parse(fs7.readFileSync(p, "utf-8"));
6283
+ const data = JSON.parse(fs8.readFileSync(p, "utf-8"));
6241
6284
  return Array.isArray(data.patterns) ? data.patterns : [];
6242
6285
  } catch {
6243
6286
  return [];
6244
6287
  }
6245
6288
  }
6246
- var fs7, path8, BUNDLED_MANIFEST;
6289
+ var fs8, path8, BUNDLED_MANIFEST;
6247
6290
  var init_rules_loader = __esm({
6248
6291
  "src/lib/rules-loader.ts"() {
6249
6292
  "use strict";
6250
- fs7 = __toESM(require("fs"));
6293
+ fs8 = __toESM(require("fs"));
6251
6294
  path8 = __toESM(require("path"));
6252
6295
  init_config();
6253
6296
  BUNDLED_MANIFEST = path8.resolve(__dirname, "..", "..", "assets", "detection-rules.json");
@@ -7282,7 +7325,7 @@ function Ht(n7) {
7282
7325
  return isNaN(n7) ? n7.charCodeAt(0) : parseInt(n7, 10);
7283
7326
  }
7284
7327
  function ps(n7) {
7285
- return n7.replace(as, fe).replace(ls, ue).replace(cs, qt).replace(fs8, de).replace(us, pe);
7328
+ return n7.replace(as, fe).replace(ls, ue).replace(cs, qt).replace(fs9, de).replace(us, pe);
7286
7329
  }
7287
7330
  function ms(n7) {
7288
7331
  return n7.replace(is, "\\").replace(rs, "{").replace(ns, "}").replace(os5, ",").replace(hs, ".");
@@ -7385,7 +7428,7 @@ function Ut(n7, t = {}) {
7385
7428
  function es(n7, t = {}) {
7386
7429
  return new I(n7, t).iterate();
7387
7430
  }
7388
- 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, os5, hs, as, ls, cs, fs8, 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;
7431
+ 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, os5, hs, as, ls, cs, fs9, 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;
7389
7432
  var init_index_min = __esm({
7390
7433
  "node_modules/glob/dist/esm/index.min.js"() {
7391
7434
  import_node_url = require("node:url");
@@ -7437,7 +7480,7 @@ var init_index_min = __esm({
7437
7480
  as = /\\\\/g;
7438
7481
  ls = /\\{/g;
7439
7482
  cs = /\\}/g;
7440
- fs8 = /\\,/g;
7483
+ fs9 = /\\,/g;
7441
7484
  us = /\\./g;
7442
7485
  ds = 1e5;
7443
7486
  at = (n7) => {
@@ -10672,7 +10715,7 @@ function extractPdf(filePath) {
10672
10715
  if (out.trim())
10673
10716
  return out.trim();
10674
10717
  }
10675
- const raw = extractPdfRaw(fs9.readFileSync(filePath));
10718
+ const raw = extractPdfRaw(fs10.readFileSync(filePath));
10676
10719
  if (raw.trim().length > 20)
10677
10720
  return raw;
10678
10721
  throw new Error("could not extract text from .pdf \u2014 try pasting the draft instead");
@@ -10695,10 +10738,10 @@ function extractSkillArchive(filePath) {
10695
10738
  }
10696
10739
  function extractTextFromFile(filePath) {
10697
10740
  const resolved = path9.resolve(filePath);
10698
- if (!fs9.existsSync(resolved)) {
10741
+ if (!fs10.existsSync(resolved)) {
10699
10742
  throw new Error(`file not found: ${resolved}`);
10700
10743
  }
10701
- const stat = fs9.statSync(resolved);
10744
+ const stat = fs10.statSync(resolved);
10702
10745
  if (!stat.isFile()) {
10703
10746
  throw new Error(`not a file: ${resolved}`);
10704
10747
  }
@@ -10707,10 +10750,10 @@ function extractTextFromFile(filePath) {
10707
10750
  case ".md":
10708
10751
  case ".txt":
10709
10752
  case ".markdown":
10710
- return fs9.readFileSync(resolved, "utf-8");
10753
+ return fs10.readFileSync(resolved, "utf-8");
10711
10754
  case ".html":
10712
10755
  case ".htm":
10713
- return stripHtml(fs9.readFileSync(resolved, "utf-8"));
10756
+ return stripHtml(fs10.readFileSync(resolved, "utf-8"));
10714
10757
  case ".docx":
10715
10758
  return extractDocx(resolved);
10716
10759
  case ".pdf":
@@ -10731,10 +10774,10 @@ function listDocumentsInDir(dirPath) {
10731
10774
  }
10732
10775
  function collectDocumentsFromPath(inputPath) {
10733
10776
  const resolved = path9.resolve(inputPath.trim().replace(/^~(?=$|\/)/, os6.homedir()));
10734
- if (!fs9.existsSync(resolved)) {
10777
+ if (!fs10.existsSync(resolved)) {
10735
10778
  throw new Error(`path not found: ${resolved}`);
10736
10779
  }
10737
- const stat = fs9.statSync(resolved);
10780
+ const stat = fs10.statSync(resolved);
10738
10781
  const files = stat.isFile() ? [resolved] : listDocumentsInDir(resolved);
10739
10782
  if (!files.length) {
10740
10783
  throw new Error(
@@ -10762,17 +10805,17 @@ function readDraftInput(input) {
10762
10805
  if (!trimmed)
10763
10806
  throw new Error("empty draft");
10764
10807
  const maybePath = path9.resolve(trimmed.replace(/^~(?=$|\/)/, os6.homedir()));
10765
- if (fs9.existsSync(maybePath) && fs9.statSync(maybePath).isFile()) {
10808
+ if (fs10.existsSync(maybePath) && fs10.statSync(maybePath).isFile()) {
10766
10809
  return { text: extractTextFromFile(maybePath), source: maybePath };
10767
10810
  }
10768
10811
  return { text: trimmed, source: "paste" };
10769
10812
  }
10770
- var import_child_process2, fs9, os6, path9, SUPPORTED_EXTENSIONS, SAMPLE_GLOB, GLOB_IGNORE;
10813
+ var import_child_process2, fs10, os6, path9, SUPPORTED_EXTENSIONS, SAMPLE_GLOB, GLOB_IGNORE;
10771
10814
  var init_document_text = __esm({
10772
10815
  "src/lib/document-text.ts"() {
10773
10816
  "use strict";
10774
10817
  import_child_process2 = require("child_process");
10775
- fs9 = __toESM(require("fs"));
10818
+ fs10 = __toESM(require("fs"));
10776
10819
  os6 = __toESM(require("os"));
10777
10820
  path9 = __toESM(require("path"));
10778
10821
  init_index_min();
@@ -10849,21 +10892,21 @@ function runPipeline(text, profile, applyFixes = false) {
10849
10892
  };
10850
10893
  }
10851
10894
  function readText(source) {
10852
- const fs28 = require("fs");
10895
+ const fs29 = require("fs");
10853
10896
  const path26 = require("path");
10854
10897
  if (source === "-") {
10855
10898
  if (process.stdin.isTTY) {
10856
10899
  console.error("No input provided. Pipe content or specify a file.");
10857
10900
  process.exit(1);
10858
10901
  }
10859
- return { text: fs28.readFileSync(0, "utf-8"), path: "stdin" };
10902
+ return { text: fs29.readFileSync(0, "utf-8"), path: "stdin" };
10860
10903
  }
10861
10904
  const resolved = path26.resolve(source);
10862
- if (!fs28.existsSync(resolved)) {
10905
+ if (!fs29.existsSync(resolved)) {
10863
10906
  console.error(`File not found: ${resolved}`);
10864
10907
  process.exit(1);
10865
10908
  }
10866
- const stat = fs28.statSync(resolved);
10909
+ const stat = fs29.statSync(resolved);
10867
10910
  if (stat.isDirectory()) {
10868
10911
  console.error(`${resolved} is a directory, not a file.`);
10869
10912
  process.exit(1);
@@ -11315,10 +11358,10 @@ var init_terminal_ui = __esm({
11315
11358
  // src/lib/welcome-flow.ts
11316
11359
  function readWelcomeState() {
11317
11360
  try {
11318
- if (!fs13.existsSync(STATE_FILE)) {
11361
+ if (!fs14.existsSync(STATE_FILE)) {
11319
11362
  return { completed_steps: [], updated_at: (/* @__PURE__ */ new Date()).toISOString() };
11320
11363
  }
11321
- return JSON.parse(fs13.readFileSync(STATE_FILE, "utf-8"));
11364
+ return JSON.parse(fs14.readFileSync(STATE_FILE, "utf-8"));
11322
11365
  } catch {
11323
11366
  return { completed_steps: [], updated_at: (/* @__PURE__ */ new Date()).toISOString() };
11324
11367
  }
@@ -11330,7 +11373,7 @@ function writeWelcomeState(patch) {
11330
11373
  ...patch,
11331
11374
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
11332
11375
  };
11333
- fs13.writeFileSync(STATE_FILE, JSON.stringify(next, null, 2), { mode: 384 });
11376
+ fs14.writeFileSync(STATE_FILE, JSON.stringify(next, null, 2), { mode: 384 });
11334
11377
  return next;
11335
11378
  }
11336
11379
  function markStepComplete(step) {
@@ -11781,7 +11824,7 @@ async function stepSignup(profileName) {
11781
11824
  } else {
11782
11825
  console.log(import_chalk12.default.dim("\n already signed in \u2014 syncing profile..."));
11783
11826
  }
11784
- const content = fs13.readFileSync(
11827
+ const content = fs14.readFileSync(
11785
11828
  path13.join(os7.homedir(), ".hyv", "profiles", `${profileName}.md`),
11786
11829
  "utf-8"
11787
11830
  );
@@ -11794,15 +11837,22 @@ async function stepSignup(profileName) {
11794
11837
  })
11795
11838
  );
11796
11839
  if (response.status === 200) {
11797
- console.log(import_chalk12.default.green(" \u2713 profile synced to your account"));
11840
+ const body = response.data;
11841
+ if (body.preserved) {
11842
+ console.log(import_chalk12.default.green(" \u2713 account linked \u2014 kept your existing server profile"));
11843
+ } else {
11844
+ console.log(import_chalk12.default.green(" \u2713 profile synced to your account"));
11845
+ }
11798
11846
  } else {
11799
11847
  const detail = response.data?.error;
11800
11848
  console.log(import_chalk12.default.yellow(
11801
- ` profile saved locally \u2014 sync with \`hyv sync\`${detail ? ` (${detail})` : ` (HTTP ${response.status})`}`
11849
+ ` profile saved locally \u2014 retry \`hyv welcome\` when online${detail ? ` (${detail})` : ` (HTTP ${response.status})`}`
11802
11850
  ));
11803
11851
  }
11804
11852
  } catch (err) {
11805
- console.log(import_chalk12.default.yellow(` profile saved locally \u2014 run \`hyv sync\` (${err?.message || "sync failed"})`));
11853
+ console.log(import_chalk12.default.yellow(
11854
+ ` profile saved locally \u2014 retry \`hyv welcome\` (${err?.message || "sync failed"})`
11855
+ ));
11806
11856
  }
11807
11857
  console.log(import_chalk12.default.cyan("\n opening billing in your dashboard ($1 first month)..."));
11808
11858
  await withSpinner("opening billing\u2026", () => openAuthenticatedDashboard({ next: "/app/billing" }));
@@ -11840,12 +11890,12 @@ function getMcpWelcomeResponse(args2) {
11840
11890
  }
11841
11891
  return buildWelcomeGuide({ profileName: args2.profile, forLlm: true });
11842
11892
  }
11843
- var import_chalk12, fs13, http2, https2, os7, path13, readline, WELCOME_TAGLINE, FLOW_STEPS, STATE_FILE;
11893
+ var import_chalk12, fs14, http2, https2, os7, path13, readline, WELCOME_TAGLINE, FLOW_STEPS, STATE_FILE;
11844
11894
  var init_welcome_flow = __esm({
11845
11895
  "src/lib/welcome-flow.ts"() {
11846
11896
  "use strict";
11847
11897
  import_chalk12 = __toESM(require_source());
11848
- fs13 = __toESM(require("fs"));
11898
+ fs14 = __toESM(require("fs"));
11849
11899
  http2 = __toESM(require("http"));
11850
11900
  https2 = __toESM(require("https"));
11851
11901
  os7 = __toESM(require("os"));
@@ -12856,7 +12906,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
12856
12906
  g.minimatch.escape = vi2.escape;
12857
12907
  g.minimatch.unescape = Ei2.unescape;
12858
12908
  });
12859
- var fs28 = R2((Wt2) => {
12909
+ var fs29 = R2((Wt2) => {
12860
12910
  "use strict";
12861
12911
  Object.defineProperty(Wt2, "__esModule", { value: true });
12862
12912
  Wt2.LRUCache = void 0;
@@ -13825,7 +13875,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
13825
13875
  };
13826
13876
  Object.defineProperty(_2, "__esModule", { value: true });
13827
13877
  _2.PathScurry = _2.Path = _2.PathScurryDarwin = _2.PathScurryPosix = _2.PathScurryWin32 = _2.PathScurryBase = _2.PathPosix = _2.PathWin32 = _2.PathBase = _2.ChildrenCache = _2.ResolveCache = void 0;
13828
- var Qt2 = fs28(), 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) => {
13878
+ var Qt2 = fs29(), 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) => {
13829
13879
  let t = vs2.get(n7);
13830
13880
  if (t)
13831
13881
  return t;
@@ -15473,7 +15523,7 @@ function registerInitCommand(program3) {
15473
15523
  } else if (options?.browser === false) {
15474
15524
  console.log(import_chalk4.default.red("License key required when --no-browser is set."));
15475
15525
  console.log("\nUsage: hyv init <license-key>");
15476
- console.log("\nGenerate a license key at: https://holdyourvoice.com/dashboard");
15526
+ console.log("\nGenerate a license key at: https://holdyourvoice.com/app");
15477
15527
  process.exit(1);
15478
15528
  } else {
15479
15529
  authData = await authenticateWithBrowser();
@@ -15520,7 +15570,7 @@ init_version();
15520
15570
 
15521
15571
  // src/lib/queue-sync.ts
15522
15572
  var import_chalk6 = __toESM(require_source());
15523
- var fs5 = __toESM(require("fs"));
15573
+ var fs6 = __toESM(require("fs"));
15524
15574
  var path6 = __toESM(require("path"));
15525
15575
  init_config();
15526
15576
  init_auth();
@@ -15530,13 +15580,13 @@ async function flushQueuedSignals() {
15530
15580
  return { sent: 0, failed: 0 };
15531
15581
  let sent = 0;
15532
15582
  let failed = 0;
15533
- if (!fs5.existsSync(QUEUE_DIR))
15583
+ if (!fs6.existsSync(QUEUE_DIR))
15534
15584
  return { sent: 0, failed: 0 };
15535
- const files = fs5.readdirSync(QUEUE_DIR).filter((f) => f.endsWith(".json"));
15585
+ const files = fs6.readdirSync(QUEUE_DIR).filter((f) => f.endsWith(".json"));
15536
15586
  for (const file of files) {
15537
15587
  const filePath = path6.join(QUEUE_DIR, file);
15538
15588
  try {
15539
- const signal = JSON.parse(fs5.readFileSync(filePath, "utf-8"));
15589
+ const signal = JSON.parse(fs6.readFileSync(filePath, "utf-8"));
15540
15590
  let ok = false;
15541
15591
  if (signal.type === "reinforce") {
15542
15592
  const res = await authenticatedRequest(cliApiUrl("/cli/learning/reinforce"), {
@@ -15557,7 +15607,7 @@ async function flushQueuedSignals() {
15557
15607
  ok = res.status === 200;
15558
15608
  }
15559
15609
  if (ok) {
15560
- fs5.unlinkSync(filePath);
15610
+ fs6.unlinkSync(filePath);
15561
15611
  sent++;
15562
15612
  } else {
15563
15613
  failed++;
@@ -15714,7 +15764,7 @@ init_config();
15714
15764
  init_auth();
15715
15765
  init_access();
15716
15766
  init_profile();
15717
- var fs6 = __toESM(require("fs"));
15767
+ var fs7 = __toESM(require("fs"));
15718
15768
  var path7 = __toESM(require("path"));
15719
15769
  function registerSyncCommand(program3) {
15720
15770
  program3.command("sync").description("Sync profiles and rules from server").option("--force", "Force re-download even if cache is fresh").action(async (options) => {
@@ -15734,17 +15784,21 @@ function registerSyncCommand(program3) {
15734
15784
  ensureHyvDir();
15735
15785
  let profileCount = 0;
15736
15786
  for (const profile of data.profiles) {
15787
+ if (!profile.content?.trim()) {
15788
+ console.log(import_chalk8.default.yellow(` ! skipped empty profile cache: ${profile.name}`));
15789
+ continue;
15790
+ }
15737
15791
  const cacheKey = toSafeProfileCacheKey(profile.slug || profile.name);
15738
15792
  writeCachedProfile(cacheKey, profile.content);
15739
15793
  profileCount++;
15740
15794
  }
15741
15795
  const rulesPath = path7.join(CACHE_DIR, "rules.md");
15742
- fs6.writeFileSync(rulesPath, data.rules, { mode: 384 });
15796
+ fs7.writeFileSync(rulesPath, data.rules, { mode: 384 });
15743
15797
  const promptPath = path7.join(CACHE_DIR, "prompt-template.md");
15744
- fs6.writeFileSync(promptPath, data.prompt_template, { mode: 384 });
15798
+ fs7.writeFileSync(promptPath, data.prompt_template, { mode: 384 });
15745
15799
  if (data.detection_rules) {
15746
15800
  const rulesJson = path7.join(CACHE_DIR, "detection-rules.json");
15747
- fs6.writeFileSync(rulesJson, JSON.stringify(data.detection_rules, null, 2), { mode: 384 });
15801
+ fs7.writeFileSync(rulesJson, JSON.stringify(data.detection_rules, null, 2), { mode: 384 });
15748
15802
  }
15749
15803
  for (const profile of data.profiles) {
15750
15804
  try {
@@ -15761,7 +15815,7 @@ function registerSyncCommand(program3) {
15761
15815
  console.log(import_chalk8.default.yellow(` ! ${queueResult.failed} queued signal(s) could not send`));
15762
15816
  }
15763
15817
  const metaPath = path7.join(CACHE_DIR, "sync-meta.json");
15764
- fs6.writeFileSync(metaPath, JSON.stringify({
15818
+ fs7.writeFileSync(metaPath, JSON.stringify({
15765
15819
  synced_at: data.synced_at,
15766
15820
  profile_count: profileCount,
15767
15821
  plan: data.plan
@@ -15866,12 +15920,12 @@ Profile evolution: ${slug}
15866
15920
 
15867
15921
  // src/commands/rewrite.ts
15868
15922
  var import_chalk9 = __toESM(require_source());
15869
- var fs11 = __toESM(require("fs"));
15923
+ var fs12 = __toESM(require("fs"));
15870
15924
  var path11 = __toESM(require("path"));
15871
15925
  init_pipeline();
15872
15926
 
15873
15927
  // src/lib/prompt.ts
15874
- var fs10 = __toESM(require("fs"));
15928
+ var fs11 = __toESM(require("fs"));
15875
15929
  var path10 = __toESM(require("path"));
15876
15930
  init_config();
15877
15931
  init_signals();
@@ -15879,8 +15933,8 @@ init_profile_parse();
15879
15933
  function loadPromptTemplate() {
15880
15934
  const templatePath = path10.join(CACHE_DIR, "prompt-template.md");
15881
15935
  try {
15882
- if (fs10.existsSync(templatePath)) {
15883
- return fs10.readFileSync(templatePath, "utf-8");
15936
+ if (fs11.existsSync(templatePath)) {
15937
+ return fs11.readFileSync(templatePath, "utf-8");
15884
15938
  }
15885
15939
  } catch {
15886
15940
  }
@@ -15939,25 +15993,12 @@ Draft with line numbers ({draft_name}):
15939
15993
  `;
15940
15994
  }
15941
15995
  function loadProfile(name) {
15942
- if (name) {
15943
- const content = readCachedProfile(name);
15944
- if (content) {
15945
- return { content, name };
15946
- }
15996
+ if (!name) {
15997
+ return null;
15947
15998
  }
15948
- try {
15949
- if (!fs10.existsSync(PROFILES_DIR)) {
15950
- return null;
15951
- }
15952
- const profiles = fs10.readdirSync(PROFILES_DIR).filter((f) => f.endsWith(".md"));
15953
- if (profiles.length > 0) {
15954
- const defaultProfile = profiles[0].replace(".md", "");
15955
- const content = readCachedProfile(defaultProfile);
15956
- if (content) {
15957
- return { content, name: defaultProfile };
15958
- }
15959
- }
15960
- } catch {
15999
+ const content = readCachedProfile(name);
16000
+ if (content) {
16001
+ return { content, name };
15961
16002
  }
15962
16003
  return null;
15963
16004
  }
@@ -16081,7 +16122,7 @@ Draft: ${draftPath}`));
16081
16122
  }
16082
16123
  if (options.output) {
16083
16124
  const outputPath = path11.resolve(options.output);
16084
- fs11.writeFileSync(outputPath, promptResult.prompt);
16125
+ fs12.writeFileSync(outputPath, promptResult.prompt);
16085
16126
  console.log(import_chalk9.default.green(`
16086
16127
  \u2713 Prompt written to ${outputPath}`));
16087
16128
  } else {
@@ -16101,7 +16142,7 @@ Draft: ${draftPath}`));
16101
16142
 
16102
16143
  // src/commands/learning.ts
16103
16144
  var import_chalk10 = __toESM(require_source());
16104
- var fs12 = __toESM(require("fs"));
16145
+ var fs13 = __toESM(require("fs"));
16105
16146
  var path12 = __toESM(require("path"));
16106
16147
 
16107
16148
  // src/lib/diff.ts
@@ -16248,16 +16289,16 @@ function registerLearningCommands(program3) {
16248
16289
  }
16249
16290
  origPath = path12.resolve(original);
16250
16291
  editPath = path12.resolve(edited);
16251
- if (!fs12.existsSync(origPath)) {
16292
+ if (!fs13.existsSync(origPath)) {
16252
16293
  console.error(import_chalk10.default.red(`Original file not found: ${origPath}`));
16253
16294
  process.exit(1);
16254
16295
  }
16255
- if (!fs12.existsSync(editPath)) {
16296
+ if (!fs13.existsSync(editPath)) {
16256
16297
  console.error(import_chalk10.default.red(`Edited file not found: ${editPath}`));
16257
16298
  process.exit(1);
16258
16299
  }
16259
- origText = fs12.readFileSync(origPath, "utf-8");
16260
- editText = fs12.readFileSync(editPath, "utf-8");
16300
+ origText = fs13.readFileSync(origPath, "utf-8");
16301
+ editText = fs13.readFileSync(editPath, "utf-8");
16261
16302
  saveLastEditSession({
16262
16303
  original_path: origPath,
16263
16304
  edited_path: editPath,
@@ -16424,7 +16465,7 @@ function printProfileImpact(impact, data) {
16424
16465
 
16425
16466
  // src/commands/onboarding.ts
16426
16467
  var import_chalk13 = __toESM(require_source());
16427
- var fs14 = __toESM(require("fs"));
16468
+ var fs15 = __toESM(require("fs"));
16428
16469
  var path14 = __toESM(require("path"));
16429
16470
  init_config();
16430
16471
  init_auth();
@@ -16577,20 +16618,20 @@ Industry: ${industry}
16577
16618
  }
16578
16619
  async function createFromSamples(name, sampleDir, token) {
16579
16620
  const dirPath = path14.resolve(sampleDir);
16580
- if (!fs14.existsSync(dirPath)) {
16621
+ if (!fs15.existsSync(dirPath)) {
16581
16622
  throw new Error(`Directory not found: ${dirPath}`);
16582
16623
  }
16583
16624
  console.log(import_chalk13.default.bold(`
16584
16625
  Creating voice profile: ${name}`));
16585
16626
  console.log(import_chalk13.default.dim(`Reading samples from: ${dirPath}
16586
16627
  `));
16587
- const files = fs14.readdirSync(dirPath).filter((f) => f.endsWith(".md") || f.endsWith(".txt")).map((f) => path14.join(dirPath, f));
16628
+ const files = fs15.readdirSync(dirPath).filter((f) => f.endsWith(".md") || f.endsWith(".txt")).map((f) => path14.join(dirPath, f));
16588
16629
  if (files.length === 0) {
16589
16630
  throw new Error("No .md or .txt files found in directory");
16590
16631
  }
16591
16632
  const samples = [];
16592
16633
  for (const file of files) {
16593
- const text = fs14.readFileSync(file, "utf-8");
16634
+ const text = fs15.readFileSync(file, "utf-8");
16594
16635
  if (text.trim().length > 0) {
16595
16636
  samples.push({ path: file, text });
16596
16637
  console.log(import_chalk13.default.dim(` \u2022 ${path14.basename(file)} (${words(text).length} words)`));
@@ -16665,11 +16706,11 @@ function registerImportCommand(program3) {
16665
16706
  try {
16666
16707
  assertSafeProfileName(name);
16667
16708
  const filePath = path14.resolve(file);
16668
- if (!fs14.existsSync(filePath)) {
16709
+ if (!fs15.existsSync(filePath)) {
16669
16710
  console.error(import_chalk13.default.red(`File not found: ${filePath}`));
16670
16711
  process.exit(1);
16671
16712
  }
16672
- const content = fs14.readFileSync(filePath, "utf-8");
16713
+ const content = fs15.readFileSync(filePath, "utf-8");
16673
16714
  ensureHyvDir();
16674
16715
  writeCachedProfile(name, content);
16675
16716
  console.log(import_chalk13.default.green(`
@@ -16865,13 +16906,13 @@ async function openBillingPortal() {
16865
16906
  }
16866
16907
  } else {
16867
16908
  console.log(import_chalk14.default.yellow("Could not open billing portal."));
16868
- console.log(import_chalk14.default.dim("Visit https://holdyourvoice.com/dashboard to manage billing."));
16909
+ console.log(import_chalk14.default.dim(`Visit ${DASHBOARD_BILLING_URL} to manage billing.`));
16869
16910
  }
16870
16911
  }
16871
16912
  async function downgradePlan() {
16872
16913
  console.log(import_chalk14.default.yellow("\nDowngrade Plan\n"));
16873
16914
  console.log("To downgrade your plan, please visit:");
16874
- console.log(import_chalk14.default.dim(" https://holdyourvoice.com/dashboard"));
16915
+ console.log(import_chalk14.default.dim(` ${DASHBOARD_BILLING_URL}`));
16875
16916
  console.log("\nOr contact support at shashank@holdyourvoice.com");
16876
16917
  }
16877
16918
 
@@ -17040,7 +17081,7 @@ async function runHybridAnalysis(text, profile, opts = {}) {
17040
17081
 
17041
17082
  // src/commands/history.ts
17042
17083
  var import_chalk16 = __toESM(require_source());
17043
- var fs15 = __toESM(require("fs"));
17084
+ var fs16 = __toESM(require("fs"));
17044
17085
  var path15 = __toESM(require("path"));
17045
17086
  init_config();
17046
17087
  var HISTORY_DIR = path15.join(HYV_DIR, "history");
@@ -17054,9 +17095,9 @@ function logScan(entry) {
17054
17095
  }
17055
17096
  function readHistory() {
17056
17097
  try {
17057
- if (!fs15.existsSync(HISTORY_FILE))
17098
+ if (!fs16.existsSync(HISTORY_FILE))
17058
17099
  return [];
17059
- const lines = fs15.readFileSync(HISTORY_FILE, "utf-8").trim().split("\n").filter(Boolean);
17100
+ const lines = fs16.readFileSync(HISTORY_FILE, "utf-8").trim().split("\n").filter(Boolean);
17060
17101
  return lines.map((l) => JSON.parse(l));
17061
17102
  } catch {
17062
17103
  return [];
@@ -17088,8 +17129,8 @@ function registerHistoryCommand(program3) {
17088
17129
  program3.command("history").description("Show past scan scores and track improvement").option("--limit <n>", "Number of entries to show", "20").option("--file <path>", "Filter by file path").option("--since <date>", "Show entries since (e.g., 7d, 1m, 2024-01-01)").option("--chart", "Show ASCII sparkline chart").option("--clear", "Clear history").option("--format <type>", "Output format (text, json)", "text").action(async (options) => {
17089
17130
  try {
17090
17131
  if (options.clear) {
17091
- if (fs15.existsSync(HISTORY_FILE)) {
17092
- fs15.unlinkSync(HISTORY_FILE);
17132
+ if (fs16.existsSync(HISTORY_FILE)) {
17133
+ fs16.unlinkSync(HISTORY_FILE);
17093
17134
  }
17094
17135
  console.log(import_chalk16.default.green("\n\u2713 History cleared"));
17095
17136
  return;
@@ -17255,7 +17296,7 @@ hyv scan ${filePath}`));
17255
17296
 
17256
17297
  // src/commands/doctor.ts
17257
17298
  var import_chalk18 = __toESM(require_source());
17258
- var fs17 = __toESM(require("fs"));
17299
+ var fs18 = __toESM(require("fs"));
17259
17300
  var path17 = __toESM(require("path"));
17260
17301
  var os8 = __toESM(require("os"));
17261
17302
  init_config();
@@ -17268,7 +17309,7 @@ init_version();
17268
17309
  var import_child_process3 = require("child_process");
17269
17310
 
17270
17311
  // src/lib/cli-entry.ts
17271
- var fs16 = __toESM(require("fs"));
17312
+ var fs17 = __toESM(require("fs"));
17272
17313
  var path16 = __toESM(require("path"));
17273
17314
  function resolveCliEntry() {
17274
17315
  const candidates = [
@@ -17276,7 +17317,7 @@ function resolveCliEntry() {
17276
17317
  path16.resolve(__dirname, "index.js"),
17277
17318
  path16.resolve(__dirname, "..", "dist", "index.js")
17278
17319
  ];
17279
- return candidates.find((p) => p && fs16.existsSync(p)) || null;
17320
+ return candidates.find((p) => p && fs17.existsSync(p)) || null;
17280
17321
  }
17281
17322
  function mcpServerCommand() {
17282
17323
  const entry = resolveCliEntry();
@@ -17373,9 +17414,9 @@ function claudeDesktopDir() {
17373
17414
  }
17374
17415
  function isOwnerOnlyFile(filePath) {
17375
17416
  try {
17376
- if (!fs17.existsSync(filePath))
17417
+ if (!fs18.existsSync(filePath))
17377
17418
  return true;
17378
- const mode = fs17.statSync(filePath).mode & 511;
17419
+ const mode = fs18.statSync(filePath).mode & 511;
17379
17420
  return (mode & 63) === 0;
17380
17421
  } catch {
17381
17422
  return false;
@@ -17383,9 +17424,9 @@ function isOwnerOnlyFile(filePath) {
17383
17424
  }
17384
17425
  function readMcpHyv(configFile) {
17385
17426
  try {
17386
- if (!fs17.existsSync(configFile))
17427
+ if (!fs18.existsSync(configFile))
17387
17428
  return false;
17388
- const cfg = JSON.parse(fs17.readFileSync(configFile, "utf-8"));
17429
+ const cfg = JSON.parse(fs18.readFileSync(configFile, "utf-8"));
17389
17430
  return Boolean(cfg.mcpServers?.hyv);
17390
17431
  } catch {
17391
17432
  return false;
@@ -17406,28 +17447,28 @@ function registerDoctorCommand(program3) {
17406
17447
  console.log(import_chalk18.default.dim("tip: run hyv welcome for free capabilities\n"));
17407
17448
  console.log(import_chalk18.default.dim("checking cli installation..."));
17408
17449
  const cliPath = process.argv[1];
17409
- if (cliPath && fs17.existsSync(cliPath)) {
17450
+ if (cliPath && fs18.existsSync(cliPath)) {
17410
17451
  console.log(import_chalk18.default.green(" \u2713 cli installed"));
17411
17452
  } else {
17412
17453
  console.log(import_chalk18.default.red(" \u2717 cli not found"));
17413
17454
  issues++;
17414
17455
  }
17415
17456
  console.log(import_chalk18.default.dim("checking .hyv directory..."));
17416
- if (fs17.existsSync(HYV_DIR)) {
17457
+ if (fs18.existsSync(HYV_DIR)) {
17417
17458
  console.log(import_chalk18.default.green(" \u2713 .hyv directory exists"));
17418
17459
  } else {
17419
17460
  console.log(import_chalk18.default.yellow(" ! .hyv directory missing \u2014 creating..."));
17420
- fs17.mkdirSync(HYV_DIR, { recursive: true, mode: 448 });
17461
+ fs18.mkdirSync(HYV_DIR, { recursive: true, mode: 448 });
17421
17462
  fixed++;
17422
17463
  }
17423
17464
  console.log(import_chalk18.default.dim("checking cache..."));
17424
17465
  const diskProfiles = listDiskCachedProfiles();
17425
17466
  const syncMeta = path17.join(CACHE_DIR, "sync-meta.json");
17426
- if (diskProfiles.length > 0 || fs17.existsSync(syncMeta)) {
17467
+ if (diskProfiles.length > 0 || fs18.existsSync(syncMeta)) {
17427
17468
  console.log(import_chalk18.default.green(` \u2713 profile cache (${diskProfiles.length} full profile(s))`));
17428
- if (fs17.existsSync(syncMeta)) {
17469
+ if (fs18.existsSync(syncMeta)) {
17429
17470
  try {
17430
- const meta = JSON.parse(fs17.readFileSync(syncMeta, "utf-8"));
17471
+ const meta = JSON.parse(fs18.readFileSync(syncMeta, "utf-8"));
17431
17472
  console.log(import_chalk18.default.dim(` last sync: ${meta.synced_at || "unknown"}`));
17432
17473
  } catch {
17433
17474
  }
@@ -17436,8 +17477,8 @@ function registerDoctorCommand(program3) {
17436
17477
  console.log(import_chalk18.default.dim(" - no full profile cache (free local engine still works)"));
17437
17478
  }
17438
17479
  console.log(import_chalk18.default.dim("checking file permissions..."));
17439
- if (fs17.existsSync(HYV_DIR)) {
17440
- const hyvMode = fs17.statSync(HYV_DIR).mode & 511;
17480
+ if (fs18.existsSync(HYV_DIR)) {
17481
+ const hyvMode = fs18.statSync(HYV_DIR).mode & 511;
17441
17482
  if ((hyvMode & 63) === 0) {
17442
17483
  console.log(import_chalk18.default.green(" \u2713 .hyv directory permissions"));
17443
17484
  } else {
@@ -17446,7 +17487,7 @@ function registerDoctorCommand(program3) {
17446
17487
  issues++;
17447
17488
  }
17448
17489
  }
17449
- if (fs17.existsSync(AUTH_FILE)) {
17490
+ if (fs18.existsSync(AUTH_FILE)) {
17450
17491
  if (isOwnerOnlyFile(AUTH_FILE)) {
17451
17492
  console.log(import_chalk18.default.green(" \u2713 auth.json permissions"));
17452
17493
  } else {
@@ -17480,8 +17521,8 @@ function registerDoctorCommand(program3) {
17480
17521
  }
17481
17522
  console.log(import_chalk18.default.dim("checking voice profile..."));
17482
17523
  const voiceMd = path17.join(HYV_DIR, "voice.md");
17483
- const hasVoiceMd = fs17.existsSync(voiceMd) && fs17.readFileSync(voiceMd, "utf-8").trim().length > 50;
17484
- const profileFiles = fs17.existsSync(PROFILES_DIR) ? fs17.readdirSync(PROFILES_DIR).filter((f) => f.endsWith(".md") && f !== "voice.md") : [];
17524
+ const hasVoiceMd = fs18.existsSync(voiceMd) && fs18.readFileSync(voiceMd, "utf-8").trim().length > 50;
17525
+ const profileFiles = fs18.existsSync(PROFILES_DIR) ? fs18.readdirSync(PROFILES_DIR).filter((f) => f.endsWith(".md") && f !== "voice.md") : [];
17485
17526
  if (hasVoiceMd || profileFiles.length > 0 || diskProfiles.length > 0) {
17486
17527
  if (hasVoiceMd)
17487
17528
  console.log(import_chalk18.default.green(" \u2713 voice.md exists"));
@@ -17496,7 +17537,7 @@ function registerDoctorCommand(program3) {
17496
17537
  console.log(import_chalk18.default.dim("checking agent configurations..."));
17497
17538
  const cursorLegacyRule = path17.join(HOME, ".cursor", "rules", "hyv.md");
17498
17539
  const cursorRule = path17.join(HOME, ".cursor", "rules", "hyv.mdc");
17499
- if (fs17.existsSync(cursorLegacyRule) && fs17.existsSync(cursorRule)) {
17540
+ if (fs18.existsSync(cursorLegacyRule) && fs18.existsSync(cursorRule)) {
17500
17541
  console.log(import_chalk18.default.yellow(" ! stale cursor rule ~/.cursor/rules/hyv.md (use hyv.mdc)"));
17501
17542
  console.log(import_chalk18.default.dim(" run: rm ~/.cursor/rules/hyv.md (or hyv doctor --fix-agents)"));
17502
17543
  issues++;
@@ -17504,11 +17545,11 @@ function registerDoctorCommand(program3) {
17504
17545
  const agentChecks = [
17505
17546
  { name: "claude desktop mcp", ok: readMcpHyv(path17.join(claudeDesktopDir(), "claude_desktop_config.json")) },
17506
17547
  { name: "cursor mcp", ok: readMcpHyv(path17.join(HOME, ".cursor", "mcp.json")) },
17507
- { name: "cursor rule", ok: fs17.existsSync(cursorRule) },
17508
- { name: "claude code command", ok: fs17.existsSync(path17.join(HOME, ".claude", "commands", "hyv.md")) },
17509
- { name: "claude code skill", ok: fs17.existsSync(path17.join(HOME, ".claude", "skills", "hold-your-voice", "SKILL.md")) },
17510
- { name: "codex agents", ok: fs17.existsSync(path17.join(HOME, ".codex", "AGENTS.md")) && fs17.readFileSync(path17.join(HOME, ".codex", "AGENTS.md"), "utf-8").includes("hyv") },
17511
- { name: "command code skill", ok: fs17.existsSync(path17.join(HOME, ".commandcode", "skills", "hyv", "SKILL.md")) }
17548
+ { name: "cursor rule", ok: fs18.existsSync(cursorRule) },
17549
+ { name: "claude code command", ok: fs18.existsSync(path17.join(HOME, ".claude", "commands", "hyv.md")) },
17550
+ { name: "claude code skill", ok: fs18.existsSync(path17.join(HOME, ".claude", "skills", "hold-your-voice", "SKILL.md")) },
17551
+ { name: "codex agents", ok: fs18.existsSync(path17.join(HOME, ".codex", "AGENTS.md")) && fs18.readFileSync(path17.join(HOME, ".codex", "AGENTS.md"), "utf-8").includes("hyv") },
17552
+ { name: "command code skill", ok: fs18.existsSync(path17.join(HOME, ".commandcode", "skills", "hyv", "SKILL.md")) }
17512
17553
  ];
17513
17554
  for (const agent of agentChecks) {
17514
17555
  if (agent.ok) {
@@ -17642,7 +17683,7 @@ init_access();
17642
17683
  init_config();
17643
17684
 
17644
17685
  // src/lib/destructive-write.ts
17645
- var fs18 = __toESM(require("fs"));
17686
+ var fs19 = __toESM(require("fs"));
17646
17687
  var path18 = __toESM(require("path"));
17647
17688
  var readline2 = __toESM(require("readline"));
17648
17689
  var import_chalk20 = __toESM(require_source());
@@ -17669,8 +17710,8 @@ A .bak backup will be created. Proceed? [y/N] `;
17669
17710
  }
17670
17711
  function writeInPlaceWithBackup(filePath, content) {
17671
17712
  const backupPath = filePath + ".bak";
17672
- fs18.copyFileSync(filePath, backupPath);
17673
- fs18.writeFileSync(filePath, content);
17713
+ fs19.copyFileSync(filePath, backupPath);
17714
+ fs19.writeFileSync(filePath, content);
17674
17715
  return backupPath;
17675
17716
  }
17676
17717
  function backupBasename(filePath) {
@@ -17768,19 +17809,19 @@ function registerCheckCommand(program3) {
17768
17809
  const profile = await loadProfileForCommand(options.profile);
17769
17810
  let inputText = text;
17770
17811
  if (text === "-") {
17771
- const fs29 = require("fs");
17812
+ const fs30 = require("fs");
17772
17813
  if (process.stdin.isTTY) {
17773
17814
  console.error(import_chalk22.default.red("No input provided. Pipe content or pass text as argument."));
17774
17815
  process.exit(1);
17775
17816
  }
17776
- inputText = fs29.readFileSync(0, "utf-8");
17817
+ inputText = fs30.readFileSync(0, "utf-8");
17777
17818
  }
17778
17819
  if (!inputText.trim()) {
17779
17820
  console.error(import_chalk22.default.red("No text provided."));
17780
17821
  process.exit(1);
17781
17822
  }
17782
- const fs28 = require("fs");
17783
- if (text !== "-" && fs28.existsSync(text)) {
17823
+ const fs29 = require("fs");
17824
+ if (text !== "-" && fs29.existsSync(text)) {
17784
17825
  console.log(import_chalk22.default.yellow(`"${text}" looks like a file. Did you mean: hyv scan ${text}`));
17785
17826
  process.exit(1);
17786
17827
  }
@@ -17907,11 +17948,11 @@ function registerDiffCommand(program3) {
17907
17948
  ${result.changes.length} auto-fix${result.changes.length === 1 ? "" : "es"} available`));
17908
17949
  console.log(import_chalk24.default.dim(` run: hyv fix ${file} -i to apply`));
17909
17950
  if (options.apply && filePath !== "stdin") {
17910
- const fs28 = require("fs");
17951
+ const fs29 = require("fs");
17911
17952
  const path26 = require("path");
17912
17953
  const backupPath = filePath + ".bak";
17913
- fs28.copyFileSync(filePath, backupPath);
17914
- fs28.writeFileSync(filePath, result.fixed);
17954
+ fs29.copyFileSync(filePath, backupPath);
17955
+ fs29.writeFileSync(filePath, result.fixed);
17915
17956
  console.log(import_chalk24.default.green(` \u2713 Applied. Backup: ${path26.basename(backupPath)}`));
17916
17957
  }
17917
17958
  } catch (error) {
@@ -18087,7 +18128,7 @@ function registerRulesCommand(program3) {
18087
18128
 
18088
18129
  // src/commands/batch.ts
18089
18130
  var import_chalk26 = __toESM(require_source());
18090
- var fs19 = __toESM(require("fs"));
18131
+ var fs20 = __toESM(require("fs"));
18091
18132
  var path19 = __toESM(require("path"));
18092
18133
  init_pipeline();
18093
18134
  init_local_profile();
@@ -18122,9 +18163,9 @@ No files matching: ${pattern}`));
18122
18163
  const results = [];
18123
18164
  for (const file of files) {
18124
18165
  const absPath = path19.resolve(file);
18125
- if (!fs19.existsSync(absPath))
18166
+ if (!fs20.existsSync(absPath))
18126
18167
  continue;
18127
- const text = fs19.readFileSync(absPath, "utf-8");
18168
+ const text = fs20.readFileSync(absPath, "utf-8");
18128
18169
  const result = runPipeline(text, profile, options.fix || false);
18129
18170
  results.push({
18130
18171
  file,
@@ -18190,7 +18231,7 @@ No files matching: ${pattern}`));
18190
18231
 
18191
18232
  // src/commands/watch.ts
18192
18233
  var import_chalk27 = __toESM(require_source());
18193
- var fs20 = __toESM(require("fs"));
18234
+ var fs21 = __toESM(require("fs"));
18194
18235
  var path20 = __toESM(require("path"));
18195
18236
  init_pipeline();
18196
18237
  init_local_profile();
@@ -18199,7 +18240,7 @@ function registerWatchCommand(program3) {
18199
18240
  try {
18200
18241
  const profile = await loadProfileForCommand(options.profile);
18201
18242
  const absPath = path20.resolve(file);
18202
- if (!fs20.existsSync(absPath)) {
18243
+ if (!fs21.existsSync(absPath)) {
18203
18244
  console.error(import_chalk27.default.red(`File not found: ${absPath}`));
18204
18245
  process.exit(1);
18205
18246
  }
@@ -18222,7 +18263,7 @@ watching ${absPath}`));
18222
18263
  let lastScore = 0;
18223
18264
  let ignoreWatchUntil = 0;
18224
18265
  const runScan = () => {
18225
- const text = fs20.readFileSync(absPath, "utf-8");
18266
+ const text = fs21.readFileSync(absPath, "utf-8");
18226
18267
  const result = runPipeline(text, profile, options.command === "fix");
18227
18268
  scanCount++;
18228
18269
  const now = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
@@ -18264,7 +18305,7 @@ watching ${absPath}`));
18264
18305
  console.log("");
18265
18306
  };
18266
18307
  runScan();
18267
- fs20.watch(absPath, (eventType) => {
18308
+ fs21.watch(absPath, (eventType) => {
18268
18309
  if (eventType !== "change")
18269
18310
  return;
18270
18311
  if (Date.now() < ignoreWatchUntil)
@@ -18289,7 +18330,7 @@ watching ${absPath}`));
18289
18330
 
18290
18331
  // src/commands/demo.ts
18291
18332
  var import_chalk28 = __toESM(require_source());
18292
- var fs21 = __toESM(require("fs"));
18333
+ var fs22 = __toESM(require("fs"));
18293
18334
  var SAMPLES = {
18294
18335
  linkedin: {
18295
18336
  text: `In today's fast-paced digital landscape, it's important to note that leveraging the right tools is not just nice to have, but essential for success. Let's delve into the holistic approach that will transform your workflow.
@@ -18384,7 +18425,7 @@ function registerDemoCommand(program3) {
18384
18425
  }
18385
18426
  if (options.output) {
18386
18427
  const outputPath = require("path").resolve(options.output);
18387
- fs21.writeFileSync(outputPath, sample.text);
18428
+ fs22.writeFileSync(outputPath, sample.text);
18388
18429
  console.log(import_chalk28.default.green(`
18389
18430
  \u2713 Sample written to ${outputPath}`));
18390
18431
  if (sample.patterns.length > 0) {
@@ -18451,22 +18492,22 @@ function registerOpenCommand(program3) {
18451
18492
  init_welcome();
18452
18493
 
18453
18494
  // src/lib/onboarding.ts
18454
- var fs22 = __toESM(require("fs"));
18495
+ var fs23 = __toESM(require("fs"));
18455
18496
  var path21 = __toESM(require("path"));
18456
18497
  var os9 = __toESM(require("os"));
18457
18498
  var hyvDir = path21.join(os9.homedir(), ".hyv");
18458
18499
  var onboardingFile = path21.join(hyvDir, "onboarding-complete.json");
18459
18500
  function hasCompletedOnboarding() {
18460
18501
  try {
18461
- return fs22.existsSync(onboardingFile);
18502
+ return fs23.existsSync(onboardingFile);
18462
18503
  } catch {
18463
18504
  return false;
18464
18505
  }
18465
18506
  }
18466
18507
  function markOnboardingComplete(version) {
18467
- if (!fs22.existsSync(hyvDir))
18468
- fs22.mkdirSync(hyvDir, { recursive: true });
18469
- fs22.writeFileSync(
18508
+ if (!fs23.existsSync(hyvDir))
18509
+ fs23.mkdirSync(hyvDir, { recursive: true });
18510
+ fs23.writeFileSync(
18470
18511
  onboardingFile,
18471
18512
  JSON.stringify({ version, completed_at: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
18472
18513
  );
@@ -18474,13 +18515,13 @@ function markOnboardingComplete(version) {
18474
18515
 
18475
18516
  // src/commands/welcome.ts
18476
18517
  init_welcome_flow();
18477
- var fs23 = __toESM(require("fs"));
18518
+ var fs24 = __toESM(require("fs"));
18478
18519
  var path22 = __toESM(require("path"));
18479
18520
  function registerWelcomeCommand(program3) {
18480
18521
  const pkgVersion3 = (() => {
18481
18522
  try {
18482
18523
  const pkgPath3 = path22.resolve(__dirname, "..", "package.json");
18483
- return JSON.parse(fs23.readFileSync(pkgPath3, "utf-8")).version;
18524
+ return JSON.parse(fs24.readFileSync(pkgPath3, "utf-8")).version;
18484
18525
  } catch {
18485
18526
  return "0.0.0";
18486
18527
  }
@@ -18661,7 +18702,7 @@ Current: ${getEngineLabel()}
18661
18702
  }
18662
18703
 
18663
18704
  // src/mcp.ts
18664
- var fs24 = __toESM(require("fs"));
18705
+ var fs25 = __toESM(require("fs"));
18665
18706
  var path23 = __toESM(require("path"));
18666
18707
  var os10 = __toESM(require("os"));
18667
18708
  init_classifier();
@@ -18678,16 +18719,16 @@ var VOICE_MD = path23.join(os10.homedir(), ".hyv", "voice.md");
18678
18719
  var MAX_RESPONSE_CHARS = 12e4;
18679
18720
  var MAX_SCAN_FILE_BYTES = 2 * 1024 * 1024;
18680
18721
  function readScanFile(filePath) {
18681
- const cwdReal = fs24.realpathSync(process.cwd());
18682
- const resolved = fs24.realpathSync(path23.resolve(filePath));
18722
+ const cwdReal = fs25.realpathSync(process.cwd());
18723
+ const resolved = fs25.realpathSync(path23.resolve(filePath));
18683
18724
  if (!resolved.startsWith(cwdReal + path23.sep) && resolved !== cwdReal) {
18684
18725
  throw new Error(`file must be in the current working directory (${cwdReal})`);
18685
18726
  }
18686
- const stat = fs24.statSync(resolved);
18727
+ const stat = fs25.statSync(resolved);
18687
18728
  if (stat.size > MAX_SCAN_FILE_BYTES) {
18688
18729
  throw new Error(`file too large (max ${MAX_SCAN_FILE_BYTES} bytes)`);
18689
18730
  }
18690
- return fs24.readFileSync(resolved, "utf-8");
18731
+ return fs25.readFileSync(resolved, "utf-8");
18691
18732
  }
18692
18733
  function toolResultPayload(result) {
18693
18734
  const isError = result.startsWith("Error:") || result.startsWith("Unknown tool:");
@@ -18699,7 +18740,7 @@ function toolResultPayload(result) {
18699
18740
  var pkgPath = path23.resolve(__dirname, "..", "package.json");
18700
18741
  var pkgVersion = (() => {
18701
18742
  try {
18702
- return JSON.parse(fs24.readFileSync(pkgPath, "utf-8")).version;
18743
+ return JSON.parse(fs25.readFileSync(pkgPath, "utf-8")).version;
18703
18744
  } catch {
18704
18745
  return "2.7.1";
18705
18746
  }
@@ -19280,7 +19321,7 @@ async function handleRequest(line) {
19280
19321
  }
19281
19322
  async function startMcpServer() {
19282
19323
  const access = await getAccessState().catch(() => null);
19283
- if (fs24.existsSync(VOICE_MD)) {
19324
+ if (fs25.existsSync(VOICE_MD)) {
19284
19325
  mcpLog("info", `voice profile: ${VOICE_MD}`);
19285
19326
  } else {
19286
19327
  mcpLog("info", "free local engine ready \u2014 no voice profile yet");
@@ -19313,7 +19354,7 @@ async function startMcpServer() {
19313
19354
 
19314
19355
  // src/lib/mcp-setup.ts
19315
19356
  var import_chalk32 = __toESM(require_source());
19316
- var fs25 = __toESM(require("fs"));
19357
+ var fs26 = __toESM(require("fs"));
19317
19358
  var path24 = __toESM(require("path"));
19318
19359
  var os11 = __toESM(require("os"));
19319
19360
  init_version();
@@ -19407,7 +19448,7 @@ async function runMcpSelfTest() {
19407
19448
  failed++;
19408
19449
  }
19409
19450
  const voiceMd = path24.join(HOME2, ".hyv", "voice.md");
19410
- if (fs25.existsSync(voiceMd)) {
19451
+ if (fs26.existsSync(voiceMd)) {
19411
19452
  console.log(import_chalk32.default.green(" \u2713 voice profile found"));
19412
19453
  passed++;
19413
19454
  } else {
@@ -19447,7 +19488,7 @@ async function runMcpSelfTest() {
19447
19488
  }
19448
19489
 
19449
19490
  // src/commands/export.ts
19450
- var fs26 = __toESM(require("fs"));
19491
+ var fs27 = __toESM(require("fs"));
19451
19492
  init_api();
19452
19493
  var FORMATS = {
19453
19494
  claude: {
@@ -19521,7 +19562,7 @@ async function exportCommand(format, opts) {
19521
19562
  } else {
19522
19563
  console.log(`
19523
19564
  ${c.red("\u2717")} no voice profiles found`);
19524
- console.log(` ${c.dim("create one at")} ${c.cyan("https://holdyourvoice.com/dashboard")}`);
19565
+ console.log(` ${c.dim("create one at")} ${c.cyan("https://holdyourvoice.com/app")}`);
19525
19566
  }
19526
19567
  process.exit(1);
19527
19568
  return;
@@ -19534,7 +19575,7 @@ async function exportCommand(format, opts) {
19534
19575
  const prompt = fmt.wrap(detail.profile, detail.body);
19535
19576
  if (opts.output) {
19536
19577
  const outFile = opts.output.replace("{name}", profile.slug || profile.name);
19537
- fs26.writeFileSync(outFile, prompt);
19578
+ fs27.writeFileSync(outFile, prompt);
19538
19579
  results.push({ profile: profile.name, file: outFile });
19539
19580
  } else {
19540
19581
  results.push({ profile: profile.name, prompt });
@@ -19571,13 +19612,13 @@ async function exportCommand(format, opts) {
19571
19612
  // src/index.ts
19572
19613
  init_access();
19573
19614
  init_welcome();
19574
- var fs27 = __toESM(require("fs"));
19615
+ var fs28 = __toESM(require("fs"));
19575
19616
  var path25 = __toESM(require("path"));
19576
19617
  var program2 = new Command();
19577
19618
  var pkgPath2 = path25.resolve(__dirname, "..", "package.json");
19578
19619
  var pkgVersion2 = (() => {
19579
19620
  try {
19580
- return JSON.parse(fs27.readFileSync(pkgPath2, "utf-8")).version;
19621
+ return JSON.parse(fs28.readFileSync(pkgPath2, "utf-8")).version;
19581
19622
  } catch {
19582
19623
  return "2.7.1";
19583
19624
  }