@holdyourvoice/hyv 2.9.13 → 2.9.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/agents/chatgpt.md +12 -1
- package/agents/cursor.md +3 -1
- package/agents/generic.md +10 -1
- package/dist/index.js +1031 -451
- package/package.json +2 -2
- package/scripts/postinstall-lib.js +333 -25
package/dist/index.js
CHANGED
|
@@ -973,8 +973,8 @@ var require_command = __commonJS({
|
|
|
973
973
|
"node_modules/commander/lib/command.js"(exports2) {
|
|
974
974
|
var EventEmitter = require("node:events").EventEmitter;
|
|
975
975
|
var childProcess = require("node:child_process");
|
|
976
|
-
var
|
|
977
|
-
var
|
|
976
|
+
var path28 = require("node:path");
|
|
977
|
+
var fs31 = require("node:fs");
|
|
978
978
|
var process2 = require("node:process");
|
|
979
979
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
980
980
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1916,13 +1916,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1916
1916
|
let launchWithNode = false;
|
|
1917
1917
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1918
1918
|
function findFile(baseDir, baseName) {
|
|
1919
|
-
const localBin =
|
|
1920
|
-
if (
|
|
1919
|
+
const localBin = path28.resolve(baseDir, baseName);
|
|
1920
|
+
if (fs31.existsSync(localBin))
|
|
1921
1921
|
return localBin;
|
|
1922
|
-
if (sourceExt.includes(
|
|
1922
|
+
if (sourceExt.includes(path28.extname(baseName)))
|
|
1923
1923
|
return void 0;
|
|
1924
1924
|
const foundExt = sourceExt.find(
|
|
1925
|
-
(ext) =>
|
|
1925
|
+
(ext) => fs31.existsSync(`${localBin}${ext}`)
|
|
1926
1926
|
);
|
|
1927
1927
|
if (foundExt)
|
|
1928
1928
|
return `${localBin}${foundExt}`;
|
|
@@ -1935,21 +1935,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1935
1935
|
if (this._scriptPath) {
|
|
1936
1936
|
let resolvedScriptPath;
|
|
1937
1937
|
try {
|
|
1938
|
-
resolvedScriptPath =
|
|
1938
|
+
resolvedScriptPath = fs31.realpathSync(this._scriptPath);
|
|
1939
1939
|
} catch (err) {
|
|
1940
1940
|
resolvedScriptPath = this._scriptPath;
|
|
1941
1941
|
}
|
|
1942
|
-
executableDir =
|
|
1943
|
-
|
|
1942
|
+
executableDir = path28.resolve(
|
|
1943
|
+
path28.dirname(resolvedScriptPath),
|
|
1944
1944
|
executableDir
|
|
1945
1945
|
);
|
|
1946
1946
|
}
|
|
1947
1947
|
if (executableDir) {
|
|
1948
1948
|
let localFile = findFile(executableDir, executableFile);
|
|
1949
1949
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1950
|
-
const legacyName =
|
|
1950
|
+
const legacyName = path28.basename(
|
|
1951
1951
|
this._scriptPath,
|
|
1952
|
-
|
|
1952
|
+
path28.extname(this._scriptPath)
|
|
1953
1953
|
);
|
|
1954
1954
|
if (legacyName !== this._name) {
|
|
1955
1955
|
localFile = findFile(
|
|
@@ -1960,7 +1960,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1960
1960
|
}
|
|
1961
1961
|
executableFile = localFile || executableFile;
|
|
1962
1962
|
}
|
|
1963
|
-
launchWithNode = sourceExt.includes(
|
|
1963
|
+
launchWithNode = sourceExt.includes(path28.extname(executableFile));
|
|
1964
1964
|
let proc;
|
|
1965
1965
|
if (process2.platform !== "win32") {
|
|
1966
1966
|
if (launchWithNode) {
|
|
@@ -2817,7 +2817,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2817
2817
|
* @return {Command}
|
|
2818
2818
|
*/
|
|
2819
2819
|
nameFromFilename(filename) {
|
|
2820
|
-
this._name =
|
|
2820
|
+
this._name = path28.basename(filename, path28.extname(filename));
|
|
2821
2821
|
return this;
|
|
2822
2822
|
}
|
|
2823
2823
|
/**
|
|
@@ -2831,10 +2831,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2831
2831
|
* @param {string} [path]
|
|
2832
2832
|
* @return {(string|null|Command)}
|
|
2833
2833
|
*/
|
|
2834
|
-
executableDir(
|
|
2835
|
-
if (
|
|
2834
|
+
executableDir(path29) {
|
|
2835
|
+
if (path29 === void 0)
|
|
2836
2836
|
return this._executableDir;
|
|
2837
|
-
this._executableDir =
|
|
2837
|
+
this._executableDir = path29;
|
|
2838
2838
|
return this;
|
|
2839
2839
|
}
|
|
2840
2840
|
/**
|
|
@@ -3934,15 +3934,15 @@ var require_route = __commonJS({
|
|
|
3934
3934
|
};
|
|
3935
3935
|
}
|
|
3936
3936
|
function wrapConversion(toModel, graph) {
|
|
3937
|
-
const
|
|
3937
|
+
const path28 = [graph[toModel].parent, toModel];
|
|
3938
3938
|
let fn = conversions[graph[toModel].parent][toModel];
|
|
3939
3939
|
let cur = graph[toModel].parent;
|
|
3940
3940
|
while (graph[cur].parent) {
|
|
3941
|
-
|
|
3941
|
+
path28.unshift(graph[cur].parent);
|
|
3942
3942
|
fn = link(conversions[graph[cur].parent][cur], fn);
|
|
3943
3943
|
cur = graph[cur].parent;
|
|
3944
3944
|
}
|
|
3945
|
-
fn.conversion =
|
|
3945
|
+
fn.conversion = path28;
|
|
3946
3946
|
return fn;
|
|
3947
3947
|
}
|
|
3948
3948
|
module2.exports = function(fromModel) {
|
|
@@ -4182,7 +4182,7 @@ var require_has_flag = __commonJS({
|
|
|
4182
4182
|
var require_supports_color = __commonJS({
|
|
4183
4183
|
"node_modules/supports-color/index.js"(exports2, module2) {
|
|
4184
4184
|
"use strict";
|
|
4185
|
-
var
|
|
4185
|
+
var os15 = require("os");
|
|
4186
4186
|
var tty = require("tty");
|
|
4187
4187
|
var hasFlag = require_has_flag();
|
|
4188
4188
|
var { env } = process;
|
|
@@ -4230,7 +4230,7 @@ var require_supports_color = __commonJS({
|
|
|
4230
4230
|
return min;
|
|
4231
4231
|
}
|
|
4232
4232
|
if (process.platform === "win32") {
|
|
4233
|
-
const osRelease =
|
|
4233
|
+
const osRelease = os15.release().split(".");
|
|
4234
4234
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
4235
4235
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
4236
4236
|
}
|
|
@@ -4381,14 +4381,14 @@ var require_templates = __commonJS({
|
|
|
4381
4381
|
}
|
|
4382
4382
|
return results;
|
|
4383
4383
|
}
|
|
4384
|
-
function buildStyle(
|
|
4384
|
+
function buildStyle(chalk35, styles) {
|
|
4385
4385
|
const enabled = {};
|
|
4386
4386
|
for (const layer of styles) {
|
|
4387
4387
|
for (const style of layer.styles) {
|
|
4388
4388
|
enabled[style[0]] = layer.inverse ? null : style.slice(1);
|
|
4389
4389
|
}
|
|
4390
4390
|
}
|
|
4391
|
-
let current =
|
|
4391
|
+
let current = chalk35;
|
|
4392
4392
|
for (const [styleName, styles2] of Object.entries(enabled)) {
|
|
4393
4393
|
if (!Array.isArray(styles2)) {
|
|
4394
4394
|
continue;
|
|
@@ -4400,7 +4400,7 @@ var require_templates = __commonJS({
|
|
|
4400
4400
|
}
|
|
4401
4401
|
return current;
|
|
4402
4402
|
}
|
|
4403
|
-
module2.exports = (
|
|
4403
|
+
module2.exports = (chalk35, temporary) => {
|
|
4404
4404
|
const styles = [];
|
|
4405
4405
|
const chunks = [];
|
|
4406
4406
|
let chunk = [];
|
|
@@ -4410,13 +4410,13 @@ var require_templates = __commonJS({
|
|
|
4410
4410
|
} else if (style) {
|
|
4411
4411
|
const string = chunk.join("");
|
|
4412
4412
|
chunk = [];
|
|
4413
|
-
chunks.push(styles.length === 0 ? string : buildStyle(
|
|
4413
|
+
chunks.push(styles.length === 0 ? string : buildStyle(chalk35, styles)(string));
|
|
4414
4414
|
styles.push({ inverse, styles: parseStyle(style) });
|
|
4415
4415
|
} else if (close) {
|
|
4416
4416
|
if (styles.length === 0) {
|
|
4417
4417
|
throw new Error("Found extraneous } in Chalk template literal");
|
|
4418
4418
|
}
|
|
4419
|
-
chunks.push(buildStyle(
|
|
4419
|
+
chunks.push(buildStyle(chalk35, styles)(chunk.join("")));
|
|
4420
4420
|
chunk = [];
|
|
4421
4421
|
styles.pop();
|
|
4422
4422
|
} else {
|
|
@@ -4464,16 +4464,16 @@ var require_source = __commonJS({
|
|
|
4464
4464
|
}
|
|
4465
4465
|
};
|
|
4466
4466
|
var chalkFactory = (options) => {
|
|
4467
|
-
const
|
|
4468
|
-
applyOptions(
|
|
4469
|
-
|
|
4470
|
-
Object.setPrototypeOf(
|
|
4471
|
-
Object.setPrototypeOf(
|
|
4472
|
-
|
|
4467
|
+
const chalk36 = {};
|
|
4468
|
+
applyOptions(chalk36, options);
|
|
4469
|
+
chalk36.template = (...arguments_) => chalkTag(chalk36.template, ...arguments_);
|
|
4470
|
+
Object.setPrototypeOf(chalk36, Chalk.prototype);
|
|
4471
|
+
Object.setPrototypeOf(chalk36.template, chalk36);
|
|
4472
|
+
chalk36.template.constructor = () => {
|
|
4473
4473
|
throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.");
|
|
4474
4474
|
};
|
|
4475
|
-
|
|
4476
|
-
return
|
|
4475
|
+
chalk36.template.Instance = ChalkClass;
|
|
4476
|
+
return chalk36.template;
|
|
4477
4477
|
};
|
|
4478
4478
|
function Chalk(options) {
|
|
4479
4479
|
return chalkFactory(options);
|
|
@@ -4584,7 +4584,7 @@ var require_source = __commonJS({
|
|
|
4584
4584
|
return openAll + string + closeAll;
|
|
4585
4585
|
};
|
|
4586
4586
|
var template;
|
|
4587
|
-
var chalkTag = (
|
|
4587
|
+
var chalkTag = (chalk36, ...strings) => {
|
|
4588
4588
|
const [firstString] = strings;
|
|
4589
4589
|
if (!isArray(firstString) || !isArray(firstString.raw)) {
|
|
4590
4590
|
return strings.join(" ");
|
|
@@ -4600,14 +4600,14 @@ var require_source = __commonJS({
|
|
|
4600
4600
|
if (template === void 0) {
|
|
4601
4601
|
template = require_templates();
|
|
4602
4602
|
}
|
|
4603
|
-
return template(
|
|
4603
|
+
return template(chalk36, parts.join(""));
|
|
4604
4604
|
};
|
|
4605
4605
|
Object.defineProperties(Chalk.prototype, styles);
|
|
4606
|
-
var
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
module2.exports =
|
|
4606
|
+
var chalk35 = Chalk();
|
|
4607
|
+
chalk35.supportsColor = stdoutColor;
|
|
4608
|
+
chalk35.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
4609
|
+
chalk35.stderr.supportsColor = stderrColor;
|
|
4610
|
+
module2.exports = chalk35;
|
|
4611
4611
|
}
|
|
4612
4612
|
});
|
|
4613
4613
|
|
|
@@ -4990,11 +4990,11 @@ var init_config = __esm({
|
|
|
4990
4990
|
var require_is_docker = __commonJS({
|
|
4991
4991
|
"node_modules/is-docker/index.js"(exports2, module2) {
|
|
4992
4992
|
"use strict";
|
|
4993
|
-
var
|
|
4993
|
+
var fs31 = require("fs");
|
|
4994
4994
|
var isDocker;
|
|
4995
4995
|
function hasDockerEnv() {
|
|
4996
4996
|
try {
|
|
4997
|
-
|
|
4997
|
+
fs31.statSync("/.dockerenv");
|
|
4998
4998
|
return true;
|
|
4999
4999
|
} catch (_2) {
|
|
5000
5000
|
return false;
|
|
@@ -5002,7 +5002,7 @@ var require_is_docker = __commonJS({
|
|
|
5002
5002
|
}
|
|
5003
5003
|
function hasDockerCGroup() {
|
|
5004
5004
|
try {
|
|
5005
|
-
return
|
|
5005
|
+
return fs31.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
|
5006
5006
|
} catch (_2) {
|
|
5007
5007
|
return false;
|
|
5008
5008
|
}
|
|
@@ -5020,21 +5020,21 @@ var require_is_docker = __commonJS({
|
|
|
5020
5020
|
var require_is_wsl = __commonJS({
|
|
5021
5021
|
"node_modules/is-wsl/index.js"(exports2, module2) {
|
|
5022
5022
|
"use strict";
|
|
5023
|
-
var
|
|
5024
|
-
var
|
|
5023
|
+
var os15 = require("os");
|
|
5024
|
+
var fs31 = require("fs");
|
|
5025
5025
|
var isDocker = require_is_docker();
|
|
5026
5026
|
var isWsl = () => {
|
|
5027
5027
|
if (process.platform !== "linux") {
|
|
5028
5028
|
return false;
|
|
5029
5029
|
}
|
|
5030
|
-
if (
|
|
5030
|
+
if (os15.release().toLowerCase().includes("microsoft")) {
|
|
5031
5031
|
if (isDocker()) {
|
|
5032
5032
|
return false;
|
|
5033
5033
|
}
|
|
5034
5034
|
return true;
|
|
5035
5035
|
}
|
|
5036
5036
|
try {
|
|
5037
|
-
return
|
|
5037
|
+
return fs31.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isDocker() : false;
|
|
5038
5038
|
} catch (_2) {
|
|
5039
5039
|
return false;
|
|
5040
5040
|
}
|
|
@@ -5073,17 +5073,17 @@ var require_define_lazy_prop = __commonJS({
|
|
|
5073
5073
|
// node_modules/open/index.js
|
|
5074
5074
|
var require_open = __commonJS({
|
|
5075
5075
|
"node_modules/open/index.js"(exports2, module2) {
|
|
5076
|
-
var
|
|
5076
|
+
var path28 = require("path");
|
|
5077
5077
|
var childProcess = require("child_process");
|
|
5078
|
-
var { promises:
|
|
5078
|
+
var { promises: fs31, constants: fsConstants } = require("fs");
|
|
5079
5079
|
var isWsl = require_is_wsl();
|
|
5080
5080
|
var isDocker = require_is_docker();
|
|
5081
5081
|
var defineLazyProperty = require_define_lazy_prop();
|
|
5082
|
-
var localXdgOpenPath =
|
|
5082
|
+
var localXdgOpenPath = path28.join(__dirname, "xdg-open");
|
|
5083
5083
|
var { platform, arch } = process;
|
|
5084
5084
|
var hasContainerEnv = () => {
|
|
5085
5085
|
try {
|
|
5086
|
-
|
|
5086
|
+
fs31.statSync("/run/.containerenv");
|
|
5087
5087
|
return true;
|
|
5088
5088
|
} catch {
|
|
5089
5089
|
return false;
|
|
@@ -5106,14 +5106,14 @@ var require_open = __commonJS({
|
|
|
5106
5106
|
const configFilePath = "/etc/wsl.conf";
|
|
5107
5107
|
let isConfigFileExists = false;
|
|
5108
5108
|
try {
|
|
5109
|
-
await
|
|
5109
|
+
await fs31.access(configFilePath, fsConstants.F_OK);
|
|
5110
5110
|
isConfigFileExists = true;
|
|
5111
5111
|
} catch {
|
|
5112
5112
|
}
|
|
5113
5113
|
if (!isConfigFileExists) {
|
|
5114
5114
|
return defaultMountPoint;
|
|
5115
5115
|
}
|
|
5116
|
-
const configContent = await
|
|
5116
|
+
const configContent = await fs31.readFile(configFilePath, { encoding: "utf8" });
|
|
5117
5117
|
const configMountPoint = /(?<!#.*)root\s*=\s*(?<mountPoint>.*)/g.exec(configContent);
|
|
5118
5118
|
if (!configMountPoint) {
|
|
5119
5119
|
return defaultMountPoint;
|
|
@@ -5213,7 +5213,7 @@ var require_open = __commonJS({
|
|
|
5213
5213
|
const isBundled = !__dirname || __dirname === "/";
|
|
5214
5214
|
let exeLocalXdgOpen = false;
|
|
5215
5215
|
try {
|
|
5216
|
-
await
|
|
5216
|
+
await fs31.access(localXdgOpenPath, fsConstants.X_OK);
|
|
5217
5217
|
exeLocalXdgOpen = true;
|
|
5218
5218
|
} catch {
|
|
5219
5219
|
}
|
|
@@ -5236,14 +5236,14 @@ var require_open = __commonJS({
|
|
|
5236
5236
|
}
|
|
5237
5237
|
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
|
5238
5238
|
if (options.wait) {
|
|
5239
|
-
return new Promise((
|
|
5239
|
+
return new Promise((resolve16, reject) => {
|
|
5240
5240
|
subprocess.once("error", reject);
|
|
5241
5241
|
subprocess.once("close", (exitCode) => {
|
|
5242
5242
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
5243
5243
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
5244
5244
|
return;
|
|
5245
5245
|
}
|
|
5246
|
-
|
|
5246
|
+
resolve16(subprocess);
|
|
5247
5247
|
});
|
|
5248
5248
|
});
|
|
5249
5249
|
}
|
|
@@ -5406,7 +5406,7 @@ var init_free_paid = __esm({
|
|
|
5406
5406
|
];
|
|
5407
5407
|
COMMUNITY_URL = "https://holdyourvoice.com/community";
|
|
5408
5408
|
PRICING_URL = "https://holdyourvoice.com/#pricing";
|
|
5409
|
-
DASHBOARD_BILLING_URL = "https://holdyourvoice.com/
|
|
5409
|
+
DASHBOARD_BILLING_URL = "https://holdyourvoice.com/app/billing";
|
|
5410
5410
|
}
|
|
5411
5411
|
});
|
|
5412
5412
|
|
|
@@ -5459,16 +5459,16 @@ function compareSemver(a, b) {
|
|
|
5459
5459
|
return 0;
|
|
5460
5460
|
}
|
|
5461
5461
|
function fetchLatestNpmVersion(timeoutMs = 8e3) {
|
|
5462
|
-
return new Promise((
|
|
5462
|
+
return new Promise((resolve16) => {
|
|
5463
5463
|
(0, import_child_process.execFile)(
|
|
5464
5464
|
"npm",
|
|
5465
5465
|
["view", "@holdyourvoice/hyv", "version"],
|
|
5466
5466
|
{ timeout: timeoutMs, encoding: "utf-8" },
|
|
5467
5467
|
(err, stdout) => {
|
|
5468
5468
|
if (err || !stdout?.trim())
|
|
5469
|
-
|
|
5469
|
+
resolve16(null);
|
|
5470
5470
|
else
|
|
5471
|
-
|
|
5471
|
+
resolve16(stdout.trim());
|
|
5472
5472
|
}
|
|
5473
5473
|
);
|
|
5474
5474
|
});
|
|
@@ -5533,7 +5533,7 @@ function escapeHtml(value) {
|
|
|
5533
5533
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
5534
5534
|
}
|
|
5535
5535
|
function request(url, options = {}) {
|
|
5536
|
-
return new Promise((
|
|
5536
|
+
return new Promise((resolve16, reject) => {
|
|
5537
5537
|
const urlObj = new URL(url);
|
|
5538
5538
|
const isHttps = urlObj.protocol === "https:";
|
|
5539
5539
|
const client = isHttps ? https : http;
|
|
@@ -5554,9 +5554,9 @@ function request(url, options = {}) {
|
|
|
5554
5554
|
res.on("data", (chunk) => data += chunk);
|
|
5555
5555
|
res.on("end", () => {
|
|
5556
5556
|
try {
|
|
5557
|
-
|
|
5557
|
+
resolve16({ status: res.statusCode || 0, data: JSON.parse(data) });
|
|
5558
5558
|
} catch {
|
|
5559
|
-
|
|
5559
|
+
resolve16({ status: res.statusCode || 0, data });
|
|
5560
5560
|
}
|
|
5561
5561
|
});
|
|
5562
5562
|
});
|
|
@@ -5614,9 +5614,9 @@ async function authenticateWithLicense(licenseKey) {
|
|
|
5614
5614
|
}
|
|
5615
5615
|
async function authenticateWithBrowser() {
|
|
5616
5616
|
const server = http.createServer();
|
|
5617
|
-
const port = await new Promise((
|
|
5617
|
+
const port = await new Promise((resolve16) => {
|
|
5618
5618
|
server.listen(0, "127.0.0.1", () => {
|
|
5619
|
-
|
|
5619
|
+
resolve16(server.address().port);
|
|
5620
5620
|
});
|
|
5621
5621
|
});
|
|
5622
5622
|
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
@@ -5635,7 +5635,7 @@ async function authenticateWithBrowser() {
|
|
|
5635
5635
|
}
|
|
5636
5636
|
console.log(import_chalk2.default.cyan("\nOpening browser for authentication..."));
|
|
5637
5637
|
await (0, import_open.default)(assertSafeOAuthUrl(auth_url));
|
|
5638
|
-
const authData = await new Promise((
|
|
5638
|
+
const authData = await new Promise((resolve16, reject) => {
|
|
5639
5639
|
const timeout = setTimeout(() => {
|
|
5640
5640
|
server.close();
|
|
5641
5641
|
reject(new Error("Authentication timeout. Please try again."));
|
|
@@ -5692,7 +5692,7 @@ async function authenticateWithBrowser() {
|
|
|
5692
5692
|
`);
|
|
5693
5693
|
clearTimeout(timeout);
|
|
5694
5694
|
server.close();
|
|
5695
|
-
|
|
5695
|
+
resolve16(data);
|
|
5696
5696
|
} catch (error) {
|
|
5697
5697
|
res.writeHead(500, { "Content-Type": "text/html" });
|
|
5698
5698
|
res.end(`<h1>Authentication failed</h1><p>${escapeHtml(error.message)}</p>`);
|
|
@@ -5710,7 +5710,7 @@ async function authenticateWithBrowser() {
|
|
|
5710
5710
|
return authData;
|
|
5711
5711
|
}
|
|
5712
5712
|
async function openAuthenticatedDashboard(opts = {}) {
|
|
5713
|
-
const nextPath = opts.next || "/
|
|
5713
|
+
const nextPath = opts.next || "/app/billing";
|
|
5714
5714
|
try {
|
|
5715
5715
|
const response = await authenticatedRequest(cliApiUrl("/cli/auth/web-handoff"), {
|
|
5716
5716
|
method: "POST",
|
|
@@ -5725,7 +5725,7 @@ async function openAuthenticatedDashboard(opts = {}) {
|
|
|
5725
5725
|
}
|
|
5726
5726
|
} catch {
|
|
5727
5727
|
}
|
|
5728
|
-
const billingUrl = nextPath === "/
|
|
5728
|
+
const billingUrl = nextPath === "/app/billing" ? DASHBOARD_BILLING_URL : assertSafeOpenUrl(`https://holdyourvoice.com${nextPath}`);
|
|
5729
5729
|
await (0, import_open.default)(billingUrl);
|
|
5730
5730
|
}
|
|
5731
5731
|
async function refreshToken(tokenOverride) {
|
|
@@ -5854,17 +5854,11 @@ var init_telemetry = __esm({
|
|
|
5854
5854
|
});
|
|
5855
5855
|
|
|
5856
5856
|
// src/lib/api.ts
|
|
5857
|
-
|
|
5858
|
-
__export(api_exports, {
|
|
5859
|
-
apiGet: () => apiGet,
|
|
5860
|
-
apiPost: () => apiPost,
|
|
5861
|
-
requireSubscription: () => requireSubscription
|
|
5862
|
-
});
|
|
5863
|
-
async function request2(method, path27, body) {
|
|
5857
|
+
async function request2(method, path28, body) {
|
|
5864
5858
|
const token = await getValidToken();
|
|
5865
5859
|
if (!token)
|
|
5866
5860
|
throw new Error("you're not signed in yet. run: hyv init");
|
|
5867
|
-
const url = `${API_BASE}${
|
|
5861
|
+
const url = `${API_BASE}${path28}`;
|
|
5868
5862
|
const opts = {
|
|
5869
5863
|
method,
|
|
5870
5864
|
headers: {
|
|
@@ -5883,21 +5877,17 @@ async function request2(method, path27, body) {
|
|
|
5883
5877
|
if (res.status === 401)
|
|
5884
5878
|
throw new Error("your session expired. run: hyv init to sign in again.");
|
|
5885
5879
|
if (res.status === 403)
|
|
5886
|
-
throw new Error("you don't have access to this feature. check your plan at holdyourvoice.com/
|
|
5880
|
+
throw new Error("you don't have access to this feature. check your plan at holdyourvoice.com/app/billing");
|
|
5887
5881
|
if (!res.ok) {
|
|
5888
5882
|
throw new Error(`something went wrong (${res.status}). try again or contact support.`);
|
|
5889
5883
|
}
|
|
5890
5884
|
return res.json();
|
|
5891
5885
|
}
|
|
5892
|
-
function apiGet(
|
|
5893
|
-
return request2("GET",
|
|
5894
|
-
}
|
|
5895
|
-
function apiPost(path27, body) {
|
|
5896
|
-
return request2("POST", path27, body);
|
|
5886
|
+
function apiGet(path28) {
|
|
5887
|
+
return request2("GET", path28);
|
|
5897
5888
|
}
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
await requirePaidFeature2("profiles");
|
|
5889
|
+
function apiPost(path28, body) {
|
|
5890
|
+
return request2("POST", path28, body);
|
|
5901
5891
|
}
|
|
5902
5892
|
var init_api = __esm({
|
|
5903
5893
|
"src/lib/api.ts"() {
|
|
@@ -5907,128 +5897,6 @@ var init_api = __esm({
|
|
|
5907
5897
|
}
|
|
5908
5898
|
});
|
|
5909
5899
|
|
|
5910
|
-
// src/lib/access.ts
|
|
5911
|
-
var access_exports = {};
|
|
5912
|
-
__export(access_exports, {
|
|
5913
|
-
formatModeLabel: () => formatModeLabel,
|
|
5914
|
-
getAccessState: () => getAccessState,
|
|
5915
|
-
isLocalOnlyMode: () => isLocalOnlyMode,
|
|
5916
|
-
maybeShowLimitedModeHint: () => maybeShowLimitedModeHint,
|
|
5917
|
-
requirePaidFeature: () => requirePaidFeature,
|
|
5918
|
-
setLocalOnlyMode: () => setLocalOnlyMode
|
|
5919
|
-
});
|
|
5920
|
-
function setLocalOnlyMode(enabled) {
|
|
5921
|
-
localOnlyOverride = enabled;
|
|
5922
|
-
}
|
|
5923
|
-
function isLocalOnlyMode() {
|
|
5924
|
-
if (localOnlyOverride)
|
|
5925
|
-
return true;
|
|
5926
|
-
const env = process.env.HYV_LOCAL_ONLY;
|
|
5927
|
-
return env === "1" || env === "true";
|
|
5928
|
-
}
|
|
5929
|
-
async function getAccessState() {
|
|
5930
|
-
if (isLocalOnlyMode()) {
|
|
5931
|
-
return { authenticated: false, hasPaidPlan: false, plan: "local", localOnly: true };
|
|
5932
|
-
}
|
|
5933
|
-
const now = Date.now();
|
|
5934
|
-
if (cachedAccess && now - cachedAccess.at < ACCESS_CACHE_MS) {
|
|
5935
|
-
return cachedAccess.state;
|
|
5936
|
-
}
|
|
5937
|
-
const token = getToken();
|
|
5938
|
-
if (!token) {
|
|
5939
|
-
const state = { authenticated: false, hasPaidPlan: false, plan: "none", localOnly: false };
|
|
5940
|
-
cachedAccess = { state, at: now };
|
|
5941
|
-
return state;
|
|
5942
|
-
}
|
|
5943
|
-
try {
|
|
5944
|
-
const session = await checkSession();
|
|
5945
|
-
const plan = (session.plan || "none").toLowerCase();
|
|
5946
|
-
const hasPaidPlan = session.valid && plan !== "none" && plan !== "free" && plan !== "expired" && plan !== "unknown";
|
|
5947
|
-
const state = {
|
|
5948
|
-
authenticated: session.valid,
|
|
5949
|
-
hasPaidPlan,
|
|
5950
|
-
plan: session.plan || "none",
|
|
5951
|
-
localOnly: false
|
|
5952
|
-
};
|
|
5953
|
-
cachedAccess = { state, at: now };
|
|
5954
|
-
return state;
|
|
5955
|
-
} catch {
|
|
5956
|
-
const state = { authenticated: !!token, hasPaidPlan: false, plan: "unknown", localOnly: false };
|
|
5957
|
-
cachedAccess = { state, at: now };
|
|
5958
|
-
return state;
|
|
5959
|
-
}
|
|
5960
|
-
}
|
|
5961
|
-
async function requirePaidFeature(feature) {
|
|
5962
|
-
if (isLocalOnlyMode()) {
|
|
5963
|
-
throw new Error(
|
|
5964
|
-
`${FEATURE_MESSAGES[feature]} (local-only mode is on \u2014 unset HYV_LOCAL_ONLY or remove --local-only)`
|
|
5965
|
-
);
|
|
5966
|
-
}
|
|
5967
|
-
const token = getToken();
|
|
5968
|
-
if (!token) {
|
|
5969
|
-
throw new Error(`you're not signed in yet. run: hyv init \u2014 then ${FEATURE_MESSAGES[feature]}`);
|
|
5970
|
-
}
|
|
5971
|
-
let data;
|
|
5972
|
-
try {
|
|
5973
|
-
data = await apiGet("/cli/heartbeat");
|
|
5974
|
-
} catch (err) {
|
|
5975
|
-
const msg = err.message || "";
|
|
5976
|
-
if (msg.includes("not signed in") || msg.includes("session expired") || msg.includes("don't have access")) {
|
|
5977
|
-
throw err;
|
|
5978
|
-
}
|
|
5979
|
-
throw new Error("can't reach the server. check your internet connection and try again.");
|
|
5980
|
-
}
|
|
5981
|
-
const plan = (data.plan || "none").toLowerCase();
|
|
5982
|
-
const subStatus = String(data.subscription_status || data.status || "").toLowerCase();
|
|
5983
|
-
if (!data.plan || plan === "none" || plan === "free" || plan === "expired" || subStatus === "trialing" || subStatus === "none") {
|
|
5984
|
-
throw new Error(FEATURE_MESSAGES[feature]);
|
|
5985
|
-
}
|
|
5986
|
-
}
|
|
5987
|
-
async function maybeShowLimitedModeHint(hasProfile) {
|
|
5988
|
-
if (isLocalOnlyMode())
|
|
5989
|
-
return;
|
|
5990
|
-
const access = await getAccessState();
|
|
5991
|
-
if (access.hasPaidPlan)
|
|
5992
|
-
return;
|
|
5993
|
-
if (hasProfile) {
|
|
5994
|
-
console.log(import_chalk5.default.dim("\n using cached profile (local). sync for latest: hyv sync"));
|
|
5995
|
-
} else if (!access.authenticated) {
|
|
5996
|
-
console.log(import_chalk5.default.dim("\n local mode \u2014 free scan engine. profiles + learning: hyv init"));
|
|
5997
|
-
} else {
|
|
5998
|
-
console.log(import_chalk5.default.dim("\n local mode \u2014 upgrade for full profiles + learning: hyv upgrade"));
|
|
5999
|
-
}
|
|
6000
|
-
}
|
|
6001
|
-
function formatModeLabel(access, hasFullProfile) {
|
|
6002
|
-
if (access.localOnly)
|
|
6003
|
-
return "local-only (forced)";
|
|
6004
|
-
if (access.hasPaidPlan && hasFullProfile)
|
|
6005
|
-
return "full profile (paid)";
|
|
6006
|
-
if (hasFullProfile)
|
|
6007
|
-
return "cached profile (local)";
|
|
6008
|
-
if (access.authenticated)
|
|
6009
|
-
return "local engine (free)";
|
|
6010
|
-
return "local engine (free, not signed in)";
|
|
6011
|
-
}
|
|
6012
|
-
var import_chalk5, FEATURE_MESSAGES, localOnlyOverride, cachedAccess, ACCESS_CACHE_MS;
|
|
6013
|
-
var init_access = __esm({
|
|
6014
|
-
"src/lib/access.ts"() {
|
|
6015
|
-
"use strict";
|
|
6016
|
-
import_chalk5 = __toESM(require_source());
|
|
6017
|
-
init_config();
|
|
6018
|
-
init_auth();
|
|
6019
|
-
init_api();
|
|
6020
|
-
FEATURE_MESSAGES = {
|
|
6021
|
-
profiles: "syncing voice profiles from your account requires a paid plan. run: hyv upgrade",
|
|
6022
|
-
learning: "the learning loop (reinforce, add) requires a paid plan. run: hyv upgrade",
|
|
6023
|
-
premiumPrompts: "rich profile-aware rewrite prompts require a paid plan. run: hyv upgrade",
|
|
6024
|
-
serverAnalysis: "server-assisted analysis requires a paid plan. run: hyv upgrade"
|
|
6025
|
-
};
|
|
6026
|
-
localOnlyOverride = false;
|
|
6027
|
-
cachedAccess = null;
|
|
6028
|
-
ACCESS_CACHE_MS = 3e4;
|
|
6029
|
-
}
|
|
6030
|
-
});
|
|
6031
|
-
|
|
6032
5900
|
// src/lib/profile.ts
|
|
6033
5901
|
async function loadFullProfile(slug, opts = {}) {
|
|
6034
5902
|
const includeSamples = opts.includeSamples !== false;
|
|
@@ -6240,8 +6108,12 @@ function countLearnedPatterns(slug) {
|
|
|
6240
6108
|
async function loadProfileForCommand(name, opts = {}) {
|
|
6241
6109
|
const config = readConfig();
|
|
6242
6110
|
const candidates = [];
|
|
6243
|
-
if (name)
|
|
6111
|
+
if (name) {
|
|
6244
6112
|
candidates.push(name);
|
|
6113
|
+
const normalized = toSafeProfileCacheKey(name);
|
|
6114
|
+
if (normalized !== name)
|
|
6115
|
+
candidates.push(normalized);
|
|
6116
|
+
}
|
|
6245
6117
|
if (config.default_profile)
|
|
6246
6118
|
candidates.push(config.default_profile);
|
|
6247
6119
|
if (config.profile)
|
|
@@ -6292,6 +6164,250 @@ var init_local_profile = __esm({
|
|
|
6292
6164
|
}
|
|
6293
6165
|
});
|
|
6294
6166
|
|
|
6167
|
+
// src/lib/mcp-profile-hydrate.ts
|
|
6168
|
+
var mcp_profile_hydrate_exports = {};
|
|
6169
|
+
__export(mcp_profile_hydrate_exports, {
|
|
6170
|
+
ensureMcpProfilesHydrated: () => ensureMcpProfilesHydrated,
|
|
6171
|
+
formatMcpProfilesList: () => formatMcpProfilesList,
|
|
6172
|
+
normalizeProfileSlug: () => normalizeProfileSlug
|
|
6173
|
+
});
|
|
6174
|
+
function normalizeProfileSlug(name) {
|
|
6175
|
+
return toSafeProfileCacheKey(name);
|
|
6176
|
+
}
|
|
6177
|
+
async function ensureMcpProfilesHydrated(opts = {}) {
|
|
6178
|
+
if (process.env.VITEST) {
|
|
6179
|
+
return { ok: true, synced: [], skipped: true };
|
|
6180
|
+
}
|
|
6181
|
+
if (!getToken()) {
|
|
6182
|
+
return { ok: true, synced: [], skipped: true };
|
|
6183
|
+
}
|
|
6184
|
+
const now = Date.now();
|
|
6185
|
+
if (!opts.force && now - lastHydrateAt < HYDRATE_TTL_MS) {
|
|
6186
|
+
return { ok: true, synced: [], skipped: true };
|
|
6187
|
+
}
|
|
6188
|
+
if (hydrateInFlight && !opts.force) {
|
|
6189
|
+
return hydrateInFlight;
|
|
6190
|
+
}
|
|
6191
|
+
hydrateInFlight = runHydrate().then((result) => {
|
|
6192
|
+
lastHydrateAt = Date.now();
|
|
6193
|
+
return result;
|
|
6194
|
+
}).finally(() => {
|
|
6195
|
+
hydrateInFlight = null;
|
|
6196
|
+
});
|
|
6197
|
+
return hydrateInFlight;
|
|
6198
|
+
}
|
|
6199
|
+
async function runHydrate() {
|
|
6200
|
+
const synced = [];
|
|
6201
|
+
try {
|
|
6202
|
+
const data = await apiGet("/cli/profiles");
|
|
6203
|
+
const profiles = data.profiles || [];
|
|
6204
|
+
if (profiles.length === 0) {
|
|
6205
|
+
return { ok: true, synced: [] };
|
|
6206
|
+
}
|
|
6207
|
+
let defaultSlug;
|
|
6208
|
+
for (const row of profiles) {
|
|
6209
|
+
const slug = normalizeProfileSlug(row.slug || row.name);
|
|
6210
|
+
if (row.is_default)
|
|
6211
|
+
defaultSlug = slug;
|
|
6212
|
+
try {
|
|
6213
|
+
const detail = await apiGet(`/cli/profiles/${encodeURIComponent(slug)}`);
|
|
6214
|
+
const content = (detail.content || "").trim();
|
|
6215
|
+
if (content) {
|
|
6216
|
+
writeCachedProfile(slug, content);
|
|
6217
|
+
if (!synced.includes(slug))
|
|
6218
|
+
synced.push(slug);
|
|
6219
|
+
}
|
|
6220
|
+
await loadFullProfile(slug, {
|
|
6221
|
+
forceRefresh: true,
|
|
6222
|
+
serverUpdatedAt: row.updated_at || detail.updated_at
|
|
6223
|
+
});
|
|
6224
|
+
} catch {
|
|
6225
|
+
}
|
|
6226
|
+
}
|
|
6227
|
+
const config = readConfig();
|
|
6228
|
+
const localNames = /* @__PURE__ */ new Set([...listCachedProfiles(), ...listDiskCachedProfiles()]);
|
|
6229
|
+
const shouldSetDefault = defaultSlug && (!config.default_profile || !localNames.has(config.default_profile));
|
|
6230
|
+
if (shouldSetDefault && defaultSlug) {
|
|
6231
|
+
writeConfig({ ...config, default_profile: defaultSlug, profile: defaultSlug });
|
|
6232
|
+
}
|
|
6233
|
+
return { ok: true, synced, defaultProfile: defaultSlug || config.default_profile };
|
|
6234
|
+
} catch (err) {
|
|
6235
|
+
const message = err instanceof Error ? err.message : "profile sync failed";
|
|
6236
|
+
return { ok: false, synced, error: message };
|
|
6237
|
+
}
|
|
6238
|
+
}
|
|
6239
|
+
function formatMcpProfilesList(hydrate) {
|
|
6240
|
+
const config = readConfig();
|
|
6241
|
+
const local = [.../* @__PURE__ */ new Set([...listCachedProfiles(), ...listDiskCachedProfiles()])].sort();
|
|
6242
|
+
const active = config.default_profile || config.profile;
|
|
6243
|
+
const lines = ["### Voice profiles (MCP-ready)"];
|
|
6244
|
+
if (active && local.includes(active)) {
|
|
6245
|
+
lines.push(`Active default: **${active}** \u2014 hyv_scan / hyv_rewrite / hyv_clean use this unless you pass \`profile\`.`);
|
|
6246
|
+
} else if (local.length === 1) {
|
|
6247
|
+
lines.push(`Active default: **${local[0]}** (only local profile).`);
|
|
6248
|
+
} else if (local.length > 1) {
|
|
6249
|
+
lines.push("No default set \u2014 pass `profile` on tools, or run `hyv init` + create a default in the dashboard.");
|
|
6250
|
+
}
|
|
6251
|
+
if (local.length > 0) {
|
|
6252
|
+
lines.push("");
|
|
6253
|
+
lines.push("Local (ready for MCP tools now):");
|
|
6254
|
+
for (const name of local) {
|
|
6255
|
+
const mark = name === active ? " (default)" : "";
|
|
6256
|
+
lines.push(` \u2022 ${name}${mark}`);
|
|
6257
|
+
}
|
|
6258
|
+
} else {
|
|
6259
|
+
lines.push("");
|
|
6260
|
+
lines.push("No local profiles yet.");
|
|
6261
|
+
}
|
|
6262
|
+
if (!getToken()) {
|
|
6263
|
+
lines.push("");
|
|
6264
|
+
lines.push("Account profiles (dashboard / web): run **`hyv init`** once on this machine \u2014 MCP will auto-download them here.");
|
|
6265
|
+
lines.push("Terminal welcome (`hyv welcome`) saves locally immediately; no init needed for that path.");
|
|
6266
|
+
return lines.join("\n");
|
|
6267
|
+
}
|
|
6268
|
+
if (hydrate?.synced?.length) {
|
|
6269
|
+
lines.push("");
|
|
6270
|
+
lines.push(`Just synced from your account: ${hydrate.synced.join(", ")}`);
|
|
6271
|
+
} else if (hydrate?.error) {
|
|
6272
|
+
lines.push("");
|
|
6273
|
+
lines.push(`Account sync note: ${hydrate.error}`);
|
|
6274
|
+
} else if (local.length === 0 && hydrate?.skipped) {
|
|
6275
|
+
lines.push("");
|
|
6276
|
+
lines.push("Signed in \u2014 checking account\u2026 if profiles exist on holdyourvoice.com, they load automatically.");
|
|
6277
|
+
}
|
|
6278
|
+
lines.push("");
|
|
6279
|
+
lines.push("Same profile everywhere: build in **dashboard** or **`hyv welcome`**, then use MCP tools with no extra setup (after `hyv init` for dashboard-only profiles).");
|
|
6280
|
+
return lines.join("\n");
|
|
6281
|
+
}
|
|
6282
|
+
var lastHydrateAt, hydrateInFlight, HYDRATE_TTL_MS;
|
|
6283
|
+
var init_mcp_profile_hydrate = __esm({
|
|
6284
|
+
"src/lib/mcp-profile-hydrate.ts"() {
|
|
6285
|
+
"use strict";
|
|
6286
|
+
init_config();
|
|
6287
|
+
init_api();
|
|
6288
|
+
init_profile();
|
|
6289
|
+
init_local_profile();
|
|
6290
|
+
lastHydrateAt = 0;
|
|
6291
|
+
hydrateInFlight = null;
|
|
6292
|
+
HYDRATE_TTL_MS = 5 * 60 * 1e3;
|
|
6293
|
+
}
|
|
6294
|
+
});
|
|
6295
|
+
|
|
6296
|
+
// src/lib/access.ts
|
|
6297
|
+
function setLocalOnlyMode(enabled) {
|
|
6298
|
+
localOnlyOverride = enabled;
|
|
6299
|
+
}
|
|
6300
|
+
function isLocalOnlyMode() {
|
|
6301
|
+
if (localOnlyOverride)
|
|
6302
|
+
return true;
|
|
6303
|
+
const env = process.env.HYV_LOCAL_ONLY;
|
|
6304
|
+
return env === "1" || env === "true";
|
|
6305
|
+
}
|
|
6306
|
+
async function getAccessState() {
|
|
6307
|
+
if (isLocalOnlyMode()) {
|
|
6308
|
+
return { authenticated: false, hasPaidPlan: false, plan: "local", localOnly: true };
|
|
6309
|
+
}
|
|
6310
|
+
const now = Date.now();
|
|
6311
|
+
if (cachedAccess && now - cachedAccess.at < ACCESS_CACHE_MS) {
|
|
6312
|
+
return cachedAccess.state;
|
|
6313
|
+
}
|
|
6314
|
+
const token = getToken();
|
|
6315
|
+
if (!token) {
|
|
6316
|
+
const state = { authenticated: false, hasPaidPlan: false, plan: "none", localOnly: false };
|
|
6317
|
+
cachedAccess = { state, at: now };
|
|
6318
|
+
return state;
|
|
6319
|
+
}
|
|
6320
|
+
try {
|
|
6321
|
+
const session = await checkSession();
|
|
6322
|
+
const plan = (session.plan || "none").toLowerCase();
|
|
6323
|
+
const subStatus = String(session.subscription_status || "").toLowerCase();
|
|
6324
|
+
const activeSubscription = !subStatus || ["active", "past_due", "trialing"].includes(subStatus);
|
|
6325
|
+
const hasPaidPlan = session.valid && activeSubscription && plan !== "none" && plan !== "free" && plan !== "expired" && plan !== "unknown" && plan !== "pending";
|
|
6326
|
+
const state = {
|
|
6327
|
+
authenticated: session.valid,
|
|
6328
|
+
hasPaidPlan,
|
|
6329
|
+
plan: session.plan || "none",
|
|
6330
|
+
localOnly: false
|
|
6331
|
+
};
|
|
6332
|
+
cachedAccess = { state, at: now };
|
|
6333
|
+
return state;
|
|
6334
|
+
} catch {
|
|
6335
|
+
const state = { authenticated: !!token, hasPaidPlan: false, plan: "unknown", localOnly: false };
|
|
6336
|
+
cachedAccess = { state, at: now };
|
|
6337
|
+
return state;
|
|
6338
|
+
}
|
|
6339
|
+
}
|
|
6340
|
+
async function requirePaidFeature(feature) {
|
|
6341
|
+
if (isLocalOnlyMode()) {
|
|
6342
|
+
throw new Error(
|
|
6343
|
+
`${FEATURE_MESSAGES[feature]} (local-only mode is on \u2014 unset HYV_LOCAL_ONLY or remove --local-only)`
|
|
6344
|
+
);
|
|
6345
|
+
}
|
|
6346
|
+
const token = getToken();
|
|
6347
|
+
if (!token) {
|
|
6348
|
+
throw new Error(`you're not signed in yet. run: hyv init \u2014 then ${FEATURE_MESSAGES[feature]}`);
|
|
6349
|
+
}
|
|
6350
|
+
let data;
|
|
6351
|
+
try {
|
|
6352
|
+
data = await apiGet("/cli/heartbeat");
|
|
6353
|
+
} catch (err) {
|
|
6354
|
+
const msg = err.message || "";
|
|
6355
|
+
if (msg.includes("not signed in") || msg.includes("session expired") || msg.includes("don't have access")) {
|
|
6356
|
+
throw err;
|
|
6357
|
+
}
|
|
6358
|
+
throw new Error("can't reach the server. check your internet connection and try again.");
|
|
6359
|
+
}
|
|
6360
|
+
const plan = (data.plan || "none").toLowerCase();
|
|
6361
|
+
const subStatus = String(data.subscription_status || data.status || "").toLowerCase();
|
|
6362
|
+
if (!data.plan || plan === "none" || plan === "free" || plan === "expired" || subStatus === "trialing" || subStatus === "none") {
|
|
6363
|
+
throw new Error(FEATURE_MESSAGES[feature]);
|
|
6364
|
+
}
|
|
6365
|
+
}
|
|
6366
|
+
async function maybeShowLimitedModeHint(hasProfile) {
|
|
6367
|
+
if (isLocalOnlyMode())
|
|
6368
|
+
return;
|
|
6369
|
+
const access = await getAccessState();
|
|
6370
|
+
if (access.hasPaidPlan)
|
|
6371
|
+
return;
|
|
6372
|
+
if (hasProfile) {
|
|
6373
|
+
console.log(import_chalk5.default.dim("\n using cached profile (local). sync for latest: hyv sync"));
|
|
6374
|
+
} else if (!access.authenticated) {
|
|
6375
|
+
console.log(import_chalk5.default.dim("\n local mode \u2014 free scan engine. profiles + learning: hyv init"));
|
|
6376
|
+
} else {
|
|
6377
|
+
console.log(import_chalk5.default.dim("\n local mode \u2014 upgrade for full profiles + learning: hyv upgrade"));
|
|
6378
|
+
}
|
|
6379
|
+
}
|
|
6380
|
+
function formatModeLabel(access, hasFullProfile) {
|
|
6381
|
+
if (access.localOnly)
|
|
6382
|
+
return "local-only (forced)";
|
|
6383
|
+
if (access.hasPaidPlan && hasFullProfile)
|
|
6384
|
+
return "full profile (paid)";
|
|
6385
|
+
if (hasFullProfile)
|
|
6386
|
+
return "cached profile (local)";
|
|
6387
|
+
if (access.authenticated)
|
|
6388
|
+
return "local engine (free)";
|
|
6389
|
+
return "local engine (free, not signed in)";
|
|
6390
|
+
}
|
|
6391
|
+
var import_chalk5, FEATURE_MESSAGES, localOnlyOverride, cachedAccess, ACCESS_CACHE_MS;
|
|
6392
|
+
var init_access = __esm({
|
|
6393
|
+
"src/lib/access.ts"() {
|
|
6394
|
+
"use strict";
|
|
6395
|
+
import_chalk5 = __toESM(require_source());
|
|
6396
|
+
init_config();
|
|
6397
|
+
init_auth();
|
|
6398
|
+
init_api();
|
|
6399
|
+
FEATURE_MESSAGES = {
|
|
6400
|
+
profiles: "syncing voice profiles from your account requires a paid plan. run: hyv upgrade",
|
|
6401
|
+
learning: "the learning loop (reinforce, add) requires a paid plan. run: hyv upgrade",
|
|
6402
|
+
premiumPrompts: "rich profile-aware rewrite prompts require a paid plan. run: hyv upgrade",
|
|
6403
|
+
serverAnalysis: "server-assisted analysis requires a paid plan. run: hyv upgrade"
|
|
6404
|
+
};
|
|
6405
|
+
localOnlyOverride = false;
|
|
6406
|
+
cachedAccess = null;
|
|
6407
|
+
ACCESS_CACHE_MS = 3e4;
|
|
6408
|
+
}
|
|
6409
|
+
});
|
|
6410
|
+
|
|
6295
6411
|
// src/lib/profile-parse.ts
|
|
6296
6412
|
function parseAnchorsFromBody(body) {
|
|
6297
6413
|
const anchors = [];
|
|
@@ -7430,7 +7546,7 @@ function ps(n7) {
|
|
|
7430
7546
|
return n7.replace(as, fe).replace(ls, ue).replace(cs, qt).replace(fs10, de).replace(us, pe);
|
|
7431
7547
|
}
|
|
7432
7548
|
function ms(n7) {
|
|
7433
|
-
return n7.replace(is, "\\").replace(rs, "{").replace(ns, "}").replace(
|
|
7549
|
+
return n7.replace(is, "\\").replace(rs, "{").replace(ns, "}").replace(os7, ",").replace(hs, ".");
|
|
7434
7550
|
}
|
|
7435
7551
|
function me(n7) {
|
|
7436
7552
|
if (!n7)
|
|
@@ -7530,7 +7646,7 @@ function Ut(n7, t = {}) {
|
|
|
7530
7646
|
function es(n7, t = {}) {
|
|
7531
7647
|
return new I(n7, t).iterate();
|
|
7532
7648
|
}
|
|
7533
|
-
var import_node_url, import_node_path, import_node_url2, import_fs, xi, import_promises, import_node_events, import_node_stream, import_node_string_decoder, Gt, ce, ss, fe, ue, qt, de, pe, is, rs, ns,
|
|
7649
|
+
var import_node_url, import_node_path, import_node_url2, import_fs, xi, import_promises, import_node_events, import_node_stream, import_node_string_decoder, Gt, ce, ss, fe, ue, qt, de, pe, is, rs, ns, os7, hs, as, ls, cs, fs10, us, ds, at, Ss, lt, Es, we, ye, W, xs, be, vs, Ct, Cs, Ts, As, ks, Kt, Se, Ee, Q, tt, O, Rs, Os, Fs, Ds, Ms, Ns, _s, Ls, Ws, Ps, js, Is, zs, Bs, Us, $s, Gs, Hs, Ce, Te, Ae, xe, qs, A, Ks, Vs, Ys, Xs, Js, N, Zs, ke, Qs, ti, ve, ei, D, si, Oe, Vt, Fe, At, Re, ii, q, De, Tt, ri, ft, Ne, oi, hi, ai, G, H, K, kt, ut, Rt, _e, Ot, Le, P, et, v, dt, st, C, F, T, Yt, Ft, k, x, Xt, Jt, We, Zt, B, Qt, Dt, pt, Y, M, mt, li, ci, fi, ui, Mt, te, di, pi, V, vi, wt, Ue, $e, Ri, Oi, L, Ge, He, U, qe, Ke, X, Ve, _, gt, se, je, yt, j, Nt, Lt, Ie, Fi, ie, ze, bt, Be, _t, Wt, ne, Ye, R, Pt, jt, It, it, rt, St, Cr, Xe, Di, Mi, Ni, nt, _i, ot, oe, he, ae, Et, Li, zt, xt, vt, Pi, I, le, ji, Ii, zi, Bi, Ui, Ze;
|
|
7534
7650
|
var init_index_min = __esm({
|
|
7535
7651
|
"node_modules/glob/dist/esm/index.min.js"() {
|
|
7536
7652
|
import_node_url = require("node:url");
|
|
@@ -7577,7 +7693,7 @@ var init_index_min = __esm({
|
|
|
7577
7693
|
is = new RegExp(fe, "g");
|
|
7578
7694
|
rs = new RegExp(ue, "g");
|
|
7579
7695
|
ns = new RegExp(qt, "g");
|
|
7580
|
-
|
|
7696
|
+
os7 = new RegExp(de, "g");
|
|
7581
7697
|
hs = new RegExp(pe, "g");
|
|
7582
7698
|
as = /\\\\/g;
|
|
7583
7699
|
ls = /\\{/g;
|
|
@@ -10738,18 +10854,18 @@ function stripXmlText(xml) {
|
|
|
10738
10854
|
}
|
|
10739
10855
|
function commandExists(cmd) {
|
|
10740
10856
|
try {
|
|
10741
|
-
(0,
|
|
10857
|
+
(0, import_child_process3.execFileSync)("which", [cmd], { stdio: "ignore" });
|
|
10742
10858
|
return true;
|
|
10743
10859
|
} catch {
|
|
10744
10860
|
return false;
|
|
10745
10861
|
}
|
|
10746
10862
|
}
|
|
10747
10863
|
function unzipList(filePath) {
|
|
10748
|
-
const out = (0,
|
|
10864
|
+
const out = (0, import_child_process3.execFileSync)("unzip", ["-Z1", filePath], { encoding: "utf-8", maxBuffer: 5e6 });
|
|
10749
10865
|
return out.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
10750
10866
|
}
|
|
10751
10867
|
function unzipExtract(filePath, entry) {
|
|
10752
|
-
return (0,
|
|
10868
|
+
return (0, import_child_process3.execFileSync)("unzip", ["-p", filePath, entry], {
|
|
10753
10869
|
encoding: "utf-8",
|
|
10754
10870
|
maxBuffer: 1e7
|
|
10755
10871
|
});
|
|
@@ -10757,7 +10873,7 @@ function unzipExtract(filePath, entry) {
|
|
|
10757
10873
|
function extractDocx(filePath) {
|
|
10758
10874
|
if (process.platform === "darwin") {
|
|
10759
10875
|
try {
|
|
10760
|
-
const out = (0,
|
|
10876
|
+
const out = (0, import_child_process3.execFileSync)("textutil", ["-convert", "txt", "-stdout", filePath], {
|
|
10761
10877
|
encoding: "utf-8",
|
|
10762
10878
|
maxBuffer: 1e7
|
|
10763
10879
|
});
|
|
@@ -10800,7 +10916,7 @@ function extractPdfRaw(buffer) {
|
|
|
10800
10916
|
function extractPdf(filePath) {
|
|
10801
10917
|
if (process.platform === "darwin") {
|
|
10802
10918
|
try {
|
|
10803
|
-
const out = (0,
|
|
10919
|
+
const out = (0, import_child_process3.execFileSync)("textutil", ["-convert", "txt", "-stdout", filePath], {
|
|
10804
10920
|
encoding: "utf-8",
|
|
10805
10921
|
maxBuffer: 1e7
|
|
10806
10922
|
});
|
|
@@ -10810,7 +10926,7 @@ function extractPdf(filePath) {
|
|
|
10810
10926
|
}
|
|
10811
10927
|
}
|
|
10812
10928
|
if (commandExists("pdftotext")) {
|
|
10813
|
-
const out = (0,
|
|
10929
|
+
const out = (0, import_child_process3.execFileSync)("pdftotext", ["-layout", "-enc", "UTF-8", filePath, "-"], {
|
|
10814
10930
|
encoding: "utf-8",
|
|
10815
10931
|
maxBuffer: 1e7
|
|
10816
10932
|
});
|
|
@@ -10875,7 +10991,7 @@ function listDocumentsInDir(dirPath) {
|
|
|
10875
10991
|
}).filter(isSupportedDocument);
|
|
10876
10992
|
}
|
|
10877
10993
|
function collectDocumentsFromPath(inputPath) {
|
|
10878
|
-
const resolved = path10.resolve(inputPath.trim().replace(/^~(?=$|\/)/,
|
|
10994
|
+
const resolved = path10.resolve(inputPath.trim().replace(/^~(?=$|\/)/, os8.homedir()));
|
|
10879
10995
|
if (!fs11.existsSync(resolved)) {
|
|
10880
10996
|
throw new Error(`path not found: ${resolved}`);
|
|
10881
10997
|
}
|
|
@@ -10906,19 +11022,19 @@ function readDraftInput(input) {
|
|
|
10906
11022
|
const trimmed = input.trim();
|
|
10907
11023
|
if (!trimmed)
|
|
10908
11024
|
throw new Error("empty draft");
|
|
10909
|
-
const maybePath = path10.resolve(trimmed.replace(/^~(?=$|\/)/,
|
|
11025
|
+
const maybePath = path10.resolve(trimmed.replace(/^~(?=$|\/)/, os8.homedir()));
|
|
10910
11026
|
if (fs11.existsSync(maybePath) && fs11.statSync(maybePath).isFile()) {
|
|
10911
11027
|
return { text: extractTextFromFile(maybePath), source: maybePath };
|
|
10912
11028
|
}
|
|
10913
11029
|
return { text: trimmed, source: "paste" };
|
|
10914
11030
|
}
|
|
10915
|
-
var
|
|
11031
|
+
var import_child_process3, fs11, os8, path10, SUPPORTED_EXTENSIONS, SAMPLE_GLOB, GLOB_IGNORE;
|
|
10916
11032
|
var init_document_text = __esm({
|
|
10917
11033
|
"src/lib/document-text.ts"() {
|
|
10918
11034
|
"use strict";
|
|
10919
|
-
|
|
11035
|
+
import_child_process3 = require("child_process");
|
|
10920
11036
|
fs11 = __toESM(require("fs"));
|
|
10921
|
-
|
|
11037
|
+
os8 = __toESM(require("os"));
|
|
10922
11038
|
path10 = __toESM(require("path"));
|
|
10923
11039
|
init_index_min();
|
|
10924
11040
|
SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -10994,21 +11110,21 @@ function runPipeline(text, profile, applyFixes = false) {
|
|
|
10994
11110
|
};
|
|
10995
11111
|
}
|
|
10996
11112
|
function readText(source) {
|
|
10997
|
-
const
|
|
10998
|
-
const
|
|
11113
|
+
const fs31 = require("fs");
|
|
11114
|
+
const path28 = require("path");
|
|
10999
11115
|
if (source === "-") {
|
|
11000
11116
|
if (process.stdin.isTTY) {
|
|
11001
11117
|
console.error("No input provided. Pipe content or specify a file.");
|
|
11002
11118
|
process.exit(1);
|
|
11003
11119
|
}
|
|
11004
|
-
return { text:
|
|
11120
|
+
return { text: fs31.readFileSync(0, "utf-8"), path: "stdin" };
|
|
11005
11121
|
}
|
|
11006
|
-
const resolved =
|
|
11007
|
-
if (!
|
|
11122
|
+
const resolved = path28.resolve(source);
|
|
11123
|
+
if (!fs31.existsSync(resolved)) {
|
|
11008
11124
|
console.error(`File not found: ${resolved}`);
|
|
11009
11125
|
process.exit(1);
|
|
11010
11126
|
}
|
|
11011
|
-
const stat =
|
|
11127
|
+
const stat = fs31.statSync(resolved);
|
|
11012
11128
|
if (stat.isDirectory()) {
|
|
11013
11129
|
console.error(`${resolved} is a directory, not a file.`);
|
|
11014
11130
|
process.exit(1);
|
|
@@ -11408,7 +11524,7 @@ function isInteractiveTTY() {
|
|
|
11408
11524
|
return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
|
|
11409
11525
|
}
|
|
11410
11526
|
function briefPause(ms2 = 280) {
|
|
11411
|
-
return new Promise((
|
|
11527
|
+
return new Promise((resolve16) => setTimeout(resolve16, ms2));
|
|
11412
11528
|
}
|
|
11413
11529
|
async function withSpinner(label, fn, opts = {}) {
|
|
11414
11530
|
const minMs = opts.minMs ?? 450;
|
|
@@ -11458,6 +11574,25 @@ var init_terminal_ui = __esm({
|
|
|
11458
11574
|
});
|
|
11459
11575
|
|
|
11460
11576
|
// src/lib/welcome-flow.ts
|
|
11577
|
+
function localProfilePath(name) {
|
|
11578
|
+
return path14.join(os9.homedir(), ".hyv", "profiles", `${name}.md`);
|
|
11579
|
+
}
|
|
11580
|
+
function listLocalProfileNames() {
|
|
11581
|
+
const profilesDir = path14.join(os9.homedir(), ".hyv", "profiles");
|
|
11582
|
+
if (!fs15.existsSync(profilesDir))
|
|
11583
|
+
return [];
|
|
11584
|
+
return fs15.readdirSync(profilesDir).filter((entry) => entry.endsWith(".md")).map((entry) => entry.slice(0, -3));
|
|
11585
|
+
}
|
|
11586
|
+
function formatPlanLabel(plan) {
|
|
11587
|
+
const labels = {
|
|
11588
|
+
individual: "Individual",
|
|
11589
|
+
multiple: "Multiple",
|
|
11590
|
+
solo: "Solo",
|
|
11591
|
+
team: "Team",
|
|
11592
|
+
agency: "Agency"
|
|
11593
|
+
};
|
|
11594
|
+
return labels[plan.toLowerCase()] || plan;
|
|
11595
|
+
}
|
|
11461
11596
|
function readWelcomeState() {
|
|
11462
11597
|
try {
|
|
11463
11598
|
if (!fs15.existsSync(STATE_FILE)) {
|
|
@@ -11704,10 +11839,10 @@ function saveLocalProfile(name, content) {
|
|
|
11704
11839
|
writeWelcomeState({ profile_name: safe });
|
|
11705
11840
|
markStepComplete("name");
|
|
11706
11841
|
markStepComplete("samples");
|
|
11707
|
-
return path14.join(
|
|
11842
|
+
return path14.join(os9.homedir(), ".hyv", "profiles", `${safe}.md`);
|
|
11708
11843
|
}
|
|
11709
11844
|
function fetchUrlText(url) {
|
|
11710
|
-
return new Promise((
|
|
11845
|
+
return new Promise((resolve16, reject) => {
|
|
11711
11846
|
let parsed;
|
|
11712
11847
|
try {
|
|
11713
11848
|
parsed = new URL(url);
|
|
@@ -11736,7 +11871,7 @@ function fetchUrlText(url) {
|
|
|
11736
11871
|
});
|
|
11737
11872
|
res.on("end", () => {
|
|
11738
11873
|
const text = data.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
11739
|
-
|
|
11874
|
+
resolve16(text.slice(0, 12e3));
|
|
11740
11875
|
});
|
|
11741
11876
|
}
|
|
11742
11877
|
);
|
|
@@ -11756,10 +11891,10 @@ async function collectSamplesFromLink(url) {
|
|
|
11756
11891
|
}
|
|
11757
11892
|
function askLine(prompt) {
|
|
11758
11893
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
11759
|
-
return new Promise((
|
|
11894
|
+
return new Promise((resolve16) => {
|
|
11760
11895
|
rl.question(prompt, (answer) => {
|
|
11761
11896
|
rl.close();
|
|
11762
|
-
|
|
11897
|
+
resolve16(answer.trim());
|
|
11763
11898
|
});
|
|
11764
11899
|
});
|
|
11765
11900
|
}
|
|
@@ -11768,11 +11903,11 @@ async function askMultiline(intro) {
|
|
|
11768
11903
|
console.log(import_chalk12.default.dim(" paste below, then type --- on its own line when done\n"));
|
|
11769
11904
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
11770
11905
|
const lines = [];
|
|
11771
|
-
return new Promise((
|
|
11906
|
+
return new Promise((resolve16) => {
|
|
11772
11907
|
rl.on("line", (line) => {
|
|
11773
11908
|
if (line.trim() === "---") {
|
|
11774
11909
|
rl.close();
|
|
11775
|
-
|
|
11910
|
+
resolve16(lines.join("\n").trim());
|
|
11776
11911
|
return;
|
|
11777
11912
|
}
|
|
11778
11913
|
lines.push(line);
|
|
@@ -11794,8 +11929,28 @@ function formatScanResult(text, profile) {
|
|
|
11794
11929
|
}
|
|
11795
11930
|
async function stepName() {
|
|
11796
11931
|
console.log(import_chalk12.default.bold("\nstep 1 \xB7 name your profile\n"));
|
|
11932
|
+
const state = readWelcomeState();
|
|
11933
|
+
const existing = listLocalProfileNames();
|
|
11934
|
+
if (state.profile_name && existing.includes(state.profile_name)) {
|
|
11935
|
+
const reuse = await askYesNo(` reuse profile "${state.profile_name}"?`, true);
|
|
11936
|
+
if (reuse) {
|
|
11937
|
+
markStepComplete("name");
|
|
11938
|
+
return state.profile_name;
|
|
11939
|
+
}
|
|
11940
|
+
} else if (existing.length === 1) {
|
|
11941
|
+
const only = existing[0];
|
|
11942
|
+
const reuse = await askYesNo(` reuse existing profile "${only}"?`, true);
|
|
11943
|
+
if (reuse) {
|
|
11944
|
+
writeWelcomeState({ profile_name: only });
|
|
11945
|
+
markStepComplete("name");
|
|
11946
|
+
return only;
|
|
11947
|
+
}
|
|
11948
|
+
}
|
|
11797
11949
|
const name = await askLine(import_chalk12.default.cyan(" profile name (e.g. my-voice): "));
|
|
11798
|
-
|
|
11950
|
+
const safe = assertSafeProfileName(name);
|
|
11951
|
+
writeWelcomeState({ profile_name: safe });
|
|
11952
|
+
markStepComplete("name");
|
|
11953
|
+
return safe;
|
|
11799
11954
|
}
|
|
11800
11955
|
async function stepSamples(profileName) {
|
|
11801
11956
|
console.log(import_chalk12.default.bold("\nstep 2 \xB7 add writing samples\n"));
|
|
@@ -11859,6 +12014,8 @@ _Add pasted samples to train this profile._
|
|
|
11859
12014
|
console.log(import_chalk12.default.green(`
|
|
11860
12015
|
\u2713 profile saved`));
|
|
11861
12016
|
console.log(import_chalk12.default.dim(` ${saved}`));
|
|
12017
|
+
writeWelcomeState({ profile_name: profileName });
|
|
12018
|
+
markStepComplete("samples");
|
|
11862
12019
|
}
|
|
11863
12020
|
async function stepTest(profileName) {
|
|
11864
12021
|
console.log(import_chalk12.default.bold("\nstep 3 \xB7 test on a draft"));
|
|
@@ -11899,42 +12056,25 @@ async function stepTest(profileName) {
|
|
|
11899
12056
|
console.log(import_chalk12.default.dim(` try: hyv rewrite ${rewriteTarget} --profile ${profileName}`));
|
|
11900
12057
|
markStepComplete("test");
|
|
11901
12058
|
}
|
|
11902
|
-
async function
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
|
|
11906
|
-
|
|
11907
|
-
console.log(" then unlock learning for " + import_chalk12.default.bold("$1 your first month") + " \u2014 profiles that");
|
|
11908
|
-
console.log(" get sharper every rewrite, hybrid rewrites, and your dashboard.\n");
|
|
11909
|
-
console.log(import_chalk12.default.dim(" free forever (no account): scan, fix, check, mcp"));
|
|
11910
|
-
console.log(import_chalk12.default.dim(" $1 first month: learning loop, rich rewrites, sync across devices\n"));
|
|
11911
|
-
const ready = await askYesNo(" create your free account now? ($1 first month to unlock everything)");
|
|
11912
|
-
if (!ready) {
|
|
11913
|
-
console.log(import_chalk12.default.dim("\n no rush \u2014 your profile stays on this machine."));
|
|
11914
|
-
console.log(import_chalk12.default.dim(" whenever you want backup + learning:"));
|
|
11915
|
-
console.log(import_chalk12.default.dim(" hyv init"));
|
|
11916
|
-
console.log(import_chalk12.default.dim(" hyv plan --upgrade ($1 first month)"));
|
|
11917
|
-
console.log(import_chalk12.default.dim(` ${PRICING_URL}
|
|
11918
|
-
`));
|
|
11919
|
-
return;
|
|
12059
|
+
async function syncProfileToAccount(profileName) {
|
|
12060
|
+
const profilePath = localProfilePath(profileName);
|
|
12061
|
+
if (!fs15.existsSync(profilePath)) {
|
|
12062
|
+
console.log(import_chalk12.default.yellow(` no local profile at ${profilePath}`));
|
|
12063
|
+
return false;
|
|
11920
12064
|
}
|
|
11921
12065
|
if (!isInitialized() || !getToken()) {
|
|
11922
|
-
console.log(import_chalk12.default.cyan("\n opening browser for
|
|
11923
|
-
await withSpinner("
|
|
12066
|
+
console.log(import_chalk12.default.cyan("\n opening browser for sign-in...\n"));
|
|
12067
|
+
await withSpinner("signing in\u2026", () => authenticateWithBrowser());
|
|
11924
12068
|
await briefPause();
|
|
11925
|
-
console.log(import_chalk12.default.green(" \u2713
|
|
11926
|
-
} else {
|
|
11927
|
-
console.log(import_chalk12.default.dim("\n already signed in \u2014 syncing profile..."));
|
|
12069
|
+
console.log(import_chalk12.default.green(" \u2713 signed in"));
|
|
11928
12070
|
}
|
|
11929
|
-
const content = fs15.readFileSync(
|
|
11930
|
-
path14.join(os8.homedir(), ".hyv", "profiles", `${profileName}.md`),
|
|
11931
|
-
"utf-8"
|
|
11932
|
-
);
|
|
12071
|
+
const content = fs15.readFileSync(profilePath, "utf-8");
|
|
11933
12072
|
try {
|
|
11934
12073
|
const response = await withSpinner(
|
|
11935
12074
|
"syncing profile\u2026",
|
|
11936
12075
|
() => authenticatedRequest(cliApiUrl("/cli/profiles/new"), {
|
|
11937
12076
|
method: "POST",
|
|
12077
|
+
timeout: PROFILE_SYNC_TIMEOUT_MS,
|
|
11938
12078
|
body: { name: profileName, content, source: "welcome" }
|
|
11939
12079
|
})
|
|
11940
12080
|
);
|
|
@@ -11945,27 +12085,100 @@ async function stepSignup(profileName) {
|
|
|
11945
12085
|
} else {
|
|
11946
12086
|
console.log(import_chalk12.default.green(" \u2713 profile synced to your account"));
|
|
11947
12087
|
}
|
|
11948
|
-
|
|
11949
|
-
const detail = response.data?.error;
|
|
11950
|
-
console.log(import_chalk12.default.yellow(
|
|
11951
|
-
` profile saved locally \u2014 retry \`hyv welcome\` when online${detail ? ` (${detail})` : ` (HTTP ${response.status})`}`
|
|
11952
|
-
));
|
|
12088
|
+
return true;
|
|
11953
12089
|
}
|
|
12090
|
+
const detail = response.data?.error;
|
|
12091
|
+
console.log(import_chalk12.default.yellow(
|
|
12092
|
+
` profile saved locally \u2014 retry \`hyv sync\`${detail ? ` (${detail})` : ` (HTTP ${response.status})`}`
|
|
12093
|
+
));
|
|
11954
12094
|
} catch (err) {
|
|
11955
12095
|
console.log(import_chalk12.default.yellow(
|
|
11956
|
-
` profile saved locally \u2014 retry \`hyv
|
|
12096
|
+
` profile saved locally \u2014 retry \`hyv sync\` (${err?.message || "sync failed"})`
|
|
11957
12097
|
));
|
|
11958
12098
|
}
|
|
12099
|
+
return false;
|
|
12100
|
+
}
|
|
12101
|
+
async function stepSignup(profileName) {
|
|
12102
|
+
console.log(import_chalk12.default.bold("\nstep 4 \xB7 save & unlock\n"));
|
|
12103
|
+
const access = await getAccessState();
|
|
12104
|
+
if (access.hasPaidPlan) {
|
|
12105
|
+
console.log(` you're on ${import_chalk12.default.bold(formatPlanLabel(access.plan))} \u2014 learning, sync, and dashboard are unlocked.`);
|
|
12106
|
+
console.log(import_chalk12.default.dim("\n syncing your local profile to your account..."));
|
|
12107
|
+
await syncProfileToAccount(profileName);
|
|
12108
|
+
markStepComplete("signup");
|
|
12109
|
+
console.log(import_chalk12.default.dim("\n run `hyv scan draft.md` or `hyv sync` anytime.\n"));
|
|
12110
|
+
return;
|
|
12111
|
+
}
|
|
12112
|
+
console.log(" your profile works on this machine. scan anything, anytime \u2014 free forever.");
|
|
12113
|
+
console.log("");
|
|
12114
|
+
if (access.authenticated) {
|
|
12115
|
+
console.log(" you're signed in. sync this profile, or upgrade for learning + rich rewrites.");
|
|
12116
|
+
console.log(import_chalk12.default.dim("\n free forever: scan, fix, check, mcp"));
|
|
12117
|
+
console.log(import_chalk12.default.dim(" paid: learning loop, hybrid rewrites, sync across devices\n"));
|
|
12118
|
+
const syncNow = await askYesNo(" sync profile to your account now?", true);
|
|
12119
|
+
if (syncNow) {
|
|
12120
|
+
await syncProfileToAccount(profileName);
|
|
12121
|
+
}
|
|
12122
|
+
const upgrade = await askYesNo(" open billing to upgrade?", false);
|
|
12123
|
+
if (upgrade) {
|
|
12124
|
+
await withSpinner("opening billing\u2026", () => openAuthenticatedDashboard({ next: "/app/billing" }));
|
|
12125
|
+
await briefPause();
|
|
12126
|
+
}
|
|
12127
|
+
markStepComplete("signup");
|
|
12128
|
+
console.log(import_chalk12.default.dim("\n upgrade anytime: `hyv plan --upgrade`\n"));
|
|
12129
|
+
return;
|
|
12130
|
+
}
|
|
12131
|
+
console.log(" create a free account to back it up and sync everywhere.");
|
|
12132
|
+
console.log(" then unlock learning for " + import_chalk12.default.bold("$1 your first month") + " \u2014 profiles that");
|
|
12133
|
+
console.log(" get sharper every rewrite, hybrid rewrites, and your dashboard.\n");
|
|
12134
|
+
console.log(import_chalk12.default.dim(" free forever (no account): scan, fix, check, mcp"));
|
|
12135
|
+
console.log(import_chalk12.default.dim(" $1 first month: learning loop, rich rewrites, sync across devices\n"));
|
|
12136
|
+
const ready = await askYesNo(" create your free account now? ($1 first month to unlock everything)");
|
|
12137
|
+
if (!ready) {
|
|
12138
|
+
console.log(import_chalk12.default.dim("\n no rush \u2014 your profile stays on this machine."));
|
|
12139
|
+
console.log(import_chalk12.default.dim(" whenever you want backup + learning:"));
|
|
12140
|
+
console.log(import_chalk12.default.dim(" hyv init"));
|
|
12141
|
+
console.log(import_chalk12.default.dim(" hyv plan --upgrade ($1 first month)"));
|
|
12142
|
+
console.log(import_chalk12.default.dim(` ${PRICING_URL}
|
|
12143
|
+
`));
|
|
12144
|
+
return;
|
|
12145
|
+
}
|
|
12146
|
+
await syncProfileToAccount(profileName);
|
|
11959
12147
|
console.log(import_chalk12.default.cyan("\n opening billing in your dashboard ($1 first month)..."));
|
|
11960
|
-
await withSpinner("opening billing\u2026", () => openAuthenticatedDashboard({ next: "/
|
|
12148
|
+
await withSpinner("opening billing\u2026", () => openAuthenticatedDashboard({ next: "/app/billing" }));
|
|
11961
12149
|
await briefPause();
|
|
11962
12150
|
markStepComplete("signup");
|
|
11963
12151
|
console.log(import_chalk12.default.dim("\n you're signed in \u2014 pick a plan in billing, no second login.\n"));
|
|
11964
12152
|
}
|
|
12153
|
+
async function maybeRunPaidWelcomeShortcut() {
|
|
12154
|
+
const access = await getAccessState();
|
|
12155
|
+
if (!access.authenticated || !access.hasPaidPlan)
|
|
12156
|
+
return null;
|
|
12157
|
+
const state = readWelcomeState();
|
|
12158
|
+
const profiles = listLocalProfileNames();
|
|
12159
|
+
const profileName = state.profile_name && profiles.includes(state.profile_name) ? state.profile_name : profiles[0];
|
|
12160
|
+
if (!profileName)
|
|
12161
|
+
return null;
|
|
12162
|
+
console.log(import_chalk12.default.green(`
|
|
12163
|
+
${formatPlanLabel(access.plan)} plan active \u2014 profile "${profileName}" ready.`));
|
|
12164
|
+
const resync = await askYesNo(" sync profile to your account now?", true);
|
|
12165
|
+
if (resync) {
|
|
12166
|
+
await syncProfileToAccount(profileName);
|
|
12167
|
+
}
|
|
12168
|
+
markStepComplete("signup");
|
|
12169
|
+
console.log(import_chalk12.default.green("\ndone \u2014 your voice profile is ready.\n"));
|
|
12170
|
+
console.log(import_chalk12.default.dim(" hyv scan draft.md"));
|
|
12171
|
+
console.log(import_chalk12.default.dim(` hyv rewrite draft.md --profile ${profileName}`));
|
|
12172
|
+
console.log(import_chalk12.default.dim(" hyv mcp --setup\n"));
|
|
12173
|
+
return profileName;
|
|
12174
|
+
}
|
|
11965
12175
|
async function runInteractiveWelcome() {
|
|
11966
12176
|
recordEvent("welcome_interactive");
|
|
11967
12177
|
console.log("\n" + buildWelcomeHeader());
|
|
11968
12178
|
try {
|
|
12179
|
+
const shortcut = await maybeRunPaidWelcomeShortcut();
|
|
12180
|
+
if (shortcut)
|
|
12181
|
+
return;
|
|
11969
12182
|
const profileName = await stepName();
|
|
11970
12183
|
await stepSamples(profileName);
|
|
11971
12184
|
await stepTest(profileName);
|
|
@@ -11992,7 +12205,7 @@ function getMcpWelcomeResponse(args2) {
|
|
|
11992
12205
|
}
|
|
11993
12206
|
return buildWelcomeGuide({ profileName: args2.profile, forLlm: true });
|
|
11994
12207
|
}
|
|
11995
|
-
var import_chalk12, fs15, http2, https2,
|
|
12208
|
+
var import_chalk12, fs15, http2, https2, os9, path14, readline, PROFILE_SYNC_TIMEOUT_MS, WELCOME_TAGLINE, FLOW_STEPS, STATE_FILE;
|
|
11996
12209
|
var init_welcome_flow = __esm({
|
|
11997
12210
|
"src/lib/welcome-flow.ts"() {
|
|
11998
12211
|
"use strict";
|
|
@@ -12000,7 +12213,7 @@ var init_welcome_flow = __esm({
|
|
|
12000
12213
|
fs15 = __toESM(require("fs"));
|
|
12001
12214
|
http2 = __toESM(require("http"));
|
|
12002
12215
|
https2 = __toESM(require("https"));
|
|
12003
|
-
|
|
12216
|
+
os9 = __toESM(require("os"));
|
|
12004
12217
|
path14 = __toESM(require("path"));
|
|
12005
12218
|
readline = __toESM(require("readline"));
|
|
12006
12219
|
init_pipeline();
|
|
@@ -12009,10 +12222,12 @@ var init_welcome_flow = __esm({
|
|
|
12009
12222
|
init_terminal_ui();
|
|
12010
12223
|
init_config();
|
|
12011
12224
|
init_auth();
|
|
12225
|
+
init_access();
|
|
12012
12226
|
init_scan();
|
|
12013
12227
|
init_free_paid();
|
|
12014
12228
|
init_telemetry();
|
|
12015
12229
|
init_document_text();
|
|
12230
|
+
PROFILE_SYNC_TIMEOUT_MS = 9e4;
|
|
12016
12231
|
WELCOME_TAGLINE = "Hold Your Voice \u2014 make your AI agents sound exactly like you.";
|
|
12017
12232
|
FLOW_STEPS = [
|
|
12018
12233
|
{ n: 1, key: "name", title: "name your profile", hint: "pick a short name \u2014 e.g. my-voice" },
|
|
@@ -12020,7 +12235,7 @@ var init_welcome_flow = __esm({
|
|
|
12020
12235
|
{ n: 3, key: "test", title: "test on a draft", hint: "optional \u2014 scan or rewrite a draft" },
|
|
12021
12236
|
{ n: 4, key: "signup", title: "save & unlock", hint: "signup syncs your profile and unlocks learning" }
|
|
12022
12237
|
];
|
|
12023
|
-
STATE_FILE = path14.join(
|
|
12238
|
+
STATE_FILE = path14.join(os9.homedir(), ".hyv", "welcome-state.json");
|
|
12024
12239
|
}
|
|
12025
12240
|
});
|
|
12026
12241
|
|
|
@@ -12144,7 +12359,7 @@ __export(billing_upgrade_exports, {
|
|
|
12144
12359
|
});
|
|
12145
12360
|
async function openBillingUpgrade(opts = {}) {
|
|
12146
12361
|
const plan = opts.plan || "individual";
|
|
12147
|
-
const next = `/
|
|
12362
|
+
const next = `/app/billing?checkout=${plan}`;
|
|
12148
12363
|
const token = getToken();
|
|
12149
12364
|
if (!token) {
|
|
12150
12365
|
console.log(import_chalk14.default.cyan("\nSign in to upgrade \u2014 opening browser...\n"));
|
|
@@ -13056,15 +13271,15 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
|
|
|
13056
13271
|
g.minimatch.escape = vi2.escape;
|
|
13057
13272
|
g.minimatch.unescape = Ei2.unescape;
|
|
13058
13273
|
});
|
|
13059
|
-
var
|
|
13274
|
+
var fs31 = R2((Wt2) => {
|
|
13060
13275
|
"use strict";
|
|
13061
13276
|
Object.defineProperty(Wt2, "__esModule", { value: true });
|
|
13062
13277
|
Wt2.LRUCache = void 0;
|
|
13063
13278
|
var er = typeof performance == "object" && performance && typeof performance.now == "function" ? performance : Date, as2 = /* @__PURE__ */ new Set(), ge2 = typeof process == "object" && process ? process : {}, ls2 = (n7, t, e, s) => {
|
|
13064
13279
|
typeof ge2.emitWarning == "function" ? ge2.emitWarning(n7, t, e, s) : console.error(`[${e}] ${t}: ${n7}`);
|
|
13065
|
-
}, Lt2 = globalThis.AbortController,
|
|
13280
|
+
}, Lt2 = globalThis.AbortController, os15 = globalThis.AbortSignal;
|
|
13066
13281
|
if (typeof Lt2 > "u") {
|
|
13067
|
-
|
|
13282
|
+
os15 = class {
|
|
13068
13283
|
onabort;
|
|
13069
13284
|
_onabort = [];
|
|
13070
13285
|
reason;
|
|
@@ -13076,7 +13291,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
|
|
|
13076
13291
|
constructor() {
|
|
13077
13292
|
t();
|
|
13078
13293
|
}
|
|
13079
|
-
signal = new
|
|
13294
|
+
signal = new os15();
|
|
13080
13295
|
abort(e) {
|
|
13081
13296
|
if (!this.signal.aborted) {
|
|
13082
13297
|
this.signal.reason = e, this.signal.aborted = true;
|
|
@@ -14025,7 +14240,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s))
|
|
|
14025
14240
|
};
|
|
14026
14241
|
Object.defineProperty(_2, "__esModule", { value: true });
|
|
14027
14242
|
_2.PathScurry = _2.Path = _2.PathScurryDarwin = _2.PathScurryPosix = _2.PathScurryWin32 = _2.PathScurryBase = _2.PathPosix = _2.PathWin32 = _2.PathBase = _2.ChildrenCache = _2.ResolveCache = void 0;
|
|
14028
|
-
var Qt2 =
|
|
14243
|
+
var Qt2 = fs31(), Yt2 = require("node:path"), yr = require("node:url"), pt2 = require("fs"), Sr = br(require("node:fs")), vr = pt2.realpathSync.native, Ht2 = require("node:fs/promises"), bs2 = Oe2(), mt2 = { lstatSync: pt2.lstatSync, readdir: pt2.readdir, readdirSync: pt2.readdirSync, readlinkSync: pt2.readlinkSync, realpathSync: vr, promises: { lstat: Ht2.lstat, readdir: Ht2.readdir, readlink: Ht2.readlink, realpath: Ht2.realpath } }, _s2 = (n7) => !n7 || n7 === mt2 || n7 === Sr ? mt2 : { ...mt2, ...n7, promises: { ...mt2.promises, ...n7.promises || {} } }, Os2 = /^\\\\\?\\([a-z]:)\\?$/i, Er = (n7) => n7.replace(/\//g, "\\").replace(Os2, "$1\\"), _r = /[\\\/]/, N2 = 0, xs2 = 1, Ts2 = 2, G2 = 4, Cs2 = 6, Rs2 = 8, Q2 = 10, As2 = 12, j2 = 15, dt2 = ~j2, xe2 = 16, ys2 = 32, gt2 = 64, W2 = 128, Vt2 = 256, Xt2 = 512, Ss2 = gt2 | W2 | Xt2, Or = 1023, Te2 = (n7) => n7.isFile() ? Rs2 : n7.isDirectory() ? G2 : n7.isSymbolicLink() ? Q2 : n7.isCharacterDevice() ? Ts2 : n7.isBlockDevice() ? Cs2 : n7.isSocket() ? As2 : n7.isFIFO() ? xs2 : N2, vs2 = new Qt2.LRUCache({ max: 2 ** 12 }), wt2 = (n7) => {
|
|
14029
14244
|
let t = vs2.get(n7);
|
|
14030
14245
|
if (t)
|
|
14031
14246
|
return t;
|
|
@@ -15544,7 +15759,7 @@ var {
|
|
|
15544
15759
|
} = import_index.default;
|
|
15545
15760
|
|
|
15546
15761
|
// src/index.ts
|
|
15547
|
-
var
|
|
15762
|
+
var import_chalk34 = __toESM(require_source());
|
|
15548
15763
|
|
|
15549
15764
|
// src/commands/init.ts
|
|
15550
15765
|
var import_chalk4 = __toESM(require_source());
|
|
@@ -15690,10 +15905,19 @@ function registerInitCommand(program3) {
|
|
|
15690
15905
|
if (authData.license_key) {
|
|
15691
15906
|
console.log(import_chalk4.default.dim(` License: ${authData.license_key.slice(0, 12)}...`));
|
|
15692
15907
|
}
|
|
15908
|
+
try {
|
|
15909
|
+
const { ensureMcpProfilesHydrated: ensureMcpProfilesHydrated2 } = await Promise.resolve().then(() => (init_mcp_profile_hydrate(), mcp_profile_hydrate_exports));
|
|
15910
|
+
const hydrated = await ensureMcpProfilesHydrated2({ force: true });
|
|
15911
|
+
if (hydrated.synced?.length) {
|
|
15912
|
+
console.log(import_chalk4.default.green(`
|
|
15913
|
+
\u2713 MCP profiles ready: ${hydrated.synced.join(", ")}`));
|
|
15914
|
+
}
|
|
15915
|
+
} catch {
|
|
15916
|
+
}
|
|
15693
15917
|
const mcpResults = configureMcpForDesktop();
|
|
15694
15918
|
const { printPaidUnlockReminder: printPaidUnlockReminder2 } = await Promise.resolve().then(() => (init_marketing_hints(), marketing_hints_exports));
|
|
15695
15919
|
console.log("\nNext steps:");
|
|
15696
|
-
console.log(import_chalk4.default.dim(" 1.
|
|
15920
|
+
console.log(import_chalk4.default.dim(" 1. Voice profile: hyv welcome (or use dashboard \u2014 MCP syncs after init)"));
|
|
15697
15921
|
console.log(import_chalk4.default.dim(" 2. Scan a draft: hyv scan draft.md"));
|
|
15698
15922
|
console.log(import_chalk4.default.dim(" 3. Rewrite with voice: hyv rewrite draft.md"));
|
|
15699
15923
|
printPaidUnlockReminder2();
|
|
@@ -15917,6 +16141,8 @@ init_profile();
|
|
|
15917
16141
|
init_profile_meta();
|
|
15918
16142
|
var fs8 = __toESM(require("fs"));
|
|
15919
16143
|
var path8 = __toESM(require("path"));
|
|
16144
|
+
var os6 = __toESM(require("os"));
|
|
16145
|
+
var import_child_process2 = require("child_process");
|
|
15920
16146
|
function registerSyncCommand(program3) {
|
|
15921
16147
|
program3.command("sync").description("Sync profiles and rules from server").option("--force", "Force re-download even if cache is fresh").action(async (options) => {
|
|
15922
16148
|
try {
|
|
@@ -16004,7 +16230,15 @@ function registerSyncCommand(program3) {
|
|
|
16004
16230
|
process.exit(1);
|
|
16005
16231
|
}
|
|
16006
16232
|
});
|
|
16007
|
-
program3.command("profiles").description("List voice profiles").option("--verbose", "Show learned patterns, drift, anchors").option("--history <name>", "Show profile evolution for a slug").action(async (options) => {
|
|
16233
|
+
program3.command("profiles").description("List, edit, or delete voice profiles").option("--verbose", "Show learned patterns, drift, anchors").option("--history <name>", "Show profile evolution for a slug").option("--delete <name>", "Delete a profile (server + local cache)").option("--edit <name>", "Open a local profile in your $EDITOR").action(async (options) => {
|
|
16234
|
+
if (options.delete) {
|
|
16235
|
+
await deleteProfileByName(options.delete);
|
|
16236
|
+
return;
|
|
16237
|
+
}
|
|
16238
|
+
if (options.edit) {
|
|
16239
|
+
await editLocalProfile(options.edit);
|
|
16240
|
+
return;
|
|
16241
|
+
}
|
|
16008
16242
|
if (options.history) {
|
|
16009
16243
|
await showProfileHistory(options.history);
|
|
16010
16244
|
return;
|
|
@@ -16050,6 +16284,58 @@ ${profiles.length} profile(s) cached.`));
|
|
|
16050
16284
|
await program3.parseAsync(["node", "hyv", "sync", "--force"]);
|
|
16051
16285
|
});
|
|
16052
16286
|
}
|
|
16287
|
+
async function deleteProfileByName(name) {
|
|
16288
|
+
const token = getToken();
|
|
16289
|
+
const localKey = toSafeProfileCacheKey(name);
|
|
16290
|
+
const localPath = path8.join(os6.homedir(), ".hyv", "profiles", `${localKey}.md`);
|
|
16291
|
+
if (token) {
|
|
16292
|
+
try {
|
|
16293
|
+
const res = await authenticatedRequest(cliApiUrl("/cli/profiles/delete"), {
|
|
16294
|
+
method: "POST",
|
|
16295
|
+
body: { slug_or_id: name }
|
|
16296
|
+
});
|
|
16297
|
+
if (res.status !== 200) {
|
|
16298
|
+
const err = res.data?.error || `delete failed (HTTP ${res.status})`;
|
|
16299
|
+
console.log(import_chalk8.default.red(`
|
|
16300
|
+
${err}
|
|
16301
|
+
`));
|
|
16302
|
+
process.exit(1);
|
|
16303
|
+
}
|
|
16304
|
+
console.log(import_chalk8.default.green(`
|
|
16305
|
+
\u2713 deleted "${name}" from your account
|
|
16306
|
+
`));
|
|
16307
|
+
} catch (err) {
|
|
16308
|
+
console.log(import_chalk8.default.red(`
|
|
16309
|
+
${err.message || "delete failed"}
|
|
16310
|
+
`));
|
|
16311
|
+
process.exit(1);
|
|
16312
|
+
}
|
|
16313
|
+
} else {
|
|
16314
|
+
console.log(import_chalk8.default.yellow("\n not signed in \u2014 deleting local profile only\n"));
|
|
16315
|
+
}
|
|
16316
|
+
if (fs8.existsSync(localPath)) {
|
|
16317
|
+
fs8.unlinkSync(localPath);
|
|
16318
|
+
console.log(import_chalk8.default.dim(` removed ${localPath}`));
|
|
16319
|
+
}
|
|
16320
|
+
}
|
|
16321
|
+
async function editLocalProfile(name) {
|
|
16322
|
+
const localKey = toSafeProfileCacheKey(name);
|
|
16323
|
+
const localPath = path8.join(os6.homedir(), ".hyv", "profiles", `${localKey}.md`);
|
|
16324
|
+
if (!fs8.existsSync(localPath)) {
|
|
16325
|
+
console.log(import_chalk8.default.yellow(`
|
|
16326
|
+
no local profile at ${localPath}`));
|
|
16327
|
+
console.log(import_chalk8.default.dim(" run `hyv sync` or `hyv welcome` first\n"));
|
|
16328
|
+
process.exit(1);
|
|
16329
|
+
}
|
|
16330
|
+
const editor = process.env.EDITOR || process.env.VISUAL || (process.platform === "win32" ? "notepad" : "nano");
|
|
16331
|
+
const result = (0, import_child_process2.spawnSync)(editor, [localPath], { stdio: "inherit", shell: process.platform === "win32" });
|
|
16332
|
+
if (result.status !== 0) {
|
|
16333
|
+
process.exit(result.status || 1);
|
|
16334
|
+
}
|
|
16335
|
+
console.log(import_chalk8.default.green(`
|
|
16336
|
+
\u2713 saved ${localPath}`));
|
|
16337
|
+
console.log(import_chalk8.default.dim(" sync to account: hyv sync\n"));
|
|
16338
|
+
}
|
|
16053
16339
|
async function showProfileHistory(slug) {
|
|
16054
16340
|
const { authenticatedRequest: authenticatedRequest2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
16055
16341
|
const token = getToken();
|
|
@@ -16889,7 +17175,7 @@ function registerImportCommand(program3) {
|
|
|
16889
17175
|
});
|
|
16890
17176
|
}
|
|
16891
17177
|
function askQuestion(question) {
|
|
16892
|
-
return new Promise((
|
|
17178
|
+
return new Promise((resolve16) => {
|
|
16893
17179
|
const readline3 = require("readline");
|
|
16894
17180
|
const rl = readline3.createInterface({
|
|
16895
17181
|
input: process.stdin,
|
|
@@ -16898,7 +17184,7 @@ function askQuestion(question) {
|
|
|
16898
17184
|
rl.question(import_chalk13.default.cyan(` ${question}
|
|
16899
17185
|
> `), (answer) => {
|
|
16900
17186
|
rl.close();
|
|
16901
|
-
|
|
17187
|
+
resolve16(answer.trim());
|
|
16902
17188
|
});
|
|
16903
17189
|
});
|
|
16904
17190
|
}
|
|
@@ -17457,7 +17743,7 @@ hyv scan ${filePath}`));
|
|
|
17457
17743
|
var import_chalk19 = __toESM(require_source());
|
|
17458
17744
|
var fs19 = __toESM(require("fs"));
|
|
17459
17745
|
var path18 = __toESM(require("path"));
|
|
17460
|
-
var
|
|
17746
|
+
var os10 = __toESM(require("os"));
|
|
17461
17747
|
init_config();
|
|
17462
17748
|
init_auth();
|
|
17463
17749
|
init_access();
|
|
@@ -17465,7 +17751,7 @@ init_local_profile();
|
|
|
17465
17751
|
init_version();
|
|
17466
17752
|
|
|
17467
17753
|
// src/lib/mcp-stdio-test.ts
|
|
17468
|
-
var
|
|
17754
|
+
var import_child_process4 = require("child_process");
|
|
17469
17755
|
|
|
17470
17756
|
// src/lib/cli-entry.ts
|
|
17471
17757
|
var fs18 = __toESM(require("fs"));
|
|
@@ -17495,8 +17781,8 @@ async function testMcpStdioSubprocess() {
|
|
|
17495
17781
|
const entry = resolveCliEntry();
|
|
17496
17782
|
if (!entry)
|
|
17497
17783
|
return { ok: false };
|
|
17498
|
-
return new Promise((
|
|
17499
|
-
const child = (0,
|
|
17784
|
+
return new Promise((resolve16) => {
|
|
17785
|
+
const child = (0, import_child_process4.spawn)(process.execPath, [entry, "mcp"], {
|
|
17500
17786
|
stdio: ["pipe", "pipe", "pipe"],
|
|
17501
17787
|
env: { ...process.env, HYV_POSTINSTALL_QUIET: "1" }
|
|
17502
17788
|
});
|
|
@@ -17511,7 +17797,7 @@ async function testMcpStdioSubprocess() {
|
|
|
17511
17797
|
child.kill();
|
|
17512
17798
|
} catch {
|
|
17513
17799
|
}
|
|
17514
|
-
|
|
17800
|
+
resolve16({ ok, toolCount });
|
|
17515
17801
|
};
|
|
17516
17802
|
const timeout = setTimeout(() => finish(false), 1e4);
|
|
17517
17803
|
const handleLine = (line) => {
|
|
@@ -17562,7 +17848,7 @@ async function testMcpStdioSubprocess() {
|
|
|
17562
17848
|
}
|
|
17563
17849
|
|
|
17564
17850
|
// src/commands/doctor.ts
|
|
17565
|
-
var HOME =
|
|
17851
|
+
var HOME = os10.homedir();
|
|
17566
17852
|
var IS_WIN = process.platform === "win32";
|
|
17567
17853
|
function claudeDesktopDir() {
|
|
17568
17854
|
if (IS_WIN)
|
|
@@ -17773,7 +18059,7 @@ function registerDoctorCommand(program3) {
|
|
|
17773
18059
|
if (cursorMcp)
|
|
17774
18060
|
console.log(import_chalk19.default.green(" \u2713 mcp configured for cursor"));
|
|
17775
18061
|
} else {
|
|
17776
|
-
console.log(import_chalk19.default.yellow(" ! mcp not configured \u2014 run: hyv
|
|
18062
|
+
console.log(import_chalk19.default.yellow(" ! mcp not configured \u2014 run: hyv mcp (auto-detect) or hyv doctor --fix-agents"));
|
|
17777
18063
|
issues++;
|
|
17778
18064
|
}
|
|
17779
18065
|
try {
|
|
@@ -17916,11 +18202,11 @@ async function confirmDestructiveWrite(options) {
|
|
|
17916
18202
|
const question = `
|
|
17917
18203
|
${label}
|
|
17918
18204
|
A .bak backup will be created. Proceed? [y/N] `;
|
|
17919
|
-
const answer = await new Promise((
|
|
18205
|
+
const answer = await new Promise((resolve16) => {
|
|
17920
18206
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
17921
18207
|
rl.question(question, (value) => {
|
|
17922
18208
|
rl.close();
|
|
17923
|
-
|
|
18209
|
+
resolve16(value.trim().toLowerCase());
|
|
17924
18210
|
});
|
|
17925
18211
|
});
|
|
17926
18212
|
return answer === "y" || answer === "yes";
|
|
@@ -18026,19 +18312,19 @@ function registerCheckCommand(program3) {
|
|
|
18026
18312
|
const profile = await loadProfileForCommand(options.profile);
|
|
18027
18313
|
let inputText = text;
|
|
18028
18314
|
if (text === "-") {
|
|
18029
|
-
const
|
|
18315
|
+
const fs32 = require("fs");
|
|
18030
18316
|
if (process.stdin.isTTY) {
|
|
18031
18317
|
console.error(import_chalk23.default.red("No input provided. Pipe content or pass text as argument."));
|
|
18032
18318
|
process.exit(1);
|
|
18033
18319
|
}
|
|
18034
|
-
inputText =
|
|
18320
|
+
inputText = fs32.readFileSync(0, "utf-8");
|
|
18035
18321
|
}
|
|
18036
18322
|
if (!inputText.trim()) {
|
|
18037
18323
|
console.error(import_chalk23.default.red("No text provided."));
|
|
18038
18324
|
process.exit(1);
|
|
18039
18325
|
}
|
|
18040
|
-
const
|
|
18041
|
-
if (text !== "-" &&
|
|
18326
|
+
const fs31 = require("fs");
|
|
18327
|
+
if (text !== "-" && fs31.existsSync(text)) {
|
|
18042
18328
|
console.log(import_chalk23.default.yellow(`"${text}" looks like a file. Did you mean: hyv scan ${text}`));
|
|
18043
18329
|
process.exit(1);
|
|
18044
18330
|
}
|
|
@@ -18165,12 +18451,12 @@ function registerDiffCommand(program3) {
|
|
|
18165
18451
|
${result.changes.length} auto-fix${result.changes.length === 1 ? "" : "es"} available`));
|
|
18166
18452
|
console.log(import_chalk25.default.dim(` run: hyv fix ${file} -i to apply`));
|
|
18167
18453
|
if (options.apply && filePath !== "stdin") {
|
|
18168
|
-
const
|
|
18169
|
-
const
|
|
18454
|
+
const fs31 = require("fs");
|
|
18455
|
+
const path28 = require("path");
|
|
18170
18456
|
const backupPath = filePath + ".bak";
|
|
18171
|
-
|
|
18172
|
-
|
|
18173
|
-
console.log(import_chalk25.default.green(` \u2713 Applied. Backup: ${
|
|
18457
|
+
fs31.copyFileSync(filePath, backupPath);
|
|
18458
|
+
fs31.writeFileSync(filePath, result.fixed);
|
|
18459
|
+
console.log(import_chalk25.default.green(` \u2713 Applied. Backup: ${path28.basename(backupPath)}`));
|
|
18174
18460
|
}
|
|
18175
18461
|
} catch (error) {
|
|
18176
18462
|
console.error(import_chalk25.default.red(`Error: ${error.message}`));
|
|
@@ -18353,8 +18639,8 @@ function registerBatchCommand(program3) {
|
|
|
18353
18639
|
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) => {
|
|
18354
18640
|
try {
|
|
18355
18641
|
const profile = await loadProfileForCommand(options.profile);
|
|
18356
|
-
const
|
|
18357
|
-
const files =
|
|
18642
|
+
const { globSync } = require_index_min();
|
|
18643
|
+
const files = globSync(pattern, {
|
|
18358
18644
|
ignore: options.ignore ? options.ignore.split(",") : void 0,
|
|
18359
18645
|
nodir: true
|
|
18360
18646
|
});
|
|
@@ -18680,9 +18966,9 @@ var import_chalk30 = __toESM(require_source());
|
|
|
18680
18966
|
var PAGES = {
|
|
18681
18967
|
dashboard: "https://holdyourvoice.com/dashboard",
|
|
18682
18968
|
profiles: "https://holdyourvoice.com/dashboard?tab=profiles",
|
|
18683
|
-
pricing: "https://holdyourvoice.com/
|
|
18969
|
+
pricing: "https://holdyourvoice.com/app/billing",
|
|
18684
18970
|
settings: "https://holdyourvoice.com/dashboard",
|
|
18685
|
-
billing: "https://holdyourvoice.com/
|
|
18971
|
+
billing: "https://holdyourvoice.com/app/billing"
|
|
18686
18972
|
};
|
|
18687
18973
|
function registerOpenCommand(program3) {
|
|
18688
18974
|
program3.command("open").description("Open the web dashboard in your browser").option("--page <path>", "Page: dashboard, profiles, pricing, settings", "dashboard").option("--profile <name>", "Deep-link to a specific profile").option("--no-browser", "Print URL only, don't open").action(async (options) => {
|
|
@@ -18711,8 +18997,8 @@ init_welcome();
|
|
|
18711
18997
|
// src/lib/onboarding.ts
|
|
18712
18998
|
var fs24 = __toESM(require("fs"));
|
|
18713
18999
|
var path22 = __toESM(require("path"));
|
|
18714
|
-
var
|
|
18715
|
-
var hyvDir = path22.join(
|
|
19000
|
+
var os11 = __toESM(require("os"));
|
|
19001
|
+
var hyvDir = path22.join(os11.homedir(), ".hyv");
|
|
18716
19002
|
var onboardingFile = path22.join(hyvDir, "onboarding-complete.json");
|
|
18717
19003
|
function hasCompletedOnboarding() {
|
|
18718
19004
|
try {
|
|
@@ -18885,9 +19171,9 @@ function registerUpgradeCommand(program3) {
|
|
|
18885
19171
|
}
|
|
18886
19172
|
|
|
18887
19173
|
// src/mcp.ts
|
|
18888
|
-
var
|
|
18889
|
-
var
|
|
18890
|
-
var
|
|
19174
|
+
var fs27 = __toESM(require("fs"));
|
|
19175
|
+
var path25 = __toESM(require("path"));
|
|
19176
|
+
var os13 = __toESM(require("os"));
|
|
18891
19177
|
init_classifier();
|
|
18892
19178
|
init_autofix();
|
|
18893
19179
|
init_validator();
|
|
@@ -18895,23 +19181,262 @@ init_pipeline();
|
|
|
18895
19181
|
init_signals();
|
|
18896
19182
|
init_local_profile();
|
|
18897
19183
|
init_welcome();
|
|
18898
|
-
init_config();
|
|
18899
19184
|
init_telemetry();
|
|
18900
19185
|
init_access();
|
|
18901
|
-
|
|
19186
|
+
|
|
19187
|
+
// src/lib/mcp-integrate.ts
|
|
19188
|
+
var import_chalk32 = __toESM(require_source());
|
|
19189
|
+
var fs26 = __toESM(require("fs"));
|
|
19190
|
+
var os12 = __toESM(require("os"));
|
|
19191
|
+
var path24 = __toESM(require("path"));
|
|
19192
|
+
init_version();
|
|
19193
|
+
init_welcome_flow();
|
|
19194
|
+
init_config();
|
|
19195
|
+
init_local_profile();
|
|
19196
|
+
function resolveCliRoot() {
|
|
19197
|
+
const candidates = [
|
|
19198
|
+
path24.resolve(__dirname, ".."),
|
|
19199
|
+
path24.resolve(__dirname, "..", "..")
|
|
19200
|
+
];
|
|
19201
|
+
for (const root of candidates) {
|
|
19202
|
+
if (fs26.existsSync(path24.join(root, "scripts", "postinstall-lib.js"))) {
|
|
19203
|
+
return root;
|
|
19204
|
+
}
|
|
19205
|
+
}
|
|
19206
|
+
return candidates[0];
|
|
19207
|
+
}
|
|
19208
|
+
function loadPostinstallLib() {
|
|
19209
|
+
return require(path24.join(resolveCliRoot(), "scripts", "postinstall-lib.js"));
|
|
19210
|
+
}
|
|
19211
|
+
function runMcpAutoIntegrate(opts = {}) {
|
|
19212
|
+
const { integrateDetectedAgents } = loadPostinstallLib();
|
|
19213
|
+
return integrateDetectedAgents({
|
|
19214
|
+
pkgDir: resolveCliRoot(),
|
|
19215
|
+
quiet: true,
|
|
19216
|
+
force: Boolean(opts.force)
|
|
19217
|
+
});
|
|
19218
|
+
}
|
|
19219
|
+
function listLocalProfileNames2() {
|
|
19220
|
+
return [.../* @__PURE__ */ new Set([...listCachedProfiles(), ...listDiskCachedProfiles()])].sort();
|
|
19221
|
+
}
|
|
19222
|
+
function buildOnboardingStatusLines() {
|
|
19223
|
+
const lines = [];
|
|
19224
|
+
const welcome = readWelcomeState();
|
|
19225
|
+
const profiles = listLocalProfileNames2();
|
|
19226
|
+
const onboarded = hasCompletedOnboarding();
|
|
19227
|
+
const config = readConfig();
|
|
19228
|
+
const active = config.default_profile || config.profile;
|
|
19229
|
+
if (profiles.length > 0) {
|
|
19230
|
+
const activeNote = active && profiles.includes(active) ? ` (default: ${active})` : "";
|
|
19231
|
+
lines.push(`voice profiles (MCP-ready): ${profiles.join(", ")}${activeNote}`);
|
|
19232
|
+
} else {
|
|
19233
|
+
lines.push("voice profiles: none on this machine yet");
|
|
19234
|
+
lines.push("dashboard profile \u2192 run `hyv init` once; terminal `hyv welcome` \u2192 saved locally automatically");
|
|
19235
|
+
}
|
|
19236
|
+
if (welcome.profile_name) {
|
|
19237
|
+
lines.push(`welcome progress: profile name "${welcome.profile_name}"`);
|
|
19238
|
+
}
|
|
19239
|
+
if (welcome.completed_steps?.length) {
|
|
19240
|
+
const done = welcome.completed_steps.map((key) => FLOW_STEPS.find((s) => s.key === key)?.title || key).join(", ");
|
|
19241
|
+
lines.push(`welcome steps done: ${done}`);
|
|
19242
|
+
} else if (!onboarded) {
|
|
19243
|
+
lines.push("welcome steps: not started (or only partial)");
|
|
19244
|
+
}
|
|
19245
|
+
lines.push("free without profile: hyv_scan, hyv_demo, hyv_fix, hyv_check work offline");
|
|
19246
|
+
lines.push("with profile: hyv_rewrite, hyv_validate, hyv_clean use your voice rules");
|
|
19247
|
+
return lines;
|
|
19248
|
+
}
|
|
19249
|
+
function formatChatGptConnectorGuide() {
|
|
19250
|
+
const lib = loadPostinstallLib();
|
|
19251
|
+
const mcpCmd = lib.resolveHyvMcpCommand(resolveCliRoot());
|
|
19252
|
+
const guidePath = path24.join(os12.homedir(), ".chatgpt", "hyv-mcp-connector.txt");
|
|
19253
|
+
const lines = [
|
|
19254
|
+
"### ChatGPT Desktop connector (manual \u2014 no auto-config file)",
|
|
19255
|
+
"",
|
|
19256
|
+
"1. Open ChatGPT **desktop** app (browser chat cannot use local MCP)",
|
|
19257
|
+
"2. Settings \u2192 Connectors \u2192 Add connector",
|
|
19258
|
+
"3. Name: **hold your voice**",
|
|
19259
|
+
"4. Command: **hyv**",
|
|
19260
|
+
"5. Arguments: **mcp**",
|
|
19261
|
+
"",
|
|
19262
|
+
"If the connector fails to start, use absolute paths:",
|
|
19263
|
+
` command: ${mcpCmd.command}`,
|
|
19264
|
+
` arguments: ${mcpCmd.args.join(" ")}`,
|
|
19265
|
+
"",
|
|
19266
|
+
"6. Save, restart ChatGPT Desktop",
|
|
19267
|
+
'7. Ask: "run hyv_welcome" or "scan this draft with hold your voice"',
|
|
19268
|
+
""
|
|
19269
|
+
];
|
|
19270
|
+
if (fs26.existsSync(guidePath)) {
|
|
19271
|
+
lines.push(`Full guide on disk: ${guidePath}`);
|
|
19272
|
+
} else {
|
|
19273
|
+
lines.push("Run `hyv mcp` or `hyv doctor --fix-agents` to write the guide file.");
|
|
19274
|
+
}
|
|
19275
|
+
return lines.join("\n");
|
|
19276
|
+
}
|
|
19277
|
+
function buildMcpAgentStatus() {
|
|
19278
|
+
const {
|
|
19279
|
+
detectInstalledAgents,
|
|
19280
|
+
isAgentIntegrated,
|
|
19281
|
+
resolveHyvMcpCommand
|
|
19282
|
+
} = loadPostinstallLib();
|
|
19283
|
+
const home = os12.homedir();
|
|
19284
|
+
const detected = detectInstalledAgents(home);
|
|
19285
|
+
const mcpCmd = resolveHyvMcpCommand(resolveCliRoot());
|
|
19286
|
+
const lines = [
|
|
19287
|
+
"### HYV MCP status",
|
|
19288
|
+
"",
|
|
19289
|
+
`mcp server command: ${mcpCmd.command} ${mcpCmd.args.join(" ")}`,
|
|
19290
|
+
"",
|
|
19291
|
+
...buildOnboardingStatusLines().map((l) => `- ${l}`),
|
|
19292
|
+
""
|
|
19293
|
+
];
|
|
19294
|
+
if (detected.length === 0) {
|
|
19295
|
+
lines.push("### Installed apps");
|
|
19296
|
+
lines.push("- none detected \u2014 install Cursor, Claude Desktop, ChatGPT Desktop, etc.");
|
|
19297
|
+
lines.push("- then run `hyv mcp` in terminal or call hyv_mcp_setup with action=integrate");
|
|
19298
|
+
lines.push("");
|
|
19299
|
+
lines.push(formatChatGptConnectorGuide());
|
|
19300
|
+
return lines.join("\n");
|
|
19301
|
+
}
|
|
19302
|
+
lines.push("### Installed apps");
|
|
19303
|
+
for (const app of detected) {
|
|
19304
|
+
const integrated = isAgentIntegrated(app.id, home);
|
|
19305
|
+
const status = app.integration === "manual" ? integrated ? "guide written" : "add connector manually" : integrated ? "integrated" : "needs setup";
|
|
19306
|
+
lines.push(`- ${app.label}: ${status} (${app.integration})`);
|
|
19307
|
+
}
|
|
19308
|
+
lines.push("");
|
|
19309
|
+
lines.push("### In this chat (no terminal needed)");
|
|
19310
|
+
lines.push("- Which profile is active \u2192 hyv_profiles");
|
|
19311
|
+
lines.push("- New or partial setup \u2192 hyv_welcome (steps 1\u20134, or mode=extract_prompt for voice from chat)");
|
|
19312
|
+
lines.push("- Refresh app configs \u2192 hyv_mcp_setup with action=integrate (force=true after hyv upgrade)");
|
|
19313
|
+
lines.push("- ChatGPT connector steps \u2192 hyv_mcp_setup with action=chatgpt");
|
|
19314
|
+
lines.push("- Test free scan \u2192 hyv_demo or hyv_scan on any draft");
|
|
19315
|
+
return lines.join("\n");
|
|
19316
|
+
}
|
|
19317
|
+
function formatMcpIntegrateReportText(result, opts = {}) {
|
|
19318
|
+
const { agentIdForConfiguredLabel, isAgentIntegrated } = loadPostinstallLib();
|
|
19319
|
+
const configuredIds = new Set(
|
|
19320
|
+
result.configured.map((label) => agentIdForConfiguredLabel(label)).filter(Boolean)
|
|
19321
|
+
);
|
|
19322
|
+
const lines = [
|
|
19323
|
+
"### HYV MCP integration",
|
|
19324
|
+
"",
|
|
19325
|
+
...buildOnboardingStatusLines().map((l) => `- ${l}`),
|
|
19326
|
+
""
|
|
19327
|
+
];
|
|
19328
|
+
if (result.detected.length === 0) {
|
|
19329
|
+
lines.push("No supported AI apps detected on this machine.");
|
|
19330
|
+
lines.push("Install Cursor, Claude Desktop, Windsurf, or ChatGPT Desktop, then run integrate again.");
|
|
19331
|
+
lines.push("");
|
|
19332
|
+
lines.push(formatChatGptConnectorGuide());
|
|
19333
|
+
return lines.join("\n");
|
|
19334
|
+
}
|
|
19335
|
+
lines.push("### Apps");
|
|
19336
|
+
for (const app of result.detected) {
|
|
19337
|
+
const justConfigured = configuredIds.has(app.id);
|
|
19338
|
+
const integrated = isAgentIntegrated(app.id) || justConfigured;
|
|
19339
|
+
const status = app.integration === "manual" ? "manual connector" : justConfigured ? opts.force ? "updated now" : "configured now" : integrated ? "integrated" : "needs setup";
|
|
19340
|
+
lines.push(`- ${app.label}: ${status}`);
|
|
19341
|
+
}
|
|
19342
|
+
if (result.configured.length > 0) {
|
|
19343
|
+
lines.push("");
|
|
19344
|
+
lines.push(`Wired: ${result.configured.join(", ")}`);
|
|
19345
|
+
}
|
|
19346
|
+
if (result.warnings.length > 0) {
|
|
19347
|
+
lines.push("");
|
|
19348
|
+
lines.push("Notes:");
|
|
19349
|
+
for (const warning of result.warnings) {
|
|
19350
|
+
lines.push(`- ${warning}`);
|
|
19351
|
+
}
|
|
19352
|
+
}
|
|
19353
|
+
lines.push("");
|
|
19354
|
+
lines.push("Restart MCP hosts (Cursor, Claude Desktop, Antigravity, OpenCode) after config changes.");
|
|
19355
|
+
if (result.detected.some((a) => a.integration === "manual")) {
|
|
19356
|
+
lines.push("");
|
|
19357
|
+
lines.push(formatChatGptConnectorGuide());
|
|
19358
|
+
}
|
|
19359
|
+
return lines.join("\n");
|
|
19360
|
+
}
|
|
19361
|
+
function printMcpIntegrateReport(result, opts = {}) {
|
|
19362
|
+
const { agentIdForConfiguredLabel, isAgentIntegrated } = loadPostinstallLib();
|
|
19363
|
+
const configuredIds = new Set(
|
|
19364
|
+
result.configured.map((label) => agentIdForConfiguredLabel(label)).filter(Boolean)
|
|
19365
|
+
);
|
|
19366
|
+
console.log(import_chalk32.default.bold("\nhold your voice \u2014 mcp integration\n"));
|
|
19367
|
+
console.log(import_chalk32.default.dim(` ${getEngineLabel()}
|
|
19368
|
+
`));
|
|
19369
|
+
const welcome = readWelcomeState();
|
|
19370
|
+
const profiles = listLocalProfileNames2();
|
|
19371
|
+
if (profiles.length > 0) {
|
|
19372
|
+
console.log(import_chalk32.default.dim(` voice profiles: ${profiles.join(", ")}`));
|
|
19373
|
+
} else {
|
|
19374
|
+
console.log(import_chalk32.default.yellow(" no voice profile yet \u2014 mcp still works (free scan). finish onboarding in terminal or in-chat via hyv_welcome"));
|
|
19375
|
+
}
|
|
19376
|
+
if (welcome.completed_steps?.length) {
|
|
19377
|
+
console.log(import_chalk32.default.dim(` welcome progress: ${welcome.completed_steps.join(", ")}`));
|
|
19378
|
+
}
|
|
19379
|
+
console.log("");
|
|
19380
|
+
if (result.detected.length === 0) {
|
|
19381
|
+
console.log(import_chalk32.default.yellow(" no supported ai apps detected on this machine."));
|
|
19382
|
+
console.log(import_chalk32.default.dim("\n install cursor, claude desktop, chatgpt desktop, or another supported app,"));
|
|
19383
|
+
console.log(import_chalk32.default.dim(" then run hyv mcp again \u2014 or hyv doctor --fix-agents to configure everything."));
|
|
19384
|
+
console.log(import_chalk32.default.dim("\n in chatgpt/claude/cursor: call hyv_welcome to onboard without the terminal."));
|
|
19385
|
+
console.log(import_chalk32.default.dim(" chatgpt desktop: hyv mcp --setup-chatgpt\n"));
|
|
19386
|
+
return;
|
|
19387
|
+
}
|
|
19388
|
+
console.log(import_chalk32.default.bold("detected apps"));
|
|
19389
|
+
for (const app of result.detected) {
|
|
19390
|
+
const justConfigured = configuredIds.has(app.id);
|
|
19391
|
+
const integrated = isAgentIntegrated(app.id) || justConfigured;
|
|
19392
|
+
const mark = app.integration === "manual" ? import_chalk32.default.yellow("\u25CB") : integrated ? import_chalk32.default.green("\u2713") : import_chalk32.default.cyan("\u2192");
|
|
19393
|
+
const status = app.integration === "manual" ? "manual connector \u2014 see ~/.chatgpt/hyv-mcp-connector.txt" : justConfigured ? opts.force ? "updated now" : "configured now" : integrated ? "integrated" : "needs setup";
|
|
19394
|
+
console.log(` ${mark} ${app.label} \u2014 ${status}`);
|
|
19395
|
+
console.log(import_chalk32.default.dim(` ${app.reason} \xB7 ${app.integration}`));
|
|
19396
|
+
}
|
|
19397
|
+
if (result.configured.length > 0) {
|
|
19398
|
+
console.log(import_chalk32.default.green(`
|
|
19399
|
+
wired hyv into: ${result.configured.join(", ")}`));
|
|
19400
|
+
}
|
|
19401
|
+
if (result.warnings.length > 0) {
|
|
19402
|
+
console.log(import_chalk32.default.yellow("\n notes:"));
|
|
19403
|
+
for (const warning of result.warnings) {
|
|
19404
|
+
console.log(import_chalk32.default.yellow(` ! ${warning}`));
|
|
19405
|
+
}
|
|
19406
|
+
}
|
|
19407
|
+
const mcpApps = result.detected.filter((a) => a.integration === "mcp");
|
|
19408
|
+
const manualApps = result.detected.filter((a) => a.integration === "manual");
|
|
19409
|
+
console.log(import_chalk32.default.bold("\nnext steps"));
|
|
19410
|
+
console.log(import_chalk32.default.dim(" in this app: hyv_welcome (onboarding) \xB7 hyv_mcp_setup (status/refresh) \xB7 hyv_demo (try a scan)"));
|
|
19411
|
+
if (mcpApps.length > 0) {
|
|
19412
|
+
console.log(import_chalk32.default.dim(" restart apps that use mcp (cursor, claude desktop, antigravity, opencode)"));
|
|
19413
|
+
}
|
|
19414
|
+
if (manualApps.length > 0) {
|
|
19415
|
+
console.log(import_chalk32.default.dim(" chatgpt: settings \u2192 connectors \u2192 command hyv, arguments mcp"));
|
|
19416
|
+
console.log(import_chalk32.default.dim(" full steps: hyv mcp --setup-chatgpt"));
|
|
19417
|
+
}
|
|
19418
|
+
console.log(import_chalk32.default.dim(" refresh stale configs after upgrade: hyv mcp --force"));
|
|
19419
|
+
console.log(import_chalk32.default.dim(" verify: hyv mcp --test"));
|
|
19420
|
+
console.log(import_chalk32.default.dim(" all hosts: hyv doctor --verify-hosts\n"));
|
|
19421
|
+
}
|
|
19422
|
+
|
|
19423
|
+
// src/mcp.ts
|
|
19424
|
+
init_mcp_profile_hydrate();
|
|
19425
|
+
init_profile();
|
|
19426
|
+
var VOICE_MD = path25.join(os13.homedir(), ".hyv", "voice.md");
|
|
18902
19427
|
var MAX_RESPONSE_CHARS = 12e4;
|
|
18903
19428
|
var MAX_SCAN_FILE_BYTES = 2 * 1024 * 1024;
|
|
18904
19429
|
function readScanFile(filePath) {
|
|
18905
|
-
const cwdReal =
|
|
18906
|
-
const resolved =
|
|
18907
|
-
if (!resolved.startsWith(cwdReal +
|
|
19430
|
+
const cwdReal = fs27.realpathSync(process.cwd());
|
|
19431
|
+
const resolved = fs27.realpathSync(path25.resolve(filePath));
|
|
19432
|
+
if (!resolved.startsWith(cwdReal + path25.sep) && resolved !== cwdReal) {
|
|
18908
19433
|
throw new Error(`file must be in the current working directory (${cwdReal})`);
|
|
18909
19434
|
}
|
|
18910
|
-
const stat =
|
|
19435
|
+
const stat = fs27.statSync(resolved);
|
|
18911
19436
|
if (stat.size > MAX_SCAN_FILE_BYTES) {
|
|
18912
19437
|
throw new Error(`file too large (max ${MAX_SCAN_FILE_BYTES} bytes)`);
|
|
18913
19438
|
}
|
|
18914
|
-
return
|
|
19439
|
+
return fs27.readFileSync(resolved, "utf-8");
|
|
18915
19440
|
}
|
|
18916
19441
|
function toolResultPayload(result) {
|
|
18917
19442
|
const isError = result.startsWith("Error:") || result.startsWith("Unknown tool:");
|
|
@@ -18920,20 +19445,22 @@ function toolResultPayload(result) {
|
|
|
18920
19445
|
...isError ? { isError: true } : {}
|
|
18921
19446
|
};
|
|
18922
19447
|
}
|
|
18923
|
-
var pkgPath =
|
|
19448
|
+
var pkgPath = path25.resolve(__dirname, "..", "package.json");
|
|
18924
19449
|
var pkgVersion = (() => {
|
|
18925
19450
|
try {
|
|
18926
|
-
return JSON.parse(
|
|
19451
|
+
return JSON.parse(fs27.readFileSync(pkgPath, "utf-8")).version;
|
|
18927
19452
|
} catch {
|
|
18928
19453
|
return "2.7.1";
|
|
18929
19454
|
}
|
|
18930
19455
|
})();
|
|
18931
|
-
async function resolveProfile(slug
|
|
18932
|
-
|
|
18933
|
-
|
|
18934
|
-
|
|
18935
|
-
|
|
18936
|
-
|
|
19456
|
+
async function resolveProfile(slug) {
|
|
19457
|
+
await ensureMcpProfilesHydrated();
|
|
19458
|
+
let profile = await loadProfileForCommand(slug, { allowServerFetch: true });
|
|
19459
|
+
if (!profile && slug) {
|
|
19460
|
+
try {
|
|
19461
|
+
profile = await loadFullProfile(normalizeProfileSlug(slug), { forceRefresh: true });
|
|
19462
|
+
} catch {
|
|
19463
|
+
}
|
|
18937
19464
|
}
|
|
18938
19465
|
return profile;
|
|
18939
19466
|
}
|
|
@@ -19033,27 +19560,8 @@ async function toolScan(args2) {
|
|
|
19033
19560
|
}
|
|
19034
19561
|
}
|
|
19035
19562
|
async function toolProfiles(_args) {
|
|
19036
|
-
const
|
|
19037
|
-
|
|
19038
|
-
return "Cached profiles (local):\n" + local.map((p) => ` \u2022 ${p}`).join("\n");
|
|
19039
|
-
}
|
|
19040
|
-
try {
|
|
19041
|
-
const { apiGet: apiGet2 } = await Promise.resolve().then(() => (init_api(), api_exports));
|
|
19042
|
-
const data = await apiGet2("/cli/profiles");
|
|
19043
|
-
const profiles = data.profiles || [];
|
|
19044
|
-
if (profiles.length === 0) {
|
|
19045
|
-
return "No voice profiles found. Free local scan works without a profile. Run: hyv init";
|
|
19046
|
-
}
|
|
19047
|
-
return profiles.map(
|
|
19048
|
-
(p) => `${p.name}${p.is_default ? " (default)" : ""}${p.keywords?.length ? " \u2014 " + p.keywords.slice(0, 3).join(", ") : ""}`
|
|
19049
|
-
).join("\n");
|
|
19050
|
-
} catch (err) {
|
|
19051
|
-
const msg = err.message || "";
|
|
19052
|
-
if (msg.includes("session expired") || msg.includes("not signed in")) {
|
|
19053
|
-
return "Not signed in. Free local scan/fix/check work offline. Run `hyv init` for profiles.";
|
|
19054
|
-
}
|
|
19055
|
-
return `Cached profiles: none. Free local engine ready. (${msg})`;
|
|
19056
|
-
}
|
|
19563
|
+
const hydrate = await ensureMcpProfilesHydrated();
|
|
19564
|
+
return formatMcpProfilesList(hydrate);
|
|
19057
19565
|
}
|
|
19058
19566
|
async function toolValidate(args2) {
|
|
19059
19567
|
const text = args2.text || "";
|
|
@@ -19161,6 +19669,22 @@ function toolListFreeTools() {
|
|
|
19161
19669
|
function toolDemo() {
|
|
19162
19670
|
return getDemoText();
|
|
19163
19671
|
}
|
|
19672
|
+
function toolMcpSetup(args2 = {}) {
|
|
19673
|
+
const action = (args2.action || "status").toLowerCase();
|
|
19674
|
+
const force = Boolean(args2.force);
|
|
19675
|
+
switch (action) {
|
|
19676
|
+
case "status":
|
|
19677
|
+
return buildMcpAgentStatus();
|
|
19678
|
+
case "integrate": {
|
|
19679
|
+
const result = runMcpAutoIntegrate({ force });
|
|
19680
|
+
return formatMcpIntegrateReportText(result, { force });
|
|
19681
|
+
}
|
|
19682
|
+
case "chatgpt":
|
|
19683
|
+
return formatChatGptConnectorGuide();
|
|
19684
|
+
default:
|
|
19685
|
+
return `Error: unknown action "${args2.action}". Use status, integrate, or chatgpt.`;
|
|
19686
|
+
}
|
|
19687
|
+
}
|
|
19164
19688
|
async function toolAnalyze(args2) {
|
|
19165
19689
|
const text = args2.text || "";
|
|
19166
19690
|
if (!text.trim())
|
|
@@ -19255,6 +19779,23 @@ async function toolClean(args2) {
|
|
|
19255
19779
|
}
|
|
19256
19780
|
}
|
|
19257
19781
|
var TOOLS = [
|
|
19782
|
+
{
|
|
19783
|
+
name: "hyv_mcp_setup",
|
|
19784
|
+
description: "MCP host setup without terminal: status of installed apps, auto-integrate configs, or ChatGPT Desktop connector steps. Works with or without a voice profile \u2014 use hyv_welcome for onboarding.",
|
|
19785
|
+
inputSchema: {
|
|
19786
|
+
type: "object",
|
|
19787
|
+
properties: {
|
|
19788
|
+
action: {
|
|
19789
|
+
type: "string",
|
|
19790
|
+
description: "status (default) | integrate (wire hyv into Cursor/Claude/etc.) | chatgpt (desktop connector steps)"
|
|
19791
|
+
},
|
|
19792
|
+
force: {
|
|
19793
|
+
type: "boolean",
|
|
19794
|
+
description: "Refresh MCP configs even when already integrated (e.g. after hyv upgrade)"
|
|
19795
|
+
}
|
|
19796
|
+
}
|
|
19797
|
+
}
|
|
19798
|
+
},
|
|
19258
19799
|
{
|
|
19259
19800
|
name: "hyv_welcome",
|
|
19260
19801
|
description: "Profile-first onboarding: name \u2192 samples \u2192 test draft \u2192 signup. Call when the user is new. Use step (1-4) for one step, mode extract_prompt for chat voice extraction.",
|
|
@@ -19377,7 +19918,7 @@ var TOOLS = [
|
|
|
19377
19918
|
},
|
|
19378
19919
|
{
|
|
19379
19920
|
name: "hyv_profiles",
|
|
19380
|
-
description: "List
|
|
19921
|
+
description: "List voice profiles ready for MCP tools (local + account after hyv init). Shows active default. Call before hyv_rewrite/hyv_clean if unsure which profile to use.",
|
|
19381
19922
|
inputSchema: { type: "object", properties: {} }
|
|
19382
19923
|
},
|
|
19383
19924
|
{
|
|
@@ -19402,14 +19943,15 @@ var PROMPTS = [
|
|
|
19402
19943
|
];
|
|
19403
19944
|
var HYV_STATUS_PROMPT = `Use hold your voice MCP tools:
|
|
19404
19945
|
|
|
19405
|
-
|
|
19406
|
-
|
|
19407
|
-
|
|
19408
|
-
|
|
19409
|
-
|
|
19946
|
+
0. MCP setup \u2192 hyv_mcp_setup (status | integrate | chatgpt). Profiles \u2192 hyv_profiles (lists MCP-ready profiles).
|
|
19947
|
+
1. Profiles work automatically: terminal \`hyv welcome\` saves locally; dashboard profiles need \`hyv init\` once on this machine (MCP auto-syncs).
|
|
19948
|
+
2. New onboarding in chat \u2192 hyv_welcome. Step 2: mode=extract_prompt. Save markdown \u2192 hyv import or dashboard.
|
|
19949
|
+
3. Writing (use active profile from hyv_profiles): hyv_scan \u2192 hyv_fix / hyv_rewrite \u2192 hyv_validate. Optional profile= slug.
|
|
19950
|
+
4. Paid extras \u2192 hyv init + hyv plan --upgrade (signup last).
|
|
19410
19951
|
|
|
19411
19952
|
Keep the answer compact.`;
|
|
19412
19953
|
var TOOL_HANDLERS = {
|
|
19954
|
+
hyv_mcp_setup: toolMcpSetup,
|
|
19413
19955
|
hyv_welcome: toolWelcome,
|
|
19414
19956
|
hyv_list_free_tools: () => toolListFreeTools(),
|
|
19415
19957
|
hyv_demo: () => toolDemo(),
|
|
@@ -19504,14 +20046,31 @@ async function handleRequest(line) {
|
|
|
19504
20046
|
}
|
|
19505
20047
|
async function startMcpServer() {
|
|
19506
20048
|
const access = await getAccessState().catch(() => null);
|
|
19507
|
-
|
|
20049
|
+
const config = (() => {
|
|
20050
|
+
try {
|
|
20051
|
+
return JSON.parse(fs27.readFileSync(path25.join(os13.homedir(), ".hyv", "config.json"), "utf-8"));
|
|
20052
|
+
} catch {
|
|
20053
|
+
return {};
|
|
20054
|
+
}
|
|
20055
|
+
})();
|
|
20056
|
+
const defaultProfile = config.default_profile || config.profile;
|
|
20057
|
+
if (defaultProfile) {
|
|
20058
|
+
mcpLog("info", `default profile: ${defaultProfile}`);
|
|
20059
|
+
} else if (fs27.existsSync(VOICE_MD)) {
|
|
19508
20060
|
mcpLog("info", `voice profile: ${VOICE_MD}`);
|
|
19509
20061
|
} else {
|
|
19510
|
-
mcpLog("info", "free local engine ready \u2014 no voice profile yet");
|
|
20062
|
+
mcpLog("info", "free local engine ready \u2014 no voice profile yet (hyv_profiles / hyv init)");
|
|
19511
20063
|
}
|
|
19512
20064
|
if (access) {
|
|
19513
20065
|
mcpLog("info", `mode: ${access.hasPaidPlan ? "paid" : "free local"}${access.authenticated ? "" : " (not signed in)"}`);
|
|
19514
20066
|
}
|
|
20067
|
+
ensureMcpProfilesHydrated().then((r) => {
|
|
20068
|
+
if (r.synced?.length)
|
|
20069
|
+
mcpLog("info", `synced account profiles: ${r.synced.join(", ")}`);
|
|
20070
|
+
else if (r.error)
|
|
20071
|
+
mcpLog("info", `account profile sync skipped: ${r.error}`);
|
|
20072
|
+
}).catch(() => {
|
|
20073
|
+
});
|
|
19515
20074
|
let buffer = "";
|
|
19516
20075
|
process.stdin.setEncoding("utf-8");
|
|
19517
20076
|
let requestChain = Promise.resolve();
|
|
@@ -19536,150 +20095,176 @@ async function startMcpServer() {
|
|
|
19536
20095
|
}
|
|
19537
20096
|
|
|
19538
20097
|
// src/lib/mcp-setup.ts
|
|
19539
|
-
var
|
|
19540
|
-
var
|
|
19541
|
-
var
|
|
19542
|
-
var
|
|
20098
|
+
var import_chalk33 = __toESM(require_source());
|
|
20099
|
+
var fs28 = __toESM(require("fs"));
|
|
20100
|
+
var path26 = __toESM(require("path"));
|
|
20101
|
+
var os14 = __toESM(require("os"));
|
|
19543
20102
|
init_version();
|
|
19544
|
-
var HOME2 =
|
|
20103
|
+
var HOME2 = os14.homedir();
|
|
19545
20104
|
var IS_WIN2 = process.platform === "win32";
|
|
19546
20105
|
function claudeDesktopConfigPath() {
|
|
19547
20106
|
if (IS_WIN2)
|
|
19548
|
-
return
|
|
20107
|
+
return path26.join(HOME2, "AppData", "Roaming", "Claude", "claude_desktop_config.json");
|
|
19549
20108
|
if (process.platform === "linux")
|
|
19550
|
-
return
|
|
19551
|
-
return
|
|
20109
|
+
return path26.join(HOME2, ".config", "Claude", "claude_desktop_config.json");
|
|
20110
|
+
return path26.join(HOME2, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
19552
20111
|
}
|
|
19553
20112
|
function printMcpSetup() {
|
|
19554
|
-
console.log(
|
|
19555
|
-
console.log(
|
|
20113
|
+
console.log(import_chalk33.default.bold("\nhold your voice \u2014 mcp setup\n"));
|
|
20114
|
+
console.log(import_chalk33.default.dim(` ${getEngineLabel()}
|
|
19556
20115
|
`));
|
|
19557
|
-
console.log(
|
|
19558
|
-
console.log(
|
|
19559
|
-
console.log(
|
|
19560
|
-
console.log(
|
|
20116
|
+
console.log(import_chalk33.default.bold("Claude Desktop"));
|
|
20117
|
+
console.log(import_chalk33.default.dim(" Add to claude_desktop_config.json \u2192 mcpServers.hyv:"));
|
|
20118
|
+
console.log(import_chalk33.default.cyan(` ${mcpServerSnippet().split("\n").join("\n ")}`));
|
|
20119
|
+
console.log(import_chalk33.default.dim(` Config: ${claudeDesktopConfigPath()}
|
|
19561
20120
|
`));
|
|
19562
|
-
console.log(
|
|
19563
|
-
console.log(
|
|
19564
|
-
console.log(
|
|
19565
|
-
console.log(
|
|
19566
|
-
console.log(
|
|
19567
|
-
console.log(
|
|
19568
|
-
console.log(
|
|
19569
|
-
console.log(
|
|
19570
|
-
console.log(
|
|
19571
|
-
console.log(
|
|
19572
|
-
console.log(
|
|
19573
|
-
console.log(
|
|
19574
|
-
console.log(
|
|
19575
|
-
console.log(
|
|
19576
|
-
console.log(
|
|
19577
|
-
console.log(
|
|
19578
|
-
console.log(
|
|
19579
|
-
console.log(
|
|
19580
|
-
console.log(
|
|
19581
|
-
console.log(
|
|
19582
|
-
console.log(
|
|
19583
|
-
console.log(
|
|
19584
|
-
console.log(
|
|
19585
|
-
console.log(
|
|
19586
|
-
console.log(
|
|
19587
|
-
console.log(
|
|
19588
|
-
console.log(
|
|
19589
|
-
console.log(
|
|
20121
|
+
console.log(import_chalk33.default.bold("Cursor"));
|
|
20122
|
+
console.log(import_chalk33.default.dim(" MCP: ~/.cursor/mcp.json \u2192 mcpServers.hyv (same JSON as above)"));
|
|
20123
|
+
console.log(import_chalk33.default.dim(" Rule: ~/.cursor/rules/hyv.mdc (alwaysApply \u2014 auto via postinstall)\n"));
|
|
20124
|
+
console.log(import_chalk33.default.bold("Claude Code"));
|
|
20125
|
+
console.log(import_chalk33.default.dim(" Command: ~/.claude/commands/hyv.md"));
|
|
20126
|
+
console.log(import_chalk33.default.dim(" Skill: ~/.claude/skills/hold-your-voice/SKILL.md\n"));
|
|
20127
|
+
console.log(import_chalk33.default.bold("Windsurf"));
|
|
20128
|
+
console.log(import_chalk33.default.dim(" Rule: ~/.windsurf/rules/hyv.md (trigger: always_on)\n"));
|
|
20129
|
+
console.log(import_chalk33.default.bold("Codex"));
|
|
20130
|
+
console.log(import_chalk33.default.dim(" Instructions: ~/.codex/AGENTS.md (merged on install)\n"));
|
|
20131
|
+
console.log(import_chalk33.default.bold("Command Code"));
|
|
20132
|
+
console.log(import_chalk33.default.dim(" Skill: ~/.commandcode/skills/hyv/SKILL.md\n"));
|
|
20133
|
+
console.log(import_chalk33.default.bold("ChatGPT Desktop (manual connector)"));
|
|
20134
|
+
console.log(import_chalk33.default.dim(" Settings \u2192 Connectors \u2192 add connector"));
|
|
20135
|
+
console.log(import_chalk33.default.dim(" Name: hold your voice | Command: hyv | Arguments: mcp"));
|
|
20136
|
+
console.log(import_chalk33.default.dim(" Guide: ~/.chatgpt/hyv-mcp-connector.txt (after hyv doctor --fix-agents)"));
|
|
20137
|
+
console.log(import_chalk33.default.dim(" hyv mcp --setup-chatgpt\n"));
|
|
20138
|
+
console.log(import_chalk33.default.bold("Antigravity"));
|
|
20139
|
+
console.log(import_chalk33.default.dim(" MCP: ~/.gemini/config/mcp_config.json \u2192 mcpServers.hyv (auto via postinstall)\n"));
|
|
20140
|
+
console.log(import_chalk33.default.bold("OpenCode"));
|
|
20141
|
+
console.log(import_chalk33.default.dim(" MCP: ~/.config/opencode/opencode.jsonc \u2192 mcp.hyv (auto via postinstall)"));
|
|
20142
|
+
console.log(import_chalk33.default.dim(" Rules: ~/.config/opencode/AGENTS.md\n"));
|
|
20143
|
+
console.log(import_chalk33.default.bold("Auto-configure"));
|
|
20144
|
+
console.log(import_chalk33.default.dim(" hyv mcp (detect installed apps + wire mcp into them)"));
|
|
20145
|
+
console.log(import_chalk33.default.dim(" hyv mcp --force (refresh configs after hyv upgrade)"));
|
|
20146
|
+
console.log(import_chalk33.default.dim(" hyv doctor --fix-agents (configure all apps, not just detected)"));
|
|
20147
|
+
console.log(import_chalk33.default.dim(" HYV_AUTO_CONFIGURE_AGENTS=0 npm i -g @holdyourvoice/hyv (skip)\n"));
|
|
20148
|
+
console.log(import_chalk33.default.bold("In-chat (no terminal)"));
|
|
20149
|
+
console.log(import_chalk33.default.dim(" hyv_mcp_setup \u2014 status, integrate, or chatgpt connector steps"));
|
|
20150
|
+
console.log(import_chalk33.default.dim(" hyv_welcome \u2014 finish onboarding inside Cursor/Claude/ChatGPT\n"));
|
|
20151
|
+
console.log(import_chalk33.default.bold("Verify"));
|
|
20152
|
+
console.log(import_chalk33.default.dim(" hyv mcp --test"));
|
|
20153
|
+
console.log(import_chalk33.default.dim(" HYV_TELEMETRY=1 hyv mcp (optional usage logging to ~/.hyv/telemetry/)\n"));
|
|
19590
20154
|
}
|
|
19591
20155
|
async function runMcpSelfTest() {
|
|
19592
|
-
console.log(
|
|
19593
|
-
console.log(
|
|
20156
|
+
console.log(import_chalk33.default.bold("\nhold your voice \u2014 mcp self-test\n"));
|
|
20157
|
+
console.log(import_chalk33.default.dim(` ${getEngineLabel()}
|
|
19594
20158
|
`));
|
|
19595
20159
|
let passed = 0;
|
|
19596
20160
|
let failed = 0;
|
|
19597
20161
|
const tools = getMcpToolNames();
|
|
19598
20162
|
if (tools.length >= 10) {
|
|
19599
|
-
console.log(
|
|
20163
|
+
console.log(import_chalk33.default.green(` \u2713 ${tools.length} MCP tools registered`));
|
|
19600
20164
|
passed++;
|
|
19601
20165
|
} else {
|
|
19602
|
-
console.log(
|
|
20166
|
+
console.log(import_chalk33.default.red(` \u2717 expected 10+ tools, got ${tools.length}`));
|
|
19603
20167
|
failed++;
|
|
19604
20168
|
}
|
|
19605
|
-
const required = [
|
|
20169
|
+
const required = [
|
|
20170
|
+
"hyv_mcp_setup",
|
|
20171
|
+
"hyv_welcome",
|
|
20172
|
+
"hyv_scan",
|
|
20173
|
+
"hyv_analyze",
|
|
20174
|
+
"hyv_clean",
|
|
20175
|
+
"hyv_validate",
|
|
20176
|
+
"hyv_list_free_tools"
|
|
20177
|
+
];
|
|
19606
20178
|
for (const name of required) {
|
|
19607
20179
|
if (tools.includes(name)) {
|
|
19608
|
-
console.log(
|
|
20180
|
+
console.log(import_chalk33.default.green(` \u2713 tool: ${name}`));
|
|
19609
20181
|
passed++;
|
|
19610
20182
|
} else {
|
|
19611
|
-
console.log(
|
|
20183
|
+
console.log(import_chalk33.default.red(` \u2717 missing tool: ${name}`));
|
|
19612
20184
|
failed++;
|
|
19613
20185
|
}
|
|
19614
20186
|
}
|
|
19615
20187
|
try {
|
|
19616
20188
|
const welcome = await invokeMcpTool("hyv_welcome", {});
|
|
19617
20189
|
if (welcome.includes("Hold Your Voice") || welcome.includes("hold your voice")) {
|
|
19618
|
-
console.log(
|
|
20190
|
+
console.log(import_chalk33.default.green(" \u2713 hyv_welcome responds"));
|
|
20191
|
+
passed++;
|
|
20192
|
+
} else {
|
|
20193
|
+
console.log(import_chalk33.default.red(" \u2717 hyv_welcome unexpected output"));
|
|
20194
|
+
failed++;
|
|
20195
|
+
}
|
|
20196
|
+
} catch (e) {
|
|
20197
|
+
console.log(import_chalk33.default.red(` \u2717 hyv_welcome failed: ${e.message}`));
|
|
20198
|
+
failed++;
|
|
20199
|
+
}
|
|
20200
|
+
try {
|
|
20201
|
+
const setup = await invokeMcpTool("hyv_mcp_setup", { action: "status" });
|
|
20202
|
+
if (setup.includes("HYV MCP status") && setup.includes("hyv_welcome")) {
|
|
20203
|
+
console.log(import_chalk33.default.green(" \u2713 hyv_mcp_setup responds"));
|
|
19619
20204
|
passed++;
|
|
19620
20205
|
} else {
|
|
19621
|
-
console.log(
|
|
20206
|
+
console.log(import_chalk33.default.red(" \u2717 hyv_mcp_setup unexpected output"));
|
|
19622
20207
|
failed++;
|
|
19623
20208
|
}
|
|
19624
20209
|
} catch (e) {
|
|
19625
|
-
console.log(
|
|
20210
|
+
console.log(import_chalk33.default.red(` \u2717 hyv_mcp_setup failed: ${e.message}`));
|
|
19626
20211
|
failed++;
|
|
19627
20212
|
}
|
|
19628
20213
|
try {
|
|
19629
20214
|
const demo = await invokeMcpTool("hyv_demo", {});
|
|
19630
20215
|
if (demo.includes("Score") || demo.includes("issues")) {
|
|
19631
|
-
console.log(
|
|
20216
|
+
console.log(import_chalk33.default.green(" \u2713 hyv_demo pipeline works"));
|
|
19632
20217
|
passed++;
|
|
19633
20218
|
} else {
|
|
19634
|
-
console.log(
|
|
20219
|
+
console.log(import_chalk33.default.red(" \u2717 hyv_demo unexpected output"));
|
|
19635
20220
|
failed++;
|
|
19636
20221
|
}
|
|
19637
20222
|
} catch (e) {
|
|
19638
|
-
console.log(
|
|
20223
|
+
console.log(import_chalk33.default.red(` \u2717 hyv_demo failed: ${e.message}`));
|
|
19639
20224
|
failed++;
|
|
19640
20225
|
}
|
|
19641
|
-
const voiceMd =
|
|
19642
|
-
if (
|
|
19643
|
-
console.log(
|
|
20226
|
+
const voiceMd = path26.join(HOME2, ".hyv", "voice.md");
|
|
20227
|
+
if (fs28.existsSync(voiceMd)) {
|
|
20228
|
+
console.log(import_chalk33.default.green(" \u2713 voice profile found"));
|
|
19644
20229
|
passed++;
|
|
19645
20230
|
} else {
|
|
19646
|
-
console.log(
|
|
20231
|
+
console.log(import_chalk33.default.dim(" - no voice.md (free local engine still works)"));
|
|
19647
20232
|
}
|
|
19648
20233
|
if (getDemoText().length > 100) {
|
|
19649
|
-
console.log(
|
|
20234
|
+
console.log(import_chalk33.default.green(" \u2713 demo content available"));
|
|
19650
20235
|
passed++;
|
|
19651
20236
|
} else {
|
|
19652
|
-
console.log(
|
|
20237
|
+
console.log(import_chalk33.default.red(" \u2717 demo content missing"));
|
|
19653
20238
|
failed++;
|
|
19654
20239
|
}
|
|
19655
20240
|
try {
|
|
19656
20241
|
const stdio = await testMcpStdioSubprocess();
|
|
19657
20242
|
if (stdio.ok && (stdio.toolCount || 0) >= 10) {
|
|
19658
|
-
console.log(
|
|
20243
|
+
console.log(import_chalk33.default.green(` \u2713 stdio MCP subprocess responds (${stdio.toolCount} tools)`));
|
|
19659
20244
|
passed++;
|
|
19660
20245
|
} else if (stdio.ok) {
|
|
19661
|
-
console.log(
|
|
20246
|
+
console.log(import_chalk33.default.yellow(` ! stdio MCP subprocess ok but only ${stdio.toolCount || 0} tools`));
|
|
19662
20247
|
failed++;
|
|
19663
20248
|
} else {
|
|
19664
|
-
console.log(
|
|
20249
|
+
console.log(import_chalk33.default.red(" \u2717 stdio MCP subprocess failed"));
|
|
19665
20250
|
failed++;
|
|
19666
20251
|
}
|
|
19667
20252
|
} catch (e) {
|
|
19668
|
-
console.log(
|
|
20253
|
+
console.log(import_chalk33.default.red(` \u2717 stdio MCP subprocess failed: ${e.message}`));
|
|
19669
20254
|
failed++;
|
|
19670
20255
|
}
|
|
19671
20256
|
console.log("");
|
|
19672
20257
|
if (failed === 0) {
|
|
19673
|
-
console.log(
|
|
19674
|
-
console.log(
|
|
20258
|
+
console.log(import_chalk33.default.green(`\u2713 all checks passed (${passed})`));
|
|
20259
|
+
console.log(import_chalk33.default.dim("\nStart server: hyv mcp\n"));
|
|
19675
20260
|
return true;
|
|
19676
20261
|
}
|
|
19677
|
-
console.log(
|
|
20262
|
+
console.log(import_chalk33.default.yellow(`! ${failed} check(s) failed, ${passed} passed`));
|
|
19678
20263
|
return false;
|
|
19679
20264
|
}
|
|
19680
20265
|
|
|
19681
20266
|
// src/commands/export.ts
|
|
19682
|
-
var
|
|
20267
|
+
var fs29 = __toESM(require("fs"));
|
|
19683
20268
|
init_api();
|
|
19684
20269
|
var FORMATS = {
|
|
19685
20270
|
claude: {
|
|
@@ -19766,7 +20351,7 @@ async function exportCommand(format, opts) {
|
|
|
19766
20351
|
const prompt = fmt.wrap(detail.profile, detail.body);
|
|
19767
20352
|
if (opts.output) {
|
|
19768
20353
|
const outFile = opts.output.replace("{name}", profile.slug || profile.name);
|
|
19769
|
-
|
|
20354
|
+
fs29.writeFileSync(outFile, prompt);
|
|
19770
20355
|
results.push({ profile: profile.name, file: outFile });
|
|
19771
20356
|
} else {
|
|
19772
20357
|
results.push({ profile: profile.name, prompt });
|
|
@@ -19803,13 +20388,13 @@ async function exportCommand(format, opts) {
|
|
|
19803
20388
|
// src/index.ts
|
|
19804
20389
|
init_access();
|
|
19805
20390
|
init_welcome();
|
|
19806
|
-
var
|
|
19807
|
-
var
|
|
20391
|
+
var fs30 = __toESM(require("fs"));
|
|
20392
|
+
var path27 = __toESM(require("path"));
|
|
19808
20393
|
var program2 = new Command();
|
|
19809
|
-
var pkgPath2 =
|
|
20394
|
+
var pkgPath2 = path27.resolve(__dirname, "..", "package.json");
|
|
19810
20395
|
var pkgVersion2 = (() => {
|
|
19811
20396
|
try {
|
|
19812
|
-
return JSON.parse(
|
|
20397
|
+
return JSON.parse(fs30.readFileSync(pkgPath2, "utf-8")).version;
|
|
19813
20398
|
} catch {
|
|
19814
20399
|
return "2.7.1";
|
|
19815
20400
|
}
|
|
@@ -19842,7 +20427,7 @@ registerOpenCommand(program2);
|
|
|
19842
20427
|
registerWelcomeCommand(program2);
|
|
19843
20428
|
registerContentCommand(program2);
|
|
19844
20429
|
registerUpgradeCommand(program2);
|
|
19845
|
-
program2.command("mcp").description("
|
|
20430
|
+
program2.command("mcp").description("Detect local AI apps, wire hyv MCP into them, or start stdio server for hosts").option("--setup", "Show MCP setup for Claude Desktop, Cursor, Windsurf, Codex").option("--test", "Run MCP health check (tools, profile, stdio)").option("--setup-chatgpt", "Show ChatGPT connector setup instructions").option("--force", "Refresh MCP configs even when already integrated (e.g. after hyv upgrade)").option("--stdio", "Start MCP stdio server (used by Cursor, Claude Desktop, etc.)").option("--integrate-only", "Detect and configure apps without starting stdio server").action(async (opts) => {
|
|
19846
20431
|
if (opts.setup) {
|
|
19847
20432
|
printMcpSetup();
|
|
19848
20433
|
return;
|
|
@@ -19853,26 +20438,21 @@ program2.command("mcp").description("Start MCP server (for Claude Desktop and ot
|
|
|
19853
20438
|
return;
|
|
19854
20439
|
}
|
|
19855
20440
|
if (opts.setupChatgpt) {
|
|
19856
|
-
|
|
19857
|
-
|
|
19858
|
-
console.log(
|
|
19859
|
-
console.log("ChatGPT
|
|
19860
|
-
console.log(import_chalk33.default.dim(" 1. Install hyv: ") + import_chalk33.default.cyan("npm i -g @holdyourvoice/hyv@latest && hyv welcome"));
|
|
19861
|
-
console.log(import_chalk33.default.dim(" 2. Open ") + import_chalk33.default.cyan("https://chatgpt.com/#settings/Connectors"));
|
|
19862
|
-
console.log(import_chalk33.default.dim(" 3. Add connector"));
|
|
19863
|
-
console.log(import_chalk33.default.dim(" 4. Name: ") + import_chalk33.default.cyan("hold your voice"));
|
|
19864
|
-
console.log(import_chalk33.default.dim(" 5. Command: ") + import_chalk33.default.cyan("hyv"));
|
|
19865
|
-
console.log(import_chalk33.default.dim(" 6. Arguments: ") + import_chalk33.default.cyan("mcp"));
|
|
19866
|
-
console.log(import_chalk33.default.dim(" 7. Save, restart ChatGPT Desktop, ask: scan this with hold your voice"));
|
|
19867
|
-
console.log("");
|
|
19868
|
-
if (require("fs").existsSync(guide)) {
|
|
19869
|
-
console.log(import_chalk33.default.dim(`Full guide written to: ${guide}`));
|
|
19870
|
-
} else {
|
|
19871
|
-
console.log(import_chalk33.default.dim("Run hyv doctor --fix-agents to write ~/.chatgpt/hyv-mcp-connector.txt"));
|
|
19872
|
-
}
|
|
19873
|
-
console.log(import_chalk33.default.dim("\nBrowser chatgpt cannot use local MCP \u2014 desktop app only."));
|
|
20441
|
+
console.log(import_chalk34.default.bold("\nhold your voice \u2014 chatgpt desktop mcp setup\n"));
|
|
20442
|
+
console.log(formatChatGptConnectorGuide());
|
|
20443
|
+
console.log(import_chalk34.default.dim("\nBrowser chatgpt cannot use local MCP \u2014 desktop app only."));
|
|
20444
|
+
console.log(import_chalk34.default.dim("In ChatGPT chat: call hyv_mcp_setup or hyv_welcome \u2014 no terminal needed.\n"));
|
|
19874
20445
|
return;
|
|
19875
20446
|
}
|
|
20447
|
+
const wantsIntegrate = Boolean(opts.integrateOnly || process.stdin.isTTY);
|
|
20448
|
+
if (wantsIntegrate) {
|
|
20449
|
+
const integrateOpts = { force: Boolean(opts.force) };
|
|
20450
|
+
const result = runMcpAutoIntegrate(integrateOpts);
|
|
20451
|
+
printMcpIntegrateReport(result, integrateOpts);
|
|
20452
|
+
if (!opts.stdio)
|
|
20453
|
+
return;
|
|
20454
|
+
console.log(import_chalk34.default.dim("starting stdio mcp server for local testing (ctrl+c to stop)\u2026\n"));
|
|
20455
|
+
}
|
|
19876
20456
|
startMcpServer();
|
|
19877
20457
|
});
|
|
19878
20458
|
program2.command("export").description("Export voice profile for LLMs").argument("[format]", "Export format (claude, chatgpt, generic, cursor)", "claude").option("--output <file>", "Write to file instead of stdout").option("--json", "Output as JSON").action(async (format, opts) => {
|