@holdyourvoice/hyv 2.8.7 → 2.8.9
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 +32 -0
- package/README.md +26 -3
- package/agents/cursor.md +1 -1
- package/dist/index.js +951 -463
- package/package.json +3 -2
- 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
|
@@ -973,7 +973,7 @@ var require_command = __commonJS({
|
|
|
973
973
|
"node_modules/commander/lib/command.js"(exports2) {
|
|
974
974
|
var EventEmitter = require("node:events").EventEmitter;
|
|
975
975
|
var childProcess = require("node:child_process");
|
|
976
|
-
var
|
|
976
|
+
var path24 = require("node:path");
|
|
977
977
|
var fs25 = require("node:fs");
|
|
978
978
|
var process2 = require("node:process");
|
|
979
979
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
@@ -1916,10 +1916,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1916
1916
|
let launchWithNode = false;
|
|
1917
1917
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1918
1918
|
function findFile(baseDir, baseName) {
|
|
1919
|
-
const localBin =
|
|
1919
|
+
const localBin = path24.resolve(baseDir, baseName);
|
|
1920
1920
|
if (fs25.existsSync(localBin))
|
|
1921
1921
|
return localBin;
|
|
1922
|
-
if (sourceExt.includes(
|
|
1922
|
+
if (sourceExt.includes(path24.extname(baseName)))
|
|
1923
1923
|
return void 0;
|
|
1924
1924
|
const foundExt = sourceExt.find(
|
|
1925
1925
|
(ext) => fs25.existsSync(`${localBin}${ext}`)
|
|
@@ -1939,17 +1939,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1939
1939
|
} catch (err) {
|
|
1940
1940
|
resolvedScriptPath = this._scriptPath;
|
|
1941
1941
|
}
|
|
1942
|
-
executableDir =
|
|
1943
|
-
|
|
1942
|
+
executableDir = path24.resolve(
|
|
1943
|
+
path24.dirname(resolvedScriptPath),
|
|
1944
1944
|
executableDir
|
|
1945
1945
|
);
|
|
1946
1946
|
}
|
|
1947
1947
|
if (executableDir) {
|
|
1948
1948
|
let localFile = findFile(executableDir, executableFile);
|
|
1949
1949
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1950
|
-
const legacyName =
|
|
1950
|
+
const legacyName = path24.basename(
|
|
1951
1951
|
this._scriptPath,
|
|
1952
|
-
|
|
1952
|
+
path24.extname(this._scriptPath)
|
|
1953
1953
|
);
|
|
1954
1954
|
if (legacyName !== this._name) {
|
|
1955
1955
|
localFile = findFile(
|
|
@@ -1960,7 +1960,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1960
1960
|
}
|
|
1961
1961
|
executableFile = localFile || executableFile;
|
|
1962
1962
|
}
|
|
1963
|
-
launchWithNode = sourceExt.includes(
|
|
1963
|
+
launchWithNode = sourceExt.includes(path24.extname(executableFile));
|
|
1964
1964
|
let proc;
|
|
1965
1965
|
if (process2.platform !== "win32") {
|
|
1966
1966
|
if (launchWithNode) {
|
|
@@ -2817,7 +2817,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2817
2817
|
* @return {Command}
|
|
2818
2818
|
*/
|
|
2819
2819
|
nameFromFilename(filename) {
|
|
2820
|
-
this._name =
|
|
2820
|
+
this._name = path24.basename(filename, path24.extname(filename));
|
|
2821
2821
|
return this;
|
|
2822
2822
|
}
|
|
2823
2823
|
/**
|
|
@@ -2831,10 +2831,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2831
2831
|
* @param {string} [path]
|
|
2832
2832
|
* @return {(string|null|Command)}
|
|
2833
2833
|
*/
|
|
2834
|
-
executableDir(
|
|
2835
|
-
if (
|
|
2834
|
+
executableDir(path25) {
|
|
2835
|
+
if (path25 === void 0)
|
|
2836
2836
|
return this._executableDir;
|
|
2837
|
-
this._executableDir =
|
|
2837
|
+
this._executableDir = path25;
|
|
2838
2838
|
return this;
|
|
2839
2839
|
}
|
|
2840
2840
|
/**
|
|
@@ -3934,15 +3934,15 @@ var require_route = __commonJS({
|
|
|
3934
3934
|
};
|
|
3935
3935
|
}
|
|
3936
3936
|
function wrapConversion(toModel, graph) {
|
|
3937
|
-
const
|
|
3937
|
+
const path24 = [graph[toModel].parent, toModel];
|
|
3938
3938
|
let fn = conversions[graph[toModel].parent][toModel];
|
|
3939
3939
|
let cur = graph[toModel].parent;
|
|
3940
3940
|
while (graph[cur].parent) {
|
|
3941
|
-
|
|
3941
|
+
path24.unshift(graph[cur].parent);
|
|
3942
3942
|
fn = link(conversions[graph[cur].parent][cur], fn);
|
|
3943
3943
|
cur = graph[cur].parent;
|
|
3944
3944
|
}
|
|
3945
|
-
fn.conversion =
|
|
3945
|
+
fn.conversion = path24;
|
|
3946
3946
|
return fn;
|
|
3947
3947
|
}
|
|
3948
3948
|
module2.exports = function(fromModel) {
|
|
@@ -4381,14 +4381,14 @@ var require_templates = __commonJS({
|
|
|
4381
4381
|
}
|
|
4382
4382
|
return results;
|
|
4383
4383
|
}
|
|
4384
|
-
function buildStyle(
|
|
4384
|
+
function buildStyle(chalk32, styles) {
|
|
4385
4385
|
const enabled = {};
|
|
4386
4386
|
for (const layer of styles) {
|
|
4387
4387
|
for (const style of layer.styles) {
|
|
4388
4388
|
enabled[style[0]] = layer.inverse ? null : style.slice(1);
|
|
4389
4389
|
}
|
|
4390
4390
|
}
|
|
4391
|
-
let current =
|
|
4391
|
+
let current = chalk32;
|
|
4392
4392
|
for (const [styleName, styles2] of Object.entries(enabled)) {
|
|
4393
4393
|
if (!Array.isArray(styles2)) {
|
|
4394
4394
|
continue;
|
|
@@ -4400,7 +4400,7 @@ var require_templates = __commonJS({
|
|
|
4400
4400
|
}
|
|
4401
4401
|
return current;
|
|
4402
4402
|
}
|
|
4403
|
-
module2.exports = (
|
|
4403
|
+
module2.exports = (chalk32, temporary) => {
|
|
4404
4404
|
const styles = [];
|
|
4405
4405
|
const chunks = [];
|
|
4406
4406
|
let chunk = [];
|
|
@@ -4410,13 +4410,13 @@ var require_templates = __commonJS({
|
|
|
4410
4410
|
} else if (style) {
|
|
4411
4411
|
const string = chunk.join("");
|
|
4412
4412
|
chunk = [];
|
|
4413
|
-
chunks.push(styles.length === 0 ? string : buildStyle(
|
|
4413
|
+
chunks.push(styles.length === 0 ? string : buildStyle(chalk32, styles)(string));
|
|
4414
4414
|
styles.push({ inverse, styles: parseStyle(style) });
|
|
4415
4415
|
} else if (close) {
|
|
4416
4416
|
if (styles.length === 0) {
|
|
4417
4417
|
throw new Error("Found extraneous } in Chalk template literal");
|
|
4418
4418
|
}
|
|
4419
|
-
chunks.push(buildStyle(
|
|
4419
|
+
chunks.push(buildStyle(chalk32, styles)(chunk.join("")));
|
|
4420
4420
|
chunk = [];
|
|
4421
4421
|
styles.pop();
|
|
4422
4422
|
} else {
|
|
@@ -4464,16 +4464,16 @@ var require_source = __commonJS({
|
|
|
4464
4464
|
}
|
|
4465
4465
|
};
|
|
4466
4466
|
var chalkFactory = (options) => {
|
|
4467
|
-
const
|
|
4468
|
-
applyOptions(
|
|
4469
|
-
|
|
4470
|
-
Object.setPrototypeOf(
|
|
4471
|
-
Object.setPrototypeOf(
|
|
4472
|
-
|
|
4467
|
+
const chalk33 = {};
|
|
4468
|
+
applyOptions(chalk33, options);
|
|
4469
|
+
chalk33.template = (...arguments_) => chalkTag(chalk33.template, ...arguments_);
|
|
4470
|
+
Object.setPrototypeOf(chalk33, Chalk.prototype);
|
|
4471
|
+
Object.setPrototypeOf(chalk33.template, chalk33);
|
|
4472
|
+
chalk33.template.constructor = () => {
|
|
4473
4473
|
throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.");
|
|
4474
4474
|
};
|
|
4475
|
-
|
|
4476
|
-
return
|
|
4475
|
+
chalk33.template.Instance = ChalkClass;
|
|
4476
|
+
return chalk33.template;
|
|
4477
4477
|
};
|
|
4478
4478
|
function Chalk(options) {
|
|
4479
4479
|
return chalkFactory(options);
|
|
@@ -4584,7 +4584,7 @@ var require_source = __commonJS({
|
|
|
4584
4584
|
return openAll + string + closeAll;
|
|
4585
4585
|
};
|
|
4586
4586
|
var template;
|
|
4587
|
-
var chalkTag = (
|
|
4587
|
+
var chalkTag = (chalk33, ...strings) => {
|
|
4588
4588
|
const [firstString] = strings;
|
|
4589
4589
|
if (!isArray(firstString) || !isArray(firstString.raw)) {
|
|
4590
4590
|
return strings.join(" ");
|
|
@@ -4600,26 +4600,109 @@ var require_source = __commonJS({
|
|
|
4600
4600
|
if (template === void 0) {
|
|
4601
4601
|
template = require_templates();
|
|
4602
4602
|
}
|
|
4603
|
-
return template(
|
|
4603
|
+
return template(chalk33, parts.join(""));
|
|
4604
4604
|
};
|
|
4605
4605
|
Object.defineProperties(Chalk.prototype, styles);
|
|
4606
|
-
var
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
module2.exports =
|
|
4606
|
+
var chalk32 = Chalk();
|
|
4607
|
+
chalk32.supportsColor = stdoutColor;
|
|
4608
|
+
chalk32.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
4609
|
+
chalk32.stderr.supportsColor = stderrColor;
|
|
4610
|
+
module2.exports = chalk32;
|
|
4611
4611
|
}
|
|
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
|
|
|
@@ -4825,13 +4917,13 @@ var require_define_lazy_prop = __commonJS({
|
|
|
4825
4917
|
// node_modules/open/index.js
|
|
4826
4918
|
var require_open = __commonJS({
|
|
4827
4919
|
"node_modules/open/index.js"(exports2, module2) {
|
|
4828
|
-
var
|
|
4920
|
+
var path24 = require("path");
|
|
4829
4921
|
var childProcess = require("child_process");
|
|
4830
4922
|
var { promises: fs25, 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();
|
|
4834
|
-
var localXdgOpenPath =
|
|
4926
|
+
var localXdgOpenPath = path24.join(__dirname, "xdg-open");
|
|
4835
4927
|
var { platform, arch } = process;
|
|
4836
4928
|
var hasContainerEnv = () => {
|
|
4837
4929
|
try {
|
|
@@ -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,108 @@ 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
|
+
|
|
5247
|
+
// src/lib/auth-refresh.ts
|
|
5248
|
+
function tokenExpiresAtMs(expiresAt) {
|
|
5249
|
+
if (!expiresAt)
|
|
5250
|
+
return null;
|
|
5251
|
+
const ms = new Date(expiresAt).getTime();
|
|
5252
|
+
return Number.isFinite(ms) ? ms : null;
|
|
5253
|
+
}
|
|
5254
|
+
function shouldRefreshToken(expiresAt, now = Date.now()) {
|
|
5255
|
+
const expiresMs = tokenExpiresAtMs(expiresAt);
|
|
5256
|
+
if (expiresMs === null)
|
|
5257
|
+
return false;
|
|
5258
|
+
return expiresMs <= now + REFRESH_LEAD_MS;
|
|
5259
|
+
}
|
|
5260
|
+
function isTokenExpired(expiresAt, now = Date.now()) {
|
|
5261
|
+
const expiresMs = tokenExpiresAtMs(expiresAt);
|
|
5262
|
+
if (expiresMs === null)
|
|
5263
|
+
return false;
|
|
5264
|
+
return expiresMs < now;
|
|
5265
|
+
}
|
|
5266
|
+
var REFRESH_LEAD_MS;
|
|
5267
|
+
var init_auth_refresh = __esm({
|
|
5268
|
+
"src/lib/auth-refresh.ts"() {
|
|
5269
|
+
"use strict";
|
|
5270
|
+
REFRESH_LEAD_MS = 5 * 60 * 1e3;
|
|
5271
|
+
}
|
|
5272
|
+
});
|
|
5273
|
+
|
|
5080
5274
|
// src/lib/auth.ts
|
|
5081
5275
|
var auth_exports = {};
|
|
5082
5276
|
__export(auth_exports, {
|
|
@@ -5084,10 +5278,20 @@ __export(auth_exports, {
|
|
|
5084
5278
|
authenticateWithLicense: () => authenticateWithLicense,
|
|
5085
5279
|
authenticatedRequest: () => authenticatedRequest,
|
|
5086
5280
|
checkSession: () => checkSession,
|
|
5087
|
-
|
|
5281
|
+
getValidToken: () => getValidToken,
|
|
5282
|
+
refreshToken: () => refreshToken,
|
|
5283
|
+
verifyOAuthState: () => verifyOAuthState
|
|
5088
5284
|
});
|
|
5285
|
+
function verifyOAuthState(received, expected) {
|
|
5286
|
+
if (!received || !expected || received !== expected) {
|
|
5287
|
+
throw new Error("OAuth state mismatch \u2014 possible CSRF attempt");
|
|
5288
|
+
}
|
|
5289
|
+
}
|
|
5290
|
+
function escapeHtml(value) {
|
|
5291
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
5292
|
+
}
|
|
5089
5293
|
function request(url, options = {}) {
|
|
5090
|
-
return new Promise((
|
|
5294
|
+
return new Promise((resolve14, reject) => {
|
|
5091
5295
|
const urlObj = new URL(url);
|
|
5092
5296
|
const isHttps = urlObj.protocol === "https:";
|
|
5093
5297
|
const client = isHttps ? https : http;
|
|
@@ -5098,7 +5302,7 @@ function request(url, options = {}) {
|
|
|
5098
5302
|
method: options.method || "GET",
|
|
5099
5303
|
headers: {
|
|
5100
5304
|
"Content-Type": "application/json",
|
|
5101
|
-
"User-Agent":
|
|
5305
|
+
"User-Agent": `hyv-cli/${getCliVersion()}`,
|
|
5102
5306
|
...options.headers
|
|
5103
5307
|
},
|
|
5104
5308
|
timeout: options.timeout || 3e4
|
|
@@ -5108,9 +5312,9 @@ function request(url, options = {}) {
|
|
|
5108
5312
|
res.on("data", (chunk) => data += chunk);
|
|
5109
5313
|
res.on("end", () => {
|
|
5110
5314
|
try {
|
|
5111
|
-
|
|
5315
|
+
resolve14({ status: res.statusCode || 0, data: JSON.parse(data) });
|
|
5112
5316
|
} catch {
|
|
5113
|
-
|
|
5317
|
+
resolve14({ status: res.statusCode || 0, data });
|
|
5114
5318
|
}
|
|
5115
5319
|
});
|
|
5116
5320
|
});
|
|
@@ -5125,8 +5329,21 @@ function request(url, options = {}) {
|
|
|
5125
5329
|
req.end();
|
|
5126
5330
|
});
|
|
5127
5331
|
}
|
|
5332
|
+
async function getValidToken() {
|
|
5333
|
+
const auth = readAuth();
|
|
5334
|
+
if (!auth?.token)
|
|
5335
|
+
return null;
|
|
5336
|
+
if (shouldRefreshToken(auth.expires_at)) {
|
|
5337
|
+
const ok = await refreshToken(auth.token);
|
|
5338
|
+
if (ok)
|
|
5339
|
+
return getToken();
|
|
5340
|
+
if (isTokenExpired(auth.expires_at))
|
|
5341
|
+
return null;
|
|
5342
|
+
}
|
|
5343
|
+
return auth.token;
|
|
5344
|
+
}
|
|
5128
5345
|
async function authenticatedRequest(url, options = {}) {
|
|
5129
|
-
const token =
|
|
5346
|
+
const token = await getValidToken();
|
|
5130
5347
|
if (!token) {
|
|
5131
5348
|
throw new Error("Not authenticated. Run `hyv init` first.");
|
|
5132
5349
|
}
|
|
@@ -5155,9 +5372,9 @@ async function authenticateWithLicense(licenseKey) {
|
|
|
5155
5372
|
}
|
|
5156
5373
|
async function authenticateWithBrowser() {
|
|
5157
5374
|
const server = http.createServer();
|
|
5158
|
-
const port = await new Promise((
|
|
5375
|
+
const port = await new Promise((resolve14) => {
|
|
5159
5376
|
server.listen(0, "127.0.0.1", () => {
|
|
5160
|
-
|
|
5377
|
+
resolve14(server.address().port);
|
|
5161
5378
|
});
|
|
5162
5379
|
});
|
|
5163
5380
|
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
@@ -5169,10 +5386,14 @@ async function authenticateWithBrowser() {
|
|
|
5169
5386
|
server.close();
|
|
5170
5387
|
throw new Error("Failed to start authentication flow");
|
|
5171
5388
|
}
|
|
5172
|
-
const { auth_url } = response.data;
|
|
5389
|
+
const { auth_url, state: expectedState } = response.data;
|
|
5390
|
+
if (!expectedState) {
|
|
5391
|
+
server.close();
|
|
5392
|
+
throw new Error("Authentication server did not return OAuth state");
|
|
5393
|
+
}
|
|
5173
5394
|
console.log(import_chalk.default.cyan("\nOpening browser for authentication..."));
|
|
5174
|
-
await (0, import_open.default)(auth_url);
|
|
5175
|
-
const authData = await new Promise((
|
|
5395
|
+
await (0, import_open.default)(assertSafeOpenUrl(auth_url));
|
|
5396
|
+
const authData = await new Promise((resolve14, reject) => {
|
|
5176
5397
|
const timeout = setTimeout(() => {
|
|
5177
5398
|
server.close();
|
|
5178
5399
|
reject(new Error("Authentication timeout. Please try again."));
|
|
@@ -5190,6 +5411,16 @@ async function authenticateWithBrowser() {
|
|
|
5190
5411
|
reject(new Error("Invalid callback parameters"));
|
|
5191
5412
|
return;
|
|
5192
5413
|
}
|
|
5414
|
+
try {
|
|
5415
|
+
verifyOAuthState(state, expectedState);
|
|
5416
|
+
} catch (stateErr) {
|
|
5417
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
5418
|
+
res.end("<h1>Authentication failed</h1><p>Invalid OAuth state.</p>");
|
|
5419
|
+
clearTimeout(timeout);
|
|
5420
|
+
server.close();
|
|
5421
|
+
reject(stateErr);
|
|
5422
|
+
return;
|
|
5423
|
+
}
|
|
5193
5424
|
try {
|
|
5194
5425
|
const callbackResponse = await request(`${API_BASE}/cli/auth/callback`, {
|
|
5195
5426
|
method: "POST",
|
|
@@ -5210,10 +5441,10 @@ async function authenticateWithBrowser() {
|
|
|
5210
5441
|
`);
|
|
5211
5442
|
clearTimeout(timeout);
|
|
5212
5443
|
server.close();
|
|
5213
|
-
|
|
5444
|
+
resolve14(data);
|
|
5214
5445
|
} catch (error) {
|
|
5215
5446
|
res.writeHead(500, { "Content-Type": "text/html" });
|
|
5216
|
-
res.end(`<h1>Authentication failed</h1><p>${error.message}</p>`);
|
|
5447
|
+
res.end(`<h1>Authentication failed</h1><p>${escapeHtml(error.message)}</p>`);
|
|
5217
5448
|
clearTimeout(timeout);
|
|
5218
5449
|
server.close();
|
|
5219
5450
|
reject(error);
|
|
@@ -5227,8 +5458,8 @@ async function authenticateWithBrowser() {
|
|
|
5227
5458
|
writeAuth(authData);
|
|
5228
5459
|
return authData;
|
|
5229
5460
|
}
|
|
5230
|
-
async function refreshToken() {
|
|
5231
|
-
const token =
|
|
5461
|
+
async function refreshToken(tokenOverride) {
|
|
5462
|
+
const token = tokenOverride || readAuth()?.token;
|
|
5232
5463
|
if (!token)
|
|
5233
5464
|
return false;
|
|
5234
5465
|
try {
|
|
@@ -5254,7 +5485,7 @@ async function refreshToken() {
|
|
|
5254
5485
|
}
|
|
5255
5486
|
}
|
|
5256
5487
|
async function checkSession() {
|
|
5257
|
-
const token =
|
|
5488
|
+
const token = await getValidToken();
|
|
5258
5489
|
if (!token)
|
|
5259
5490
|
return { valid: false };
|
|
5260
5491
|
try {
|
|
@@ -5280,6 +5511,8 @@ var init_auth = __esm({
|
|
|
5280
5511
|
import_chalk = __toESM(require_source());
|
|
5281
5512
|
import_open = __toESM(require_open());
|
|
5282
5513
|
init_config();
|
|
5514
|
+
init_version();
|
|
5515
|
+
init_auth_refresh();
|
|
5283
5516
|
}
|
|
5284
5517
|
});
|
|
5285
5518
|
|
|
@@ -5413,25 +5646,23 @@ function recordEvent(event, meta) {
|
|
|
5413
5646
|
if (!isTelemetryEnabled())
|
|
5414
5647
|
return;
|
|
5415
5648
|
try {
|
|
5416
|
-
|
|
5417
|
-
fs2.mkdirSync(TELEMETRY_DIR, { recursive: true });
|
|
5418
|
-
fs2.appendFileSync(TELEMETRY_FILE, JSON.stringify({
|
|
5649
|
+
appendSecureLine(TELEMETRY_FILE, JSON.stringify({
|
|
5419
5650
|
event,
|
|
5420
5651
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5421
5652
|
...meta
|
|
5422
|
-
}) + "\n");
|
|
5653
|
+
}) + "\n", TELEMETRY_DIR);
|
|
5423
5654
|
} catch {
|
|
5424
5655
|
}
|
|
5425
5656
|
}
|
|
5426
|
-
var
|
|
5657
|
+
var path3, os2, TELEMETRY_DIR, TELEMETRY_FILE;
|
|
5427
5658
|
var init_telemetry = __esm({
|
|
5428
5659
|
"src/lib/telemetry.ts"() {
|
|
5429
5660
|
"use strict";
|
|
5430
|
-
|
|
5431
|
-
path2 = __toESM(require("path"));
|
|
5661
|
+
path3 = __toESM(require("path"));
|
|
5432
5662
|
os2 = __toESM(require("os"));
|
|
5433
|
-
|
|
5434
|
-
|
|
5663
|
+
init_config();
|
|
5664
|
+
TELEMETRY_DIR = path3.join(os2.homedir(), ".hyv", "telemetry");
|
|
5665
|
+
TELEMETRY_FILE = path3.join(TELEMETRY_DIR, "events.jsonl");
|
|
5435
5666
|
}
|
|
5436
5667
|
});
|
|
5437
5668
|
|
|
@@ -5442,11 +5673,11 @@ __export(api_exports, {
|
|
|
5442
5673
|
apiPost: () => apiPost,
|
|
5443
5674
|
requireSubscription: () => requireSubscription
|
|
5444
5675
|
});
|
|
5445
|
-
async function request2(method,
|
|
5446
|
-
const token =
|
|
5676
|
+
async function request2(method, path24, body) {
|
|
5677
|
+
const token = await getValidToken();
|
|
5447
5678
|
if (!token)
|
|
5448
5679
|
throw new Error("you're not signed in yet. run: hyv init");
|
|
5449
|
-
const url = `${API_BASE}${
|
|
5680
|
+
const url = `${API_BASE}${path24}`;
|
|
5450
5681
|
const opts = {
|
|
5451
5682
|
method,
|
|
5452
5683
|
headers: {
|
|
@@ -5471,11 +5702,11 @@ async function request2(method, path23, body) {
|
|
|
5471
5702
|
}
|
|
5472
5703
|
return res.json();
|
|
5473
5704
|
}
|
|
5474
|
-
function apiGet(
|
|
5475
|
-
return request2("GET",
|
|
5705
|
+
function apiGet(path24) {
|
|
5706
|
+
return request2("GET", path24);
|
|
5476
5707
|
}
|
|
5477
|
-
function apiPost(
|
|
5478
|
-
return request2("POST",
|
|
5708
|
+
function apiPost(path24, body) {
|
|
5709
|
+
return request2("POST", path24, body);
|
|
5479
5710
|
}
|
|
5480
5711
|
async function requireSubscription() {
|
|
5481
5712
|
const { requirePaidFeature: requirePaidFeature2 } = await Promise.resolve().then(() => (init_access(), access_exports));
|
|
@@ -5485,6 +5716,7 @@ var init_api = __esm({
|
|
|
5485
5716
|
"src/lib/api.ts"() {
|
|
5486
5717
|
"use strict";
|
|
5487
5718
|
init_config();
|
|
5719
|
+
init_auth();
|
|
5488
5720
|
}
|
|
5489
5721
|
});
|
|
5490
5722
|
|
|
@@ -5679,7 +5911,7 @@ async function refreshInBackground(slug) {
|
|
|
5679
5911
|
}
|
|
5680
5912
|
}
|
|
5681
5913
|
function getDiskCachePath(slug) {
|
|
5682
|
-
return
|
|
5914
|
+
return path4.join(DISK_CACHE_DIR, `${slug.replace(/[^a-z0-9-]/gi, "_")}.json`);
|
|
5683
5915
|
}
|
|
5684
5916
|
function loadFromDiskCache(slug) {
|
|
5685
5917
|
try {
|
|
@@ -5718,18 +5950,18 @@ function buildMinimalProfile(slug, body) {
|
|
|
5718
5950
|
cadence: {}
|
|
5719
5951
|
};
|
|
5720
5952
|
}
|
|
5721
|
-
var fs3,
|
|
5953
|
+
var fs3, path4, os3, CACHE_TTL, memoryCache, DISK_CACHE_DIR;
|
|
5722
5954
|
var init_profile = __esm({
|
|
5723
5955
|
"src/lib/profile.ts"() {
|
|
5724
5956
|
"use strict";
|
|
5725
5957
|
init_api();
|
|
5726
5958
|
init_config();
|
|
5727
5959
|
fs3 = __toESM(require("fs"));
|
|
5728
|
-
|
|
5960
|
+
path4 = __toESM(require("path"));
|
|
5729
5961
|
os3 = __toESM(require("os"));
|
|
5730
5962
|
CACHE_TTL = 5 * 60 * 1e3;
|
|
5731
5963
|
memoryCache = /* @__PURE__ */ new Map();
|
|
5732
|
-
DISK_CACHE_DIR =
|
|
5964
|
+
DISK_CACHE_DIR = path4.join(os3.homedir(), ".hyv", "cache", "profiles");
|
|
5733
5965
|
}
|
|
5734
5966
|
});
|
|
5735
5967
|
|
|
@@ -5744,7 +5976,7 @@ __export(local_profile_exports, {
|
|
|
5744
5976
|
loadProfileFromDiskCache: () => loadProfileFromDiskCache
|
|
5745
5977
|
});
|
|
5746
5978
|
function cachePathForSlug(slug) {
|
|
5747
|
-
return
|
|
5979
|
+
return path5.join(DISK_CACHE_DIR2, `${slug.replace(/[^a-z0-9-]/gi, "_")}.json`);
|
|
5748
5980
|
}
|
|
5749
5981
|
function loadProfileFromDiskCache(slug) {
|
|
5750
5982
|
try {
|
|
@@ -5844,17 +6076,17 @@ function hasRichProfile(profile) {
|
|
|
5844
6076
|
return false;
|
|
5845
6077
|
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
6078
|
}
|
|
5847
|
-
var fs4,
|
|
6079
|
+
var fs4, path5, os4, DISK_CACHE_DIR2;
|
|
5848
6080
|
var init_local_profile = __esm({
|
|
5849
6081
|
"src/lib/local-profile.ts"() {
|
|
5850
6082
|
"use strict";
|
|
5851
6083
|
fs4 = __toESM(require("fs"));
|
|
5852
|
-
|
|
6084
|
+
path5 = __toESM(require("path"));
|
|
5853
6085
|
os4 = __toESM(require("os"));
|
|
5854
6086
|
init_config();
|
|
5855
6087
|
init_config();
|
|
5856
6088
|
init_profile();
|
|
5857
|
-
DISK_CACHE_DIR2 =
|
|
6089
|
+
DISK_CACHE_DIR2 = path5.join(os4.homedir(), ".hyv", "cache", "profiles");
|
|
5858
6090
|
}
|
|
5859
6091
|
});
|
|
5860
6092
|
|
|
@@ -5946,19 +6178,19 @@ var init_profile_parse = __esm({
|
|
|
5946
6178
|
function loadSupplementalPatterns() {
|
|
5947
6179
|
const p = path8.join(CACHE_DIR, "supplemental-rules.json");
|
|
5948
6180
|
try {
|
|
5949
|
-
if (!
|
|
6181
|
+
if (!fs7.existsSync(p))
|
|
5950
6182
|
return [];
|
|
5951
|
-
const data = JSON.parse(
|
|
6183
|
+
const data = JSON.parse(fs7.readFileSync(p, "utf-8"));
|
|
5952
6184
|
return Array.isArray(data.patterns) ? data.patterns : [];
|
|
5953
6185
|
} catch {
|
|
5954
6186
|
return [];
|
|
5955
6187
|
}
|
|
5956
6188
|
}
|
|
5957
|
-
var
|
|
6189
|
+
var fs7, path8, BUNDLED_MANIFEST;
|
|
5958
6190
|
var init_rules_loader = __esm({
|
|
5959
6191
|
"src/lib/rules-loader.ts"() {
|
|
5960
6192
|
"use strict";
|
|
5961
|
-
|
|
6193
|
+
fs7 = __toESM(require("fs"));
|
|
5962
6194
|
path8 = __toESM(require("path"));
|
|
5963
6195
|
init_config();
|
|
5964
6196
|
BUNDLED_MANIFEST = path8.resolve(__dirname, "..", "..", "assets", "detection-rules.json");
|
|
@@ -7047,7 +7279,7 @@ function runPipeline(text, profile, applyFixes = false) {
|
|
|
7047
7279
|
}
|
|
7048
7280
|
function readText(source) {
|
|
7049
7281
|
const fs25 = require("fs");
|
|
7050
|
-
const
|
|
7282
|
+
const path24 = require("path");
|
|
7051
7283
|
if (source === "-") {
|
|
7052
7284
|
if (process.stdin.isTTY) {
|
|
7053
7285
|
console.error("No input provided. Pipe content or specify a file.");
|
|
@@ -7055,7 +7287,7 @@ function readText(source) {
|
|
|
7055
7287
|
}
|
|
7056
7288
|
return { text: fs25.readFileSync(0, "utf-8"), path: "stdin" };
|
|
7057
7289
|
}
|
|
7058
|
-
const resolved =
|
|
7290
|
+
const resolved = path24.resolve(source);
|
|
7059
7291
|
if (!fs25.existsSync(resolved)) {
|
|
7060
7292
|
console.error(`File not found: ${resolved}`);
|
|
7061
7293
|
process.exit(1);
|
|
@@ -10561,7 +10793,7 @@ var {
|
|
|
10561
10793
|
} = import_index.default;
|
|
10562
10794
|
|
|
10563
10795
|
// src/index.ts
|
|
10564
|
-
var
|
|
10796
|
+
var import_chalk31 = __toESM(require_source());
|
|
10565
10797
|
|
|
10566
10798
|
// src/commands/init.ts
|
|
10567
10799
|
var import_chalk4 = __toESM(require_source());
|
|
@@ -10733,79 +10965,11 @@ init_config();
|
|
|
10733
10965
|
init_auth();
|
|
10734
10966
|
init_access();
|
|
10735
10967
|
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
|
-
}
|
|
10968
|
+
init_version();
|
|
10805
10969
|
|
|
10806
10970
|
// src/lib/queue-sync.ts
|
|
10807
10971
|
var import_chalk6 = __toESM(require_source());
|
|
10808
|
-
var
|
|
10972
|
+
var fs5 = __toESM(require("fs"));
|
|
10809
10973
|
var path6 = __toESM(require("path"));
|
|
10810
10974
|
init_config();
|
|
10811
10975
|
init_auth();
|
|
@@ -10815,34 +10979,34 @@ async function flushQueuedSignals() {
|
|
|
10815
10979
|
return { sent: 0, failed: 0 };
|
|
10816
10980
|
let sent = 0;
|
|
10817
10981
|
let failed = 0;
|
|
10818
|
-
if (!
|
|
10982
|
+
if (!fs5.existsSync(QUEUE_DIR))
|
|
10819
10983
|
return { sent: 0, failed: 0 };
|
|
10820
|
-
const files =
|
|
10984
|
+
const files = fs5.readdirSync(QUEUE_DIR).filter((f) => f.endsWith(".json"));
|
|
10821
10985
|
for (const file of files) {
|
|
10822
10986
|
const filePath = path6.join(QUEUE_DIR, file);
|
|
10823
10987
|
try {
|
|
10824
|
-
const signal = JSON.parse(
|
|
10988
|
+
const signal = JSON.parse(fs5.readFileSync(filePath, "utf-8"));
|
|
10825
10989
|
let ok = false;
|
|
10826
10990
|
if (signal.type === "reinforce") {
|
|
10827
|
-
const res = await authenticatedRequest("
|
|
10991
|
+
const res = await authenticatedRequest(cliApiUrl("/cli/learning/reinforce"), {
|
|
10828
10992
|
method: "POST",
|
|
10829
10993
|
body: {
|
|
10830
10994
|
profile_id: signal.profile,
|
|
10831
|
-
original_text: signal.report?.
|
|
10832
|
-
accepted_text: signal.report?.
|
|
10995
|
+
original_text: signal.original_text ?? signal.report?.original_text,
|
|
10996
|
+
accepted_text: signal.accepted_text ?? signal.report?.accepted_text,
|
|
10833
10997
|
signal_report: signal.report
|
|
10834
10998
|
}
|
|
10835
10999
|
});
|
|
10836
11000
|
ok = res.status === 200;
|
|
10837
11001
|
} else if (signal.type === "add_instruction") {
|
|
10838
|
-
const res = await authenticatedRequest("
|
|
11002
|
+
const res = await authenticatedRequest(cliApiUrl("/cli/learning/add"), {
|
|
10839
11003
|
method: "POST",
|
|
10840
11004
|
body: { profile_id: signal.profile, instruction: signal.instruction }
|
|
10841
11005
|
});
|
|
10842
11006
|
ok = res.status === 200;
|
|
10843
11007
|
}
|
|
10844
11008
|
if (ok) {
|
|
10845
|
-
|
|
11009
|
+
fs5.unlinkSync(filePath);
|
|
10846
11010
|
sent++;
|
|
10847
11011
|
} else {
|
|
10848
11012
|
failed++;
|
|
@@ -10971,7 +11135,7 @@ async function printEvolutionSummary(slug) {
|
|
|
10971
11135
|
return;
|
|
10972
11136
|
try {
|
|
10973
11137
|
const res = await authenticatedRequest(
|
|
10974
|
-
|
|
11138
|
+
cliApiUrl(`/cli/profiles/${encodeURIComponent(slug)}/evolution`),
|
|
10975
11139
|
{ method: "GET" }
|
|
10976
11140
|
);
|
|
10977
11141
|
if (res.status !== 200 || !res.data)
|
|
@@ -10999,7 +11163,7 @@ init_config();
|
|
|
10999
11163
|
init_auth();
|
|
11000
11164
|
init_access();
|
|
11001
11165
|
init_profile();
|
|
11002
|
-
var
|
|
11166
|
+
var fs6 = __toESM(require("fs"));
|
|
11003
11167
|
var path7 = __toESM(require("path"));
|
|
11004
11168
|
function registerSyncCommand(program3) {
|
|
11005
11169
|
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 +11171,7 @@ function registerSyncCommand(program3) {
|
|
|
11007
11171
|
await requirePaidFeature("profiles");
|
|
11008
11172
|
console.log(import_chalk8.default.cyan("Syncing profiles and rules..."));
|
|
11009
11173
|
const response = await authenticatedRequest(
|
|
11010
|
-
"
|
|
11174
|
+
cliApiUrl("/cli/sync"),
|
|
11011
11175
|
{ method: "GET" }
|
|
11012
11176
|
);
|
|
11013
11177
|
if (response.status !== 200) {
|
|
@@ -11023,12 +11187,12 @@ function registerSyncCommand(program3) {
|
|
|
11023
11187
|
profileCount++;
|
|
11024
11188
|
}
|
|
11025
11189
|
const rulesPath = path7.join(CACHE_DIR, "rules.md");
|
|
11026
|
-
|
|
11190
|
+
fs6.writeFileSync(rulesPath, data.rules, { mode: 384 });
|
|
11027
11191
|
const promptPath = path7.join(CACHE_DIR, "prompt-template.md");
|
|
11028
|
-
|
|
11192
|
+
fs6.writeFileSync(promptPath, data.prompt_template, { mode: 384 });
|
|
11029
11193
|
if (data.detection_rules) {
|
|
11030
11194
|
const rulesJson = path7.join(CACHE_DIR, "detection-rules.json");
|
|
11031
|
-
|
|
11195
|
+
fs6.writeFileSync(rulesJson, JSON.stringify(data.detection_rules, null, 2), { mode: 384 });
|
|
11032
11196
|
}
|
|
11033
11197
|
for (const profile of data.profiles) {
|
|
11034
11198
|
try {
|
|
@@ -11044,7 +11208,7 @@ function registerSyncCommand(program3) {
|
|
|
11044
11208
|
console.log(import_chalk8.default.yellow(` ! ${queueResult.failed} queued signal(s) could not send`));
|
|
11045
11209
|
}
|
|
11046
11210
|
const metaPath = path7.join(CACHE_DIR, "sync-meta.json");
|
|
11047
|
-
|
|
11211
|
+
fs6.writeFileSync(metaPath, JSON.stringify({
|
|
11048
11212
|
synced_at: data.synced_at,
|
|
11049
11213
|
profile_count: profileCount,
|
|
11050
11214
|
plan: data.plan
|
|
@@ -11120,7 +11284,7 @@ async function showProfileHistory(slug) {
|
|
|
11120
11284
|
return;
|
|
11121
11285
|
}
|
|
11122
11286
|
try {
|
|
11123
|
-
const res = await authenticatedRequest2(
|
|
11287
|
+
const res = await authenticatedRequest2(cliApiUrl(`/cli/profiles/${encodeURIComponent(slug)}/evolution`), { method: "GET" });
|
|
11124
11288
|
if (res.status !== 200) {
|
|
11125
11289
|
console.log(import_chalk8.default.red("Could not load profile history."));
|
|
11126
11290
|
return;
|
|
@@ -11149,12 +11313,12 @@ Profile evolution: ${slug}
|
|
|
11149
11313
|
|
|
11150
11314
|
// src/commands/rewrite.ts
|
|
11151
11315
|
var import_chalk9 = __toESM(require_source());
|
|
11152
|
-
var
|
|
11316
|
+
var fs9 = __toESM(require("fs"));
|
|
11153
11317
|
var path10 = __toESM(require("path"));
|
|
11154
11318
|
init_pipeline();
|
|
11155
11319
|
|
|
11156
11320
|
// src/lib/prompt.ts
|
|
11157
|
-
var
|
|
11321
|
+
var fs8 = __toESM(require("fs"));
|
|
11158
11322
|
var path9 = __toESM(require("path"));
|
|
11159
11323
|
init_config();
|
|
11160
11324
|
init_signals();
|
|
@@ -11162,8 +11326,8 @@ init_profile_parse();
|
|
|
11162
11326
|
function loadPromptTemplate() {
|
|
11163
11327
|
const templatePath = path9.join(CACHE_DIR, "prompt-template.md");
|
|
11164
11328
|
try {
|
|
11165
|
-
if (
|
|
11166
|
-
return
|
|
11329
|
+
if (fs8.existsSync(templatePath)) {
|
|
11330
|
+
return fs8.readFileSync(templatePath, "utf-8");
|
|
11167
11331
|
}
|
|
11168
11332
|
} catch {
|
|
11169
11333
|
}
|
|
@@ -11229,10 +11393,10 @@ function loadProfile(name) {
|
|
|
11229
11393
|
}
|
|
11230
11394
|
}
|
|
11231
11395
|
try {
|
|
11232
|
-
if (!
|
|
11396
|
+
if (!fs8.existsSync(PROFILES_DIR)) {
|
|
11233
11397
|
return null;
|
|
11234
11398
|
}
|
|
11235
|
-
const profiles =
|
|
11399
|
+
const profiles = fs8.readdirSync(PROFILES_DIR).filter((f) => f.endsWith(".md"));
|
|
11236
11400
|
if (profiles.length > 0) {
|
|
11237
11401
|
const defaultProfile = profiles[0].replace(".md", "");
|
|
11238
11402
|
const content = readCachedProfile(defaultProfile);
|
|
@@ -11364,7 +11528,7 @@ Draft: ${draftPath}`));
|
|
|
11364
11528
|
}
|
|
11365
11529
|
if (options.output) {
|
|
11366
11530
|
const outputPath = path10.resolve(options.output);
|
|
11367
|
-
|
|
11531
|
+
fs9.writeFileSync(outputPath, promptResult.prompt);
|
|
11368
11532
|
console.log(import_chalk9.default.green(`
|
|
11369
11533
|
\u2713 Prompt written to ${outputPath}`));
|
|
11370
11534
|
} else {
|
|
@@ -11384,7 +11548,7 @@ Draft: ${draftPath}`));
|
|
|
11384
11548
|
|
|
11385
11549
|
// src/commands/learning.ts
|
|
11386
11550
|
var import_chalk10 = __toESM(require_source());
|
|
11387
|
-
var
|
|
11551
|
+
var fs10 = __toESM(require("fs"));
|
|
11388
11552
|
var path11 = __toESM(require("path"));
|
|
11389
11553
|
|
|
11390
11554
|
// src/lib/patterns.ts
|
|
@@ -11889,16 +12053,16 @@ function registerLearningCommands(program3) {
|
|
|
11889
12053
|
}
|
|
11890
12054
|
origPath = path11.resolve(original);
|
|
11891
12055
|
editPath = path11.resolve(edited);
|
|
11892
|
-
if (!
|
|
12056
|
+
if (!fs10.existsSync(origPath)) {
|
|
11893
12057
|
console.error(import_chalk10.default.red(`Original file not found: ${origPath}`));
|
|
11894
12058
|
process.exit(1);
|
|
11895
12059
|
}
|
|
11896
|
-
if (!
|
|
12060
|
+
if (!fs10.existsSync(editPath)) {
|
|
11897
12061
|
console.error(import_chalk10.default.red(`Edited file not found: ${editPath}`));
|
|
11898
12062
|
process.exit(1);
|
|
11899
12063
|
}
|
|
11900
|
-
origText =
|
|
11901
|
-
editText =
|
|
12064
|
+
origText = fs10.readFileSync(origPath, "utf-8");
|
|
12065
|
+
editText = fs10.readFileSync(editPath, "utf-8");
|
|
11902
12066
|
saveLastEditSession({
|
|
11903
12067
|
original_path: origPath,
|
|
11904
12068
|
edited_path: editPath,
|
|
@@ -11914,6 +12078,8 @@ function registerLearningCommands(program3) {
|
|
|
11914
12078
|
queueSignal({
|
|
11915
12079
|
type: "reinforce",
|
|
11916
12080
|
profile: options.profile,
|
|
12081
|
+
original_text: origText,
|
|
12082
|
+
accepted_text: editText,
|
|
11917
12083
|
report,
|
|
11918
12084
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11919
12085
|
});
|
|
@@ -11927,6 +12093,8 @@ ${err.message}`));
|
|
|
11927
12093
|
queueSignal({
|
|
11928
12094
|
type: "reinforce",
|
|
11929
12095
|
profile: options.profile,
|
|
12096
|
+
original_text: origText,
|
|
12097
|
+
accepted_text: editText,
|
|
11930
12098
|
report,
|
|
11931
12099
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11932
12100
|
});
|
|
@@ -11939,6 +12107,8 @@ ${err.message}`));
|
|
|
11939
12107
|
queueSignal({
|
|
11940
12108
|
type: "reinforce",
|
|
11941
12109
|
profile: options.profile,
|
|
12110
|
+
original_text: origText,
|
|
12111
|
+
accepted_text: editText,
|
|
11942
12112
|
report,
|
|
11943
12113
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11944
12114
|
});
|
|
@@ -11946,7 +12116,7 @@ ${err.message}`));
|
|
|
11946
12116
|
}
|
|
11947
12117
|
console.log(import_chalk10.default.cyan("\nSending to server..."));
|
|
11948
12118
|
const response = await authenticatedRequest(
|
|
11949
|
-
"
|
|
12119
|
+
cliApiUrl("/cli/learning/reinforce"),
|
|
11950
12120
|
{
|
|
11951
12121
|
method: "POST",
|
|
11952
12122
|
body: {
|
|
@@ -11968,6 +12138,8 @@ ${err.message}`));
|
|
|
11968
12138
|
queueSignal({
|
|
11969
12139
|
type: "reinforce",
|
|
11970
12140
|
profile: options.profile,
|
|
12141
|
+
original_text: origText,
|
|
12142
|
+
accepted_text: editText,
|
|
11971
12143
|
report,
|
|
11972
12144
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11973
12145
|
});
|
|
@@ -11994,7 +12166,7 @@ ${err.message}`));
|
|
|
11994
12166
|
}
|
|
11995
12167
|
console.log(import_chalk10.default.cyan("Adding instruction..."));
|
|
11996
12168
|
const response = await authenticatedRequest(
|
|
11997
|
-
"
|
|
12169
|
+
cliApiUrl("/cli/learning/add"),
|
|
11998
12170
|
{
|
|
11999
12171
|
method: "POST",
|
|
12000
12172
|
body: {
|
|
@@ -12057,7 +12229,7 @@ function printProfileImpact(impact, data) {
|
|
|
12057
12229
|
|
|
12058
12230
|
// src/commands/onboarding.ts
|
|
12059
12231
|
var import_chalk11 = __toESM(require_source());
|
|
12060
|
-
var
|
|
12232
|
+
var fs11 = __toESM(require("fs"));
|
|
12061
12233
|
var path12 = __toESM(require("path"));
|
|
12062
12234
|
init_config();
|
|
12063
12235
|
init_auth();
|
|
@@ -12133,6 +12305,7 @@ function extractStats(samples) {
|
|
|
12133
12305
|
function registerOnboardingCommands(program3) {
|
|
12134
12306
|
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
12307
|
try {
|
|
12308
|
+
assertSafeProfileName(name);
|
|
12136
12309
|
const token = getToken();
|
|
12137
12310
|
if (options.fromSamples) {
|
|
12138
12311
|
await createFromSamples(name, options.fromSamples, token);
|
|
@@ -12147,6 +12320,7 @@ Error: ${error.message}`));
|
|
|
12147
12320
|
process.exit(1);
|
|
12148
12321
|
}
|
|
12149
12322
|
});
|
|
12323
|
+
registerImportCommand(program3);
|
|
12150
12324
|
}
|
|
12151
12325
|
async function flashcardOnboarding(name, token) {
|
|
12152
12326
|
const { printWelcome: printWelcome2 } = await Promise.resolve().then(() => (init_welcome(), welcome_exports));
|
|
@@ -12170,7 +12344,7 @@ Industry: ${industry}
|
|
|
12170
12344
|
if (token) {
|
|
12171
12345
|
console.log(import_chalk11.default.cyan("\nGenerating profile on server..."));
|
|
12172
12346
|
const response = await authenticatedRequest(
|
|
12173
|
-
"
|
|
12347
|
+
cliApiUrl("/cli/profiles/new"),
|
|
12174
12348
|
{
|
|
12175
12349
|
method: "POST",
|
|
12176
12350
|
body: {
|
|
@@ -12207,20 +12381,20 @@ Industry: ${industry}
|
|
|
12207
12381
|
}
|
|
12208
12382
|
async function createFromSamples(name, sampleDir, token) {
|
|
12209
12383
|
const dirPath = path12.resolve(sampleDir);
|
|
12210
|
-
if (!
|
|
12384
|
+
if (!fs11.existsSync(dirPath)) {
|
|
12211
12385
|
throw new Error(`Directory not found: ${dirPath}`);
|
|
12212
12386
|
}
|
|
12213
12387
|
console.log(import_chalk11.default.bold(`
|
|
12214
12388
|
Creating voice profile: ${name}`));
|
|
12215
12389
|
console.log(import_chalk11.default.dim(`Reading samples from: ${dirPath}
|
|
12216
12390
|
`));
|
|
12217
|
-
const files =
|
|
12391
|
+
const files = fs11.readdirSync(dirPath).filter((f) => f.endsWith(".md") || f.endsWith(".txt")).map((f) => path12.join(dirPath, f));
|
|
12218
12392
|
if (files.length === 0) {
|
|
12219
12393
|
throw new Error("No .md or .txt files found in directory");
|
|
12220
12394
|
}
|
|
12221
12395
|
const samples = [];
|
|
12222
12396
|
for (const file of files) {
|
|
12223
|
-
const text =
|
|
12397
|
+
const text = fs11.readFileSync(file, "utf-8");
|
|
12224
12398
|
if (text.trim().length > 0) {
|
|
12225
12399
|
samples.push({ path: file, text });
|
|
12226
12400
|
console.log(import_chalk11.default.dim(` \u2022 ${path12.basename(file)} (${words(text).length} words)`));
|
|
@@ -12240,7 +12414,7 @@ Stats extracted:`));
|
|
|
12240
12414
|
if (token) {
|
|
12241
12415
|
console.log(import_chalk11.default.cyan("\nGenerating profile on server..."));
|
|
12242
12416
|
const response = await authenticatedRequest(
|
|
12243
|
-
"
|
|
12417
|
+
cliApiUrl("/cli/profiles/new"),
|
|
12244
12418
|
{
|
|
12245
12419
|
method: "POST",
|
|
12246
12420
|
body: {
|
|
@@ -12290,17 +12464,37 @@ hyv import ${name} <file.md>
|
|
|
12290
12464
|
Or paste the profile content and I'll save it.`;
|
|
12291
12465
|
console.log(prompt);
|
|
12292
12466
|
}
|
|
12467
|
+
function registerImportCommand(program3) {
|
|
12468
|
+
program3.command("import").description("Import a voice profile from file").argument("<name>", "Profile name").argument("<file>", "Profile markdown file").action(async (name, file) => {
|
|
12469
|
+
try {
|
|
12470
|
+
assertSafeProfileName(name);
|
|
12471
|
+
const filePath = path12.resolve(file);
|
|
12472
|
+
if (!fs11.existsSync(filePath)) {
|
|
12473
|
+
console.error(import_chalk11.default.red(`File not found: ${filePath}`));
|
|
12474
|
+
process.exit(1);
|
|
12475
|
+
}
|
|
12476
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
12477
|
+
ensureHyvDir();
|
|
12478
|
+
writeCachedProfile(name, content);
|
|
12479
|
+
console.log(import_chalk11.default.green(`
|
|
12480
|
+
\u2713 Profile imported: ${name}`));
|
|
12481
|
+
} catch (error) {
|
|
12482
|
+
console.error(import_chalk11.default.red(`Error: ${error.message}`));
|
|
12483
|
+
process.exit(1);
|
|
12484
|
+
}
|
|
12485
|
+
});
|
|
12486
|
+
}
|
|
12293
12487
|
function askQuestion(question) {
|
|
12294
|
-
return new Promise((
|
|
12295
|
-
const
|
|
12296
|
-
const rl =
|
|
12488
|
+
return new Promise((resolve14) => {
|
|
12489
|
+
const readline2 = require("readline");
|
|
12490
|
+
const rl = readline2.createInterface({
|
|
12297
12491
|
input: process.stdin,
|
|
12298
12492
|
output: process.stdout
|
|
12299
12493
|
});
|
|
12300
12494
|
rl.question(import_chalk11.default.cyan(` ${question}
|
|
12301
12495
|
> `), (answer) => {
|
|
12302
12496
|
rl.close();
|
|
12303
|
-
|
|
12497
|
+
resolve14(answer.trim());
|
|
12304
12498
|
});
|
|
12305
12499
|
});
|
|
12306
12500
|
}
|
|
@@ -12404,7 +12598,7 @@ Error: ${error.message}`));
|
|
|
12404
12598
|
async function showPlan() {
|
|
12405
12599
|
console.log(import_chalk12.default.bold("\nSubscription Plan\n"));
|
|
12406
12600
|
const response = await authenticatedRequest(
|
|
12407
|
-
"
|
|
12601
|
+
cliApiUrl("/cli/heartbeat"),
|
|
12408
12602
|
{ method: "GET" }
|
|
12409
12603
|
);
|
|
12410
12604
|
if (response.status !== 200) {
|
|
@@ -12448,7 +12642,7 @@ async function showPlan() {
|
|
|
12448
12642
|
async function upgradePlan() {
|
|
12449
12643
|
console.log(import_chalk12.default.cyan("\nOpening checkout...\n"));
|
|
12450
12644
|
const response = await authenticatedRequest(
|
|
12451
|
-
"
|
|
12645
|
+
cliApiUrl("/cli/subscribe"),
|
|
12452
12646
|
{
|
|
12453
12647
|
method: "POST",
|
|
12454
12648
|
body: { plan: "individual" }
|
|
@@ -12459,7 +12653,7 @@ async function upgradePlan() {
|
|
|
12459
12653
|
const checkoutUrl = data.checkout_url;
|
|
12460
12654
|
if (checkoutUrl) {
|
|
12461
12655
|
console.log(import_chalk12.default.dim("Opening browser..."));
|
|
12462
|
-
await (0, import_open2.default)(checkoutUrl);
|
|
12656
|
+
await (0, import_open2.default)(assertSafeOpenUrl(checkoutUrl));
|
|
12463
12657
|
console.log(import_chalk12.default.green("\n\u2713 Checkout opened in browser"));
|
|
12464
12658
|
console.log(import_chalk12.default.dim("Complete the checkout to activate your plan."));
|
|
12465
12659
|
} else {
|
|
@@ -12473,7 +12667,7 @@ async function upgradePlan() {
|
|
|
12473
12667
|
async function openBillingPortal() {
|
|
12474
12668
|
console.log(import_chalk12.default.cyan("\nOpening billing portal...\n"));
|
|
12475
12669
|
const response = await authenticatedRequest(
|
|
12476
|
-
"
|
|
12670
|
+
cliApiUrl("/cli/subscribe/manage"),
|
|
12477
12671
|
{ method: "POST" }
|
|
12478
12672
|
);
|
|
12479
12673
|
if (response.status === 200) {
|
|
@@ -12481,7 +12675,7 @@ async function openBillingPortal() {
|
|
|
12481
12675
|
const portalUrl = data.portal_url;
|
|
12482
12676
|
if (portalUrl) {
|
|
12483
12677
|
console.log(import_chalk12.default.dim("Opening browser..."));
|
|
12484
|
-
await (0, import_open2.default)(portalUrl);
|
|
12678
|
+
await (0, import_open2.default)(assertSafeOpenUrl(portalUrl));
|
|
12485
12679
|
console.log(import_chalk12.default.green("\n\u2713 Billing portal opened"));
|
|
12486
12680
|
} else {
|
|
12487
12681
|
console.log(import_chalk12.default.yellow("No portal URL received."));
|
|
@@ -12663,7 +12857,7 @@ async function runHybridAnalysis(text, profile, opts = {}) {
|
|
|
12663
12857
|
|
|
12664
12858
|
// src/commands/history.ts
|
|
12665
12859
|
var import_chalk14 = __toESM(require_source());
|
|
12666
|
-
var
|
|
12860
|
+
var fs12 = __toESM(require("fs"));
|
|
12667
12861
|
var path13 = __toESM(require("path"));
|
|
12668
12862
|
init_config();
|
|
12669
12863
|
var HISTORY_DIR = path13.join(HYV_DIR, "history");
|
|
@@ -12671,17 +12865,15 @@ var HISTORY_FILE = path13.join(HISTORY_DIR, "scans.jsonl");
|
|
|
12671
12865
|
function logScan(entry) {
|
|
12672
12866
|
try {
|
|
12673
12867
|
ensureHyvDir();
|
|
12674
|
-
|
|
12675
|
-
fs13.mkdirSync(HISTORY_DIR, { recursive: true });
|
|
12676
|
-
fs13.appendFileSync(HISTORY_FILE, JSON.stringify(entry) + "\n");
|
|
12868
|
+
appendSecureLine(HISTORY_FILE, JSON.stringify(entry) + "\n", HISTORY_DIR);
|
|
12677
12869
|
} catch {
|
|
12678
12870
|
}
|
|
12679
12871
|
}
|
|
12680
12872
|
function readHistory() {
|
|
12681
12873
|
try {
|
|
12682
|
-
if (!
|
|
12874
|
+
if (!fs12.existsSync(HISTORY_FILE))
|
|
12683
12875
|
return [];
|
|
12684
|
-
const lines =
|
|
12876
|
+
const lines = fs12.readFileSync(HISTORY_FILE, "utf-8").trim().split("\n").filter(Boolean);
|
|
12685
12877
|
return lines.map((l) => JSON.parse(l));
|
|
12686
12878
|
} catch {
|
|
12687
12879
|
return [];
|
|
@@ -12713,8 +12905,8 @@ function registerHistoryCommand(program3) {
|
|
|
12713
12905
|
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
12906
|
try {
|
|
12715
12907
|
if (options.clear) {
|
|
12716
|
-
if (
|
|
12717
|
-
|
|
12908
|
+
if (fs12.existsSync(HISTORY_FILE)) {
|
|
12909
|
+
fs12.unlinkSync(HISTORY_FILE);
|
|
12718
12910
|
}
|
|
12719
12911
|
console.log(import_chalk14.default.green("\n\u2713 History cleared"));
|
|
12720
12912
|
return;
|
|
@@ -12869,7 +13061,7 @@ hyv scan ${filePath}`));
|
|
|
12869
13061
|
hasProfile: !!profile
|
|
12870
13062
|
});
|
|
12871
13063
|
if (options.failOnHit && signals.length > 0) {
|
|
12872
|
-
process.exit(
|
|
13064
|
+
process.exit(2);
|
|
12873
13065
|
}
|
|
12874
13066
|
} catch (error) {
|
|
12875
13067
|
console.error(import_chalk15.default.red(`Error: ${error.message}`));
|
|
@@ -12881,14 +13073,141 @@ hyv scan ${filePath}`));
|
|
|
12881
13073
|
// src/commands/doctor.ts
|
|
12882
13074
|
var import_chalk16 = __toESM(require_source());
|
|
12883
13075
|
var fs14 = __toESM(require("fs"));
|
|
12884
|
-
var
|
|
13076
|
+
var path15 = __toESM(require("path"));
|
|
12885
13077
|
var os5 = __toESM(require("os"));
|
|
12886
13078
|
init_config();
|
|
12887
13079
|
init_auth();
|
|
12888
13080
|
init_access();
|
|
12889
13081
|
init_local_profile();
|
|
13082
|
+
init_version();
|
|
13083
|
+
|
|
13084
|
+
// src/lib/mcp-stdio-test.ts
|
|
13085
|
+
var import_child_process2 = require("child_process");
|
|
13086
|
+
|
|
13087
|
+
// src/lib/cli-entry.ts
|
|
13088
|
+
var fs13 = __toESM(require("fs"));
|
|
13089
|
+
var path14 = __toESM(require("path"));
|
|
13090
|
+
function resolveCliEntry() {
|
|
13091
|
+
const candidates = [
|
|
13092
|
+
path14.resolve(process.argv[1] || ""),
|
|
13093
|
+
path14.resolve(__dirname, "index.js"),
|
|
13094
|
+
path14.resolve(__dirname, "..", "dist", "index.js")
|
|
13095
|
+
];
|
|
13096
|
+
return candidates.find((p) => p && fs13.existsSync(p)) || null;
|
|
13097
|
+
}
|
|
13098
|
+
function mcpServerCommand() {
|
|
13099
|
+
const entry = resolveCliEntry();
|
|
13100
|
+
if (entry) {
|
|
13101
|
+
return { command: process.execPath, args: [entry, "mcp"] };
|
|
13102
|
+
}
|
|
13103
|
+
return { command: "hyv", args: ["mcp"] };
|
|
13104
|
+
}
|
|
13105
|
+
function mcpServerSnippet() {
|
|
13106
|
+
const { command, args: args2 } = mcpServerCommand();
|
|
13107
|
+
return JSON.stringify({ command, args: args2 }, null, 2);
|
|
13108
|
+
}
|
|
13109
|
+
|
|
13110
|
+
// src/lib/mcp-stdio-test.ts
|
|
13111
|
+
async function testMcpStdioSubprocess() {
|
|
13112
|
+
const entry = resolveCliEntry();
|
|
13113
|
+
if (!entry)
|
|
13114
|
+
return { ok: false };
|
|
13115
|
+
return new Promise((resolve14) => {
|
|
13116
|
+
const child = (0, import_child_process2.spawn)(process.execPath, [entry, "mcp"], {
|
|
13117
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
13118
|
+
env: { ...process.env, HYV_POSTINSTALL_QUIET: "1" }
|
|
13119
|
+
});
|
|
13120
|
+
let buffer = "";
|
|
13121
|
+
let settled = false;
|
|
13122
|
+
const finish = (ok, toolCount) => {
|
|
13123
|
+
if (settled)
|
|
13124
|
+
return;
|
|
13125
|
+
settled = true;
|
|
13126
|
+
clearTimeout(timeout);
|
|
13127
|
+
try {
|
|
13128
|
+
child.kill();
|
|
13129
|
+
} catch {
|
|
13130
|
+
}
|
|
13131
|
+
resolve14({ ok, toolCount });
|
|
13132
|
+
};
|
|
13133
|
+
const timeout = setTimeout(() => finish(false), 1e4);
|
|
13134
|
+
const handleLine = (line) => {
|
|
13135
|
+
const trimmed = line.trim();
|
|
13136
|
+
if (!trimmed.startsWith("{"))
|
|
13137
|
+
return;
|
|
13138
|
+
try {
|
|
13139
|
+
const msg = JSON.parse(trimmed);
|
|
13140
|
+
if (msg.id === 2 && Array.isArray(msg.result?.tools) && msg.result.tools.length > 0) {
|
|
13141
|
+
finish(true, msg.result.tools.length);
|
|
13142
|
+
}
|
|
13143
|
+
} catch {
|
|
13144
|
+
}
|
|
13145
|
+
};
|
|
13146
|
+
child.stdout.on("data", (chunk) => {
|
|
13147
|
+
buffer += chunk.toString();
|
|
13148
|
+
const lines = buffer.split("\n");
|
|
13149
|
+
buffer = lines.pop() || "";
|
|
13150
|
+
for (const line of lines)
|
|
13151
|
+
handleLine(line);
|
|
13152
|
+
});
|
|
13153
|
+
child.on("error", () => finish(false));
|
|
13154
|
+
child.on("exit", () => {
|
|
13155
|
+
if (!settled) {
|
|
13156
|
+
handleLine(buffer);
|
|
13157
|
+
finish(buffer.includes("hyv_scan"));
|
|
13158
|
+
}
|
|
13159
|
+
});
|
|
13160
|
+
setTimeout(() => {
|
|
13161
|
+
const send2 = (payload) => {
|
|
13162
|
+
child.stdin.write(`${JSON.stringify(payload)}
|
|
13163
|
+
`);
|
|
13164
|
+
};
|
|
13165
|
+
send2({
|
|
13166
|
+
jsonrpc: "2.0",
|
|
13167
|
+
id: 1,
|
|
13168
|
+
method: "initialize",
|
|
13169
|
+
params: {
|
|
13170
|
+
protocolVersion: "2024-11-05",
|
|
13171
|
+
capabilities: {},
|
|
13172
|
+
clientInfo: { name: "hyv-self-test", version: "1.0" }
|
|
13173
|
+
}
|
|
13174
|
+
});
|
|
13175
|
+
send2({ jsonrpc: "2.0", method: "notifications/initialized" });
|
|
13176
|
+
send2({ jsonrpc: "2.0", id: 2, method: "tools/list", params: {} });
|
|
13177
|
+
}, 500);
|
|
13178
|
+
});
|
|
13179
|
+
}
|
|
13180
|
+
|
|
13181
|
+
// src/commands/doctor.ts
|
|
12890
13182
|
var HOME = os5.homedir();
|
|
12891
13183
|
var IS_WIN = process.platform === "win32";
|
|
13184
|
+
function claudeDesktopDir() {
|
|
13185
|
+
if (IS_WIN)
|
|
13186
|
+
return path15.join(HOME, "AppData", "Roaming", "Claude");
|
|
13187
|
+
if (process.platform === "linux")
|
|
13188
|
+
return path15.join(HOME, ".config", "Claude");
|
|
13189
|
+
return path15.join(HOME, "Library", "Application Support", "Claude");
|
|
13190
|
+
}
|
|
13191
|
+
function isOwnerOnlyFile(filePath) {
|
|
13192
|
+
try {
|
|
13193
|
+
if (!fs14.existsSync(filePath))
|
|
13194
|
+
return true;
|
|
13195
|
+
const mode = fs14.statSync(filePath).mode & 511;
|
|
13196
|
+
return (mode & 63) === 0;
|
|
13197
|
+
} catch {
|
|
13198
|
+
return false;
|
|
13199
|
+
}
|
|
13200
|
+
}
|
|
13201
|
+
function readMcpHyv(configFile) {
|
|
13202
|
+
try {
|
|
13203
|
+
if (!fs14.existsSync(configFile))
|
|
13204
|
+
return false;
|
|
13205
|
+
const cfg = JSON.parse(fs14.readFileSync(configFile, "utf-8"));
|
|
13206
|
+
return Boolean(cfg.mcpServers?.hyv);
|
|
13207
|
+
} catch {
|
|
13208
|
+
return false;
|
|
13209
|
+
}
|
|
13210
|
+
}
|
|
12892
13211
|
function registerDoctorCommand(program3) {
|
|
12893
13212
|
program3.command("doctor").description("Diagnose CLI health: engine, cache, auth, agents").option("--fix-agents", "Re-run agent config copy (idempotent)").action(async (opts) => {
|
|
12894
13213
|
console.log(import_chalk16.default.bold("\nhold your voice \u2014 doctor\n"));
|
|
@@ -12915,12 +13234,12 @@ function registerDoctorCommand(program3) {
|
|
|
12915
13234
|
console.log(import_chalk16.default.green(" \u2713 .hyv directory exists"));
|
|
12916
13235
|
} else {
|
|
12917
13236
|
console.log(import_chalk16.default.yellow(" ! .hyv directory missing \u2014 creating..."));
|
|
12918
|
-
fs14.mkdirSync(HYV_DIR, { recursive: true });
|
|
13237
|
+
fs14.mkdirSync(HYV_DIR, { recursive: true, mode: 448 });
|
|
12919
13238
|
fixed++;
|
|
12920
13239
|
}
|
|
12921
13240
|
console.log(import_chalk16.default.dim("checking cache..."));
|
|
12922
13241
|
const diskProfiles = listDiskCachedProfiles();
|
|
12923
|
-
const syncMeta =
|
|
13242
|
+
const syncMeta = path15.join(CACHE_DIR, "sync-meta.json");
|
|
12924
13243
|
if (diskProfiles.length > 0 || fs14.existsSync(syncMeta)) {
|
|
12925
13244
|
console.log(import_chalk16.default.green(` \u2713 profile cache (${diskProfiles.length} full profile(s))`));
|
|
12926
13245
|
if (fs14.existsSync(syncMeta)) {
|
|
@@ -12933,6 +13252,26 @@ function registerDoctorCommand(program3) {
|
|
|
12933
13252
|
} else {
|
|
12934
13253
|
console.log(import_chalk16.default.dim(" - no full profile cache (free local engine still works)"));
|
|
12935
13254
|
}
|
|
13255
|
+
console.log(import_chalk16.default.dim("checking file permissions..."));
|
|
13256
|
+
if (fs14.existsSync(HYV_DIR)) {
|
|
13257
|
+
const hyvMode = fs14.statSync(HYV_DIR).mode & 511;
|
|
13258
|
+
if ((hyvMode & 63) === 0) {
|
|
13259
|
+
console.log(import_chalk16.default.green(" \u2713 .hyv directory permissions"));
|
|
13260
|
+
} else {
|
|
13261
|
+
console.log(import_chalk16.default.yellow(" ! .hyv directory is world/group accessible"));
|
|
13262
|
+
console.log(import_chalk16.default.dim(" run: chmod 700 ~/.hyv"));
|
|
13263
|
+
issues++;
|
|
13264
|
+
}
|
|
13265
|
+
}
|
|
13266
|
+
if (fs14.existsSync(AUTH_FILE)) {
|
|
13267
|
+
if (isOwnerOnlyFile(AUTH_FILE)) {
|
|
13268
|
+
console.log(import_chalk16.default.green(" \u2713 auth.json permissions"));
|
|
13269
|
+
} else {
|
|
13270
|
+
console.log(import_chalk16.default.yellow(" ! auth.json is world/group readable"));
|
|
13271
|
+
console.log(import_chalk16.default.dim(" run: chmod 600 ~/.hyv/auth.json"));
|
|
13272
|
+
issues++;
|
|
13273
|
+
}
|
|
13274
|
+
}
|
|
12936
13275
|
console.log(import_chalk16.default.dim("checking authentication..."));
|
|
12937
13276
|
if (isInitialized()) {
|
|
12938
13277
|
const auth = readAuth();
|
|
@@ -12957,7 +13296,7 @@ function registerDoctorCommand(program3) {
|
|
|
12957
13296
|
console.log(import_chalk16.default.dim(" run: hyv init for profiles + learning"));
|
|
12958
13297
|
}
|
|
12959
13298
|
console.log(import_chalk16.default.dim("checking voice profile..."));
|
|
12960
|
-
const voiceMd =
|
|
13299
|
+
const voiceMd = path15.join(HYV_DIR, "voice.md");
|
|
12961
13300
|
const hasVoiceMd = fs14.existsSync(voiceMd) && fs14.readFileSync(voiceMd, "utf-8").trim().length > 50;
|
|
12962
13301
|
const profileFiles = fs14.existsSync(PROFILES_DIR) ? fs14.readdirSync(PROFILES_DIR).filter((f) => f.endsWith(".md") && f !== "voice.md") : [];
|
|
12963
13302
|
if (hasVoiceMd || profileFiles.length > 0 || diskProfiles.length > 0) {
|
|
@@ -12972,15 +13311,24 @@ function registerDoctorCommand(program3) {
|
|
|
12972
13311
|
console.log(import_chalk16.default.dim(" run: hyv new <name> or hyv init"));
|
|
12973
13312
|
}
|
|
12974
13313
|
console.log(import_chalk16.default.dim("checking agent configurations..."));
|
|
12975
|
-
const
|
|
12976
|
-
const
|
|
12977
|
-
|
|
12978
|
-
|
|
12979
|
-
|
|
12980
|
-
|
|
13314
|
+
const cursorLegacyRule = path15.join(HOME, ".cursor", "rules", "hyv.md");
|
|
13315
|
+
const cursorRule = path15.join(HOME, ".cursor", "rules", "hyv.mdc");
|
|
13316
|
+
if (fs14.existsSync(cursorLegacyRule) && fs14.existsSync(cursorRule)) {
|
|
13317
|
+
console.log(import_chalk16.default.yellow(" ! stale cursor rule ~/.cursor/rules/hyv.md (use hyv.mdc)"));
|
|
13318
|
+
console.log(import_chalk16.default.dim(" run: rm ~/.cursor/rules/hyv.md (or hyv doctor --fix-agents)"));
|
|
13319
|
+
issues++;
|
|
13320
|
+
}
|
|
13321
|
+
const agentChecks = [
|
|
13322
|
+
{ name: "claude desktop mcp", ok: readMcpHyv(path15.join(claudeDesktopDir(), "claude_desktop_config.json")) },
|
|
13323
|
+
{ name: "cursor mcp", ok: readMcpHyv(path15.join(HOME, ".cursor", "mcp.json")) },
|
|
13324
|
+
{ name: "cursor rule", ok: fs14.existsSync(cursorRule) },
|
|
13325
|
+
{ name: "claude code command", ok: fs14.existsSync(path15.join(HOME, ".claude", "commands", "hyv.md")) },
|
|
13326
|
+
{ name: "claude code skill", ok: fs14.existsSync(path15.join(HOME, ".claude", "skills", "hold-your-voice", "SKILL.md")) },
|
|
13327
|
+
{ name: "codex agents", ok: fs14.existsSync(path15.join(HOME, ".codex", "AGENTS.md")) && fs14.readFileSync(path15.join(HOME, ".codex", "AGENTS.md"), "utf-8").includes("hyv") },
|
|
13328
|
+
{ name: "command code skill", ok: fs14.existsSync(path15.join(HOME, ".commandcode", "skills", "hyv", "SKILL.md")) }
|
|
12981
13329
|
];
|
|
12982
|
-
for (const agent of
|
|
12983
|
-
if (
|
|
13330
|
+
for (const agent of agentChecks) {
|
|
13331
|
+
if (agent.ok) {
|
|
12984
13332
|
console.log(import_chalk16.default.green(` \u2713 ${agent.name}`));
|
|
12985
13333
|
} else {
|
|
12986
13334
|
console.log(import_chalk16.default.dim(` - ${agent.name} not configured`));
|
|
@@ -12988,35 +13336,45 @@ function registerDoctorCommand(program3) {
|
|
|
12988
13336
|
}
|
|
12989
13337
|
if (opts.fixAgents) {
|
|
12990
13338
|
try {
|
|
12991
|
-
const
|
|
12992
|
-
|
|
12993
|
-
|
|
12994
|
-
|
|
12995
|
-
|
|
12996
|
-
|
|
12997
|
-
|
|
12998
|
-
|
|
13339
|
+
const pkgDir = path15.resolve(__dirname, "..");
|
|
13340
|
+
const { setupAgents } = require(path15.join(pkgDir, "scripts", "postinstall-lib.js"));
|
|
13341
|
+
const result = setupAgents({ pkgDir, quiet: true });
|
|
13342
|
+
console.log(import_chalk16.default.green(` \u2713 re-ran agent setup (${result.configured.join(", ") || "no changes"})`));
|
|
13343
|
+
if (result.warnings.length) {
|
|
13344
|
+
console.log(import_chalk16.default.yellow(` notes: ${result.warnings.join("; ")}`));
|
|
13345
|
+
}
|
|
13346
|
+
fixed++;
|
|
13347
|
+
} catch (err) {
|
|
13348
|
+
console.log(import_chalk16.default.yellow(` ! could not re-run agent setup: ${err.message}`));
|
|
12999
13349
|
}
|
|
13000
13350
|
}
|
|
13001
13351
|
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
|
-
}
|
|
13352
|
+
const claudeMcp = readMcpHyv(path15.join(claudeDesktopDir(), "claude_desktop_config.json"));
|
|
13353
|
+
const cursorMcp = readMcpHyv(path15.join(HOME, ".cursor", "mcp.json"));
|
|
13354
|
+
if (claudeMcp || cursorMcp) {
|
|
13355
|
+
if (claudeMcp)
|
|
13356
|
+
console.log(import_chalk16.default.green(" \u2713 mcp configured for claude desktop"));
|
|
13357
|
+
if (cursorMcp)
|
|
13358
|
+
console.log(import_chalk16.default.green(" \u2713 mcp configured for cursor"));
|
|
13018
13359
|
} else {
|
|
13019
|
-
console.log(import_chalk16.default.
|
|
13360
|
+
console.log(import_chalk16.default.yellow(" ! mcp not configured \u2014 run: hyv doctor --fix-agents or hyv mcp --setup"));
|
|
13361
|
+
issues++;
|
|
13362
|
+
}
|
|
13363
|
+
try {
|
|
13364
|
+
const stdio = await testMcpStdioSubprocess();
|
|
13365
|
+
if (stdio.ok && (stdio.toolCount || 0) >= 10) {
|
|
13366
|
+
console.log(import_chalk16.default.green(` \u2713 mcp stdio subprocess healthy (${stdio.toolCount} tools)`));
|
|
13367
|
+
} else if (stdio.ok) {
|
|
13368
|
+
console.log(import_chalk16.default.yellow(` ! mcp stdio ok but only ${stdio.toolCount || 0} tools`));
|
|
13369
|
+
issues++;
|
|
13370
|
+
} else {
|
|
13371
|
+
console.log(import_chalk16.default.red(" \u2717 mcp stdio subprocess failed"));
|
|
13372
|
+
console.log(import_chalk16.default.dim(" run: hyv mcp --test"));
|
|
13373
|
+
issues++;
|
|
13374
|
+
}
|
|
13375
|
+
} catch (err) {
|
|
13376
|
+
console.log(import_chalk16.default.red(` \u2717 mcp stdio probe failed: ${err.message}`));
|
|
13377
|
+
issues++;
|
|
13020
13378
|
}
|
|
13021
13379
|
console.log("");
|
|
13022
13380
|
if (issues === 0 && fixed === 0) {
|
|
@@ -13065,7 +13423,7 @@ function registerRenameCommand(program3) {
|
|
|
13065
13423
|
return;
|
|
13066
13424
|
}
|
|
13067
13425
|
const response = await authenticatedRequest(
|
|
13068
|
-
"
|
|
13426
|
+
cliApiUrl("/cli/profiles/rename"),
|
|
13069
13427
|
{
|
|
13070
13428
|
method: "POST",
|
|
13071
13429
|
body: {
|
|
@@ -13094,15 +13452,51 @@ error: ${error.message}
|
|
|
13094
13452
|
}
|
|
13095
13453
|
|
|
13096
13454
|
// src/commands/fix.ts
|
|
13097
|
-
var
|
|
13098
|
-
var fs15 = __toESM(require("fs"));
|
|
13099
|
-
var path15 = __toESM(require("path"));
|
|
13455
|
+
var import_chalk19 = __toESM(require_source());
|
|
13100
13456
|
init_pipeline();
|
|
13101
13457
|
init_local_profile();
|
|
13102
13458
|
init_access();
|
|
13103
13459
|
init_config();
|
|
13460
|
+
|
|
13461
|
+
// src/lib/destructive-write.ts
|
|
13462
|
+
var fs15 = __toESM(require("fs"));
|
|
13463
|
+
var path16 = __toESM(require("path"));
|
|
13464
|
+
var readline = __toESM(require("readline"));
|
|
13465
|
+
var import_chalk18 = __toESM(require_source());
|
|
13466
|
+
async function confirmDestructiveWrite(options) {
|
|
13467
|
+
if (options.yes)
|
|
13468
|
+
return true;
|
|
13469
|
+
const label = options.target ? `${options.action} (${options.target})` : options.action;
|
|
13470
|
+
if (!process.stdin.isTTY) {
|
|
13471
|
+
console.error(import_chalk18.default.red("\nRefusing destructive write without confirmation (non-interactive)."));
|
|
13472
|
+
console.error(import_chalk18.default.dim(" Re-run with --yes to create .bak backups and proceed.\n"));
|
|
13473
|
+
return false;
|
|
13474
|
+
}
|
|
13475
|
+
const question = `
|
|
13476
|
+
${label}
|
|
13477
|
+
A .bak backup will be created. Proceed? [y/N] `;
|
|
13478
|
+
const answer = await new Promise((resolve14) => {
|
|
13479
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
13480
|
+
rl.question(question, (value) => {
|
|
13481
|
+
rl.close();
|
|
13482
|
+
resolve14(value.trim().toLowerCase());
|
|
13483
|
+
});
|
|
13484
|
+
});
|
|
13485
|
+
return answer === "y" || answer === "yes";
|
|
13486
|
+
}
|
|
13487
|
+
function writeInPlaceWithBackup(filePath, content) {
|
|
13488
|
+
const backupPath = filePath + ".bak";
|
|
13489
|
+
fs15.copyFileSync(filePath, backupPath);
|
|
13490
|
+
fs15.writeFileSync(filePath, content);
|
|
13491
|
+
return backupPath;
|
|
13492
|
+
}
|
|
13493
|
+
function backupBasename(filePath) {
|
|
13494
|
+
return path16.basename(filePath) + ".bak";
|
|
13495
|
+
}
|
|
13496
|
+
|
|
13497
|
+
// src/commands/fix.ts
|
|
13104
13498
|
function registerFixCommand(program3) {
|
|
13105
|
-
program3.command("fix").description("Apply auto-fixes (word swaps, connector removals) without an LLM").argument("<file>", "File to fix (or - for stdin)").option("--dry-run", "Show changes without writing").option("-i, --in-place", "Write fixes back to the file").option("--profile <name>", "Voice profile for never-list checks").option("--ignore <rules>", "Comma-separated rule IDs to skip").option("--format <type>", "Output format (text or json)", "text").action(async (file, options) => {
|
|
13499
|
+
program3.command("fix").description("Apply auto-fixes (word swaps, connector removals) without an LLM").argument("<file>", "File to fix (or - for stdin)").option("--dry-run", "Show changes without writing").option("-i, --in-place", "Write fixes back to the file").option("-y, --yes", "Confirm in-place write without prompting (creates .bak backup)").option("--profile <name>", "Voice profile for never-list checks").option("--ignore <rules>", "Comma-separated rule IDs to skip").option("--format <type>", "Output format (text or json)", "text").action(async (file, options) => {
|
|
13106
13500
|
try {
|
|
13107
13501
|
const profile = await loadProfileForCommand(options.profile);
|
|
13108
13502
|
const { text, path: filePath } = readText(file);
|
|
@@ -13111,9 +13505,9 @@ function registerFixCommand(program3) {
|
|
|
13111
13505
|
if (options.format === "json") {
|
|
13112
13506
|
console.log(JSON.stringify({ file: filePath, autoFixes: 0, llmIssues: result.stats.needsLLM, changes: [] }));
|
|
13113
13507
|
} else {
|
|
13114
|
-
console.log(
|
|
13508
|
+
console.log(import_chalk19.default.green("\n\u2713 No auto-fixable issues found."));
|
|
13115
13509
|
if (result.stats.needsLLM > 0) {
|
|
13116
|
-
console.log(
|
|
13510
|
+
console.log(import_chalk19.default.dim(` ${result.stats.needsLLM} issues need LLM rewrite \u2014 run: hyv rewrite ${file}`));
|
|
13117
13511
|
}
|
|
13118
13512
|
}
|
|
13119
13513
|
return;
|
|
@@ -13127,24 +13521,30 @@ function registerFixCommand(program3) {
|
|
|
13127
13521
|
fixed: options.dryRun ? void 0 : result.fixed
|
|
13128
13522
|
}, null, 2));
|
|
13129
13523
|
} else {
|
|
13130
|
-
console.log(
|
|
13524
|
+
console.log(import_chalk19.default.dim(`
|
|
13131
13525
|
hyv fix ${filePath}
|
|
13132
13526
|
`));
|
|
13133
13527
|
for (const change of result.changes) {
|
|
13134
|
-
console.log(
|
|
13528
|
+
console.log(import_chalk19.default.dim(` Line ${change.line}: `) + import_chalk19.default.red(change.before) + import_chalk19.default.dim(" \u2192 ") + import_chalk19.default.green(change.after));
|
|
13135
13529
|
}
|
|
13136
|
-
console.log(
|
|
13530
|
+
console.log(import_chalk19.default.green(`
|
|
13137
13531
|
\u2713 ${result.changes.length} auto-fix${result.changes.length === 1 ? "" : "es"} applied`));
|
|
13138
13532
|
if (result.stats.needsLLM > 0) {
|
|
13139
|
-
console.log(
|
|
13533
|
+
console.log(import_chalk19.default.dim(` ${result.stats.needsLLM} issues need LLM rewrite \u2014 run: hyv rewrite ${file}`));
|
|
13140
13534
|
}
|
|
13141
13535
|
}
|
|
13142
13536
|
if (!options.dryRun) {
|
|
13143
13537
|
if (options.inPlace && filePath !== "stdin") {
|
|
13144
|
-
const
|
|
13145
|
-
|
|
13146
|
-
|
|
13147
|
-
|
|
13538
|
+
const confirmed = await confirmDestructiveWrite({
|
|
13539
|
+
yes: options.yes,
|
|
13540
|
+
action: "Apply auto-fixes in-place",
|
|
13541
|
+
target: filePath
|
|
13542
|
+
});
|
|
13543
|
+
if (!confirmed) {
|
|
13544
|
+
process.exit(1);
|
|
13545
|
+
}
|
|
13546
|
+
const backupPath = writeInPlaceWithBackup(filePath, result.fixed);
|
|
13547
|
+
console.log(import_chalk19.default.dim(` Written to ${filePath} (backup: ${backupBasename(filePath)})`));
|
|
13148
13548
|
saveLastEditSession({
|
|
13149
13549
|
original_path: filePath,
|
|
13150
13550
|
edited_path: filePath,
|
|
@@ -13152,7 +13552,7 @@ hyv fix ${filePath}
|
|
|
13152
13552
|
edited_text: result.fixed,
|
|
13153
13553
|
profile: options.profile
|
|
13154
13554
|
});
|
|
13155
|
-
console.log(
|
|
13555
|
+
console.log(import_chalk19.default.dim(" Tip: hyv reinforce --last to teach your profile from this edit"));
|
|
13156
13556
|
} else if (filePath === "stdin" || !options.inPlace) {
|
|
13157
13557
|
process.stdout.write("\n" + result.fixed + "\n");
|
|
13158
13558
|
if (filePath !== "stdin") {
|
|
@@ -13168,14 +13568,14 @@ hyv fix ${filePath}
|
|
|
13168
13568
|
}
|
|
13169
13569
|
await maybeShowLimitedModeHint(!!profile);
|
|
13170
13570
|
} catch (error) {
|
|
13171
|
-
console.error(
|
|
13571
|
+
console.error(import_chalk19.default.red(`Error: ${error.message}`));
|
|
13172
13572
|
process.exit(1);
|
|
13173
13573
|
}
|
|
13174
13574
|
});
|
|
13175
13575
|
}
|
|
13176
13576
|
|
|
13177
13577
|
// src/commands/check.ts
|
|
13178
|
-
var
|
|
13578
|
+
var import_chalk20 = __toESM(require_source());
|
|
13179
13579
|
init_pipeline();
|
|
13180
13580
|
init_local_profile();
|
|
13181
13581
|
init_access();
|
|
@@ -13187,18 +13587,18 @@ function registerCheckCommand(program3) {
|
|
|
13187
13587
|
if (text === "-") {
|
|
13188
13588
|
const fs26 = require("fs");
|
|
13189
13589
|
if (process.stdin.isTTY) {
|
|
13190
|
-
console.error(
|
|
13590
|
+
console.error(import_chalk20.default.red("No input provided. Pipe content or pass text as argument."));
|
|
13191
13591
|
process.exit(1);
|
|
13192
13592
|
}
|
|
13193
13593
|
inputText = fs26.readFileSync(0, "utf-8");
|
|
13194
13594
|
}
|
|
13195
13595
|
if (!inputText.trim()) {
|
|
13196
|
-
console.error(
|
|
13596
|
+
console.error(import_chalk20.default.red("No text provided."));
|
|
13197
13597
|
process.exit(1);
|
|
13198
13598
|
}
|
|
13199
13599
|
const fs25 = require("fs");
|
|
13200
13600
|
if (text !== "-" && fs25.existsSync(text)) {
|
|
13201
|
-
console.log(
|
|
13601
|
+
console.log(import_chalk20.default.yellow(`"${text}" looks like a file. Did you mean: hyv scan ${text}`));
|
|
13202
13602
|
process.exit(1);
|
|
13203
13603
|
}
|
|
13204
13604
|
const result = runPipeline(inputText, profile, false);
|
|
@@ -13222,30 +13622,30 @@ function registerCheckCommand(program3) {
|
|
|
13222
13622
|
}, null, 2));
|
|
13223
13623
|
} else {
|
|
13224
13624
|
if (result.stats.totalSignals === 0) {
|
|
13225
|
-
console.log(
|
|
13226
|
-
console.log(
|
|
13625
|
+
console.log(import_chalk20.default.green("\n\u2713 Clean \u2014 no AI patterns found."));
|
|
13626
|
+
console.log(import_chalk20.default.dim(` score: ${result.score}/100`));
|
|
13227
13627
|
} else {
|
|
13228
13628
|
console.log("");
|
|
13229
13629
|
printGroupedSignals(result.signalMap.signals.slice(0, 15), profile);
|
|
13230
13630
|
if (result.signalMap.signals.length > 15) {
|
|
13231
|
-
console.log(
|
|
13631
|
+
console.log(import_chalk20.default.dim(` ... and ${result.signalMap.signals.length - 15} more`));
|
|
13232
13632
|
}
|
|
13233
|
-
console.log(
|
|
13633
|
+
console.log(import_chalk20.default.yellow(`
|
|
13234
13634
|
${result.stats.totalSignals} issues (${result.stats.red} red, ${result.stats.yellow} yellow)`));
|
|
13235
|
-
console.log(
|
|
13635
|
+
console.log(import_chalk20.default.dim(` score: ${result.score}/100`));
|
|
13236
13636
|
}
|
|
13237
13637
|
await maybeShowLimitedModeHint(!!profile);
|
|
13238
13638
|
}
|
|
13239
13639
|
process.exit(result.stats.totalSignals > 0 ? 1 : 0);
|
|
13240
13640
|
} catch (error) {
|
|
13241
|
-
console.error(
|
|
13641
|
+
console.error(import_chalk20.default.red(`Error: ${error.message}`));
|
|
13242
13642
|
process.exit(1);
|
|
13243
13643
|
}
|
|
13244
13644
|
});
|
|
13245
13645
|
}
|
|
13246
13646
|
|
|
13247
13647
|
// src/commands/score.ts
|
|
13248
|
-
var
|
|
13648
|
+
var import_chalk21 = __toESM(require_source());
|
|
13249
13649
|
init_pipeline();
|
|
13250
13650
|
init_local_profile();
|
|
13251
13651
|
function registerScoreCommand(program3) {
|
|
@@ -13270,14 +13670,14 @@ function registerScoreCommand(program3) {
|
|
|
13270
13670
|
process.exit(1);
|
|
13271
13671
|
}
|
|
13272
13672
|
} catch (error) {
|
|
13273
|
-
console.error(
|
|
13673
|
+
console.error(import_chalk21.default.red(`Error: ${error.message}`));
|
|
13274
13674
|
process.exit(1);
|
|
13275
13675
|
}
|
|
13276
13676
|
});
|
|
13277
13677
|
}
|
|
13278
13678
|
|
|
13279
13679
|
// src/commands/diff.ts
|
|
13280
|
-
var
|
|
13680
|
+
var import_chalk22 = __toESM(require_source());
|
|
13281
13681
|
init_pipeline();
|
|
13282
13682
|
init_local_profile();
|
|
13283
13683
|
function registerDiffCommand(program3) {
|
|
@@ -13287,9 +13687,9 @@ function registerDiffCommand(program3) {
|
|
|
13287
13687
|
const { text, path: filePath } = readText(file);
|
|
13288
13688
|
const result = runPipeline(text, profile, true);
|
|
13289
13689
|
if (result.changes.length === 0) {
|
|
13290
|
-
console.log(
|
|
13690
|
+
console.log(import_chalk22.default.green("\n\u2713 No auto-fixable changes."));
|
|
13291
13691
|
if (result.stats.needsLLM > 0) {
|
|
13292
|
-
console.log(
|
|
13692
|
+
console.log(import_chalk22.default.dim(` ${result.stats.needsLLM} issues need LLM rewrite`));
|
|
13293
13693
|
}
|
|
13294
13694
|
return;
|
|
13295
13695
|
}
|
|
@@ -13304,42 +13704,42 @@ function registerDiffCommand(program3) {
|
|
|
13304
13704
|
const originalLines = text.split("\n");
|
|
13305
13705
|
const fixedLines = result.fixed.split("\n");
|
|
13306
13706
|
const contextN = parseInt(options.context, 10);
|
|
13307
|
-
console.log(
|
|
13308
|
-
console.log(
|
|
13707
|
+
console.log(import_chalk22.default.dim(`--- ${filePath}`));
|
|
13708
|
+
console.log(import_chalk22.default.dim(`+++ ${filePath} (fixed)`));
|
|
13309
13709
|
for (const change of result.changes) {
|
|
13310
13710
|
const lineIdx = change.line - 1;
|
|
13311
13711
|
const start = Math.max(0, lineIdx - contextN);
|
|
13312
13712
|
const end = Math.min(originalLines.length, lineIdx + contextN + 1);
|
|
13313
|
-
console.log(
|
|
13713
|
+
console.log(import_chalk22.default.dim(`@@ -${start + 1},${end - start} +${start + 1},${end - start} @@`));
|
|
13314
13714
|
for (let i = start; i < end; i++) {
|
|
13315
13715
|
if (i === lineIdx) {
|
|
13316
|
-
console.log(
|
|
13317
|
-
console.log(
|
|
13716
|
+
console.log(import_chalk22.default.red(`-${originalLines[i]}`));
|
|
13717
|
+
console.log(import_chalk22.default.green(`+${fixedLines[i]}`));
|
|
13318
13718
|
} else {
|
|
13319
|
-
console.log(
|
|
13719
|
+
console.log(import_chalk22.default.dim(` ${originalLines[i]}`));
|
|
13320
13720
|
}
|
|
13321
13721
|
}
|
|
13322
13722
|
}
|
|
13323
|
-
console.log(
|
|
13723
|
+
console.log(import_chalk22.default.green(`
|
|
13324
13724
|
${result.changes.length} auto-fix${result.changes.length === 1 ? "" : "es"} available`));
|
|
13325
|
-
console.log(
|
|
13725
|
+
console.log(import_chalk22.default.dim(` run: hyv fix ${file} -i to apply`));
|
|
13326
13726
|
if (options.apply && filePath !== "stdin") {
|
|
13327
13727
|
const fs25 = require("fs");
|
|
13328
|
-
const
|
|
13728
|
+
const path24 = require("path");
|
|
13329
13729
|
const backupPath = filePath + ".bak";
|
|
13330
13730
|
fs25.copyFileSync(filePath, backupPath);
|
|
13331
13731
|
fs25.writeFileSync(filePath, result.fixed);
|
|
13332
|
-
console.log(
|
|
13732
|
+
console.log(import_chalk22.default.green(` \u2713 Applied. Backup: ${path24.basename(backupPath)}`));
|
|
13333
13733
|
}
|
|
13334
13734
|
} catch (error) {
|
|
13335
|
-
console.error(
|
|
13735
|
+
console.error(import_chalk22.default.red(`Error: ${error.message}`));
|
|
13336
13736
|
process.exit(1);
|
|
13337
13737
|
}
|
|
13338
13738
|
});
|
|
13339
13739
|
}
|
|
13340
13740
|
|
|
13341
13741
|
// src/commands/rules.ts
|
|
13342
|
-
var
|
|
13742
|
+
var import_chalk23 = __toESM(require_source());
|
|
13343
13743
|
init_config();
|
|
13344
13744
|
var RULE_CATALOG = [
|
|
13345
13745
|
// AI Overused Words
|
|
@@ -13433,7 +13833,7 @@ function registerRulesCommand(program3) {
|
|
|
13433
13833
|
for (const id of ids)
|
|
13434
13834
|
disabledRules.delete(id);
|
|
13435
13835
|
writeConfig({ ...config, disabled_rules: [...disabledRules] });
|
|
13436
|
-
console.log(
|
|
13836
|
+
console.log(import_chalk23.default.green(`
|
|
13437
13837
|
\u2713 Enabled: ${ids.join(", ")}`));
|
|
13438
13838
|
return;
|
|
13439
13839
|
}
|
|
@@ -13442,13 +13842,13 @@ function registerRulesCommand(program3) {
|
|
|
13442
13842
|
for (const id of ids)
|
|
13443
13843
|
disabledRules.add(id);
|
|
13444
13844
|
writeConfig({ ...config, disabled_rules: [...disabledRules] });
|
|
13445
|
-
console.log(
|
|
13845
|
+
console.log(import_chalk23.default.green(`
|
|
13446
13846
|
\u2713 Disabled: ${ids.join(", ")}`));
|
|
13447
13847
|
return;
|
|
13448
13848
|
}
|
|
13449
13849
|
if (options.reset) {
|
|
13450
13850
|
writeConfig({ ...config, disabled_rules: [] });
|
|
13451
|
-
console.log(
|
|
13851
|
+
console.log(import_chalk23.default.green("\n\u2713 All rules reset to default (enabled)"));
|
|
13452
13852
|
return;
|
|
13453
13853
|
}
|
|
13454
13854
|
let rules = [...RULE_CATALOG];
|
|
@@ -13476,40 +13876,40 @@ function registerRulesCommand(program3) {
|
|
|
13476
13876
|
}
|
|
13477
13877
|
console.log("");
|
|
13478
13878
|
for (const [cat, catRules] of categories) {
|
|
13479
|
-
console.log(
|
|
13879
|
+
console.log(import_chalk23.default.bold(` ${cat} rules (${catRules.length})
|
|
13480
13880
|
`));
|
|
13481
|
-
console.log(
|
|
13482
|
-
console.log(
|
|
13881
|
+
console.log(import_chalk23.default.dim(" ID Sev AutoFix Status"));
|
|
13882
|
+
console.log(import_chalk23.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
13483
13883
|
for (const rule of catRules) {
|
|
13484
|
-
const sev = rule.severity === "red" ?
|
|
13485
|
-
const fix = rule.autoFixable ?
|
|
13486
|
-
const enabled2 = disabledRules.has(rule.id) ?
|
|
13884
|
+
const sev = rule.severity === "red" ? import_chalk23.default.red("red") : import_chalk23.default.yellow("yel");
|
|
13885
|
+
const fix = rule.autoFixable ? import_chalk23.default.green(" \u2713") : import_chalk23.default.dim(" \u2717");
|
|
13886
|
+
const enabled2 = disabledRules.has(rule.id) ? import_chalk23.default.red(" \u2717 disabled") : import_chalk23.default.green(" \u2713 enabled");
|
|
13487
13887
|
const id = rule.id.padEnd(24);
|
|
13488
|
-
console.log(` ${
|
|
13888
|
+
console.log(` ${import_chalk23.default.dim(id)} ${sev} ${fix} ${enabled2}`);
|
|
13489
13889
|
}
|
|
13490
13890
|
console.log("");
|
|
13491
13891
|
}
|
|
13492
13892
|
const enabled = rules.filter((r) => !disabledRules.has(r.id)).length;
|
|
13493
13893
|
const disabled = rules.length - enabled;
|
|
13494
|
-
console.log(
|
|
13495
|
-
console.log(
|
|
13496
|
-
console.log(
|
|
13894
|
+
console.log(import_chalk23.default.dim(` ${rules.length} rules, ${enabled} enabled, ${disabled} disabled`));
|
|
13895
|
+
console.log(import_chalk23.default.dim(` toggle: hyv rules --disable <id>`));
|
|
13896
|
+
console.log(import_chalk23.default.dim(` reset: hyv rules --reset
|
|
13497
13897
|
`));
|
|
13498
13898
|
} catch (error) {
|
|
13499
|
-
console.error(
|
|
13899
|
+
console.error(import_chalk23.default.red(`Error: ${error.message}`));
|
|
13500
13900
|
process.exit(1);
|
|
13501
13901
|
}
|
|
13502
13902
|
});
|
|
13503
13903
|
}
|
|
13504
13904
|
|
|
13505
13905
|
// src/commands/batch.ts
|
|
13506
|
-
var
|
|
13906
|
+
var import_chalk24 = __toESM(require_source());
|
|
13507
13907
|
var fs16 = __toESM(require("fs"));
|
|
13508
|
-
var
|
|
13908
|
+
var path17 = __toESM(require("path"));
|
|
13509
13909
|
init_pipeline();
|
|
13510
13910
|
init_local_profile();
|
|
13511
13911
|
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
|
|
13912
|
+
program3.command("batch").description("Scan or fix multiple files matching a glob").argument("<pattern>", 'Glob pattern (e.g., "posts/**/*.md")').option("--fix", "Apply auto-fixes (default: scan only)").option("-i, --in-place", "Write fixes back to files").option("-y, --yes", "Confirm destructive in-place fixes without prompting").option("--threshold <n>", "Fail if any file score < threshold").option("--fail-on-hit", "Exit with code 2 if any file has issues").option("--sort <field>", "Sort by: issues, score, name", "issues").option("--format <type>", "Output format (text, json, csv)", "text").option("--profile <name>", "Voice profile").option("--ignore <patterns>", "Comma-separated glob ignores").action(async (pattern, options) => {
|
|
13513
13913
|
try {
|
|
13514
13914
|
const profile = await loadProfileForCommand(options.profile);
|
|
13515
13915
|
const glob = require_index_min();
|
|
@@ -13518,18 +13918,27 @@ function registerBatchCommand(program3) {
|
|
|
13518
13918
|
nodir: true
|
|
13519
13919
|
});
|
|
13520
13920
|
if (files.length === 0) {
|
|
13521
|
-
console.log(
|
|
13921
|
+
console.log(import_chalk24.default.yellow(`
|
|
13522
13922
|
No files matching: ${pattern}`));
|
|
13523
13923
|
return;
|
|
13524
13924
|
}
|
|
13925
|
+
if (options.fix && options.inPlace) {
|
|
13926
|
+
const confirmed = await confirmDestructiveWrite({
|
|
13927
|
+
yes: options.yes,
|
|
13928
|
+
action: `Apply auto-fixes in-place to ${files.length} file(s)`,
|
|
13929
|
+
target: pattern
|
|
13930
|
+
});
|
|
13931
|
+
if (!confirmed)
|
|
13932
|
+
process.exit(1);
|
|
13933
|
+
}
|
|
13525
13934
|
if (options.format === "text") {
|
|
13526
|
-
console.log(
|
|
13935
|
+
console.log(import_chalk24.default.dim(`
|
|
13527
13936
|
scanning ${files.length} file${files.length === 1 ? "" : "s"}...
|
|
13528
13937
|
`));
|
|
13529
13938
|
}
|
|
13530
13939
|
const results = [];
|
|
13531
13940
|
for (const file of files) {
|
|
13532
|
-
const absPath =
|
|
13941
|
+
const absPath = path17.resolve(file);
|
|
13533
13942
|
if (!fs16.existsSync(absPath))
|
|
13534
13943
|
continue;
|
|
13535
13944
|
const text = fs16.readFileSync(absPath, "utf-8");
|
|
@@ -13543,9 +13952,7 @@ No files matching: ${pattern}`));
|
|
|
13543
13952
|
autoFixes: result.changes.length
|
|
13544
13953
|
});
|
|
13545
13954
|
if (options.fix && options.inPlace && result.changes.length > 0) {
|
|
13546
|
-
|
|
13547
|
-
fs16.copyFileSync(absPath, backupPath);
|
|
13548
|
-
fs16.writeFileSync(absPath, result.fixed);
|
|
13955
|
+
writeInPlaceWithBackup(absPath, result.fixed);
|
|
13549
13956
|
}
|
|
13550
13957
|
}
|
|
13551
13958
|
if (options.sort === "score") {
|
|
@@ -13564,98 +13971,110 @@ No files matching: ${pattern}`));
|
|
|
13564
13971
|
}
|
|
13565
13972
|
} else {
|
|
13566
13973
|
for (const r of results) {
|
|
13567
|
-
const icon = r.issues > 0 ?
|
|
13568
|
-
const score = r.score < 60 ?
|
|
13569
|
-
const issueStr = r.issues > 0 ?
|
|
13974
|
+
const icon = r.issues > 0 ? import_chalk24.default.red("\u25CF") : import_chalk24.default.green("\u25CB");
|
|
13975
|
+
const score = r.score < 60 ? import_chalk24.default.red(r.score) : r.score < 80 ? import_chalk24.default.yellow(r.score) : import_chalk24.default.green(r.score);
|
|
13976
|
+
const issueStr = r.issues > 0 ? import_chalk24.default.red(`${r.issues} issues`) : import_chalk24.default.green("clean");
|
|
13570
13977
|
console.log(` ${icon} ${r.file.padEnd(40)} ${issueStr.padEnd(20)} score: ${score}`);
|
|
13571
13978
|
}
|
|
13572
13979
|
const withIssues = results.filter((r) => r.issues > 0).length;
|
|
13573
13980
|
const totalIssues = results.reduce((sum, r) => sum + r.issues, 0);
|
|
13574
13981
|
const worst = results.reduce((min, r) => r.score < min.score ? r : min, results[0]);
|
|
13575
|
-
console.log(
|
|
13982
|
+
console.log(import_chalk24.default.dim(`
|
|
13576
13983
|
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`));
|
|
13577
|
-
console.log(
|
|
13984
|
+
console.log(import_chalk24.default.dim(` ${results.length} files, ${withIssues} with issues, ${totalIssues} total issues`));
|
|
13578
13985
|
if (withIssues > 0) {
|
|
13579
|
-
console.log(
|
|
13986
|
+
console.log(import_chalk24.default.dim(` worst: ${worst.file} (${worst.score}/100)`));
|
|
13580
13987
|
}
|
|
13581
13988
|
if (options.fix && options.inPlace) {
|
|
13582
13989
|
const fixed = results.filter((r) => r.autoFixes > 0);
|
|
13583
|
-
console.log(
|
|
13990
|
+
console.log(import_chalk24.default.green(`
|
|
13584
13991
|
\u2713 ${fixed.reduce((sum, r) => sum + r.autoFixes, 0)} auto-fixes applied across ${fixed.length} files`));
|
|
13585
13992
|
}
|
|
13586
13993
|
}
|
|
13587
13994
|
const threshold = options.threshold ? parseInt(options.threshold, 10) : 0;
|
|
13588
|
-
const
|
|
13589
|
-
|
|
13590
|
-
)
|
|
13591
|
-
|
|
13995
|
+
const failOnHit = results.some((r) => options.failOnHit && r.issues > 0);
|
|
13996
|
+
const belowThreshold = results.some((r) => threshold > 0 && r.score < threshold);
|
|
13997
|
+
if (failOnHit)
|
|
13998
|
+
process.exit(2);
|
|
13999
|
+
if (belowThreshold)
|
|
13592
14000
|
process.exit(1);
|
|
13593
14001
|
} catch (error) {
|
|
13594
|
-
console.error(
|
|
14002
|
+
console.error(import_chalk24.default.red(`Error: ${error.message}`));
|
|
13595
14003
|
process.exit(1);
|
|
13596
14004
|
}
|
|
13597
14005
|
});
|
|
13598
14006
|
}
|
|
13599
14007
|
|
|
13600
14008
|
// src/commands/watch.ts
|
|
13601
|
-
var
|
|
14009
|
+
var import_chalk25 = __toESM(require_source());
|
|
13602
14010
|
var fs17 = __toESM(require("fs"));
|
|
13603
|
-
var
|
|
14011
|
+
var path18 = __toESM(require("path"));
|
|
13604
14012
|
init_pipeline();
|
|
13605
14013
|
init_local_profile();
|
|
13606
14014
|
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) => {
|
|
14015
|
+
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
14016
|
try {
|
|
13609
14017
|
const profile = await loadProfileForCommand(options.profile);
|
|
13610
|
-
const absPath =
|
|
14018
|
+
const absPath = path18.resolve(file);
|
|
13611
14019
|
if (!fs17.existsSync(absPath)) {
|
|
13612
|
-
console.error(
|
|
14020
|
+
console.error(import_chalk25.default.red(`File not found: ${absPath}`));
|
|
13613
14021
|
process.exit(1);
|
|
13614
14022
|
}
|
|
13615
|
-
|
|
14023
|
+
if (options.command === "fix") {
|
|
14024
|
+
const confirmed = await confirmDestructiveWrite({
|
|
14025
|
+
yes: options.yes,
|
|
14026
|
+
action: "Auto-fix on every save",
|
|
14027
|
+
target: absPath
|
|
14028
|
+
});
|
|
14029
|
+
if (!confirmed)
|
|
14030
|
+
process.exit(1);
|
|
14031
|
+
}
|
|
14032
|
+
console.log(import_chalk25.default.dim(`
|
|
13616
14033
|
watching ${absPath}`));
|
|
13617
|
-
console.log(
|
|
13618
|
-
console.log(
|
|
14034
|
+
console.log(import_chalk25.default.dim(`command: ${options.command} debounce: ${options.debounce}ms`));
|
|
14035
|
+
console.log(import_chalk25.default.dim("ctrl+c to stop\n"));
|
|
13619
14036
|
let debounceTimer = null;
|
|
13620
14037
|
const debounceMs = parseInt(options.debounce, 10);
|
|
13621
14038
|
let scanCount = 0;
|
|
13622
14039
|
let lastScore = 0;
|
|
14040
|
+
let ignoreWatchUntil = 0;
|
|
13623
14041
|
const runScan = () => {
|
|
13624
14042
|
const text = fs17.readFileSync(absPath, "utf-8");
|
|
13625
14043
|
const result = runPipeline(text, profile, options.command === "fix");
|
|
13626
14044
|
scanCount++;
|
|
13627
14045
|
const now = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
|
|
13628
|
-
console.log(
|
|
14046
|
+
console.log(import_chalk25.default.dim(`[${now}] saved \u2014 ${options.command}ing...`));
|
|
13629
14047
|
if (options.command === "score") {
|
|
13630
14048
|
const score = result.score;
|
|
13631
|
-
const color = score < 60 ?
|
|
14049
|
+
const color = score < 60 ? import_chalk25.default.red : score < 80 ? import_chalk25.default.yellow : import_chalk25.default.green;
|
|
13632
14050
|
console.log(` ${color(score + "/100")}`);
|
|
13633
14051
|
if (lastScore > 0 && score !== lastScore) {
|
|
13634
14052
|
const delta = score - lastScore;
|
|
13635
|
-
console.log(
|
|
14053
|
+
console.log(import_chalk25.default.dim(` ${delta > 0 ? "\u2191" : "\u2193"} ${Math.abs(delta)} from last scan`));
|
|
13636
14054
|
}
|
|
13637
14055
|
lastScore = score;
|
|
13638
14056
|
} else if (options.command === "fix") {
|
|
13639
14057
|
if (result.changes.length > 0) {
|
|
13640
14058
|
for (const change of result.changes) {
|
|
13641
|
-
console.log(
|
|
14059
|
+
console.log(import_chalk25.default.dim(` Line ${change.line}: `) + import_chalk25.default.red(change.before) + import_chalk25.default.dim(" \u2192 ") + import_chalk25.default.green(change.after));
|
|
13642
14060
|
}
|
|
13643
|
-
|
|
13644
|
-
|
|
14061
|
+
ignoreWatchUntil = Date.now() + debounceMs + 200;
|
|
14062
|
+
writeInPlaceWithBackup(absPath, result.fixed);
|
|
14063
|
+
console.log(import_chalk25.default.green(` \u2713 ${result.changes.length} auto-fixes applied`));
|
|
13645
14064
|
} else {
|
|
13646
|
-
console.log(
|
|
14065
|
+
console.log(import_chalk25.default.green(" \u2713 no auto-fixable issues"));
|
|
13647
14066
|
}
|
|
13648
14067
|
} else {
|
|
13649
14068
|
if (result.stats.totalSignals === 0) {
|
|
13650
|
-
console.log(
|
|
14069
|
+
console.log(import_chalk25.default.green(` \u2713 clean \u2014 score: ${result.score}/100`));
|
|
13651
14070
|
} else {
|
|
13652
|
-
console.log(
|
|
14071
|
+
console.log(import_chalk25.default.yellow(` ${result.stats.totalSignals} issues (${result.stats.red} red, ${result.stats.yellow} yellow) score: ${result.score}/100`));
|
|
13653
14072
|
for (const signal of result.signalMap.signals.slice(0, 3)) {
|
|
13654
|
-
const sev = signal.severity === "red" ?
|
|
14073
|
+
const sev = signal.severity === "red" ? import_chalk25.default.red("\u25CF") : import_chalk25.default.yellow("\u25CB");
|
|
13655
14074
|
console.log(` ${sev} line ${signal.line}: ${signal.id} \u2014 ${signal.suggestion}`);
|
|
13656
14075
|
}
|
|
13657
14076
|
if (result.signalMap.signals.length > 3) {
|
|
13658
|
-
console.log(
|
|
14077
|
+
console.log(import_chalk25.default.dim(` ... and ${result.signalMap.signals.length - 3} more`));
|
|
13659
14078
|
}
|
|
13660
14079
|
}
|
|
13661
14080
|
}
|
|
@@ -13665,26 +14084,28 @@ watching ${absPath}`));
|
|
|
13665
14084
|
fs17.watch(absPath, (eventType) => {
|
|
13666
14085
|
if (eventType !== "change")
|
|
13667
14086
|
return;
|
|
14087
|
+
if (Date.now() < ignoreWatchUntil)
|
|
14088
|
+
return;
|
|
13668
14089
|
if (debounceTimer)
|
|
13669
14090
|
clearTimeout(debounceTimer);
|
|
13670
14091
|
debounceTimer = setTimeout(runScan, debounceMs);
|
|
13671
14092
|
});
|
|
13672
14093
|
process.on("SIGINT", () => {
|
|
13673
|
-
console.log(
|
|
14094
|
+
console.log(import_chalk25.default.dim(`
|
|
13674
14095
|
${scanCount} scans completed. exiting.`));
|
|
13675
14096
|
process.exit(0);
|
|
13676
14097
|
});
|
|
13677
14098
|
await new Promise(() => {
|
|
13678
14099
|
});
|
|
13679
14100
|
} catch (error) {
|
|
13680
|
-
console.error(
|
|
14101
|
+
console.error(import_chalk25.default.red(`Error: ${error.message}`));
|
|
13681
14102
|
process.exit(1);
|
|
13682
14103
|
}
|
|
13683
14104
|
});
|
|
13684
14105
|
}
|
|
13685
14106
|
|
|
13686
14107
|
// src/commands/demo.ts
|
|
13687
|
-
var
|
|
14108
|
+
var import_chalk26 = __toESM(require_source());
|
|
13688
14109
|
var fs18 = __toESM(require("fs"));
|
|
13689
14110
|
var SAMPLES = {
|
|
13690
14111
|
linkedin: {
|
|
@@ -13775,46 +14196,46 @@ function registerDemoCommand(program3) {
|
|
|
13775
14196
|
const style = options.clean ? "clean" : options.style;
|
|
13776
14197
|
const sample = SAMPLES[style];
|
|
13777
14198
|
if (!sample) {
|
|
13778
|
-
console.error(
|
|
14199
|
+
console.error(import_chalk26.default.red(`Unknown style: ${options.style}. Valid: ${Object.keys(SAMPLES).filter((k) => k !== "clean").join(", ")}`));
|
|
13779
14200
|
process.exit(1);
|
|
13780
14201
|
}
|
|
13781
14202
|
if (options.output) {
|
|
13782
14203
|
const outputPath = require("path").resolve(options.output);
|
|
13783
14204
|
fs18.writeFileSync(outputPath, sample.text);
|
|
13784
|
-
console.log(
|
|
14205
|
+
console.log(import_chalk26.default.green(`
|
|
13785
14206
|
\u2713 Sample written to ${outputPath}`));
|
|
13786
14207
|
if (sample.patterns.length > 0) {
|
|
13787
|
-
console.log(
|
|
14208
|
+
console.log(import_chalk26.default.dim(` Contains ${sample.patterns.length} AI patterns: ${sample.patterns.slice(0, 5).join(", ")}...`));
|
|
13788
14209
|
}
|
|
13789
|
-
console.log(
|
|
14210
|
+
console.log(import_chalk26.default.dim(`
|
|
13790
14211
|
Scan it: hyv scan ${options.output}`));
|
|
13791
|
-
console.log(
|
|
14212
|
+
console.log(import_chalk26.default.dim(` Fix it: hyv fix ${options.output}`));
|
|
13792
14213
|
} else {
|
|
13793
|
-
console.log(
|
|
14214
|
+
console.log(import_chalk26.default.bold(`
|
|
13794
14215
|
\u2500\u2500\u2500 sample (${style}) \u2500\u2500\u2500
|
|
13795
14216
|
`));
|
|
13796
14217
|
console.log(sample.text);
|
|
13797
|
-
console.log(
|
|
14218
|
+
console.log(import_chalk26.default.dim(`
|
|
13798
14219
|
\u2500\u2500\u2500 end \u2500\u2500\u2500`));
|
|
13799
14220
|
if (sample.patterns.length > 0) {
|
|
13800
|
-
console.log(
|
|
14221
|
+
console.log(import_chalk26.default.dim(`
|
|
13801
14222
|
${sample.patterns.length} AI patterns embedded: ${sample.patterns.slice(0, 8).join(", ")}...`));
|
|
13802
14223
|
}
|
|
13803
|
-
console.log(
|
|
14224
|
+
console.log(import_chalk26.default.dim(`
|
|
13804
14225
|
Save to file: hyv demo --output demo.md`));
|
|
13805
|
-
console.log(
|
|
13806
|
-
console.log(
|
|
14226
|
+
console.log(import_chalk26.default.dim(` Scan it: hyv scan demo.md`));
|
|
14227
|
+
console.log(import_chalk26.default.dim(` Fix it: hyv fix demo.md
|
|
13807
14228
|
`));
|
|
13808
14229
|
}
|
|
13809
14230
|
} catch (error) {
|
|
13810
|
-
console.error(
|
|
14231
|
+
console.error(import_chalk26.default.red(`Error: ${error.message}`));
|
|
13811
14232
|
process.exit(1);
|
|
13812
14233
|
}
|
|
13813
14234
|
});
|
|
13814
14235
|
}
|
|
13815
14236
|
|
|
13816
14237
|
// src/commands/open.ts
|
|
13817
|
-
var
|
|
14238
|
+
var import_chalk27 = __toESM(require_source());
|
|
13818
14239
|
var PAGES = {
|
|
13819
14240
|
dashboard: "https://holdyourvoice.com/dashboard",
|
|
13820
14241
|
profiles: "https://holdyourvoice.com/dashboard",
|
|
@@ -13831,12 +14252,12 @@ function registerOpenCommand(program3) {
|
|
|
13831
14252
|
return;
|
|
13832
14253
|
}
|
|
13833
14254
|
const open3 = (await Promise.resolve().then(() => __toESM(require_open()))).default;
|
|
13834
|
-
console.log(
|
|
14255
|
+
console.log(import_chalk27.default.dim(`
|
|
13835
14256
|
Opening ${url}...`));
|
|
13836
14257
|
await open3(url);
|
|
13837
|
-
console.log(
|
|
14258
|
+
console.log(import_chalk27.default.green(" \u2713 Opened in browser\n"));
|
|
13838
14259
|
} catch (error) {
|
|
13839
|
-
console.error(
|
|
14260
|
+
console.error(import_chalk27.default.red(`Error: ${error.message}`));
|
|
13840
14261
|
process.exit(1);
|
|
13841
14262
|
}
|
|
13842
14263
|
});
|
|
@@ -13847,10 +14268,10 @@ init_welcome();
|
|
|
13847
14268
|
|
|
13848
14269
|
// src/lib/onboarding.ts
|
|
13849
14270
|
var fs19 = __toESM(require("fs"));
|
|
13850
|
-
var
|
|
14271
|
+
var path19 = __toESM(require("path"));
|
|
13851
14272
|
var os6 = __toESM(require("os"));
|
|
13852
|
-
var hyvDir =
|
|
13853
|
-
var onboardingFile =
|
|
14273
|
+
var hyvDir = path19.join(os6.homedir(), ".hyv");
|
|
14274
|
+
var onboardingFile = path19.join(hyvDir, "onboarding-complete.json");
|
|
13854
14275
|
function hasCompletedOnboarding() {
|
|
13855
14276
|
try {
|
|
13856
14277
|
return fs19.existsSync(onboardingFile);
|
|
@@ -13869,11 +14290,11 @@ function markOnboardingComplete(version) {
|
|
|
13869
14290
|
|
|
13870
14291
|
// src/commands/welcome.ts
|
|
13871
14292
|
var fs20 = __toESM(require("fs"));
|
|
13872
|
-
var
|
|
14293
|
+
var path20 = __toESM(require("path"));
|
|
13873
14294
|
function registerWelcomeCommand(program3) {
|
|
13874
14295
|
const pkgVersion3 = (() => {
|
|
13875
14296
|
try {
|
|
13876
|
-
const pkgPath3 =
|
|
14297
|
+
const pkgPath3 = path20.resolve(__dirname, "..", "package.json");
|
|
13877
14298
|
return JSON.parse(fs20.readFileSync(pkgPath3, "utf-8")).version;
|
|
13878
14299
|
} catch {
|
|
13879
14300
|
return "0.0.0";
|
|
@@ -13898,7 +14319,7 @@ function getWelcomeText() {
|
|
|
13898
14319
|
}
|
|
13899
14320
|
|
|
13900
14321
|
// src/commands/content.ts
|
|
13901
|
-
var
|
|
14322
|
+
var import_chalk28 = __toESM(require_source());
|
|
13902
14323
|
init_free_paid();
|
|
13903
14324
|
var TEMPLATES = {
|
|
13904
14325
|
cursor: {
|
|
@@ -13972,59 +14393,60 @@ ${COMMUNITY_URL}`
|
|
|
13972
14393
|
function registerContentCommand(program3) {
|
|
13973
14394
|
program3.command("content").description("Blog outlines, CI snippets, and share templates").argument("[topic]", "cursor | agents | ci | share", "cursor").option("--list", "List available templates").action((topic, opts) => {
|
|
13974
14395
|
if (opts.list) {
|
|
13975
|
-
console.log(
|
|
14396
|
+
console.log(import_chalk28.default.bold("\nhyv content templates\n"));
|
|
13976
14397
|
for (const [key, t2] of Object.entries(TEMPLATES)) {
|
|
13977
|
-
console.log(
|
|
14398
|
+
console.log(import_chalk28.default.dim(` ${key}`) + ` \u2014 ${t2.title}`);
|
|
13978
14399
|
}
|
|
13979
14400
|
console.log("");
|
|
13980
14401
|
return;
|
|
13981
14402
|
}
|
|
13982
14403
|
const t = TEMPLATES[topic] || TEMPLATES.cursor;
|
|
13983
|
-
console.log(
|
|
14404
|
+
console.log(import_chalk28.default.bold(`
|
|
13984
14405
|
${t.title}
|
|
13985
14406
|
`));
|
|
13986
14407
|
console.log(t.body);
|
|
13987
|
-
console.log(
|
|
14408
|
+
console.log(import_chalk28.default.dim("\nBlog: https://holdyourvoice.com/blog\n"));
|
|
13988
14409
|
});
|
|
13989
14410
|
}
|
|
13990
14411
|
|
|
13991
14412
|
// src/commands/upgrade.ts
|
|
13992
|
-
var
|
|
13993
|
-
var
|
|
14413
|
+
var import_chalk29 = __toESM(require_source());
|
|
14414
|
+
var import_child_process3 = require("child_process");
|
|
14415
|
+
init_version();
|
|
13994
14416
|
function registerUpgradeCommand(program3) {
|
|
13995
14417
|
program3.command("upgrade").description("Upgrade to the latest @holdyourvoice/hyv").option("--check", "Only check if an update is available").action(async (opts) => {
|
|
13996
14418
|
const current = getCliVersion();
|
|
13997
|
-
console.log(
|
|
14419
|
+
console.log(import_chalk29.default.dim(`
|
|
13998
14420
|
Current: ${getEngineLabel()}
|
|
13999
14421
|
`));
|
|
14000
14422
|
let latest = current;
|
|
14001
14423
|
try {
|
|
14002
|
-
const out = (0,
|
|
14424
|
+
const out = (0, import_child_process3.execSync)("npm view @holdyourvoice/hyv version", { encoding: "utf-8", timeout: 15e3 });
|
|
14003
14425
|
latest = out.trim();
|
|
14004
14426
|
} catch {
|
|
14005
|
-
console.log(
|
|
14427
|
+
console.log(import_chalk29.default.yellow("Could not reach npm registry. Try: npm i -g @holdyourvoice/hyv@latest"));
|
|
14006
14428
|
return;
|
|
14007
14429
|
}
|
|
14008
14430
|
const cmp = compareSemver(current, latest);
|
|
14009
14431
|
if (cmp === 0) {
|
|
14010
|
-
console.log(
|
|
14432
|
+
console.log(import_chalk29.default.green("\u2713 You are on the latest version."));
|
|
14011
14433
|
return;
|
|
14012
14434
|
}
|
|
14013
14435
|
if (cmp > 0) {
|
|
14014
|
-
console.log(
|
|
14436
|
+
console.log(import_chalk29.default.green(`\u2713 You are ahead of npm (published: ${latest}).`));
|
|
14015
14437
|
return;
|
|
14016
14438
|
}
|
|
14017
|
-
console.log(
|
|
14439
|
+
console.log(import_chalk29.default.cyan(`Update available: ${current} \u2192 ${latest}`));
|
|
14018
14440
|
if (opts.check) {
|
|
14019
|
-
console.log(
|
|
14441
|
+
console.log(import_chalk29.default.dim("\nRun: hyv upgrade or npm i -g @holdyourvoice/hyv@latest\n"));
|
|
14020
14442
|
return;
|
|
14021
14443
|
}
|
|
14022
|
-
console.log(
|
|
14444
|
+
console.log(import_chalk29.default.dim("Installing..."));
|
|
14023
14445
|
try {
|
|
14024
|
-
(0,
|
|
14025
|
-
console.log(
|
|
14446
|
+
(0, import_child_process3.execSync)("npm i -g @holdyourvoice/hyv@latest", { stdio: "inherit" });
|
|
14447
|
+
console.log(import_chalk29.default.green("\n\u2713 Upgraded successfully. Restart your terminal.\n"));
|
|
14026
14448
|
} catch {
|
|
14027
|
-
console.log(
|
|
14449
|
+
console.log(import_chalk29.default.red("\nUpgrade failed. Run manually: npm i -g @holdyourvoice/hyv@latest\n"));
|
|
14028
14450
|
process.exit(1);
|
|
14029
14451
|
}
|
|
14030
14452
|
});
|
|
@@ -14032,7 +14454,7 @@ Current: ${getEngineLabel()}
|
|
|
14032
14454
|
|
|
14033
14455
|
// src/mcp.ts
|
|
14034
14456
|
var fs21 = __toESM(require("fs"));
|
|
14035
|
-
var
|
|
14457
|
+
var path21 = __toESM(require("path"));
|
|
14036
14458
|
var os7 = __toESM(require("os"));
|
|
14037
14459
|
init_classifier();
|
|
14038
14460
|
init_autofix();
|
|
@@ -14044,9 +14466,29 @@ init_welcome();
|
|
|
14044
14466
|
init_config();
|
|
14045
14467
|
init_telemetry();
|
|
14046
14468
|
init_access();
|
|
14047
|
-
var VOICE_MD =
|
|
14469
|
+
var VOICE_MD = path21.join(os7.homedir(), ".hyv", "voice.md");
|
|
14048
14470
|
var MAX_RESPONSE_CHARS = 12e4;
|
|
14049
|
-
var
|
|
14471
|
+
var MAX_SCAN_FILE_BYTES = 2 * 1024 * 1024;
|
|
14472
|
+
function readScanFile(filePath) {
|
|
14473
|
+
const cwdReal = fs21.realpathSync(process.cwd());
|
|
14474
|
+
const resolved = fs21.realpathSync(path21.resolve(filePath));
|
|
14475
|
+
if (!resolved.startsWith(cwdReal + path21.sep) && resolved !== cwdReal) {
|
|
14476
|
+
throw new Error(`file must be in the current working directory (${cwdReal})`);
|
|
14477
|
+
}
|
|
14478
|
+
const stat = fs21.statSync(resolved);
|
|
14479
|
+
if (stat.size > MAX_SCAN_FILE_BYTES) {
|
|
14480
|
+
throw new Error(`file too large (max ${MAX_SCAN_FILE_BYTES} bytes)`);
|
|
14481
|
+
}
|
|
14482
|
+
return fs21.readFileSync(resolved, "utf-8");
|
|
14483
|
+
}
|
|
14484
|
+
function toolResultPayload(result) {
|
|
14485
|
+
const isError = result.startsWith("Error:") || result.startsWith("Unknown tool:");
|
|
14486
|
+
return {
|
|
14487
|
+
content: [{ type: "text", text: truncateResponse(result) }],
|
|
14488
|
+
...isError ? { isError: true } : {}
|
|
14489
|
+
};
|
|
14490
|
+
}
|
|
14491
|
+
var pkgPath = path21.resolve(__dirname, "..", "package.json");
|
|
14050
14492
|
var pkgVersion = (() => {
|
|
14051
14493
|
try {
|
|
14052
14494
|
return JSON.parse(fs21.readFileSync(pkgPath, "utf-8")).version;
|
|
@@ -14054,8 +14496,14 @@ var pkgVersion = (() => {
|
|
|
14054
14496
|
return "2.7.1";
|
|
14055
14497
|
}
|
|
14056
14498
|
})();
|
|
14057
|
-
async function resolveProfile(slug) {
|
|
14058
|
-
|
|
14499
|
+
async function resolveProfile(slug, allowServerFetch = false) {
|
|
14500
|
+
const profile = await loadProfileForCommand(slug, { allowServerFetch });
|
|
14501
|
+
if (slug && !profile) {
|
|
14502
|
+
const { requirePaidFeature: requirePaidFeature2 } = await Promise.resolve().then(() => (init_access(), access_exports));
|
|
14503
|
+
await requirePaidFeature2("premiumPrompts");
|
|
14504
|
+
return loadProfileForCommand(slug, { allowServerFetch: true });
|
|
14505
|
+
}
|
|
14506
|
+
return profile;
|
|
14059
14507
|
}
|
|
14060
14508
|
function jsonRpcOk(id, result) {
|
|
14061
14509
|
return JSON.stringify({ jsonrpc: "2.0", id, result });
|
|
@@ -14116,14 +14564,11 @@ async function toolScan(args2) {
|
|
|
14116
14564
|
let scanText2 = text;
|
|
14117
14565
|
const profile = await resolveProfile(args2.profile);
|
|
14118
14566
|
if (filePath) {
|
|
14119
|
-
|
|
14120
|
-
|
|
14121
|
-
|
|
14122
|
-
return `Error:
|
|
14567
|
+
try {
|
|
14568
|
+
scanText2 = readScanFile(filePath);
|
|
14569
|
+
} catch (err) {
|
|
14570
|
+
return `Error: ${err.message}`;
|
|
14123
14571
|
}
|
|
14124
|
-
if (!fs21.existsSync(resolved))
|
|
14125
|
-
return `Error: file not found: ${filePath}`;
|
|
14126
|
-
scanText2 = fs21.readFileSync(resolved, "utf-8");
|
|
14127
14572
|
}
|
|
14128
14573
|
const result = runPipeline(scanText2, profile, false);
|
|
14129
14574
|
if (result.stats.totalSignals === 0) {
|
|
@@ -14135,13 +14580,19 @@ async function toolScan(args2) {
|
|
|
14135
14580
|
const lines = [
|
|
14136
14581
|
`Score: ${result.score}/100. Found ${result.stats.totalSignals} issues (${result.stats.red} red, ${result.stats.yellow} yellow):`
|
|
14137
14582
|
];
|
|
14583
|
+
const shown = /* @__PURE__ */ new Set();
|
|
14138
14584
|
if (profile && profileIssues.length > 0) {
|
|
14139
14585
|
lines.push(`Profile-specific (${profileIssues.length}):`);
|
|
14140
14586
|
for (const s of profileIssues.slice(0, 5)) {
|
|
14587
|
+
const key = `${s.line}:${s.id}`;
|
|
14588
|
+
shown.add(key);
|
|
14141
14589
|
lines.push(` line ${s.line}: [${s.severity}] ${s.id} \u2014 ${s.suggestion}`);
|
|
14142
14590
|
}
|
|
14143
14591
|
}
|
|
14144
14592
|
for (const s of result.signalMap.signals.slice(0, 15)) {
|
|
14593
|
+
const key = `${s.line}:${s.id}`;
|
|
14594
|
+
if (shown.has(key))
|
|
14595
|
+
continue;
|
|
14145
14596
|
lines.push(`line ${s.line}: [${s.severity}] ${s.id} \u2014 ${s.suggestion}`);
|
|
14146
14597
|
}
|
|
14147
14598
|
return lines.join("\n");
|
|
@@ -14284,7 +14735,7 @@ async function toolAnalyze(args2) {
|
|
|
14284
14735
|
return "Error: no text provided";
|
|
14285
14736
|
try {
|
|
14286
14737
|
const profile = await resolveProfile(args2.profile);
|
|
14287
|
-
const preferServer = args2.prefer_server
|
|
14738
|
+
const preferServer = args2.prefer_server === true;
|
|
14288
14739
|
const result = await runHybridAnalysis(text, profile, {
|
|
14289
14740
|
preferServer,
|
|
14290
14741
|
profileSlug: args2.profile || profile?.slug
|
|
@@ -14407,7 +14858,7 @@ var TOOLS = [
|
|
|
14407
14858
|
properties: {
|
|
14408
14859
|
text: { type: "string", description: "Text to analyze" },
|
|
14409
14860
|
profile: { type: "string", description: "Voice profile slug" },
|
|
14410
|
-
prefer_server: { type: "boolean", description: "Use server hybrid engine when paid (default
|
|
14861
|
+
prefer_server: { type: "boolean", description: "Use server hybrid engine when paid (default false)" }
|
|
14411
14862
|
},
|
|
14412
14863
|
required: ["text"]
|
|
14413
14864
|
}
|
|
@@ -14599,9 +15050,12 @@ async function handleRequest(line) {
|
|
|
14599
15050
|
mcpLog("error", `tool ${toolName}: ${err.message}`);
|
|
14600
15051
|
recordEvent("mcp_tool_error", { tool: toolName, error: err.message });
|
|
14601
15052
|
}
|
|
14602
|
-
send(jsonRpcOk(id,
|
|
15053
|
+
send(jsonRpcOk(id, toolResultPayload(result)));
|
|
14603
15054
|
break;
|
|
14604
15055
|
}
|
|
15056
|
+
case "ping":
|
|
15057
|
+
send(jsonRpcOk(id, {}));
|
|
15058
|
+
break;
|
|
14605
15059
|
default:
|
|
14606
15060
|
if (id !== void 0) {
|
|
14607
15061
|
send(jsonRpcError(id, -32601, `Method not found: ${method}`));
|
|
@@ -14621,16 +15075,17 @@ async function startMcpServer() {
|
|
|
14621
15075
|
}
|
|
14622
15076
|
let buffer = "";
|
|
14623
15077
|
process.stdin.setEncoding("utf-8");
|
|
15078
|
+
let requestChain = Promise.resolve();
|
|
15079
|
+
const enqueueRequest = (line) => {
|
|
15080
|
+
requestChain = requestChain.then(() => handleRequest(line)).catch((err) => mcpLog("error", err.message));
|
|
15081
|
+
};
|
|
14624
15082
|
process.stdin.on("data", (chunk) => {
|
|
14625
15083
|
buffer += chunk;
|
|
14626
15084
|
const lines = buffer.split("\n");
|
|
14627
15085
|
buffer = lines.pop() || "";
|
|
14628
15086
|
for (const line of lines) {
|
|
14629
|
-
if (line.trim())
|
|
14630
|
-
|
|
14631
|
-
mcpLog("error", err.message);
|
|
14632
|
-
});
|
|
14633
|
-
}
|
|
15087
|
+
if (line.trim())
|
|
15088
|
+
enqueueRequest(line.trim());
|
|
14634
15089
|
}
|
|
14635
15090
|
});
|
|
14636
15091
|
process.stdin.on("end", () => process.exit(0));
|
|
@@ -14642,104 +15097,137 @@ async function startMcpServer() {
|
|
|
14642
15097
|
}
|
|
14643
15098
|
|
|
14644
15099
|
// src/lib/mcp-setup.ts
|
|
14645
|
-
var
|
|
15100
|
+
var import_chalk30 = __toESM(require_source());
|
|
14646
15101
|
var fs22 = __toESM(require("fs"));
|
|
14647
|
-
var
|
|
15102
|
+
var path22 = __toESM(require("path"));
|
|
14648
15103
|
var os8 = __toESM(require("os"));
|
|
15104
|
+
init_version();
|
|
14649
15105
|
var HOME2 = os8.homedir();
|
|
14650
15106
|
var IS_WIN2 = process.platform === "win32";
|
|
15107
|
+
function claudeDesktopConfigPath() {
|
|
15108
|
+
if (IS_WIN2)
|
|
15109
|
+
return path22.join(HOME2, "AppData", "Roaming", "Claude", "claude_desktop_config.json");
|
|
15110
|
+
if (process.platform === "linux")
|
|
15111
|
+
return path22.join(HOME2, ".config", "Claude", "claude_desktop_config.json");
|
|
15112
|
+
return path22.join(HOME2, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
15113
|
+
}
|
|
14651
15114
|
function printMcpSetup() {
|
|
14652
|
-
|
|
14653
|
-
console.log(
|
|
14654
|
-
console.log(import_chalk29.default.dim(` ${getEngineLabel()}
|
|
15115
|
+
console.log(import_chalk30.default.bold("\nhold your voice \u2014 mcp setup\n"));
|
|
15116
|
+
console.log(import_chalk30.default.dim(` ${getEngineLabel()}
|
|
14655
15117
|
`));
|
|
14656
|
-
console.log(
|
|
14657
|
-
console.log(
|
|
14658
|
-
console.log(
|
|
14659
|
-
console.log(
|
|
15118
|
+
console.log(import_chalk30.default.bold("Claude Desktop"));
|
|
15119
|
+
console.log(import_chalk30.default.dim(" Add to claude_desktop_config.json \u2192 mcpServers.hyv:"));
|
|
15120
|
+
console.log(import_chalk30.default.cyan(` ${mcpServerSnippet().split("\n").join("\n ")}`));
|
|
15121
|
+
console.log(import_chalk30.default.dim(` Config: ${claudeDesktopConfigPath()}
|
|
14660
15122
|
`));
|
|
14661
|
-
console.log(
|
|
14662
|
-
console.log(
|
|
14663
|
-
console.log(
|
|
14664
|
-
console.log(
|
|
14665
|
-
console.log(
|
|
14666
|
-
console.log(
|
|
14667
|
-
console.log(
|
|
14668
|
-
console.log(
|
|
14669
|
-
console.log(
|
|
14670
|
-
console.log(
|
|
15123
|
+
console.log(import_chalk30.default.bold("Cursor"));
|
|
15124
|
+
console.log(import_chalk30.default.dim(" MCP: ~/.cursor/mcp.json \u2192 mcpServers.hyv (same JSON as above)"));
|
|
15125
|
+
console.log(import_chalk30.default.dim(" Rule: ~/.cursor/rules/hyv.mdc (alwaysApply \u2014 auto via postinstall)\n"));
|
|
15126
|
+
console.log(import_chalk30.default.bold("Claude Code"));
|
|
15127
|
+
console.log(import_chalk30.default.dim(" Command: ~/.claude/commands/hyv.md"));
|
|
15128
|
+
console.log(import_chalk30.default.dim(" Skill: ~/.claude/skills/hold-your-voice/SKILL.md\n"));
|
|
15129
|
+
console.log(import_chalk30.default.bold("Windsurf"));
|
|
15130
|
+
console.log(import_chalk30.default.dim(" Rule: ~/.windsurf/rules/hyv.md (trigger: always_on)\n"));
|
|
15131
|
+
console.log(import_chalk30.default.bold("Codex"));
|
|
15132
|
+
console.log(import_chalk30.default.dim(" Instructions: ~/.codex/AGENTS.md (merged on install)\n"));
|
|
15133
|
+
console.log(import_chalk30.default.bold("Command Code"));
|
|
15134
|
+
console.log(import_chalk30.default.dim(" Skill: ~/.commandcode/skills/hyv/SKILL.md\n"));
|
|
15135
|
+
console.log(import_chalk30.default.bold("ChatGPT"));
|
|
15136
|
+
console.log(import_chalk30.default.dim(" hyv mcp --setup-chatgpt\n"));
|
|
15137
|
+
console.log(import_chalk30.default.bold("Auto-configure"));
|
|
15138
|
+
console.log(import_chalk30.default.dim(" hyv doctor --fix-agents"));
|
|
15139
|
+
console.log(import_chalk30.default.dim(" HYV_AUTO_CONFIGURE_AGENTS=0 npm i -g @holdyourvoice/hyv (skip)\n"));
|
|
15140
|
+
console.log(import_chalk30.default.bold("Verify"));
|
|
15141
|
+
console.log(import_chalk30.default.dim(" hyv mcp --test"));
|
|
15142
|
+
console.log(import_chalk30.default.dim(" HYV_TELEMETRY=1 hyv mcp (optional usage logging to ~/.hyv/telemetry/)\n"));
|
|
14671
15143
|
}
|
|
14672
15144
|
async function runMcpSelfTest() {
|
|
14673
|
-
console.log(
|
|
14674
|
-
console.log(
|
|
15145
|
+
console.log(import_chalk30.default.bold("\nhold your voice \u2014 mcp self-test\n"));
|
|
15146
|
+
console.log(import_chalk30.default.dim(` ${getEngineLabel()}
|
|
14675
15147
|
`));
|
|
14676
15148
|
let passed = 0;
|
|
14677
15149
|
let failed = 0;
|
|
14678
15150
|
const tools = getMcpToolNames();
|
|
14679
15151
|
if (tools.length >= 10) {
|
|
14680
|
-
console.log(
|
|
15152
|
+
console.log(import_chalk30.default.green(` \u2713 ${tools.length} MCP tools registered`));
|
|
14681
15153
|
passed++;
|
|
14682
15154
|
} else {
|
|
14683
|
-
console.log(
|
|
15155
|
+
console.log(import_chalk30.default.red(` \u2717 expected 10+ tools, got ${tools.length}`));
|
|
14684
15156
|
failed++;
|
|
14685
15157
|
}
|
|
14686
|
-
const required = ["hyv_welcome", "hyv_scan", "hyv_analyze", "hyv_clean", "hyv_validate"];
|
|
15158
|
+
const required = ["hyv_welcome", "hyv_scan", "hyv_analyze", "hyv_clean", "hyv_validate", "hyv_list_free_tools"];
|
|
14687
15159
|
for (const name of required) {
|
|
14688
15160
|
if (tools.includes(name)) {
|
|
14689
|
-
console.log(
|
|
15161
|
+
console.log(import_chalk30.default.green(` \u2713 tool: ${name}`));
|
|
14690
15162
|
passed++;
|
|
14691
15163
|
} else {
|
|
14692
|
-
console.log(
|
|
15164
|
+
console.log(import_chalk30.default.red(` \u2717 missing tool: ${name}`));
|
|
14693
15165
|
failed++;
|
|
14694
15166
|
}
|
|
14695
15167
|
}
|
|
14696
15168
|
try {
|
|
14697
15169
|
const welcome = await invokeMcpTool("hyv_welcome", {});
|
|
14698
15170
|
if (welcome.includes("Hold Your Voice") || welcome.includes("hold your voice")) {
|
|
14699
|
-
console.log(
|
|
15171
|
+
console.log(import_chalk30.default.green(" \u2713 hyv_welcome responds"));
|
|
14700
15172
|
passed++;
|
|
14701
15173
|
} else {
|
|
14702
|
-
console.log(
|
|
15174
|
+
console.log(import_chalk30.default.red(" \u2717 hyv_welcome unexpected output"));
|
|
14703
15175
|
failed++;
|
|
14704
15176
|
}
|
|
14705
15177
|
} catch (e) {
|
|
14706
|
-
console.log(
|
|
15178
|
+
console.log(import_chalk30.default.red(` \u2717 hyv_welcome failed: ${e.message}`));
|
|
14707
15179
|
failed++;
|
|
14708
15180
|
}
|
|
14709
15181
|
try {
|
|
14710
15182
|
const demo = await invokeMcpTool("hyv_demo", {});
|
|
14711
15183
|
if (demo.includes("Score") || demo.includes("issues")) {
|
|
14712
|
-
console.log(
|
|
15184
|
+
console.log(import_chalk30.default.green(" \u2713 hyv_demo pipeline works"));
|
|
14713
15185
|
passed++;
|
|
14714
15186
|
} else {
|
|
14715
|
-
console.log(
|
|
15187
|
+
console.log(import_chalk30.default.red(" \u2717 hyv_demo unexpected output"));
|
|
14716
15188
|
failed++;
|
|
14717
15189
|
}
|
|
14718
15190
|
} catch (e) {
|
|
14719
|
-
console.log(
|
|
15191
|
+
console.log(import_chalk30.default.red(` \u2717 hyv_demo failed: ${e.message}`));
|
|
14720
15192
|
failed++;
|
|
14721
15193
|
}
|
|
14722
|
-
const voiceMd =
|
|
15194
|
+
const voiceMd = path22.join(HOME2, ".hyv", "voice.md");
|
|
14723
15195
|
if (fs22.existsSync(voiceMd)) {
|
|
14724
|
-
console.log(
|
|
15196
|
+
console.log(import_chalk30.default.green(" \u2713 voice profile found"));
|
|
14725
15197
|
passed++;
|
|
14726
15198
|
} else {
|
|
14727
|
-
console.log(
|
|
15199
|
+
console.log(import_chalk30.default.dim(" - no voice.md (free local engine still works)"));
|
|
14728
15200
|
}
|
|
14729
15201
|
if (getDemoText().length > 100) {
|
|
14730
|
-
console.log(
|
|
15202
|
+
console.log(import_chalk30.default.green(" \u2713 demo content available"));
|
|
14731
15203
|
passed++;
|
|
14732
15204
|
} else {
|
|
14733
|
-
console.log(
|
|
15205
|
+
console.log(import_chalk30.default.red(" \u2717 demo content missing"));
|
|
15206
|
+
failed++;
|
|
15207
|
+
}
|
|
15208
|
+
try {
|
|
15209
|
+
const stdio = await testMcpStdioSubprocess();
|
|
15210
|
+
if (stdio.ok && (stdio.toolCount || 0) >= 10) {
|
|
15211
|
+
console.log(import_chalk30.default.green(` \u2713 stdio MCP subprocess responds (${stdio.toolCount} tools)`));
|
|
15212
|
+
passed++;
|
|
15213
|
+
} else if (stdio.ok) {
|
|
15214
|
+
console.log(import_chalk30.default.yellow(` ! stdio MCP subprocess ok but only ${stdio.toolCount || 0} tools`));
|
|
15215
|
+
failed++;
|
|
15216
|
+
} else {
|
|
15217
|
+
console.log(import_chalk30.default.red(" \u2717 stdio MCP subprocess failed"));
|
|
15218
|
+
failed++;
|
|
15219
|
+
}
|
|
15220
|
+
} catch (e) {
|
|
15221
|
+
console.log(import_chalk30.default.red(` \u2717 stdio MCP subprocess failed: ${e.message}`));
|
|
14734
15222
|
failed++;
|
|
14735
15223
|
}
|
|
14736
15224
|
console.log("");
|
|
14737
15225
|
if (failed === 0) {
|
|
14738
|
-
console.log(
|
|
14739
|
-
console.log(
|
|
15226
|
+
console.log(import_chalk30.default.green(`\u2713 all checks passed (${passed})`));
|
|
15227
|
+
console.log(import_chalk30.default.dim("\nStart server: hyv mcp\n"));
|
|
14740
15228
|
return true;
|
|
14741
15229
|
}
|
|
14742
|
-
console.log(
|
|
15230
|
+
console.log(import_chalk30.default.yellow(`! ${failed} check(s) failed, ${passed} passed`));
|
|
14743
15231
|
return false;
|
|
14744
15232
|
}
|
|
14745
15233
|
|
|
@@ -14869,9 +15357,9 @@ async function exportCommand(format, opts) {
|
|
|
14869
15357
|
init_access();
|
|
14870
15358
|
init_welcome();
|
|
14871
15359
|
var fs24 = __toESM(require("fs"));
|
|
14872
|
-
var
|
|
15360
|
+
var path23 = __toESM(require("path"));
|
|
14873
15361
|
var program2 = new Command();
|
|
14874
|
-
var pkgPath2 =
|
|
15362
|
+
var pkgPath2 = path23.resolve(__dirname, "..", "package.json");
|
|
14875
15363
|
var pkgVersion2 = (() => {
|
|
14876
15364
|
try {
|
|
14877
15365
|
return JSON.parse(fs24.readFileSync(pkgPath2, "utf-8")).version;
|
|
@@ -14918,15 +15406,15 @@ program2.command("mcp").description("Start MCP server (for Claude Desktop and ot
|
|
|
14918
15406
|
return;
|
|
14919
15407
|
}
|
|
14920
15408
|
if (opts.setupChatgpt) {
|
|
14921
|
-
console.log(
|
|
15409
|
+
console.log(import_chalk31.default.bold("\nhold your voice \u2014 chatgpt setup\n"));
|
|
14922
15410
|
console.log("To connect HYV to ChatGPT:");
|
|
14923
|
-
console.log(
|
|
14924
|
-
console.log(
|
|
14925
|
-
console.log(
|
|
14926
|
-
console.log(
|
|
15411
|
+
console.log(import_chalk31.default.dim(" 1. Go to ") + import_chalk31.default.cyan("https://chatgpt.com/#settings/Connectors"));
|
|
15412
|
+
console.log(import_chalk31.default.dim(" 2. Add a new connector"));
|
|
15413
|
+
console.log(import_chalk31.default.dim(" 3. For local MCP, use: ") + import_chalk31.default.cyan("hyv mcp"));
|
|
15414
|
+
console.log(import_chalk31.default.dim(" 4. ChatGPT Desktop supports stdio MCP servers"));
|
|
14927
15415
|
console.log("");
|
|
14928
|
-
console.log(
|
|
14929
|
-
console.log(
|
|
15416
|
+
console.log(import_chalk31.default.dim("Note: The remote HTTP MCP endpoint is not yet available."));
|
|
15417
|
+
console.log(import_chalk31.default.dim("Use the local stdio MCP server with Claude Desktop or Claude Code instead."));
|
|
14930
15418
|
return;
|
|
14931
15419
|
}
|
|
14932
15420
|
startMcpServer();
|