@holdyourvoice/hyv 2.8.7 → 2.8.8
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/CHANGELOG.md +20 -0
- package/README.md +1 -1
- package/agents/cursor.md +1 -1
- package/dist/index.js +644 -304
- package/package.json +1 -1
- package/scripts/postinstall-lib.js +232 -7
- package/scripts/postinstall.js +8 -92
- package/assets/ai-eliminator-skill.md +0 -63
- package/assets/claude-code-skill.md +0 -24
- package/assets/cursor-rules.md +0 -12
- package/assets/hold-your-voice-skill.md +0 -174
- package/assets/voice-matcher-skill.md +0 -57
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 path23 = require("node:path");
|
|
977
|
-
var
|
|
977
|
+
var fs24 = 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 = path23.resolve(baseDir, baseName);
|
|
1920
|
-
if (
|
|
1920
|
+
if (fs24.existsSync(localBin))
|
|
1921
1921
|
return localBin;
|
|
1922
1922
|
if (sourceExt.includes(path23.extname(baseName)))
|
|
1923
1923
|
return void 0;
|
|
1924
1924
|
const foundExt = sourceExt.find(
|
|
1925
|
-
(ext) =>
|
|
1925
|
+
(ext) => fs24.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 =
|
|
1938
|
+
resolvedScriptPath = fs24.realpathSync(this._scriptPath);
|
|
1939
1939
|
} catch (err) {
|
|
1940
1940
|
resolvedScriptPath = this._scriptPath;
|
|
1941
1941
|
}
|
|
@@ -4612,14 +4612,97 @@ var require_source = __commonJS({
|
|
|
4612
4612
|
});
|
|
4613
4613
|
|
|
4614
4614
|
// src/lib/config.ts
|
|
4615
|
+
function validateApiBase(raw) {
|
|
4616
|
+
const trimmed = raw.replace(/\/$/, "");
|
|
4617
|
+
let parsed;
|
|
4618
|
+
try {
|
|
4619
|
+
parsed = new URL(trimmed);
|
|
4620
|
+
} catch {
|
|
4621
|
+
throw new Error(`Invalid HYV_API_URL: ${raw}`);
|
|
4622
|
+
}
|
|
4623
|
+
if (!ALLOWED_API_HOSTS.has(parsed.hostname)) {
|
|
4624
|
+
throw new Error(`HYV_API_URL host not allowed: ${parsed.hostname}`);
|
|
4625
|
+
}
|
|
4626
|
+
if (parsed.hostname !== "localhost" && parsed.hostname !== "127.0.0.1" && parsed.protocol !== "https:") {
|
|
4627
|
+
throw new Error("HYV_API_URL must use https://");
|
|
4628
|
+
}
|
|
4629
|
+
return trimmed;
|
|
4630
|
+
}
|
|
4631
|
+
function cliApiUrl(apiPath) {
|
|
4632
|
+
const p = apiPath.startsWith("/") ? apiPath : `/${apiPath}`;
|
|
4633
|
+
return `${API_BASE}${p}`;
|
|
4634
|
+
}
|
|
4635
|
+
function assertSafeOpenUrl(url) {
|
|
4636
|
+
let parsed;
|
|
4637
|
+
try {
|
|
4638
|
+
parsed = new URL(url);
|
|
4639
|
+
} catch {
|
|
4640
|
+
throw new Error("Invalid URL");
|
|
4641
|
+
}
|
|
4642
|
+
if (parsed.protocol !== "https:") {
|
|
4643
|
+
throw new Error("Only https:// URLs can be opened");
|
|
4644
|
+
}
|
|
4645
|
+
if (!ALLOWED_API_HOSTS.has(parsed.hostname)) {
|
|
4646
|
+
throw new Error(`URL host not allowed: ${parsed.hostname}`);
|
|
4647
|
+
}
|
|
4648
|
+
return url;
|
|
4649
|
+
}
|
|
4650
|
+
function assertSafeProfileName(name) {
|
|
4651
|
+
const normalized = String(name || "").trim();
|
|
4652
|
+
if (!normalized)
|
|
4653
|
+
throw new Error("Profile name is required");
|
|
4654
|
+
if (/[/\\]|\.\.|\u0000/.test(normalized)) {
|
|
4655
|
+
throw new Error("Invalid profile name: use letters, numbers, hyphens, and underscores only");
|
|
4656
|
+
}
|
|
4657
|
+
if (!PROFILE_NAME_RE.test(normalized)) {
|
|
4658
|
+
throw new Error("Invalid profile name: use letters, numbers, hyphens, and underscores only");
|
|
4659
|
+
}
|
|
4660
|
+
return normalized;
|
|
4661
|
+
}
|
|
4662
|
+
function profilePathForName(name) {
|
|
4663
|
+
const safe = assertSafeProfileName(name);
|
|
4664
|
+
ensureHyvDir();
|
|
4665
|
+
const profilePath = path.resolve(PROFILES_DIR, `${safe}.md`);
|
|
4666
|
+
const profilesRoot = path.resolve(PROFILES_DIR) + path.sep;
|
|
4667
|
+
if (!profilePath.startsWith(profilesRoot)) {
|
|
4668
|
+
throw new Error("Invalid profile name");
|
|
4669
|
+
}
|
|
4670
|
+
return profilePath;
|
|
4671
|
+
}
|
|
4615
4672
|
function ensureHyvDir() {
|
|
4616
4673
|
const dirs = [HYV_DIR, PROFILES_DIR, CACHE_DIR, QUEUE_DIR];
|
|
4617
4674
|
for (const dir of dirs) {
|
|
4618
4675
|
if (!fs.existsSync(dir)) {
|
|
4619
4676
|
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
4677
|
+
} else {
|
|
4678
|
+
try {
|
|
4679
|
+
fs.chmodSync(dir, 448);
|
|
4680
|
+
} catch {
|
|
4681
|
+
}
|
|
4620
4682
|
}
|
|
4621
4683
|
}
|
|
4622
4684
|
}
|
|
4685
|
+
function appendSecureLine(filePath, line, dir) {
|
|
4686
|
+
if (dir) {
|
|
4687
|
+
if (!fs.existsSync(dir))
|
|
4688
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
4689
|
+
else {
|
|
4690
|
+
try {
|
|
4691
|
+
fs.chmodSync(dir, 448);
|
|
4692
|
+
} catch {
|
|
4693
|
+
}
|
|
4694
|
+
}
|
|
4695
|
+
}
|
|
4696
|
+
if (!fs.existsSync(filePath)) {
|
|
4697
|
+
fs.writeFileSync(filePath, line, { mode: 384 });
|
|
4698
|
+
return;
|
|
4699
|
+
}
|
|
4700
|
+
try {
|
|
4701
|
+
fs.chmodSync(filePath, 384);
|
|
4702
|
+
} catch {
|
|
4703
|
+
}
|
|
4704
|
+
fs.appendFileSync(filePath, line);
|
|
4705
|
+
}
|
|
4623
4706
|
function isInitialized() {
|
|
4624
4707
|
return fs.existsSync(AUTH_FILE);
|
|
4625
4708
|
}
|
|
@@ -4673,18 +4756,19 @@ function listCachedProfiles() {
|
|
|
4673
4756
|
}
|
|
4674
4757
|
}
|
|
4675
4758
|
function readCachedProfile(name) {
|
|
4676
|
-
const profilePath =
|
|
4759
|
+
const profilePath = profilePathForName(name);
|
|
4677
4760
|
try {
|
|
4678
4761
|
if (!fs.existsSync(profilePath))
|
|
4679
4762
|
return null;
|
|
4680
4763
|
return fs.readFileSync(profilePath, "utf-8");
|
|
4681
|
-
} catch {
|
|
4764
|
+
} catch (err) {
|
|
4765
|
+
if (err.message?.includes("Invalid profile name"))
|
|
4766
|
+
throw err;
|
|
4682
4767
|
return null;
|
|
4683
4768
|
}
|
|
4684
4769
|
}
|
|
4685
4770
|
function writeCachedProfile(name, content) {
|
|
4686
|
-
|
|
4687
|
-
const profilePath = path.join(PROFILES_DIR, `${name}.md`);
|
|
4771
|
+
const profilePath = profilePathForName(name);
|
|
4688
4772
|
fs.writeFileSync(profilePath, content, { mode: 384 });
|
|
4689
4773
|
}
|
|
4690
4774
|
function getQueuedSignals() {
|
|
@@ -4704,7 +4788,7 @@ function queueSignal(signal) {
|
|
|
4704
4788
|
ensureHyvDir();
|
|
4705
4789
|
const id = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
4706
4790
|
const filePath = path.join(QUEUE_DIR, `${id}.json`);
|
|
4707
|
-
fs.writeFileSync(filePath, JSON.stringify(signal, null, 2));
|
|
4791
|
+
fs.writeFileSync(filePath, JSON.stringify(signal, null, 2), { mode: 384 });
|
|
4708
4792
|
}
|
|
4709
4793
|
function saveLastEditSession(session) {
|
|
4710
4794
|
ensureHyvDir();
|
|
@@ -4720,7 +4804,7 @@ function readLastEditSession() {
|
|
|
4720
4804
|
return null;
|
|
4721
4805
|
}
|
|
4722
4806
|
}
|
|
4723
|
-
var fs, path, os, HYV_DIR, AUTH_FILE, CONFIG_FILE, PROFILES_DIR, CACHE_DIR, QUEUE_DIR, LAST_SESSION_FILE, API_BASE;
|
|
4807
|
+
var fs, path, os, HYV_DIR, AUTH_FILE, CONFIG_FILE, PROFILES_DIR, CACHE_DIR, QUEUE_DIR, LAST_SESSION_FILE, ALLOWED_API_HOSTS, API_BASE, PROFILE_NAME_RE;
|
|
4724
4808
|
var init_config = __esm({
|
|
4725
4809
|
"src/lib/config.ts"() {
|
|
4726
4810
|
"use strict";
|
|
@@ -4734,7 +4818,15 @@ var init_config = __esm({
|
|
|
4734
4818
|
CACHE_DIR = path.join(HYV_DIR, "cache");
|
|
4735
4819
|
QUEUE_DIR = path.join(HYV_DIR, "queue");
|
|
4736
4820
|
LAST_SESSION_FILE = path.join(HYV_DIR, "last-session.json");
|
|
4737
|
-
|
|
4821
|
+
ALLOWED_API_HOSTS = /* @__PURE__ */ new Set([
|
|
4822
|
+
"holdyourvoice.com",
|
|
4823
|
+
"www.holdyourvoice.com",
|
|
4824
|
+
"staging.holdyourvoice.com",
|
|
4825
|
+
"localhost",
|
|
4826
|
+
"127.0.0.1"
|
|
4827
|
+
]);
|
|
4828
|
+
API_BASE = validateApiBase(process.env.HYV_API_URL || "https://holdyourvoice.com");
|
|
4829
|
+
PROFILE_NAME_RE = /^[a-z0-9][a-z0-9._-]{0,62}$/i;
|
|
4738
4830
|
}
|
|
4739
4831
|
});
|
|
4740
4832
|
|
|
@@ -4742,11 +4834,11 @@ var init_config = __esm({
|
|
|
4742
4834
|
var require_is_docker = __commonJS({
|
|
4743
4835
|
"node_modules/is-docker/index.js"(exports2, module2) {
|
|
4744
4836
|
"use strict";
|
|
4745
|
-
var
|
|
4837
|
+
var fs24 = require("fs");
|
|
4746
4838
|
var isDocker;
|
|
4747
4839
|
function hasDockerEnv() {
|
|
4748
4840
|
try {
|
|
4749
|
-
|
|
4841
|
+
fs24.statSync("/.dockerenv");
|
|
4750
4842
|
return true;
|
|
4751
4843
|
} catch (_) {
|
|
4752
4844
|
return false;
|
|
@@ -4754,7 +4846,7 @@ var require_is_docker = __commonJS({
|
|
|
4754
4846
|
}
|
|
4755
4847
|
function hasDockerCGroup() {
|
|
4756
4848
|
try {
|
|
4757
|
-
return
|
|
4849
|
+
return fs24.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
|
4758
4850
|
} catch (_) {
|
|
4759
4851
|
return false;
|
|
4760
4852
|
}
|
|
@@ -4773,7 +4865,7 @@ var require_is_wsl = __commonJS({
|
|
|
4773
4865
|
"node_modules/is-wsl/index.js"(exports2, module2) {
|
|
4774
4866
|
"use strict";
|
|
4775
4867
|
var os9 = require("os");
|
|
4776
|
-
var
|
|
4868
|
+
var fs24 = require("fs");
|
|
4777
4869
|
var isDocker = require_is_docker();
|
|
4778
4870
|
var isWsl = () => {
|
|
4779
4871
|
if (process.platform !== "linux") {
|
|
@@ -4786,7 +4878,7 @@ var require_is_wsl = __commonJS({
|
|
|
4786
4878
|
return true;
|
|
4787
4879
|
}
|
|
4788
4880
|
try {
|
|
4789
|
-
return
|
|
4881
|
+
return fs24.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isDocker() : false;
|
|
4790
4882
|
} catch (_) {
|
|
4791
4883
|
return false;
|
|
4792
4884
|
}
|
|
@@ -4827,7 +4919,7 @@ var require_open = __commonJS({
|
|
|
4827
4919
|
"node_modules/open/index.js"(exports2, module2) {
|
|
4828
4920
|
var path23 = require("path");
|
|
4829
4921
|
var childProcess = require("child_process");
|
|
4830
|
-
var { promises:
|
|
4922
|
+
var { promises: fs24, constants: fsConstants } = require("fs");
|
|
4831
4923
|
var isWsl = require_is_wsl();
|
|
4832
4924
|
var isDocker = require_is_docker();
|
|
4833
4925
|
var defineLazyProperty = require_define_lazy_prop();
|
|
@@ -4835,7 +4927,7 @@ var require_open = __commonJS({
|
|
|
4835
4927
|
var { platform, arch } = process;
|
|
4836
4928
|
var hasContainerEnv = () => {
|
|
4837
4929
|
try {
|
|
4838
|
-
|
|
4930
|
+
fs24.statSync("/run/.containerenv");
|
|
4839
4931
|
return true;
|
|
4840
4932
|
} catch {
|
|
4841
4933
|
return false;
|
|
@@ -4858,14 +4950,14 @@ var require_open = __commonJS({
|
|
|
4858
4950
|
const configFilePath = "/etc/wsl.conf";
|
|
4859
4951
|
let isConfigFileExists = false;
|
|
4860
4952
|
try {
|
|
4861
|
-
await
|
|
4953
|
+
await fs24.access(configFilePath, fsConstants.F_OK);
|
|
4862
4954
|
isConfigFileExists = true;
|
|
4863
4955
|
} catch {
|
|
4864
4956
|
}
|
|
4865
4957
|
if (!isConfigFileExists) {
|
|
4866
4958
|
return defaultMountPoint;
|
|
4867
4959
|
}
|
|
4868
|
-
const configContent = await
|
|
4960
|
+
const configContent = await fs24.readFile(configFilePath, { encoding: "utf8" });
|
|
4869
4961
|
const configMountPoint = /(?<!#.*)root\s*=\s*(?<mountPoint>.*)/g.exec(configContent);
|
|
4870
4962
|
if (!configMountPoint) {
|
|
4871
4963
|
return defaultMountPoint;
|
|
@@ -4965,7 +5057,7 @@ var require_open = __commonJS({
|
|
|
4965
5057
|
const isBundled = !__dirname || __dirname === "/";
|
|
4966
5058
|
let exeLocalXdgOpen = false;
|
|
4967
5059
|
try {
|
|
4968
|
-
await
|
|
5060
|
+
await fs24.access(localXdgOpenPath, fsConstants.X_OK);
|
|
4969
5061
|
exeLocalXdgOpen = true;
|
|
4970
5062
|
} catch {
|
|
4971
5063
|
}
|
|
@@ -4988,14 +5080,14 @@ var require_open = __commonJS({
|
|
|
4988
5080
|
}
|
|
4989
5081
|
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
|
4990
5082
|
if (options.wait) {
|
|
4991
|
-
return new Promise((
|
|
5083
|
+
return new Promise((resolve14, reject) => {
|
|
4992
5084
|
subprocess.once("error", reject);
|
|
4993
5085
|
subprocess.once("close", (exitCode) => {
|
|
4994
5086
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
4995
5087
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
4996
5088
|
return;
|
|
4997
5089
|
}
|
|
4998
|
-
|
|
5090
|
+
resolve14(subprocess);
|
|
4999
5091
|
});
|
|
5000
5092
|
});
|
|
5001
5093
|
}
|
|
@@ -5077,6 +5169,81 @@ var require_open = __commonJS({
|
|
|
5077
5169
|
}
|
|
5078
5170
|
});
|
|
5079
5171
|
|
|
5172
|
+
// src/lib/version.ts
|
|
5173
|
+
function pkgRoot() {
|
|
5174
|
+
const candidates = [
|
|
5175
|
+
path2.resolve(__dirname, ".."),
|
|
5176
|
+
// dist/ or src/lib/ → cli/
|
|
5177
|
+
path2.resolve(__dirname, "..", "..")
|
|
5178
|
+
// src/lib/ → cli/
|
|
5179
|
+
];
|
|
5180
|
+
for (const root of candidates) {
|
|
5181
|
+
if (fs2.existsSync(path2.join(root, "package.json")))
|
|
5182
|
+
return root;
|
|
5183
|
+
}
|
|
5184
|
+
return path2.resolve(__dirname, "..");
|
|
5185
|
+
}
|
|
5186
|
+
function getCliVersion() {
|
|
5187
|
+
try {
|
|
5188
|
+
const pkg = JSON.parse(fs2.readFileSync(path2.join(PKG_ROOT, "package.json"), "utf-8"));
|
|
5189
|
+
return pkg.version || "unknown";
|
|
5190
|
+
} catch {
|
|
5191
|
+
return "unknown";
|
|
5192
|
+
}
|
|
5193
|
+
}
|
|
5194
|
+
function getRulesVersion() {
|
|
5195
|
+
try {
|
|
5196
|
+
if (fs2.existsSync(RULES_MANIFEST)) {
|
|
5197
|
+
return JSON.parse(fs2.readFileSync(RULES_MANIFEST, "utf-8")).version || "unknown";
|
|
5198
|
+
}
|
|
5199
|
+
} catch {
|
|
5200
|
+
}
|
|
5201
|
+
return "unknown";
|
|
5202
|
+
}
|
|
5203
|
+
function getEngineLabel() {
|
|
5204
|
+
return `hyv v${getCliVersion()} / rules v${getRulesVersion()}`;
|
|
5205
|
+
}
|
|
5206
|
+
function compareSemver(a, b) {
|
|
5207
|
+
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
5208
|
+
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|
|
5209
|
+
const len = Math.max(pa.length, pb.length);
|
|
5210
|
+
for (let i = 0; i < len; i++) {
|
|
5211
|
+
const da = pa[i] ?? 0;
|
|
5212
|
+
const db = pb[i] ?? 0;
|
|
5213
|
+
if (da > db)
|
|
5214
|
+
return 1;
|
|
5215
|
+
if (da < db)
|
|
5216
|
+
return -1;
|
|
5217
|
+
}
|
|
5218
|
+
return 0;
|
|
5219
|
+
}
|
|
5220
|
+
function fetchLatestNpmVersion(timeoutMs = 8e3) {
|
|
5221
|
+
return new Promise((resolve14) => {
|
|
5222
|
+
(0, import_child_process.execFile)(
|
|
5223
|
+
"npm",
|
|
5224
|
+
["view", "@holdyourvoice/hyv", "version"],
|
|
5225
|
+
{ timeout: timeoutMs, encoding: "utf-8" },
|
|
5226
|
+
(err, stdout) => {
|
|
5227
|
+
if (err || !stdout?.trim())
|
|
5228
|
+
resolve14(null);
|
|
5229
|
+
else
|
|
5230
|
+
resolve14(stdout.trim());
|
|
5231
|
+
}
|
|
5232
|
+
);
|
|
5233
|
+
});
|
|
5234
|
+
}
|
|
5235
|
+
var fs2, path2, import_child_process, PKG_ROOT, RULES_MANIFEST;
|
|
5236
|
+
var init_version = __esm({
|
|
5237
|
+
"src/lib/version.ts"() {
|
|
5238
|
+
"use strict";
|
|
5239
|
+
fs2 = __toESM(require("fs"));
|
|
5240
|
+
path2 = __toESM(require("path"));
|
|
5241
|
+
import_child_process = require("child_process");
|
|
5242
|
+
PKG_ROOT = pkgRoot();
|
|
5243
|
+
RULES_MANIFEST = path2.join(PKG_ROOT, "assets", "detection-rules.json");
|
|
5244
|
+
}
|
|
5245
|
+
});
|
|
5246
|
+
|
|
5080
5247
|
// src/lib/auth.ts
|
|
5081
5248
|
var auth_exports = {};
|
|
5082
5249
|
__export(auth_exports, {
|
|
@@ -5084,10 +5251,14 @@ __export(auth_exports, {
|
|
|
5084
5251
|
authenticateWithLicense: () => authenticateWithLicense,
|
|
5085
5252
|
authenticatedRequest: () => authenticatedRequest,
|
|
5086
5253
|
checkSession: () => checkSession,
|
|
5254
|
+
getValidToken: () => getValidToken,
|
|
5087
5255
|
refreshToken: () => refreshToken
|
|
5088
5256
|
});
|
|
5257
|
+
function escapeHtml(value) {
|
|
5258
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
5259
|
+
}
|
|
5089
5260
|
function request(url, options = {}) {
|
|
5090
|
-
return new Promise((
|
|
5261
|
+
return new Promise((resolve14, reject) => {
|
|
5091
5262
|
const urlObj = new URL(url);
|
|
5092
5263
|
const isHttps = urlObj.protocol === "https:";
|
|
5093
5264
|
const client = isHttps ? https : http;
|
|
@@ -5098,7 +5269,7 @@ function request(url, options = {}) {
|
|
|
5098
5269
|
method: options.method || "GET",
|
|
5099
5270
|
headers: {
|
|
5100
5271
|
"Content-Type": "application/json",
|
|
5101
|
-
"User-Agent":
|
|
5272
|
+
"User-Agent": `hyv-cli/${getCliVersion()}`,
|
|
5102
5273
|
...options.headers
|
|
5103
5274
|
},
|
|
5104
5275
|
timeout: options.timeout || 3e4
|
|
@@ -5108,9 +5279,9 @@ function request(url, options = {}) {
|
|
|
5108
5279
|
res.on("data", (chunk) => data += chunk);
|
|
5109
5280
|
res.on("end", () => {
|
|
5110
5281
|
try {
|
|
5111
|
-
|
|
5282
|
+
resolve14({ status: res.statusCode || 0, data: JSON.parse(data) });
|
|
5112
5283
|
} catch {
|
|
5113
|
-
|
|
5284
|
+
resolve14({ status: res.statusCode || 0, data });
|
|
5114
5285
|
}
|
|
5115
5286
|
});
|
|
5116
5287
|
});
|
|
@@ -5125,8 +5296,25 @@ function request(url, options = {}) {
|
|
|
5125
5296
|
req.end();
|
|
5126
5297
|
});
|
|
5127
5298
|
}
|
|
5299
|
+
async function getValidToken() {
|
|
5300
|
+
const auth = readAuth();
|
|
5301
|
+
if (!auth?.token)
|
|
5302
|
+
return null;
|
|
5303
|
+
if (auth.expires_at) {
|
|
5304
|
+
const expires = new Date(auth.expires_at);
|
|
5305
|
+
const refreshBy = Date.now() + 5 * 60 * 1e3;
|
|
5306
|
+
if (expires.getTime() <= refreshBy) {
|
|
5307
|
+
const ok = await refreshToken(auth.token);
|
|
5308
|
+
if (ok)
|
|
5309
|
+
return getToken();
|
|
5310
|
+
if (expires.getTime() < Date.now())
|
|
5311
|
+
return null;
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5314
|
+
return auth.token;
|
|
5315
|
+
}
|
|
5128
5316
|
async function authenticatedRequest(url, options = {}) {
|
|
5129
|
-
const token =
|
|
5317
|
+
const token = await getValidToken();
|
|
5130
5318
|
if (!token) {
|
|
5131
5319
|
throw new Error("Not authenticated. Run `hyv init` first.");
|
|
5132
5320
|
}
|
|
@@ -5155,9 +5343,9 @@ async function authenticateWithLicense(licenseKey) {
|
|
|
5155
5343
|
}
|
|
5156
5344
|
async function authenticateWithBrowser() {
|
|
5157
5345
|
const server = http.createServer();
|
|
5158
|
-
const port = await new Promise((
|
|
5346
|
+
const port = await new Promise((resolve14) => {
|
|
5159
5347
|
server.listen(0, "127.0.0.1", () => {
|
|
5160
|
-
|
|
5348
|
+
resolve14(server.address().port);
|
|
5161
5349
|
});
|
|
5162
5350
|
});
|
|
5163
5351
|
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
@@ -5169,10 +5357,14 @@ async function authenticateWithBrowser() {
|
|
|
5169
5357
|
server.close();
|
|
5170
5358
|
throw new Error("Failed to start authentication flow");
|
|
5171
5359
|
}
|
|
5172
|
-
const { auth_url } = response.data;
|
|
5360
|
+
const { auth_url, state: expectedState } = response.data;
|
|
5361
|
+
if (!expectedState) {
|
|
5362
|
+
server.close();
|
|
5363
|
+
throw new Error("Authentication server did not return OAuth state");
|
|
5364
|
+
}
|
|
5173
5365
|
console.log(import_chalk.default.cyan("\nOpening browser for authentication..."));
|
|
5174
|
-
await (0, import_open.default)(auth_url);
|
|
5175
|
-
const authData = await new Promise((
|
|
5366
|
+
await (0, import_open.default)(assertSafeOpenUrl(auth_url));
|
|
5367
|
+
const authData = await new Promise((resolve14, reject) => {
|
|
5176
5368
|
const timeout = setTimeout(() => {
|
|
5177
5369
|
server.close();
|
|
5178
5370
|
reject(new Error("Authentication timeout. Please try again."));
|
|
@@ -5190,6 +5382,14 @@ async function authenticateWithBrowser() {
|
|
|
5190
5382
|
reject(new Error("Invalid callback parameters"));
|
|
5191
5383
|
return;
|
|
5192
5384
|
}
|
|
5385
|
+
if (state !== expectedState) {
|
|
5386
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
5387
|
+
res.end("<h1>Authentication failed</h1><p>Invalid OAuth state.</p>");
|
|
5388
|
+
clearTimeout(timeout);
|
|
5389
|
+
server.close();
|
|
5390
|
+
reject(new Error("OAuth state mismatch \u2014 possible CSRF attempt"));
|
|
5391
|
+
return;
|
|
5392
|
+
}
|
|
5193
5393
|
try {
|
|
5194
5394
|
const callbackResponse = await request(`${API_BASE}/cli/auth/callback`, {
|
|
5195
5395
|
method: "POST",
|
|
@@ -5210,10 +5410,10 @@ async function authenticateWithBrowser() {
|
|
|
5210
5410
|
`);
|
|
5211
5411
|
clearTimeout(timeout);
|
|
5212
5412
|
server.close();
|
|
5213
|
-
|
|
5413
|
+
resolve14(data);
|
|
5214
5414
|
} catch (error) {
|
|
5215
5415
|
res.writeHead(500, { "Content-Type": "text/html" });
|
|
5216
|
-
res.end(`<h1>Authentication failed</h1><p>${error.message}</p>`);
|
|
5416
|
+
res.end(`<h1>Authentication failed</h1><p>${escapeHtml(error.message)}</p>`);
|
|
5217
5417
|
clearTimeout(timeout);
|
|
5218
5418
|
server.close();
|
|
5219
5419
|
reject(error);
|
|
@@ -5227,8 +5427,8 @@ async function authenticateWithBrowser() {
|
|
|
5227
5427
|
writeAuth(authData);
|
|
5228
5428
|
return authData;
|
|
5229
5429
|
}
|
|
5230
|
-
async function refreshToken() {
|
|
5231
|
-
const token =
|
|
5430
|
+
async function refreshToken(tokenOverride) {
|
|
5431
|
+
const token = tokenOverride || readAuth()?.token;
|
|
5232
5432
|
if (!token)
|
|
5233
5433
|
return false;
|
|
5234
5434
|
try {
|
|
@@ -5254,7 +5454,7 @@ async function refreshToken() {
|
|
|
5254
5454
|
}
|
|
5255
5455
|
}
|
|
5256
5456
|
async function checkSession() {
|
|
5257
|
-
const token =
|
|
5457
|
+
const token = await getValidToken();
|
|
5258
5458
|
if (!token)
|
|
5259
5459
|
return { valid: false };
|
|
5260
5460
|
try {
|
|
@@ -5280,6 +5480,7 @@ var init_auth = __esm({
|
|
|
5280
5480
|
import_chalk = __toESM(require_source());
|
|
5281
5481
|
import_open = __toESM(require_open());
|
|
5282
5482
|
init_config();
|
|
5483
|
+
init_version();
|
|
5283
5484
|
}
|
|
5284
5485
|
});
|
|
5285
5486
|
|
|
@@ -5413,25 +5614,23 @@ function recordEvent(event, meta) {
|
|
|
5413
5614
|
if (!isTelemetryEnabled())
|
|
5414
5615
|
return;
|
|
5415
5616
|
try {
|
|
5416
|
-
|
|
5417
|
-
fs2.mkdirSync(TELEMETRY_DIR, { recursive: true });
|
|
5418
|
-
fs2.appendFileSync(TELEMETRY_FILE, JSON.stringify({
|
|
5617
|
+
appendSecureLine(TELEMETRY_FILE, JSON.stringify({
|
|
5419
5618
|
event,
|
|
5420
5619
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5421
5620
|
...meta
|
|
5422
|
-
}) + "\n");
|
|
5621
|
+
}) + "\n", TELEMETRY_DIR);
|
|
5423
5622
|
} catch {
|
|
5424
5623
|
}
|
|
5425
5624
|
}
|
|
5426
|
-
var
|
|
5625
|
+
var path3, os2, TELEMETRY_DIR, TELEMETRY_FILE;
|
|
5427
5626
|
var init_telemetry = __esm({
|
|
5428
5627
|
"src/lib/telemetry.ts"() {
|
|
5429
5628
|
"use strict";
|
|
5430
|
-
|
|
5431
|
-
path2 = __toESM(require("path"));
|
|
5629
|
+
path3 = __toESM(require("path"));
|
|
5432
5630
|
os2 = __toESM(require("os"));
|
|
5433
|
-
|
|
5434
|
-
|
|
5631
|
+
init_config();
|
|
5632
|
+
TELEMETRY_DIR = path3.join(os2.homedir(), ".hyv", "telemetry");
|
|
5633
|
+
TELEMETRY_FILE = path3.join(TELEMETRY_DIR, "events.jsonl");
|
|
5435
5634
|
}
|
|
5436
5635
|
});
|
|
5437
5636
|
|
|
@@ -5443,7 +5642,7 @@ __export(api_exports, {
|
|
|
5443
5642
|
requireSubscription: () => requireSubscription
|
|
5444
5643
|
});
|
|
5445
5644
|
async function request2(method, path23, body) {
|
|
5446
|
-
const token =
|
|
5645
|
+
const token = await getValidToken();
|
|
5447
5646
|
if (!token)
|
|
5448
5647
|
throw new Error("you're not signed in yet. run: hyv init");
|
|
5449
5648
|
const url = `${API_BASE}${path23}`;
|
|
@@ -5485,6 +5684,7 @@ var init_api = __esm({
|
|
|
5485
5684
|
"src/lib/api.ts"() {
|
|
5486
5685
|
"use strict";
|
|
5487
5686
|
init_config();
|
|
5687
|
+
init_auth();
|
|
5488
5688
|
}
|
|
5489
5689
|
});
|
|
5490
5690
|
|
|
@@ -5679,7 +5879,7 @@ async function refreshInBackground(slug) {
|
|
|
5679
5879
|
}
|
|
5680
5880
|
}
|
|
5681
5881
|
function getDiskCachePath(slug) {
|
|
5682
|
-
return
|
|
5882
|
+
return path4.join(DISK_CACHE_DIR, `${slug.replace(/[^a-z0-9-]/gi, "_")}.json`);
|
|
5683
5883
|
}
|
|
5684
5884
|
function loadFromDiskCache(slug) {
|
|
5685
5885
|
try {
|
|
@@ -5718,18 +5918,18 @@ function buildMinimalProfile(slug, body) {
|
|
|
5718
5918
|
cadence: {}
|
|
5719
5919
|
};
|
|
5720
5920
|
}
|
|
5721
|
-
var fs3,
|
|
5921
|
+
var fs3, path4, os3, CACHE_TTL, memoryCache, DISK_CACHE_DIR;
|
|
5722
5922
|
var init_profile = __esm({
|
|
5723
5923
|
"src/lib/profile.ts"() {
|
|
5724
5924
|
"use strict";
|
|
5725
5925
|
init_api();
|
|
5726
5926
|
init_config();
|
|
5727
5927
|
fs3 = __toESM(require("fs"));
|
|
5728
|
-
|
|
5928
|
+
path4 = __toESM(require("path"));
|
|
5729
5929
|
os3 = __toESM(require("os"));
|
|
5730
5930
|
CACHE_TTL = 5 * 60 * 1e3;
|
|
5731
5931
|
memoryCache = /* @__PURE__ */ new Map();
|
|
5732
|
-
DISK_CACHE_DIR =
|
|
5932
|
+
DISK_CACHE_DIR = path4.join(os3.homedir(), ".hyv", "cache", "profiles");
|
|
5733
5933
|
}
|
|
5734
5934
|
});
|
|
5735
5935
|
|
|
@@ -5744,7 +5944,7 @@ __export(local_profile_exports, {
|
|
|
5744
5944
|
loadProfileFromDiskCache: () => loadProfileFromDiskCache
|
|
5745
5945
|
});
|
|
5746
5946
|
function cachePathForSlug(slug) {
|
|
5747
|
-
return
|
|
5947
|
+
return path5.join(DISK_CACHE_DIR2, `${slug.replace(/[^a-z0-9-]/gi, "_")}.json`);
|
|
5748
5948
|
}
|
|
5749
5949
|
function loadProfileFromDiskCache(slug) {
|
|
5750
5950
|
try {
|
|
@@ -5844,17 +6044,17 @@ function hasRichProfile(profile) {
|
|
|
5844
6044
|
return false;
|
|
5845
6045
|
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;
|
|
5846
6046
|
}
|
|
5847
|
-
var fs4,
|
|
6047
|
+
var fs4, path5, os4, DISK_CACHE_DIR2;
|
|
5848
6048
|
var init_local_profile = __esm({
|
|
5849
6049
|
"src/lib/local-profile.ts"() {
|
|
5850
6050
|
"use strict";
|
|
5851
6051
|
fs4 = __toESM(require("fs"));
|
|
5852
|
-
|
|
6052
|
+
path5 = __toESM(require("path"));
|
|
5853
6053
|
os4 = __toESM(require("os"));
|
|
5854
6054
|
init_config();
|
|
5855
6055
|
init_config();
|
|
5856
6056
|
init_profile();
|
|
5857
|
-
DISK_CACHE_DIR2 =
|
|
6057
|
+
DISK_CACHE_DIR2 = path5.join(os4.homedir(), ".hyv", "cache", "profiles");
|
|
5858
6058
|
}
|
|
5859
6059
|
});
|
|
5860
6060
|
|
|
@@ -5946,19 +6146,19 @@ var init_profile_parse = __esm({
|
|
|
5946
6146
|
function loadSupplementalPatterns() {
|
|
5947
6147
|
const p = path8.join(CACHE_DIR, "supplemental-rules.json");
|
|
5948
6148
|
try {
|
|
5949
|
-
if (!
|
|
6149
|
+
if (!fs7.existsSync(p))
|
|
5950
6150
|
return [];
|
|
5951
|
-
const data = JSON.parse(
|
|
6151
|
+
const data = JSON.parse(fs7.readFileSync(p, "utf-8"));
|
|
5952
6152
|
return Array.isArray(data.patterns) ? data.patterns : [];
|
|
5953
6153
|
} catch {
|
|
5954
6154
|
return [];
|
|
5955
6155
|
}
|
|
5956
6156
|
}
|
|
5957
|
-
var
|
|
6157
|
+
var fs7, path8, BUNDLED_MANIFEST;
|
|
5958
6158
|
var init_rules_loader = __esm({
|
|
5959
6159
|
"src/lib/rules-loader.ts"() {
|
|
5960
6160
|
"use strict";
|
|
5961
|
-
|
|
6161
|
+
fs7 = __toESM(require("fs"));
|
|
5962
6162
|
path8 = __toESM(require("path"));
|
|
5963
6163
|
init_config();
|
|
5964
6164
|
BUNDLED_MANIFEST = path8.resolve(__dirname, "..", "..", "assets", "detection-rules.json");
|
|
@@ -7046,26 +7246,26 @@ function runPipeline(text, profile, applyFixes = false) {
|
|
|
7046
7246
|
};
|
|
7047
7247
|
}
|
|
7048
7248
|
function readText(source) {
|
|
7049
|
-
const
|
|
7249
|
+
const fs24 = require("fs");
|
|
7050
7250
|
const path23 = require("path");
|
|
7051
7251
|
if (source === "-") {
|
|
7052
7252
|
if (process.stdin.isTTY) {
|
|
7053
7253
|
console.error("No input provided. Pipe content or specify a file.");
|
|
7054
7254
|
process.exit(1);
|
|
7055
7255
|
}
|
|
7056
|
-
return { text:
|
|
7256
|
+
return { text: fs24.readFileSync(0, "utf-8"), path: "stdin" };
|
|
7057
7257
|
}
|
|
7058
7258
|
const resolved = path23.resolve(source);
|
|
7059
|
-
if (!
|
|
7259
|
+
if (!fs24.existsSync(resolved)) {
|
|
7060
7260
|
console.error(`File not found: ${resolved}`);
|
|
7061
7261
|
process.exit(1);
|
|
7062
7262
|
}
|
|
7063
|
-
const stat =
|
|
7263
|
+
const stat = fs24.statSync(resolved);
|
|
7064
7264
|
if (stat.isDirectory()) {
|
|
7065
7265
|
console.error(`${resolved} is a directory, not a file.`);
|
|
7066
7266
|
process.exit(1);
|
|
7067
7267
|
}
|
|
7068
|
-
return { text:
|
|
7268
|
+
return { text: fs24.readFileSync(resolved, "utf-8"), path: resolved };
|
|
7069
7269
|
}
|
|
7070
7270
|
var init_pipeline = __esm({
|
|
7071
7271
|
"src/lib/pipeline.ts"() {
|
|
@@ -8073,7 +8273,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
|
|
|
8073
8273
|
g.minimatch.escape = vi.escape;
|
|
8074
8274
|
g.minimatch.unescape = Ei.unescape;
|
|
8075
8275
|
});
|
|
8076
|
-
var
|
|
8276
|
+
var fs24 = R((Wt) => {
|
|
8077
8277
|
"use strict";
|
|
8078
8278
|
Object.defineProperty(Wt, "__esModule", { value: true });
|
|
8079
8279
|
Wt.LRUCache = void 0;
|
|
@@ -9042,7 +9242,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
|
|
|
9042
9242
|
};
|
|
9043
9243
|
Object.defineProperty(_, "__esModule", { value: true });
|
|
9044
9244
|
_.PathScurry = _.Path = _.PathScurryDarwin = _.PathScurryPosix = _.PathScurryWin32 = _.PathScurryBase = _.PathPosix = _.PathWin32 = _.PathBase = _.ChildrenCache = _.ResolveCache = void 0;
|
|
9045
|
-
var Qt =
|
|
9245
|
+
var Qt = fs24(), Yt = require("node:path"), yr = require("node:url"), pt = require("fs"), Sr = br(require("node:fs")), vr = pt.realpathSync.native, Ht = require("node:fs/promises"), bs = Oe(), mt = { lstatSync: pt.lstatSync, readdir: pt.readdir, readdirSync: pt.readdirSync, readlinkSync: pt.readlinkSync, realpathSync: vr, promises: { lstat: Ht.lstat, readdir: Ht.readdir, readlink: Ht.readlink, realpath: Ht.realpath } }, _s = (n) => !n || n === mt || n === Sr ? mt : { ...mt, ...n, promises: { ...mt.promises, ...n.promises || {} } }, Os = /^\\\\\?\\([a-z]:)\\?$/i, Er = (n) => n.replace(/\//g, "\\").replace(Os, "$1\\"), _r = /[\\\/]/, N = 0, xs = 1, Ts = 2, G = 4, Cs = 6, Rs = 8, Q = 10, As = 12, j = 15, dt = ~j, xe = 16, ys = 32, gt = 64, W = 128, Vt = 256, Xt = 512, Ss = gt | W | Xt, Or = 1023, Te = (n) => n.isFile() ? Rs : n.isDirectory() ? G : n.isSymbolicLink() ? Q : n.isCharacterDevice() ? Ts : n.isBlockDevice() ? Cs : n.isSocket() ? As : n.isFIFO() ? xs : N, vs = new Qt.LRUCache({ max: 2 ** 12 }), wt = (n) => {
|
|
9046
9246
|
let t = vs.get(n);
|
|
9047
9247
|
if (t)
|
|
9048
9248
|
return t;
|
|
@@ -10733,79 +10933,11 @@ init_config();
|
|
|
10733
10933
|
init_auth();
|
|
10734
10934
|
init_access();
|
|
10735
10935
|
init_local_profile();
|
|
10736
|
-
|
|
10737
|
-
// src/lib/version.ts
|
|
10738
|
-
var fs5 = __toESM(require("fs"));
|
|
10739
|
-
var path5 = __toESM(require("path"));
|
|
10740
|
-
var import_child_process = require("child_process");
|
|
10741
|
-
function pkgRoot() {
|
|
10742
|
-
const candidates = [
|
|
10743
|
-
path5.resolve(__dirname, ".."),
|
|
10744
|
-
// dist/ or src/lib/ → cli/
|
|
10745
|
-
path5.resolve(__dirname, "..", "..")
|
|
10746
|
-
// src/lib/ → cli/
|
|
10747
|
-
];
|
|
10748
|
-
for (const root of candidates) {
|
|
10749
|
-
if (fs5.existsSync(path5.join(root, "package.json")))
|
|
10750
|
-
return root;
|
|
10751
|
-
}
|
|
10752
|
-
return path5.resolve(__dirname, "..");
|
|
10753
|
-
}
|
|
10754
|
-
var PKG_ROOT = pkgRoot();
|
|
10755
|
-
var RULES_MANIFEST = path5.join(PKG_ROOT, "assets", "detection-rules.json");
|
|
10756
|
-
function getCliVersion() {
|
|
10757
|
-
try {
|
|
10758
|
-
const pkg = JSON.parse(fs5.readFileSync(path5.join(PKG_ROOT, "package.json"), "utf-8"));
|
|
10759
|
-
return pkg.version || "unknown";
|
|
10760
|
-
} catch {
|
|
10761
|
-
return "unknown";
|
|
10762
|
-
}
|
|
10763
|
-
}
|
|
10764
|
-
function getRulesVersion() {
|
|
10765
|
-
try {
|
|
10766
|
-
if (fs5.existsSync(RULES_MANIFEST)) {
|
|
10767
|
-
return JSON.parse(fs5.readFileSync(RULES_MANIFEST, "utf-8")).version || "unknown";
|
|
10768
|
-
}
|
|
10769
|
-
} catch {
|
|
10770
|
-
}
|
|
10771
|
-
return "unknown";
|
|
10772
|
-
}
|
|
10773
|
-
function getEngineLabel() {
|
|
10774
|
-
return `hyv v${getCliVersion()} / rules v${getRulesVersion()}`;
|
|
10775
|
-
}
|
|
10776
|
-
function compareSemver(a, b) {
|
|
10777
|
-
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
10778
|
-
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|
|
10779
|
-
const len = Math.max(pa.length, pb.length);
|
|
10780
|
-
for (let i = 0; i < len; i++) {
|
|
10781
|
-
const da = pa[i] ?? 0;
|
|
10782
|
-
const db = pb[i] ?? 0;
|
|
10783
|
-
if (da > db)
|
|
10784
|
-
return 1;
|
|
10785
|
-
if (da < db)
|
|
10786
|
-
return -1;
|
|
10787
|
-
}
|
|
10788
|
-
return 0;
|
|
10789
|
-
}
|
|
10790
|
-
function fetchLatestNpmVersion(timeoutMs = 8e3) {
|
|
10791
|
-
return new Promise((resolve12) => {
|
|
10792
|
-
(0, import_child_process.execFile)(
|
|
10793
|
-
"npm",
|
|
10794
|
-
["view", "@holdyourvoice/hyv", "version"],
|
|
10795
|
-
{ timeout: timeoutMs, encoding: "utf-8" },
|
|
10796
|
-
(err, stdout) => {
|
|
10797
|
-
if (err || !stdout?.trim())
|
|
10798
|
-
resolve12(null);
|
|
10799
|
-
else
|
|
10800
|
-
resolve12(stdout.trim());
|
|
10801
|
-
}
|
|
10802
|
-
);
|
|
10803
|
-
});
|
|
10804
|
-
}
|
|
10936
|
+
init_version();
|
|
10805
10937
|
|
|
10806
10938
|
// src/lib/queue-sync.ts
|
|
10807
10939
|
var import_chalk6 = __toESM(require_source());
|
|
10808
|
-
var
|
|
10940
|
+
var fs5 = __toESM(require("fs"));
|
|
10809
10941
|
var path6 = __toESM(require("path"));
|
|
10810
10942
|
init_config();
|
|
10811
10943
|
init_auth();
|
|
@@ -10815,34 +10947,34 @@ async function flushQueuedSignals() {
|
|
|
10815
10947
|
return { sent: 0, failed: 0 };
|
|
10816
10948
|
let sent = 0;
|
|
10817
10949
|
let failed = 0;
|
|
10818
|
-
if (!
|
|
10950
|
+
if (!fs5.existsSync(QUEUE_DIR))
|
|
10819
10951
|
return { sent: 0, failed: 0 };
|
|
10820
|
-
const files =
|
|
10952
|
+
const files = fs5.readdirSync(QUEUE_DIR).filter((f) => f.endsWith(".json"));
|
|
10821
10953
|
for (const file of files) {
|
|
10822
10954
|
const filePath = path6.join(QUEUE_DIR, file);
|
|
10823
10955
|
try {
|
|
10824
|
-
const signal = JSON.parse(
|
|
10956
|
+
const signal = JSON.parse(fs5.readFileSync(filePath, "utf-8"));
|
|
10825
10957
|
let ok = false;
|
|
10826
10958
|
if (signal.type === "reinforce") {
|
|
10827
|
-
const res = await authenticatedRequest("
|
|
10959
|
+
const res = await authenticatedRequest(cliApiUrl("/cli/learning/reinforce"), {
|
|
10828
10960
|
method: "POST",
|
|
10829
10961
|
body: {
|
|
10830
10962
|
profile_id: signal.profile,
|
|
10831
|
-
original_text: signal.report?.
|
|
10832
|
-
accepted_text: signal.report?.
|
|
10963
|
+
original_text: signal.original_text ?? signal.report?.original_text,
|
|
10964
|
+
accepted_text: signal.accepted_text ?? signal.report?.accepted_text,
|
|
10833
10965
|
signal_report: signal.report
|
|
10834
10966
|
}
|
|
10835
10967
|
});
|
|
10836
10968
|
ok = res.status === 200;
|
|
10837
10969
|
} else if (signal.type === "add_instruction") {
|
|
10838
|
-
const res = await authenticatedRequest("
|
|
10970
|
+
const res = await authenticatedRequest(cliApiUrl("/cli/learning/add"), {
|
|
10839
10971
|
method: "POST",
|
|
10840
10972
|
body: { profile_id: signal.profile, instruction: signal.instruction }
|
|
10841
10973
|
});
|
|
10842
10974
|
ok = res.status === 200;
|
|
10843
10975
|
}
|
|
10844
10976
|
if (ok) {
|
|
10845
|
-
|
|
10977
|
+
fs5.unlinkSync(filePath);
|
|
10846
10978
|
sent++;
|
|
10847
10979
|
} else {
|
|
10848
10980
|
failed++;
|
|
@@ -10971,7 +11103,7 @@ async function printEvolutionSummary(slug) {
|
|
|
10971
11103
|
return;
|
|
10972
11104
|
try {
|
|
10973
11105
|
const res = await authenticatedRequest(
|
|
10974
|
-
|
|
11106
|
+
cliApiUrl(`/cli/profiles/${encodeURIComponent(slug)}/evolution`),
|
|
10975
11107
|
{ method: "GET" }
|
|
10976
11108
|
);
|
|
10977
11109
|
if (res.status !== 200 || !res.data)
|
|
@@ -10999,7 +11131,7 @@ init_config();
|
|
|
10999
11131
|
init_auth();
|
|
11000
11132
|
init_access();
|
|
11001
11133
|
init_profile();
|
|
11002
|
-
var
|
|
11134
|
+
var fs6 = __toESM(require("fs"));
|
|
11003
11135
|
var path7 = __toESM(require("path"));
|
|
11004
11136
|
function registerSyncCommand(program3) {
|
|
11005
11137
|
program3.command("sync").description("Sync profiles and rules from server").option("--force", "Force re-download even if cache is fresh").action(async (options) => {
|
|
@@ -11007,7 +11139,7 @@ function registerSyncCommand(program3) {
|
|
|
11007
11139
|
await requirePaidFeature("profiles");
|
|
11008
11140
|
console.log(import_chalk8.default.cyan("Syncing profiles and rules..."));
|
|
11009
11141
|
const response = await authenticatedRequest(
|
|
11010
|
-
"
|
|
11142
|
+
cliApiUrl("/cli/sync"),
|
|
11011
11143
|
{ method: "GET" }
|
|
11012
11144
|
);
|
|
11013
11145
|
if (response.status !== 200) {
|
|
@@ -11023,12 +11155,12 @@ function registerSyncCommand(program3) {
|
|
|
11023
11155
|
profileCount++;
|
|
11024
11156
|
}
|
|
11025
11157
|
const rulesPath = path7.join(CACHE_DIR, "rules.md");
|
|
11026
|
-
|
|
11158
|
+
fs6.writeFileSync(rulesPath, data.rules, { mode: 384 });
|
|
11027
11159
|
const promptPath = path7.join(CACHE_DIR, "prompt-template.md");
|
|
11028
|
-
|
|
11160
|
+
fs6.writeFileSync(promptPath, data.prompt_template, { mode: 384 });
|
|
11029
11161
|
if (data.detection_rules) {
|
|
11030
11162
|
const rulesJson = path7.join(CACHE_DIR, "detection-rules.json");
|
|
11031
|
-
|
|
11163
|
+
fs6.writeFileSync(rulesJson, JSON.stringify(data.detection_rules, null, 2), { mode: 384 });
|
|
11032
11164
|
}
|
|
11033
11165
|
for (const profile of data.profiles) {
|
|
11034
11166
|
try {
|
|
@@ -11044,7 +11176,7 @@ function registerSyncCommand(program3) {
|
|
|
11044
11176
|
console.log(import_chalk8.default.yellow(` ! ${queueResult.failed} queued signal(s) could not send`));
|
|
11045
11177
|
}
|
|
11046
11178
|
const metaPath = path7.join(CACHE_DIR, "sync-meta.json");
|
|
11047
|
-
|
|
11179
|
+
fs6.writeFileSync(metaPath, JSON.stringify({
|
|
11048
11180
|
synced_at: data.synced_at,
|
|
11049
11181
|
profile_count: profileCount,
|
|
11050
11182
|
plan: data.plan
|
|
@@ -11120,7 +11252,7 @@ async function showProfileHistory(slug) {
|
|
|
11120
11252
|
return;
|
|
11121
11253
|
}
|
|
11122
11254
|
try {
|
|
11123
|
-
const res = await authenticatedRequest2(
|
|
11255
|
+
const res = await authenticatedRequest2(cliApiUrl(`/cli/profiles/${encodeURIComponent(slug)}/evolution`), { method: "GET" });
|
|
11124
11256
|
if (res.status !== 200) {
|
|
11125
11257
|
console.log(import_chalk8.default.red("Could not load profile history."));
|
|
11126
11258
|
return;
|
|
@@ -11149,12 +11281,12 @@ Profile evolution: ${slug}
|
|
|
11149
11281
|
|
|
11150
11282
|
// src/commands/rewrite.ts
|
|
11151
11283
|
var import_chalk9 = __toESM(require_source());
|
|
11152
|
-
var
|
|
11284
|
+
var fs9 = __toESM(require("fs"));
|
|
11153
11285
|
var path10 = __toESM(require("path"));
|
|
11154
11286
|
init_pipeline();
|
|
11155
11287
|
|
|
11156
11288
|
// src/lib/prompt.ts
|
|
11157
|
-
var
|
|
11289
|
+
var fs8 = __toESM(require("fs"));
|
|
11158
11290
|
var path9 = __toESM(require("path"));
|
|
11159
11291
|
init_config();
|
|
11160
11292
|
init_signals();
|
|
@@ -11162,8 +11294,8 @@ init_profile_parse();
|
|
|
11162
11294
|
function loadPromptTemplate() {
|
|
11163
11295
|
const templatePath = path9.join(CACHE_DIR, "prompt-template.md");
|
|
11164
11296
|
try {
|
|
11165
|
-
if (
|
|
11166
|
-
return
|
|
11297
|
+
if (fs8.existsSync(templatePath)) {
|
|
11298
|
+
return fs8.readFileSync(templatePath, "utf-8");
|
|
11167
11299
|
}
|
|
11168
11300
|
} catch {
|
|
11169
11301
|
}
|
|
@@ -11229,10 +11361,10 @@ function loadProfile(name) {
|
|
|
11229
11361
|
}
|
|
11230
11362
|
}
|
|
11231
11363
|
try {
|
|
11232
|
-
if (!
|
|
11364
|
+
if (!fs8.existsSync(PROFILES_DIR)) {
|
|
11233
11365
|
return null;
|
|
11234
11366
|
}
|
|
11235
|
-
const profiles =
|
|
11367
|
+
const profiles = fs8.readdirSync(PROFILES_DIR).filter((f) => f.endsWith(".md"));
|
|
11236
11368
|
if (profiles.length > 0) {
|
|
11237
11369
|
const defaultProfile = profiles[0].replace(".md", "");
|
|
11238
11370
|
const content = readCachedProfile(defaultProfile);
|
|
@@ -11364,7 +11496,7 @@ Draft: ${draftPath}`));
|
|
|
11364
11496
|
}
|
|
11365
11497
|
if (options.output) {
|
|
11366
11498
|
const outputPath = path10.resolve(options.output);
|
|
11367
|
-
|
|
11499
|
+
fs9.writeFileSync(outputPath, promptResult.prompt);
|
|
11368
11500
|
console.log(import_chalk9.default.green(`
|
|
11369
11501
|
\u2713 Prompt written to ${outputPath}`));
|
|
11370
11502
|
} else {
|
|
@@ -11384,7 +11516,7 @@ Draft: ${draftPath}`));
|
|
|
11384
11516
|
|
|
11385
11517
|
// src/commands/learning.ts
|
|
11386
11518
|
var import_chalk10 = __toESM(require_source());
|
|
11387
|
-
var
|
|
11519
|
+
var fs10 = __toESM(require("fs"));
|
|
11388
11520
|
var path11 = __toESM(require("path"));
|
|
11389
11521
|
|
|
11390
11522
|
// src/lib/patterns.ts
|
|
@@ -11889,16 +12021,16 @@ function registerLearningCommands(program3) {
|
|
|
11889
12021
|
}
|
|
11890
12022
|
origPath = path11.resolve(original);
|
|
11891
12023
|
editPath = path11.resolve(edited);
|
|
11892
|
-
if (!
|
|
12024
|
+
if (!fs10.existsSync(origPath)) {
|
|
11893
12025
|
console.error(import_chalk10.default.red(`Original file not found: ${origPath}`));
|
|
11894
12026
|
process.exit(1);
|
|
11895
12027
|
}
|
|
11896
|
-
if (!
|
|
12028
|
+
if (!fs10.existsSync(editPath)) {
|
|
11897
12029
|
console.error(import_chalk10.default.red(`Edited file not found: ${editPath}`));
|
|
11898
12030
|
process.exit(1);
|
|
11899
12031
|
}
|
|
11900
|
-
origText =
|
|
11901
|
-
editText =
|
|
12032
|
+
origText = fs10.readFileSync(origPath, "utf-8");
|
|
12033
|
+
editText = fs10.readFileSync(editPath, "utf-8");
|
|
11902
12034
|
saveLastEditSession({
|
|
11903
12035
|
original_path: origPath,
|
|
11904
12036
|
edited_path: editPath,
|
|
@@ -11914,6 +12046,8 @@ function registerLearningCommands(program3) {
|
|
|
11914
12046
|
queueSignal({
|
|
11915
12047
|
type: "reinforce",
|
|
11916
12048
|
profile: options.profile,
|
|
12049
|
+
original_text: origText,
|
|
12050
|
+
accepted_text: editText,
|
|
11917
12051
|
report,
|
|
11918
12052
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11919
12053
|
});
|
|
@@ -11927,6 +12061,8 @@ ${err.message}`));
|
|
|
11927
12061
|
queueSignal({
|
|
11928
12062
|
type: "reinforce",
|
|
11929
12063
|
profile: options.profile,
|
|
12064
|
+
original_text: origText,
|
|
12065
|
+
accepted_text: editText,
|
|
11930
12066
|
report,
|
|
11931
12067
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11932
12068
|
});
|
|
@@ -11939,6 +12075,8 @@ ${err.message}`));
|
|
|
11939
12075
|
queueSignal({
|
|
11940
12076
|
type: "reinforce",
|
|
11941
12077
|
profile: options.profile,
|
|
12078
|
+
original_text: origText,
|
|
12079
|
+
accepted_text: editText,
|
|
11942
12080
|
report,
|
|
11943
12081
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11944
12082
|
});
|
|
@@ -11946,7 +12084,7 @@ ${err.message}`));
|
|
|
11946
12084
|
}
|
|
11947
12085
|
console.log(import_chalk10.default.cyan("\nSending to server..."));
|
|
11948
12086
|
const response = await authenticatedRequest(
|
|
11949
|
-
"
|
|
12087
|
+
cliApiUrl("/cli/learning/reinforce"),
|
|
11950
12088
|
{
|
|
11951
12089
|
method: "POST",
|
|
11952
12090
|
body: {
|
|
@@ -11968,6 +12106,8 @@ ${err.message}`));
|
|
|
11968
12106
|
queueSignal({
|
|
11969
12107
|
type: "reinforce",
|
|
11970
12108
|
profile: options.profile,
|
|
12109
|
+
original_text: origText,
|
|
12110
|
+
accepted_text: editText,
|
|
11971
12111
|
report,
|
|
11972
12112
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11973
12113
|
});
|
|
@@ -11994,7 +12134,7 @@ ${err.message}`));
|
|
|
11994
12134
|
}
|
|
11995
12135
|
console.log(import_chalk10.default.cyan("Adding instruction..."));
|
|
11996
12136
|
const response = await authenticatedRequest(
|
|
11997
|
-
"
|
|
12137
|
+
cliApiUrl("/cli/learning/add"),
|
|
11998
12138
|
{
|
|
11999
12139
|
method: "POST",
|
|
12000
12140
|
body: {
|
|
@@ -12057,7 +12197,7 @@ function printProfileImpact(impact, data) {
|
|
|
12057
12197
|
|
|
12058
12198
|
// src/commands/onboarding.ts
|
|
12059
12199
|
var import_chalk11 = __toESM(require_source());
|
|
12060
|
-
var
|
|
12200
|
+
var fs11 = __toESM(require("fs"));
|
|
12061
12201
|
var path12 = __toESM(require("path"));
|
|
12062
12202
|
init_config();
|
|
12063
12203
|
init_auth();
|
|
@@ -12133,6 +12273,7 @@ function extractStats(samples) {
|
|
|
12133
12273
|
function registerOnboardingCommands(program3) {
|
|
12134
12274
|
program3.command("new").description("Create a new voice profile").argument("<name>", "Profile name").option("--from-samples <dir>", "Create from writing samples").option("--from-llm", "Generate extraction prompt for LLM").action(async (name, options) => {
|
|
12135
12275
|
try {
|
|
12276
|
+
assertSafeProfileName(name);
|
|
12136
12277
|
const token = getToken();
|
|
12137
12278
|
if (options.fromSamples) {
|
|
12138
12279
|
await createFromSamples(name, options.fromSamples, token);
|
|
@@ -12147,6 +12288,7 @@ Error: ${error.message}`));
|
|
|
12147
12288
|
process.exit(1);
|
|
12148
12289
|
}
|
|
12149
12290
|
});
|
|
12291
|
+
registerImportCommand(program3);
|
|
12150
12292
|
}
|
|
12151
12293
|
async function flashcardOnboarding(name, token) {
|
|
12152
12294
|
const { printWelcome: printWelcome2 } = await Promise.resolve().then(() => (init_welcome(), welcome_exports));
|
|
@@ -12170,7 +12312,7 @@ Industry: ${industry}
|
|
|
12170
12312
|
if (token) {
|
|
12171
12313
|
console.log(import_chalk11.default.cyan("\nGenerating profile on server..."));
|
|
12172
12314
|
const response = await authenticatedRequest(
|
|
12173
|
-
"
|
|
12315
|
+
cliApiUrl("/cli/profiles/new"),
|
|
12174
12316
|
{
|
|
12175
12317
|
method: "POST",
|
|
12176
12318
|
body: {
|
|
@@ -12207,20 +12349,20 @@ Industry: ${industry}
|
|
|
12207
12349
|
}
|
|
12208
12350
|
async function createFromSamples(name, sampleDir, token) {
|
|
12209
12351
|
const dirPath = path12.resolve(sampleDir);
|
|
12210
|
-
if (!
|
|
12352
|
+
if (!fs11.existsSync(dirPath)) {
|
|
12211
12353
|
throw new Error(`Directory not found: ${dirPath}`);
|
|
12212
12354
|
}
|
|
12213
12355
|
console.log(import_chalk11.default.bold(`
|
|
12214
12356
|
Creating voice profile: ${name}`));
|
|
12215
12357
|
console.log(import_chalk11.default.dim(`Reading samples from: ${dirPath}
|
|
12216
12358
|
`));
|
|
12217
|
-
const files =
|
|
12359
|
+
const files = fs11.readdirSync(dirPath).filter((f) => f.endsWith(".md") || f.endsWith(".txt")).map((f) => path12.join(dirPath, f));
|
|
12218
12360
|
if (files.length === 0) {
|
|
12219
12361
|
throw new Error("No .md or .txt files found in directory");
|
|
12220
12362
|
}
|
|
12221
12363
|
const samples = [];
|
|
12222
12364
|
for (const file of files) {
|
|
12223
|
-
const text =
|
|
12365
|
+
const text = fs11.readFileSync(file, "utf-8");
|
|
12224
12366
|
if (text.trim().length > 0) {
|
|
12225
12367
|
samples.push({ path: file, text });
|
|
12226
12368
|
console.log(import_chalk11.default.dim(` \u2022 ${path12.basename(file)} (${words(text).length} words)`));
|
|
@@ -12240,7 +12382,7 @@ Stats extracted:`));
|
|
|
12240
12382
|
if (token) {
|
|
12241
12383
|
console.log(import_chalk11.default.cyan("\nGenerating profile on server..."));
|
|
12242
12384
|
const response = await authenticatedRequest(
|
|
12243
|
-
"
|
|
12385
|
+
cliApiUrl("/cli/profiles/new"),
|
|
12244
12386
|
{
|
|
12245
12387
|
method: "POST",
|
|
12246
12388
|
body: {
|
|
@@ -12290,8 +12432,28 @@ hyv import ${name} <file.md>
|
|
|
12290
12432
|
Or paste the profile content and I'll save it.`;
|
|
12291
12433
|
console.log(prompt);
|
|
12292
12434
|
}
|
|
12435
|
+
function registerImportCommand(program3) {
|
|
12436
|
+
program3.command("import").description("Import a voice profile from file").argument("<name>", "Profile name").argument("<file>", "Profile markdown file").action(async (name, file) => {
|
|
12437
|
+
try {
|
|
12438
|
+
assertSafeProfileName(name);
|
|
12439
|
+
const filePath = path12.resolve(file);
|
|
12440
|
+
if (!fs11.existsSync(filePath)) {
|
|
12441
|
+
console.error(import_chalk11.default.red(`File not found: ${filePath}`));
|
|
12442
|
+
process.exit(1);
|
|
12443
|
+
}
|
|
12444
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
12445
|
+
ensureHyvDir();
|
|
12446
|
+
writeCachedProfile(name, content);
|
|
12447
|
+
console.log(import_chalk11.default.green(`
|
|
12448
|
+
\u2713 Profile imported: ${name}`));
|
|
12449
|
+
} catch (error) {
|
|
12450
|
+
console.error(import_chalk11.default.red(`Error: ${error.message}`));
|
|
12451
|
+
process.exit(1);
|
|
12452
|
+
}
|
|
12453
|
+
});
|
|
12454
|
+
}
|
|
12293
12455
|
function askQuestion(question) {
|
|
12294
|
-
return new Promise((
|
|
12456
|
+
return new Promise((resolve14) => {
|
|
12295
12457
|
const readline = require("readline");
|
|
12296
12458
|
const rl = readline.createInterface({
|
|
12297
12459
|
input: process.stdin,
|
|
@@ -12300,7 +12462,7 @@ function askQuestion(question) {
|
|
|
12300
12462
|
rl.question(import_chalk11.default.cyan(` ${question}
|
|
12301
12463
|
> `), (answer) => {
|
|
12302
12464
|
rl.close();
|
|
12303
|
-
|
|
12465
|
+
resolve14(answer.trim());
|
|
12304
12466
|
});
|
|
12305
12467
|
});
|
|
12306
12468
|
}
|
|
@@ -12404,7 +12566,7 @@ Error: ${error.message}`));
|
|
|
12404
12566
|
async function showPlan() {
|
|
12405
12567
|
console.log(import_chalk12.default.bold("\nSubscription Plan\n"));
|
|
12406
12568
|
const response = await authenticatedRequest(
|
|
12407
|
-
"
|
|
12569
|
+
cliApiUrl("/cli/heartbeat"),
|
|
12408
12570
|
{ method: "GET" }
|
|
12409
12571
|
);
|
|
12410
12572
|
if (response.status !== 200) {
|
|
@@ -12448,7 +12610,7 @@ async function showPlan() {
|
|
|
12448
12610
|
async function upgradePlan() {
|
|
12449
12611
|
console.log(import_chalk12.default.cyan("\nOpening checkout...\n"));
|
|
12450
12612
|
const response = await authenticatedRequest(
|
|
12451
|
-
"
|
|
12613
|
+
cliApiUrl("/cli/subscribe"),
|
|
12452
12614
|
{
|
|
12453
12615
|
method: "POST",
|
|
12454
12616
|
body: { plan: "individual" }
|
|
@@ -12459,7 +12621,7 @@ async function upgradePlan() {
|
|
|
12459
12621
|
const checkoutUrl = data.checkout_url;
|
|
12460
12622
|
if (checkoutUrl) {
|
|
12461
12623
|
console.log(import_chalk12.default.dim("Opening browser..."));
|
|
12462
|
-
await (0, import_open2.default)(checkoutUrl);
|
|
12624
|
+
await (0, import_open2.default)(assertSafeOpenUrl(checkoutUrl));
|
|
12463
12625
|
console.log(import_chalk12.default.green("\n\u2713 Checkout opened in browser"));
|
|
12464
12626
|
console.log(import_chalk12.default.dim("Complete the checkout to activate your plan."));
|
|
12465
12627
|
} else {
|
|
@@ -12473,7 +12635,7 @@ async function upgradePlan() {
|
|
|
12473
12635
|
async function openBillingPortal() {
|
|
12474
12636
|
console.log(import_chalk12.default.cyan("\nOpening billing portal...\n"));
|
|
12475
12637
|
const response = await authenticatedRequest(
|
|
12476
|
-
"
|
|
12638
|
+
cliApiUrl("/cli/subscribe/manage"),
|
|
12477
12639
|
{ method: "POST" }
|
|
12478
12640
|
);
|
|
12479
12641
|
if (response.status === 200) {
|
|
@@ -12481,7 +12643,7 @@ async function openBillingPortal() {
|
|
|
12481
12643
|
const portalUrl = data.portal_url;
|
|
12482
12644
|
if (portalUrl) {
|
|
12483
12645
|
console.log(import_chalk12.default.dim("Opening browser..."));
|
|
12484
|
-
await (0, import_open2.default)(portalUrl);
|
|
12646
|
+
await (0, import_open2.default)(assertSafeOpenUrl(portalUrl));
|
|
12485
12647
|
console.log(import_chalk12.default.green("\n\u2713 Billing portal opened"));
|
|
12486
12648
|
} else {
|
|
12487
12649
|
console.log(import_chalk12.default.yellow("No portal URL received."));
|
|
@@ -12663,7 +12825,7 @@ async function runHybridAnalysis(text, profile, opts = {}) {
|
|
|
12663
12825
|
|
|
12664
12826
|
// src/commands/history.ts
|
|
12665
12827
|
var import_chalk14 = __toESM(require_source());
|
|
12666
|
-
var
|
|
12828
|
+
var fs12 = __toESM(require("fs"));
|
|
12667
12829
|
var path13 = __toESM(require("path"));
|
|
12668
12830
|
init_config();
|
|
12669
12831
|
var HISTORY_DIR = path13.join(HYV_DIR, "history");
|
|
@@ -12671,17 +12833,15 @@ var HISTORY_FILE = path13.join(HISTORY_DIR, "scans.jsonl");
|
|
|
12671
12833
|
function logScan(entry) {
|
|
12672
12834
|
try {
|
|
12673
12835
|
ensureHyvDir();
|
|
12674
|
-
|
|
12675
|
-
fs13.mkdirSync(HISTORY_DIR, { recursive: true });
|
|
12676
|
-
fs13.appendFileSync(HISTORY_FILE, JSON.stringify(entry) + "\n");
|
|
12836
|
+
appendSecureLine(HISTORY_FILE, JSON.stringify(entry) + "\n", HISTORY_DIR);
|
|
12677
12837
|
} catch {
|
|
12678
12838
|
}
|
|
12679
12839
|
}
|
|
12680
12840
|
function readHistory() {
|
|
12681
12841
|
try {
|
|
12682
|
-
if (!
|
|
12842
|
+
if (!fs12.existsSync(HISTORY_FILE))
|
|
12683
12843
|
return [];
|
|
12684
|
-
const lines =
|
|
12844
|
+
const lines = fs12.readFileSync(HISTORY_FILE, "utf-8").trim().split("\n").filter(Boolean);
|
|
12685
12845
|
return lines.map((l) => JSON.parse(l));
|
|
12686
12846
|
} catch {
|
|
12687
12847
|
return [];
|
|
@@ -12713,8 +12873,8 @@ function registerHistoryCommand(program3) {
|
|
|
12713
12873
|
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) => {
|
|
12714
12874
|
try {
|
|
12715
12875
|
if (options.clear) {
|
|
12716
|
-
if (
|
|
12717
|
-
|
|
12876
|
+
if (fs12.existsSync(HISTORY_FILE)) {
|
|
12877
|
+
fs12.unlinkSync(HISTORY_FILE);
|
|
12718
12878
|
}
|
|
12719
12879
|
console.log(import_chalk14.default.green("\n\u2713 History cleared"));
|
|
12720
12880
|
return;
|
|
@@ -12869,7 +13029,7 @@ hyv scan ${filePath}`));
|
|
|
12869
13029
|
hasProfile: !!profile
|
|
12870
13030
|
});
|
|
12871
13031
|
if (options.failOnHit && signals.length > 0) {
|
|
12872
|
-
process.exit(
|
|
13032
|
+
process.exit(2);
|
|
12873
13033
|
}
|
|
12874
13034
|
} catch (error) {
|
|
12875
13035
|
console.error(import_chalk15.default.red(`Error: ${error.message}`));
|
|
@@ -12880,15 +13040,33 @@ hyv scan ${filePath}`));
|
|
|
12880
13040
|
|
|
12881
13041
|
// src/commands/doctor.ts
|
|
12882
13042
|
var import_chalk16 = __toESM(require_source());
|
|
12883
|
-
var
|
|
13043
|
+
var fs13 = __toESM(require("fs"));
|
|
12884
13044
|
var path14 = __toESM(require("path"));
|
|
12885
13045
|
var os5 = __toESM(require("os"));
|
|
12886
13046
|
init_config();
|
|
12887
13047
|
init_auth();
|
|
12888
13048
|
init_access();
|
|
12889
13049
|
init_local_profile();
|
|
13050
|
+
init_version();
|
|
12890
13051
|
var HOME = os5.homedir();
|
|
12891
13052
|
var IS_WIN = process.platform === "win32";
|
|
13053
|
+
function claudeDesktopDir() {
|
|
13054
|
+
if (IS_WIN)
|
|
13055
|
+
return path14.join(HOME, "AppData", "Roaming", "Claude");
|
|
13056
|
+
if (process.platform === "linux")
|
|
13057
|
+
return path14.join(HOME, ".config", "Claude");
|
|
13058
|
+
return path14.join(HOME, "Library", "Application Support", "Claude");
|
|
13059
|
+
}
|
|
13060
|
+
function readMcpHyv(configFile) {
|
|
13061
|
+
try {
|
|
13062
|
+
if (!fs13.existsSync(configFile))
|
|
13063
|
+
return false;
|
|
13064
|
+
const cfg = JSON.parse(fs13.readFileSync(configFile, "utf-8"));
|
|
13065
|
+
return Boolean(cfg.mcpServers?.hyv);
|
|
13066
|
+
} catch {
|
|
13067
|
+
return false;
|
|
13068
|
+
}
|
|
13069
|
+
}
|
|
12892
13070
|
function registerDoctorCommand(program3) {
|
|
12893
13071
|
program3.command("doctor").description("Diagnose CLI health: engine, cache, auth, agents").option("--fix-agents", "Re-run agent config copy (idempotent)").action(async (opts) => {
|
|
12894
13072
|
console.log(import_chalk16.default.bold("\nhold your voice \u2014 doctor\n"));
|
|
@@ -12904,28 +13082,28 @@ function registerDoctorCommand(program3) {
|
|
|
12904
13082
|
console.log(import_chalk16.default.dim("tip: run hyv welcome for free capabilities\n"));
|
|
12905
13083
|
console.log(import_chalk16.default.dim("checking cli installation..."));
|
|
12906
13084
|
const cliPath = process.argv[1];
|
|
12907
|
-
if (cliPath &&
|
|
13085
|
+
if (cliPath && fs13.existsSync(cliPath)) {
|
|
12908
13086
|
console.log(import_chalk16.default.green(" \u2713 cli installed"));
|
|
12909
13087
|
} else {
|
|
12910
13088
|
console.log(import_chalk16.default.red(" \u2717 cli not found"));
|
|
12911
13089
|
issues++;
|
|
12912
13090
|
}
|
|
12913
13091
|
console.log(import_chalk16.default.dim("checking .hyv directory..."));
|
|
12914
|
-
if (
|
|
13092
|
+
if (fs13.existsSync(HYV_DIR)) {
|
|
12915
13093
|
console.log(import_chalk16.default.green(" \u2713 .hyv directory exists"));
|
|
12916
13094
|
} else {
|
|
12917
13095
|
console.log(import_chalk16.default.yellow(" ! .hyv directory missing \u2014 creating..."));
|
|
12918
|
-
|
|
13096
|
+
fs13.mkdirSync(HYV_DIR, { recursive: true, mode: 448 });
|
|
12919
13097
|
fixed++;
|
|
12920
13098
|
}
|
|
12921
13099
|
console.log(import_chalk16.default.dim("checking cache..."));
|
|
12922
13100
|
const diskProfiles = listDiskCachedProfiles();
|
|
12923
13101
|
const syncMeta = path14.join(CACHE_DIR, "sync-meta.json");
|
|
12924
|
-
if (diskProfiles.length > 0 ||
|
|
13102
|
+
if (diskProfiles.length > 0 || fs13.existsSync(syncMeta)) {
|
|
12925
13103
|
console.log(import_chalk16.default.green(` \u2713 profile cache (${diskProfiles.length} full profile(s))`));
|
|
12926
|
-
if (
|
|
13104
|
+
if (fs13.existsSync(syncMeta)) {
|
|
12927
13105
|
try {
|
|
12928
|
-
const meta = JSON.parse(
|
|
13106
|
+
const meta = JSON.parse(fs13.readFileSync(syncMeta, "utf-8"));
|
|
12929
13107
|
console.log(import_chalk16.default.dim(` last sync: ${meta.synced_at || "unknown"}`));
|
|
12930
13108
|
} catch {
|
|
12931
13109
|
}
|
|
@@ -12958,8 +13136,8 @@ function registerDoctorCommand(program3) {
|
|
|
12958
13136
|
}
|
|
12959
13137
|
console.log(import_chalk16.default.dim("checking voice profile..."));
|
|
12960
13138
|
const voiceMd = path14.join(HYV_DIR, "voice.md");
|
|
12961
|
-
const hasVoiceMd =
|
|
12962
|
-
const profileFiles =
|
|
13139
|
+
const hasVoiceMd = fs13.existsSync(voiceMd) && fs13.readFileSync(voiceMd, "utf-8").trim().length > 50;
|
|
13140
|
+
const profileFiles = fs13.existsSync(PROFILES_DIR) ? fs13.readdirSync(PROFILES_DIR).filter((f) => f.endsWith(".md") && f !== "voice.md") : [];
|
|
12963
13141
|
if (hasVoiceMd || profileFiles.length > 0 || diskProfiles.length > 0) {
|
|
12964
13142
|
if (hasVoiceMd)
|
|
12965
13143
|
console.log(import_chalk16.default.green(" \u2713 voice.md exists"));
|
|
@@ -12972,15 +13150,17 @@ function registerDoctorCommand(program3) {
|
|
|
12972
13150
|
console.log(import_chalk16.default.dim(" run: hyv new <name> or hyv init"));
|
|
12973
13151
|
}
|
|
12974
13152
|
console.log(import_chalk16.default.dim("checking agent configurations..."));
|
|
12975
|
-
const
|
|
12976
|
-
|
|
12977
|
-
{ name: "
|
|
12978
|
-
{ name: "
|
|
12979
|
-
{ name: "
|
|
12980
|
-
{ name: "
|
|
13153
|
+
const agentChecks = [
|
|
13154
|
+
{ name: "claude desktop mcp", ok: readMcpHyv(path14.join(claudeDesktopDir(), "claude_desktop_config.json")) },
|
|
13155
|
+
{ name: "cursor mcp", ok: readMcpHyv(path14.join(HOME, ".cursor", "mcp.json")) },
|
|
13156
|
+
{ name: "cursor rule", ok: fs13.existsSync(path14.join(HOME, ".cursor", "rules", "hyv.mdc")) },
|
|
13157
|
+
{ name: "claude code command", ok: fs13.existsSync(path14.join(HOME, ".claude", "commands", "hyv.md")) },
|
|
13158
|
+
{ name: "claude code skill", ok: fs13.existsSync(path14.join(HOME, ".claude", "skills", "hold-your-voice", "SKILL.md")) },
|
|
13159
|
+
{ name: "codex agents", ok: fs13.existsSync(path14.join(HOME, ".codex", "AGENTS.md")) && fs13.readFileSync(path14.join(HOME, ".codex", "AGENTS.md"), "utf-8").includes("hyv") },
|
|
13160
|
+
{ name: "command code skill", ok: fs13.existsSync(path14.join(HOME, ".commandcode", "skills", "hyv", "SKILL.md")) }
|
|
12981
13161
|
];
|
|
12982
|
-
for (const agent of
|
|
12983
|
-
if (
|
|
13162
|
+
for (const agent of agentChecks) {
|
|
13163
|
+
if (agent.ok) {
|
|
12984
13164
|
console.log(import_chalk16.default.green(` \u2713 ${agent.name}`));
|
|
12985
13165
|
} else {
|
|
12986
13166
|
console.log(import_chalk16.default.dim(` - ${agent.name} not configured`));
|
|
@@ -12988,35 +13168,29 @@ function registerDoctorCommand(program3) {
|
|
|
12988
13168
|
}
|
|
12989
13169
|
if (opts.fixAgents) {
|
|
12990
13170
|
try {
|
|
12991
|
-
const
|
|
12992
|
-
|
|
12993
|
-
|
|
12994
|
-
|
|
12995
|
-
|
|
12996
|
-
|
|
12997
|
-
|
|
12998
|
-
|
|
13171
|
+
const pkgDir = path14.resolve(__dirname, "..");
|
|
13172
|
+
const { setupAgents } = require(path14.join(pkgDir, "scripts", "postinstall-lib.js"));
|
|
13173
|
+
const result = setupAgents({ pkgDir, quiet: true });
|
|
13174
|
+
console.log(import_chalk16.default.green(` \u2713 re-ran agent setup (${result.configured.join(", ") || "no changes"})`));
|
|
13175
|
+
if (result.warnings.length) {
|
|
13176
|
+
console.log(import_chalk16.default.yellow(` notes: ${result.warnings.join("; ")}`));
|
|
13177
|
+
}
|
|
13178
|
+
fixed++;
|
|
13179
|
+
} catch (err) {
|
|
13180
|
+
console.log(import_chalk16.default.yellow(` ! could not re-run agent setup: ${err.message}`));
|
|
12999
13181
|
}
|
|
13000
13182
|
}
|
|
13001
13183
|
console.log(import_chalk16.default.dim("checking mcp server..."));
|
|
13002
|
-
const
|
|
13003
|
-
|
|
13004
|
-
|
|
13005
|
-
|
|
13006
|
-
|
|
13007
|
-
|
|
13008
|
-
|
|
13009
|
-
if (cfg.mcpServers?.hyv) {
|
|
13010
|
-
console.log(import_chalk16.default.green(" \u2713 mcp configured for claude desktop"));
|
|
13011
|
-
} else {
|
|
13012
|
-
console.log(import_chalk16.default.yellow(" ! mcp not configured \u2014 run: hyv init"));
|
|
13013
|
-
issues++;
|
|
13014
|
-
}
|
|
13015
|
-
} catch {
|
|
13016
|
-
console.log(import_chalk16.default.yellow(" ! could not read claude desktop config"));
|
|
13017
|
-
}
|
|
13184
|
+
const claudeMcp = readMcpHyv(path14.join(claudeDesktopDir(), "claude_desktop_config.json"));
|
|
13185
|
+
const cursorMcp = readMcpHyv(path14.join(HOME, ".cursor", "mcp.json"));
|
|
13186
|
+
if (claudeMcp || cursorMcp) {
|
|
13187
|
+
if (claudeMcp)
|
|
13188
|
+
console.log(import_chalk16.default.green(" \u2713 mcp configured for claude desktop"));
|
|
13189
|
+
if (cursorMcp)
|
|
13190
|
+
console.log(import_chalk16.default.green(" \u2713 mcp configured for cursor"));
|
|
13018
13191
|
} else {
|
|
13019
|
-
console.log(import_chalk16.default.
|
|
13192
|
+
console.log(import_chalk16.default.yellow(" ! mcp not configured \u2014 run: hyv doctor --fix-agents or hyv mcp --setup"));
|
|
13193
|
+
issues++;
|
|
13020
13194
|
}
|
|
13021
13195
|
console.log("");
|
|
13022
13196
|
if (issues === 0 && fixed === 0) {
|
|
@@ -13065,7 +13239,7 @@ function registerRenameCommand(program3) {
|
|
|
13065
13239
|
return;
|
|
13066
13240
|
}
|
|
13067
13241
|
const response = await authenticatedRequest(
|
|
13068
|
-
"
|
|
13242
|
+
cliApiUrl("/cli/profiles/rename"),
|
|
13069
13243
|
{
|
|
13070
13244
|
method: "POST",
|
|
13071
13245
|
body: {
|
|
@@ -13095,7 +13269,7 @@ error: ${error.message}
|
|
|
13095
13269
|
|
|
13096
13270
|
// src/commands/fix.ts
|
|
13097
13271
|
var import_chalk18 = __toESM(require_source());
|
|
13098
|
-
var
|
|
13272
|
+
var fs14 = __toESM(require("fs"));
|
|
13099
13273
|
var path15 = __toESM(require("path"));
|
|
13100
13274
|
init_pipeline();
|
|
13101
13275
|
init_local_profile();
|
|
@@ -13142,8 +13316,8 @@ hyv fix ${filePath}
|
|
|
13142
13316
|
if (!options.dryRun) {
|
|
13143
13317
|
if (options.inPlace && filePath !== "stdin") {
|
|
13144
13318
|
const backupPath = filePath + ".bak";
|
|
13145
|
-
|
|
13146
|
-
|
|
13319
|
+
fs14.copyFileSync(filePath, backupPath);
|
|
13320
|
+
fs14.writeFileSync(filePath, result.fixed);
|
|
13147
13321
|
console.log(import_chalk18.default.dim(` Written to ${filePath} (backup: ${path15.basename(backupPath)})`));
|
|
13148
13322
|
saveLastEditSession({
|
|
13149
13323
|
original_path: filePath,
|
|
@@ -13185,19 +13359,19 @@ function registerCheckCommand(program3) {
|
|
|
13185
13359
|
const profile = await loadProfileForCommand(options.profile);
|
|
13186
13360
|
let inputText = text;
|
|
13187
13361
|
if (text === "-") {
|
|
13188
|
-
const
|
|
13362
|
+
const fs25 = require("fs");
|
|
13189
13363
|
if (process.stdin.isTTY) {
|
|
13190
13364
|
console.error(import_chalk19.default.red("No input provided. Pipe content or pass text as argument."));
|
|
13191
13365
|
process.exit(1);
|
|
13192
13366
|
}
|
|
13193
|
-
inputText =
|
|
13367
|
+
inputText = fs25.readFileSync(0, "utf-8");
|
|
13194
13368
|
}
|
|
13195
13369
|
if (!inputText.trim()) {
|
|
13196
13370
|
console.error(import_chalk19.default.red("No text provided."));
|
|
13197
13371
|
process.exit(1);
|
|
13198
13372
|
}
|
|
13199
|
-
const
|
|
13200
|
-
if (text !== "-" &&
|
|
13373
|
+
const fs24 = require("fs");
|
|
13374
|
+
if (text !== "-" && fs24.existsSync(text)) {
|
|
13201
13375
|
console.log(import_chalk19.default.yellow(`"${text}" looks like a file. Did you mean: hyv scan ${text}`));
|
|
13202
13376
|
process.exit(1);
|
|
13203
13377
|
}
|
|
@@ -13324,11 +13498,11 @@ function registerDiffCommand(program3) {
|
|
|
13324
13498
|
${result.changes.length} auto-fix${result.changes.length === 1 ? "" : "es"} available`));
|
|
13325
13499
|
console.log(import_chalk21.default.dim(` run: hyv fix ${file} -i to apply`));
|
|
13326
13500
|
if (options.apply && filePath !== "stdin") {
|
|
13327
|
-
const
|
|
13501
|
+
const fs24 = require("fs");
|
|
13328
13502
|
const path23 = require("path");
|
|
13329
13503
|
const backupPath = filePath + ".bak";
|
|
13330
|
-
|
|
13331
|
-
|
|
13504
|
+
fs24.copyFileSync(filePath, backupPath);
|
|
13505
|
+
fs24.writeFileSync(filePath, result.fixed);
|
|
13332
13506
|
console.log(import_chalk21.default.green(` \u2713 Applied. Backup: ${path23.basename(backupPath)}`));
|
|
13333
13507
|
}
|
|
13334
13508
|
} catch (error) {
|
|
@@ -13504,12 +13678,12 @@ function registerRulesCommand(program3) {
|
|
|
13504
13678
|
|
|
13505
13679
|
// src/commands/batch.ts
|
|
13506
13680
|
var import_chalk23 = __toESM(require_source());
|
|
13507
|
-
var
|
|
13681
|
+
var fs15 = __toESM(require("fs"));
|
|
13508
13682
|
var path16 = __toESM(require("path"));
|
|
13509
13683
|
init_pipeline();
|
|
13510
13684
|
init_local_profile();
|
|
13511
13685
|
function registerBatchCommand(program3) {
|
|
13512
|
-
program3.command("batch").description("Scan or fix multiple files matching a glob").argument("<pattern>", 'Glob pattern (e.g., "posts/**/*.md")').option("--fix", "Apply auto-fixes (default: scan only)").option("-i, --in-place", "Write fixes back to files").option("--threshold <n>", "Fail if any file score < threshold").option("--fail-on-hit", "Exit non-zero if any file has issues").option("--sort <field>", "Sort by: issues, score, name", "issues").option("--format <type>", "Output format (text, json, csv)", "text").option("--profile <name>", "Voice profile").option("--ignore <patterns>", "Comma-separated glob ignores").action(async (pattern, options) => {
|
|
13686
|
+
program3.command("batch").description("Scan or fix multiple files matching a glob").argument("<pattern>", 'Glob pattern (e.g., "posts/**/*.md")').option("--fix", "Apply auto-fixes (default: scan only)").option("-i, --in-place", "Write fixes back to files").option("-y, --yes", "Confirm destructive in-place fixes without prompting").option("--threshold <n>", "Fail if any file score < threshold").option("--fail-on-hit", "Exit non-zero if any file has issues").option("--sort <field>", "Sort by: issues, score, name", "issues").option("--format <type>", "Output format (text, json, csv)", "text").option("--profile <name>", "Voice profile").option("--ignore <patterns>", "Comma-separated glob ignores").action(async (pattern, options) => {
|
|
13513
13687
|
try {
|
|
13514
13688
|
const profile = await loadProfileForCommand(options.profile);
|
|
13515
13689
|
const glob = require_index_min();
|
|
@@ -13522,6 +13696,11 @@ function registerBatchCommand(program3) {
|
|
|
13522
13696
|
No files matching: ${pattern}`));
|
|
13523
13697
|
return;
|
|
13524
13698
|
}
|
|
13699
|
+
if (options.fix && options.inPlace && !options.yes) {
|
|
13700
|
+
console.error(import_chalk23.default.red("\nRefusing to write fixes in-place without confirmation."));
|
|
13701
|
+
console.error(import_chalk23.default.dim(" Re-run with --yes to create .bak backups and apply fixes.\n"));
|
|
13702
|
+
process.exit(1);
|
|
13703
|
+
}
|
|
13525
13704
|
if (options.format === "text") {
|
|
13526
13705
|
console.log(import_chalk23.default.dim(`
|
|
13527
13706
|
scanning ${files.length} file${files.length === 1 ? "" : "s"}...
|
|
@@ -13530,9 +13709,9 @@ No files matching: ${pattern}`));
|
|
|
13530
13709
|
const results = [];
|
|
13531
13710
|
for (const file of files) {
|
|
13532
13711
|
const absPath = path16.resolve(file);
|
|
13533
|
-
if (!
|
|
13712
|
+
if (!fs15.existsSync(absPath))
|
|
13534
13713
|
continue;
|
|
13535
|
-
const text =
|
|
13714
|
+
const text = fs15.readFileSync(absPath, "utf-8");
|
|
13536
13715
|
const result = runPipeline(text, profile, options.fix || false);
|
|
13537
13716
|
results.push({
|
|
13538
13717
|
file,
|
|
@@ -13544,8 +13723,8 @@ No files matching: ${pattern}`));
|
|
|
13544
13723
|
});
|
|
13545
13724
|
if (options.fix && options.inPlace && result.changes.length > 0) {
|
|
13546
13725
|
const backupPath = absPath + ".bak";
|
|
13547
|
-
|
|
13548
|
-
|
|
13726
|
+
fs15.copyFileSync(absPath, backupPath);
|
|
13727
|
+
fs15.writeFileSync(absPath, result.fixed);
|
|
13549
13728
|
}
|
|
13550
13729
|
}
|
|
13551
13730
|
if (options.sort === "score") {
|
|
@@ -13585,10 +13764,11 @@ No files matching: ${pattern}`));
|
|
|
13585
13764
|
}
|
|
13586
13765
|
}
|
|
13587
13766
|
const threshold = options.threshold ? parseInt(options.threshold, 10) : 0;
|
|
13588
|
-
const
|
|
13589
|
-
|
|
13590
|
-
)
|
|
13591
|
-
|
|
13767
|
+
const failOnHit = results.some((r) => options.failOnHit && r.issues > 0);
|
|
13768
|
+
const belowThreshold = results.some((r) => threshold > 0 && r.score < threshold);
|
|
13769
|
+
if (failOnHit)
|
|
13770
|
+
process.exit(2);
|
|
13771
|
+
if (belowThreshold)
|
|
13592
13772
|
process.exit(1);
|
|
13593
13773
|
} catch (error) {
|
|
13594
13774
|
console.error(import_chalk23.default.red(`Error: ${error.message}`));
|
|
@@ -13599,19 +13779,24 @@ No files matching: ${pattern}`));
|
|
|
13599
13779
|
|
|
13600
13780
|
// src/commands/watch.ts
|
|
13601
13781
|
var import_chalk24 = __toESM(require_source());
|
|
13602
|
-
var
|
|
13782
|
+
var fs16 = __toESM(require("fs"));
|
|
13603
13783
|
var path17 = __toESM(require("path"));
|
|
13604
13784
|
init_pipeline();
|
|
13605
13785
|
init_local_profile();
|
|
13606
13786
|
function registerWatchCommand(program3) {
|
|
13607
|
-
program3.command("watch").description("Watch a file and re-scan on every save").argument("<file>", "File to watch").option("--command <cmd>", "What to run on change: scan, score, fix", "scan").option("--debounce <ms>", "Delay after save before scanning", "300").option("--notify", "OS notification when issues found").option("--profile <name>", "Voice profile").action(async (file, options) => {
|
|
13787
|
+
program3.command("watch").description("Watch a file and re-scan on every save").argument("<file>", "File to watch").option("--command <cmd>", "What to run on change: scan, score, fix", "scan").option("--debounce <ms>", "Delay after save before scanning", "300").option("--notify", "OS notification when issues found").option("-y, --yes", "Confirm destructive auto-fix writes without prompting").option("--profile <name>", "Voice profile").action(async (file, options) => {
|
|
13608
13788
|
try {
|
|
13609
13789
|
const profile = await loadProfileForCommand(options.profile);
|
|
13610
13790
|
const absPath = path17.resolve(file);
|
|
13611
|
-
if (!
|
|
13791
|
+
if (!fs16.existsSync(absPath)) {
|
|
13612
13792
|
console.error(import_chalk24.default.red(`File not found: ${absPath}`));
|
|
13613
13793
|
process.exit(1);
|
|
13614
13794
|
}
|
|
13795
|
+
if (options.command === "fix" && !options.yes) {
|
|
13796
|
+
console.error(import_chalk24.default.red("\nRefusing to auto-fix on save without confirmation."));
|
|
13797
|
+
console.error(import_chalk24.default.dim(" Re-run with --yes to create .bak backups before each fix.\n"));
|
|
13798
|
+
process.exit(1);
|
|
13799
|
+
}
|
|
13615
13800
|
console.log(import_chalk24.default.dim(`
|
|
13616
13801
|
watching ${absPath}`));
|
|
13617
13802
|
console.log(import_chalk24.default.dim(`command: ${options.command} debounce: ${options.debounce}ms`));
|
|
@@ -13621,7 +13806,7 @@ watching ${absPath}`));
|
|
|
13621
13806
|
let scanCount = 0;
|
|
13622
13807
|
let lastScore = 0;
|
|
13623
13808
|
const runScan = () => {
|
|
13624
|
-
const text =
|
|
13809
|
+
const text = fs16.readFileSync(absPath, "utf-8");
|
|
13625
13810
|
const result = runPipeline(text, profile, options.command === "fix");
|
|
13626
13811
|
scanCount++;
|
|
13627
13812
|
const now = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
|
|
@@ -13640,7 +13825,9 @@ watching ${absPath}`));
|
|
|
13640
13825
|
for (const change of result.changes) {
|
|
13641
13826
|
console.log(import_chalk24.default.dim(` Line ${change.line}: `) + import_chalk24.default.red(change.before) + import_chalk24.default.dim(" \u2192 ") + import_chalk24.default.green(change.after));
|
|
13642
13827
|
}
|
|
13643
|
-
|
|
13828
|
+
const backupPath = absPath + ".bak";
|
|
13829
|
+
fs16.copyFileSync(absPath, backupPath);
|
|
13830
|
+
fs16.writeFileSync(absPath, result.fixed);
|
|
13644
13831
|
console.log(import_chalk24.default.green(` \u2713 ${result.changes.length} auto-fixes applied`));
|
|
13645
13832
|
} else {
|
|
13646
13833
|
console.log(import_chalk24.default.green(" \u2713 no auto-fixable issues"));
|
|
@@ -13662,7 +13849,7 @@ watching ${absPath}`));
|
|
|
13662
13849
|
console.log("");
|
|
13663
13850
|
};
|
|
13664
13851
|
runScan();
|
|
13665
|
-
|
|
13852
|
+
fs16.watch(absPath, (eventType) => {
|
|
13666
13853
|
if (eventType !== "change")
|
|
13667
13854
|
return;
|
|
13668
13855
|
if (debounceTimer)
|
|
@@ -13685,7 +13872,7 @@ watching ${absPath}`));
|
|
|
13685
13872
|
|
|
13686
13873
|
// src/commands/demo.ts
|
|
13687
13874
|
var import_chalk25 = __toESM(require_source());
|
|
13688
|
-
var
|
|
13875
|
+
var fs17 = __toESM(require("fs"));
|
|
13689
13876
|
var SAMPLES = {
|
|
13690
13877
|
linkedin: {
|
|
13691
13878
|
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.
|
|
@@ -13780,7 +13967,7 @@ function registerDemoCommand(program3) {
|
|
|
13780
13967
|
}
|
|
13781
13968
|
if (options.output) {
|
|
13782
13969
|
const outputPath = require("path").resolve(options.output);
|
|
13783
|
-
|
|
13970
|
+
fs17.writeFileSync(outputPath, sample.text);
|
|
13784
13971
|
console.log(import_chalk25.default.green(`
|
|
13785
13972
|
\u2713 Sample written to ${outputPath}`));
|
|
13786
13973
|
if (sample.patterns.length > 0) {
|
|
@@ -13846,35 +14033,35 @@ function registerOpenCommand(program3) {
|
|
|
13846
14033
|
init_welcome();
|
|
13847
14034
|
|
|
13848
14035
|
// src/lib/onboarding.ts
|
|
13849
|
-
var
|
|
14036
|
+
var fs18 = __toESM(require("fs"));
|
|
13850
14037
|
var path18 = __toESM(require("path"));
|
|
13851
14038
|
var os6 = __toESM(require("os"));
|
|
13852
14039
|
var hyvDir = path18.join(os6.homedir(), ".hyv");
|
|
13853
14040
|
var onboardingFile = path18.join(hyvDir, "onboarding-complete.json");
|
|
13854
14041
|
function hasCompletedOnboarding() {
|
|
13855
14042
|
try {
|
|
13856
|
-
return
|
|
14043
|
+
return fs18.existsSync(onboardingFile);
|
|
13857
14044
|
} catch {
|
|
13858
14045
|
return false;
|
|
13859
14046
|
}
|
|
13860
14047
|
}
|
|
13861
14048
|
function markOnboardingComplete(version) {
|
|
13862
|
-
if (!
|
|
13863
|
-
|
|
13864
|
-
|
|
14049
|
+
if (!fs18.existsSync(hyvDir))
|
|
14050
|
+
fs18.mkdirSync(hyvDir, { recursive: true });
|
|
14051
|
+
fs18.writeFileSync(
|
|
13865
14052
|
onboardingFile,
|
|
13866
14053
|
JSON.stringify({ version, completed_at: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
|
|
13867
14054
|
);
|
|
13868
14055
|
}
|
|
13869
14056
|
|
|
13870
14057
|
// src/commands/welcome.ts
|
|
13871
|
-
var
|
|
14058
|
+
var fs19 = __toESM(require("fs"));
|
|
13872
14059
|
var path19 = __toESM(require("path"));
|
|
13873
14060
|
function registerWelcomeCommand(program3) {
|
|
13874
14061
|
const pkgVersion3 = (() => {
|
|
13875
14062
|
try {
|
|
13876
|
-
const pkgPath3 = path19.resolve(__dirname, "..", "
|
|
13877
|
-
return JSON.parse(
|
|
14063
|
+
const pkgPath3 = path19.resolve(__dirname, "..", "package.json");
|
|
14064
|
+
return JSON.parse(fs19.readFileSync(pkgPath3, "utf-8")).version;
|
|
13878
14065
|
} catch {
|
|
13879
14066
|
return "0.0.0";
|
|
13880
14067
|
}
|
|
@@ -13991,6 +14178,7 @@ ${t.title}
|
|
|
13991
14178
|
// src/commands/upgrade.ts
|
|
13992
14179
|
var import_chalk28 = __toESM(require_source());
|
|
13993
14180
|
var import_child_process2 = require("child_process");
|
|
14181
|
+
init_version();
|
|
13994
14182
|
function registerUpgradeCommand(program3) {
|
|
13995
14183
|
program3.command("upgrade").description("Upgrade to the latest @holdyourvoice/hyv").option("--check", "Only check if an update is available").action(async (opts) => {
|
|
13996
14184
|
const current = getCliVersion();
|
|
@@ -14031,7 +14219,7 @@ Current: ${getEngineLabel()}
|
|
|
14031
14219
|
}
|
|
14032
14220
|
|
|
14033
14221
|
// src/mcp.ts
|
|
14034
|
-
var
|
|
14222
|
+
var fs20 = __toESM(require("fs"));
|
|
14035
14223
|
var path20 = __toESM(require("path"));
|
|
14036
14224
|
var os7 = __toESM(require("os"));
|
|
14037
14225
|
init_classifier();
|
|
@@ -14046,16 +14234,42 @@ init_telemetry();
|
|
|
14046
14234
|
init_access();
|
|
14047
14235
|
var VOICE_MD = path20.join(os7.homedir(), ".hyv", "voice.md");
|
|
14048
14236
|
var MAX_RESPONSE_CHARS = 12e4;
|
|
14237
|
+
var MAX_SCAN_FILE_BYTES = 2 * 1024 * 1024;
|
|
14238
|
+
function readScanFile(filePath) {
|
|
14239
|
+
const cwdReal = fs20.realpathSync(process.cwd());
|
|
14240
|
+
const resolved = fs20.realpathSync(path20.resolve(filePath));
|
|
14241
|
+
if (!resolved.startsWith(cwdReal + path20.sep) && resolved !== cwdReal) {
|
|
14242
|
+
throw new Error(`file must be in the current working directory (${cwdReal})`);
|
|
14243
|
+
}
|
|
14244
|
+
const stat = fs20.statSync(resolved);
|
|
14245
|
+
if (stat.size > MAX_SCAN_FILE_BYTES) {
|
|
14246
|
+
throw new Error(`file too large (max ${MAX_SCAN_FILE_BYTES} bytes)`);
|
|
14247
|
+
}
|
|
14248
|
+
return fs20.readFileSync(resolved, "utf-8");
|
|
14249
|
+
}
|
|
14250
|
+
function toolResultPayload(result) {
|
|
14251
|
+
const isError = result.startsWith("Error:") || result.startsWith("Unknown tool:");
|
|
14252
|
+
return {
|
|
14253
|
+
content: [{ type: "text", text: truncateResponse(result) }],
|
|
14254
|
+
...isError ? { isError: true } : {}
|
|
14255
|
+
};
|
|
14256
|
+
}
|
|
14049
14257
|
var pkgPath = path20.resolve(__dirname, "..", "package.json");
|
|
14050
14258
|
var pkgVersion = (() => {
|
|
14051
14259
|
try {
|
|
14052
|
-
return JSON.parse(
|
|
14260
|
+
return JSON.parse(fs20.readFileSync(pkgPath, "utf-8")).version;
|
|
14053
14261
|
} catch {
|
|
14054
14262
|
return "2.7.1";
|
|
14055
14263
|
}
|
|
14056
14264
|
})();
|
|
14057
|
-
async function resolveProfile(slug) {
|
|
14058
|
-
|
|
14265
|
+
async function resolveProfile(slug, allowServerFetch = false) {
|
|
14266
|
+
const profile = await loadProfileForCommand(slug, { allowServerFetch });
|
|
14267
|
+
if (slug && !profile) {
|
|
14268
|
+
const { requirePaidFeature: requirePaidFeature2 } = await Promise.resolve().then(() => (init_access(), access_exports));
|
|
14269
|
+
await requirePaidFeature2("premiumPrompts");
|
|
14270
|
+
return loadProfileForCommand(slug, { allowServerFetch: true });
|
|
14271
|
+
}
|
|
14272
|
+
return profile;
|
|
14059
14273
|
}
|
|
14060
14274
|
function jsonRpcOk(id, result) {
|
|
14061
14275
|
return JSON.stringify({ jsonrpc: "2.0", id, result });
|
|
@@ -14116,14 +14330,11 @@ async function toolScan(args2) {
|
|
|
14116
14330
|
let scanText2 = text;
|
|
14117
14331
|
const profile = await resolveProfile(args2.profile);
|
|
14118
14332
|
if (filePath) {
|
|
14119
|
-
|
|
14120
|
-
|
|
14121
|
-
|
|
14122
|
-
return `Error:
|
|
14333
|
+
try {
|
|
14334
|
+
scanText2 = readScanFile(filePath);
|
|
14335
|
+
} catch (err) {
|
|
14336
|
+
return `Error: ${err.message}`;
|
|
14123
14337
|
}
|
|
14124
|
-
if (!fs21.existsSync(resolved))
|
|
14125
|
-
return `Error: file not found: ${filePath}`;
|
|
14126
|
-
scanText2 = fs21.readFileSync(resolved, "utf-8");
|
|
14127
14338
|
}
|
|
14128
14339
|
const result = runPipeline(scanText2, profile, false);
|
|
14129
14340
|
if (result.stats.totalSignals === 0) {
|
|
@@ -14135,13 +14346,19 @@ async function toolScan(args2) {
|
|
|
14135
14346
|
const lines = [
|
|
14136
14347
|
`Score: ${result.score}/100. Found ${result.stats.totalSignals} issues (${result.stats.red} red, ${result.stats.yellow} yellow):`
|
|
14137
14348
|
];
|
|
14349
|
+
const shown = /* @__PURE__ */ new Set();
|
|
14138
14350
|
if (profile && profileIssues.length > 0) {
|
|
14139
14351
|
lines.push(`Profile-specific (${profileIssues.length}):`);
|
|
14140
14352
|
for (const s of profileIssues.slice(0, 5)) {
|
|
14353
|
+
const key = `${s.line}:${s.id}`;
|
|
14354
|
+
shown.add(key);
|
|
14141
14355
|
lines.push(` line ${s.line}: [${s.severity}] ${s.id} \u2014 ${s.suggestion}`);
|
|
14142
14356
|
}
|
|
14143
14357
|
}
|
|
14144
14358
|
for (const s of result.signalMap.signals.slice(0, 15)) {
|
|
14359
|
+
const key = `${s.line}:${s.id}`;
|
|
14360
|
+
if (shown.has(key))
|
|
14361
|
+
continue;
|
|
14145
14362
|
lines.push(`line ${s.line}: [${s.severity}] ${s.id} \u2014 ${s.suggestion}`);
|
|
14146
14363
|
}
|
|
14147
14364
|
return lines.join("\n");
|
|
@@ -14284,7 +14501,7 @@ async function toolAnalyze(args2) {
|
|
|
14284
14501
|
return "Error: no text provided";
|
|
14285
14502
|
try {
|
|
14286
14503
|
const profile = await resolveProfile(args2.profile);
|
|
14287
|
-
const preferServer = args2.prefer_server
|
|
14504
|
+
const preferServer = args2.prefer_server === true;
|
|
14288
14505
|
const result = await runHybridAnalysis(text, profile, {
|
|
14289
14506
|
preferServer,
|
|
14290
14507
|
profileSlug: args2.profile || profile?.slug
|
|
@@ -14407,7 +14624,7 @@ var TOOLS = [
|
|
|
14407
14624
|
properties: {
|
|
14408
14625
|
text: { type: "string", description: "Text to analyze" },
|
|
14409
14626
|
profile: { type: "string", description: "Voice profile slug" },
|
|
14410
|
-
prefer_server: { type: "boolean", description: "Use server hybrid engine when paid (default
|
|
14627
|
+
prefer_server: { type: "boolean", description: "Use server hybrid engine when paid (default false)" }
|
|
14411
14628
|
},
|
|
14412
14629
|
required: ["text"]
|
|
14413
14630
|
}
|
|
@@ -14599,9 +14816,12 @@ async function handleRequest(line) {
|
|
|
14599
14816
|
mcpLog("error", `tool ${toolName}: ${err.message}`);
|
|
14600
14817
|
recordEvent("mcp_tool_error", { tool: toolName, error: err.message });
|
|
14601
14818
|
}
|
|
14602
|
-
send(jsonRpcOk(id,
|
|
14819
|
+
send(jsonRpcOk(id, toolResultPayload(result)));
|
|
14603
14820
|
break;
|
|
14604
14821
|
}
|
|
14822
|
+
case "ping":
|
|
14823
|
+
send(jsonRpcOk(id, {}));
|
|
14824
|
+
break;
|
|
14605
14825
|
default:
|
|
14606
14826
|
if (id !== void 0) {
|
|
14607
14827
|
send(jsonRpcError(id, -32601, `Method not found: ${method}`));
|
|
@@ -14611,7 +14831,7 @@ async function handleRequest(line) {
|
|
|
14611
14831
|
}
|
|
14612
14832
|
async function startMcpServer() {
|
|
14613
14833
|
const access = await getAccessState().catch(() => null);
|
|
14614
|
-
if (
|
|
14834
|
+
if (fs20.existsSync(VOICE_MD)) {
|
|
14615
14835
|
mcpLog("info", `voice profile: ${VOICE_MD}`);
|
|
14616
14836
|
} else {
|
|
14617
14837
|
mcpLog("info", "free local engine ready \u2014 no voice profile yet");
|
|
@@ -14621,16 +14841,17 @@ async function startMcpServer() {
|
|
|
14621
14841
|
}
|
|
14622
14842
|
let buffer = "";
|
|
14623
14843
|
process.stdin.setEncoding("utf-8");
|
|
14844
|
+
let requestChain = Promise.resolve();
|
|
14845
|
+
const enqueueRequest = (line) => {
|
|
14846
|
+
requestChain = requestChain.then(() => handleRequest(line)).catch((err) => mcpLog("error", err.message));
|
|
14847
|
+
};
|
|
14624
14848
|
process.stdin.on("data", (chunk) => {
|
|
14625
14849
|
buffer += chunk;
|
|
14626
14850
|
const lines = buffer.split("\n");
|
|
14627
14851
|
buffer = lines.pop() || "";
|
|
14628
14852
|
for (const line of lines) {
|
|
14629
|
-
if (line.trim())
|
|
14630
|
-
|
|
14631
|
-
mcpLog("error", err.message);
|
|
14632
|
-
});
|
|
14633
|
-
}
|
|
14853
|
+
if (line.trim())
|
|
14854
|
+
enqueueRequest(line.trim());
|
|
14634
14855
|
}
|
|
14635
14856
|
});
|
|
14636
14857
|
process.stdin.on("end", () => process.exit(0));
|
|
@@ -14643,32 +14864,135 @@ async function startMcpServer() {
|
|
|
14643
14864
|
|
|
14644
14865
|
// src/lib/mcp-setup.ts
|
|
14645
14866
|
var import_chalk29 = __toESM(require_source());
|
|
14646
|
-
var
|
|
14867
|
+
var fs21 = __toESM(require("fs"));
|
|
14647
14868
|
var path21 = __toESM(require("path"));
|
|
14648
14869
|
var os8 = __toESM(require("os"));
|
|
14870
|
+
var import_child_process3 = require("child_process");
|
|
14871
|
+
init_version();
|
|
14649
14872
|
var HOME2 = os8.homedir();
|
|
14650
14873
|
var IS_WIN2 = process.platform === "win32";
|
|
14874
|
+
function claudeDesktopConfigPath() {
|
|
14875
|
+
if (IS_WIN2)
|
|
14876
|
+
return path21.join(HOME2, "AppData", "Roaming", "Claude", "claude_desktop_config.json");
|
|
14877
|
+
if (process.platform === "linux")
|
|
14878
|
+
return path21.join(HOME2, ".config", "Claude", "claude_desktop_config.json");
|
|
14879
|
+
return path21.join(HOME2, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
14880
|
+
}
|
|
14881
|
+
function mcpSnippet() {
|
|
14882
|
+
const entry = [
|
|
14883
|
+
path21.resolve(process.argv[1] || ""),
|
|
14884
|
+
path21.resolve(__dirname, "index.js"),
|
|
14885
|
+
path21.resolve(__dirname, "..", "dist", "index.js")
|
|
14886
|
+
].find((p) => p && fs21.existsSync(p));
|
|
14887
|
+
if (entry) {
|
|
14888
|
+
return JSON.stringify({ command: process.execPath, args: [entry, "mcp"] }, null, 2);
|
|
14889
|
+
}
|
|
14890
|
+
return JSON.stringify({ command: "hyv", args: ["mcp"] }, null, 2);
|
|
14891
|
+
}
|
|
14651
14892
|
function printMcpSetup() {
|
|
14652
|
-
const claudeConfig = IS_WIN2 ? path21.join(HOME2, "AppData", "Roaming", "Claude", "claude_desktop_config.json") : path21.join(HOME2, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
14653
14893
|
console.log(import_chalk29.default.bold("\nhold your voice \u2014 mcp setup\n"));
|
|
14654
14894
|
console.log(import_chalk29.default.dim(` ${getEngineLabel()}
|
|
14655
14895
|
`));
|
|
14656
14896
|
console.log(import_chalk29.default.bold("Claude Desktop"));
|
|
14657
|
-
console.log(import_chalk29.default.dim(" Add to claude_desktop_config.json \u2192 mcpServers:"));
|
|
14658
|
-
console.log(import_chalk29.default.cyan(
|
|
14659
|
-
console.log(import_chalk29.default.dim(` Config
|
|
14897
|
+
console.log(import_chalk29.default.dim(" Add to claude_desktop_config.json \u2192 mcpServers.hyv:"));
|
|
14898
|
+
console.log(import_chalk29.default.cyan(` ${mcpSnippet().split("\n").join("\n ")}`));
|
|
14899
|
+
console.log(import_chalk29.default.dim(` Config: ${claudeDesktopConfigPath()}
|
|
14660
14900
|
`));
|
|
14661
14901
|
console.log(import_chalk29.default.bold("Cursor"));
|
|
14662
|
-
console.log(import_chalk29.default.dim("
|
|
14663
|
-
console.log(import_chalk29.default.dim("
|
|
14902
|
+
console.log(import_chalk29.default.dim(" MCP: ~/.cursor/mcp.json \u2192 mcpServers.hyv (same JSON as above)"));
|
|
14903
|
+
console.log(import_chalk29.default.dim(" Rule: ~/.cursor/rules/hyv.mdc (alwaysApply \u2014 auto via postinstall)\n"));
|
|
14664
14904
|
console.log(import_chalk29.default.bold("Claude Code"));
|
|
14665
|
-
console.log(import_chalk29.default.dim(" Command: ~/.claude/commands/hyv.md
|
|
14666
|
-
console.log(import_chalk29.default.
|
|
14667
|
-
console.log(import_chalk29.default.
|
|
14905
|
+
console.log(import_chalk29.default.dim(" Command: ~/.claude/commands/hyv.md"));
|
|
14906
|
+
console.log(import_chalk29.default.dim(" Skill: ~/.claude/skills/hold-your-voice/SKILL.md\n"));
|
|
14907
|
+
console.log(import_chalk29.default.bold("Windsurf"));
|
|
14908
|
+
console.log(import_chalk29.default.dim(" Rule: ~/.windsurf/rules/hyv.md (trigger: always_on)\n"));
|
|
14909
|
+
console.log(import_chalk29.default.bold("Codex"));
|
|
14910
|
+
console.log(import_chalk29.default.dim(" Instructions: ~/.codex/AGENTS.md (merged on install)\n"));
|
|
14911
|
+
console.log(import_chalk29.default.bold("Command Code"));
|
|
14912
|
+
console.log(import_chalk29.default.dim(" Skill: ~/.commandcode/skills/hyv/SKILL.md\n"));
|
|
14913
|
+
console.log(import_chalk29.default.bold("ChatGPT"));
|
|
14914
|
+
console.log(import_chalk29.default.dim(" hyv mcp --setup-chatgpt\n"));
|
|
14915
|
+
console.log(import_chalk29.default.bold("Auto-configure"));
|
|
14916
|
+
console.log(import_chalk29.default.dim(" hyv doctor --fix-agents"));
|
|
14917
|
+
console.log(import_chalk29.default.dim(" HYV_AUTO_CONFIGURE_AGENTS=0 npm i -g @holdyourvoice/hyv (skip)\n"));
|
|
14668
14918
|
console.log(import_chalk29.default.bold("Verify"));
|
|
14669
14919
|
console.log(import_chalk29.default.dim(" hyv mcp --test"));
|
|
14670
14920
|
console.log(import_chalk29.default.dim(" HYV_TELEMETRY=1 hyv mcp (optional usage logging to ~/.hyv/telemetry/)\n"));
|
|
14671
14921
|
}
|
|
14922
|
+
async function testMcpStdioSubprocess() {
|
|
14923
|
+
const candidates = [
|
|
14924
|
+
path21.resolve(process.argv[1] || ""),
|
|
14925
|
+
path21.resolve(__dirname, "index.js"),
|
|
14926
|
+
path21.resolve(__dirname, "..", "dist", "index.js")
|
|
14927
|
+
];
|
|
14928
|
+
const entry = candidates.find((p) => p && fs21.existsSync(p));
|
|
14929
|
+
if (!entry)
|
|
14930
|
+
return { ok: false };
|
|
14931
|
+
return new Promise((resolve14) => {
|
|
14932
|
+
const child = (0, import_child_process3.spawn)(process.execPath, [entry, "mcp"], {
|
|
14933
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
14934
|
+
env: { ...process.env, HYV_POSTINSTALL_QUIET: "1" }
|
|
14935
|
+
});
|
|
14936
|
+
let buffer = "";
|
|
14937
|
+
let settled = false;
|
|
14938
|
+
const finish = (ok, toolCount) => {
|
|
14939
|
+
if (settled)
|
|
14940
|
+
return;
|
|
14941
|
+
settled = true;
|
|
14942
|
+
clearTimeout(timeout);
|
|
14943
|
+
try {
|
|
14944
|
+
child.kill();
|
|
14945
|
+
} catch {
|
|
14946
|
+
}
|
|
14947
|
+
resolve14({ ok, toolCount });
|
|
14948
|
+
};
|
|
14949
|
+
const timeout = setTimeout(() => finish(false), 1e4);
|
|
14950
|
+
const handleLine = (line) => {
|
|
14951
|
+
const trimmed = line.trim();
|
|
14952
|
+
if (!trimmed.startsWith("{"))
|
|
14953
|
+
return;
|
|
14954
|
+
try {
|
|
14955
|
+
const msg = JSON.parse(trimmed);
|
|
14956
|
+
if (msg.id === 2 && Array.isArray(msg.result?.tools) && msg.result.tools.length > 0) {
|
|
14957
|
+
finish(true, msg.result.tools.length);
|
|
14958
|
+
}
|
|
14959
|
+
} catch {
|
|
14960
|
+
}
|
|
14961
|
+
};
|
|
14962
|
+
child.stdout.on("data", (chunk) => {
|
|
14963
|
+
buffer += chunk.toString();
|
|
14964
|
+
const lines = buffer.split("\n");
|
|
14965
|
+
buffer = lines.pop() || "";
|
|
14966
|
+
for (const line of lines)
|
|
14967
|
+
handleLine(line);
|
|
14968
|
+
});
|
|
14969
|
+
child.on("error", () => finish(false));
|
|
14970
|
+
child.on("exit", () => {
|
|
14971
|
+
if (!settled) {
|
|
14972
|
+
handleLine(buffer);
|
|
14973
|
+
finish(buffer.includes("hyv_scan"));
|
|
14974
|
+
}
|
|
14975
|
+
});
|
|
14976
|
+
setTimeout(() => {
|
|
14977
|
+
const send2 = (payload) => {
|
|
14978
|
+
child.stdin.write(`${JSON.stringify(payload)}
|
|
14979
|
+
`);
|
|
14980
|
+
};
|
|
14981
|
+
send2({
|
|
14982
|
+
jsonrpc: "2.0",
|
|
14983
|
+
id: 1,
|
|
14984
|
+
method: "initialize",
|
|
14985
|
+
params: {
|
|
14986
|
+
protocolVersion: "2024-11-05",
|
|
14987
|
+
capabilities: {},
|
|
14988
|
+
clientInfo: { name: "hyv-self-test", version: "1.0" }
|
|
14989
|
+
}
|
|
14990
|
+
});
|
|
14991
|
+
send2({ jsonrpc: "2.0", method: "notifications/initialized" });
|
|
14992
|
+
send2({ jsonrpc: "2.0", id: 2, method: "tools/list", params: {} });
|
|
14993
|
+
}, 500);
|
|
14994
|
+
});
|
|
14995
|
+
}
|
|
14672
14996
|
async function runMcpSelfTest() {
|
|
14673
14997
|
console.log(import_chalk29.default.bold("\nhold your voice \u2014 mcp self-test\n"));
|
|
14674
14998
|
console.log(import_chalk29.default.dim(` ${getEngineLabel()}
|
|
@@ -14683,7 +15007,7 @@ async function runMcpSelfTest() {
|
|
|
14683
15007
|
console.log(import_chalk29.default.red(` \u2717 expected 10+ tools, got ${tools.length}`));
|
|
14684
15008
|
failed++;
|
|
14685
15009
|
}
|
|
14686
|
-
const required = ["hyv_welcome", "hyv_scan", "hyv_analyze", "hyv_clean", "hyv_validate"];
|
|
15010
|
+
const required = ["hyv_welcome", "hyv_scan", "hyv_analyze", "hyv_clean", "hyv_validate", "hyv_list_free_tools"];
|
|
14687
15011
|
for (const name of required) {
|
|
14688
15012
|
if (tools.includes(name)) {
|
|
14689
15013
|
console.log(import_chalk29.default.green(` \u2713 tool: ${name}`));
|
|
@@ -14720,7 +15044,7 @@ async function runMcpSelfTest() {
|
|
|
14720
15044
|
failed++;
|
|
14721
15045
|
}
|
|
14722
15046
|
const voiceMd = path21.join(HOME2, ".hyv", "voice.md");
|
|
14723
|
-
if (
|
|
15047
|
+
if (fs21.existsSync(voiceMd)) {
|
|
14724
15048
|
console.log(import_chalk29.default.green(" \u2713 voice profile found"));
|
|
14725
15049
|
passed++;
|
|
14726
15050
|
} else {
|
|
@@ -14733,6 +15057,22 @@ async function runMcpSelfTest() {
|
|
|
14733
15057
|
console.log(import_chalk29.default.red(" \u2717 demo content missing"));
|
|
14734
15058
|
failed++;
|
|
14735
15059
|
}
|
|
15060
|
+
try {
|
|
15061
|
+
const stdio = await testMcpStdioSubprocess();
|
|
15062
|
+
if (stdio.ok && (stdio.toolCount || 0) >= 10) {
|
|
15063
|
+
console.log(import_chalk29.default.green(` \u2713 stdio MCP subprocess responds (${stdio.toolCount} tools)`));
|
|
15064
|
+
passed++;
|
|
15065
|
+
} else if (stdio.ok) {
|
|
15066
|
+
console.log(import_chalk29.default.yellow(` ! stdio MCP subprocess ok but only ${stdio.toolCount || 0} tools`));
|
|
15067
|
+
failed++;
|
|
15068
|
+
} else {
|
|
15069
|
+
console.log(import_chalk29.default.red(" \u2717 stdio MCP subprocess failed"));
|
|
15070
|
+
failed++;
|
|
15071
|
+
}
|
|
15072
|
+
} catch (e) {
|
|
15073
|
+
console.log(import_chalk29.default.red(` \u2717 stdio MCP subprocess failed: ${e.message}`));
|
|
15074
|
+
failed++;
|
|
15075
|
+
}
|
|
14736
15076
|
console.log("");
|
|
14737
15077
|
if (failed === 0) {
|
|
14738
15078
|
console.log(import_chalk29.default.green(`\u2713 all checks passed (${passed})`));
|
|
@@ -14744,7 +15084,7 @@ async function runMcpSelfTest() {
|
|
|
14744
15084
|
}
|
|
14745
15085
|
|
|
14746
15086
|
// src/commands/export.ts
|
|
14747
|
-
var
|
|
15087
|
+
var fs22 = __toESM(require("fs"));
|
|
14748
15088
|
init_api();
|
|
14749
15089
|
var FORMATS = {
|
|
14750
15090
|
claude: {
|
|
@@ -14831,7 +15171,7 @@ async function exportCommand(format, opts) {
|
|
|
14831
15171
|
const prompt = fmt.wrap(detail.profile, detail.body);
|
|
14832
15172
|
if (opts.output) {
|
|
14833
15173
|
const outFile = opts.output.replace("{name}", profile.slug || profile.name);
|
|
14834
|
-
|
|
15174
|
+
fs22.writeFileSync(outFile, prompt);
|
|
14835
15175
|
results.push({ profile: profile.name, file: outFile });
|
|
14836
15176
|
} else {
|
|
14837
15177
|
results.push({ profile: profile.name, prompt });
|
|
@@ -14868,13 +15208,13 @@ async function exportCommand(format, opts) {
|
|
|
14868
15208
|
// src/index.ts
|
|
14869
15209
|
init_access();
|
|
14870
15210
|
init_welcome();
|
|
14871
|
-
var
|
|
15211
|
+
var fs23 = __toESM(require("fs"));
|
|
14872
15212
|
var path22 = __toESM(require("path"));
|
|
14873
15213
|
var program2 = new Command();
|
|
14874
15214
|
var pkgPath2 = path22.resolve(__dirname, "..", "package.json");
|
|
14875
15215
|
var pkgVersion2 = (() => {
|
|
14876
15216
|
try {
|
|
14877
|
-
return JSON.parse(
|
|
15217
|
+
return JSON.parse(fs23.readFileSync(pkgPath2, "utf-8")).version;
|
|
14878
15218
|
} catch {
|
|
14879
15219
|
return "2.7.1";
|
|
14880
15220
|
}
|