@holdyourvoice/hyv 2.4.1 → 2.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11669,7 +11669,7 @@ function request(url, options = {}) {
11669
11669
  method: options.method || "GET",
11670
11670
  headers: {
11671
11671
  "Content-Type": "application/json",
11672
- "User-Agent": "hyv-cli/2.0.0",
11672
+ "User-Agent": "hyv-cli/2.4.3",
11673
11673
  ...options.headers
11674
11674
  },
11675
11675
  timeout: options.timeout || 3e4
@@ -12982,6 +12982,25 @@ hyv import ${name} <file.md>
12982
12982
  Or paste the profile content and I'll save it.`;
12983
12983
  console.log(prompt);
12984
12984
  }
12985
+ function registerImportCommand(program3) {
12986
+ program3.command("import").description("Import a voice profile from file").argument("<name>", "Profile name").argument("<file>", "Profile markdown file").action(async (name, file) => {
12987
+ try {
12988
+ const filePath = path6.resolve(file);
12989
+ if (!fs6.existsSync(filePath)) {
12990
+ console.error(import_chalk7.default.red(`File not found: ${filePath}`));
12991
+ process.exit(1);
12992
+ }
12993
+ const content = fs6.readFileSync(filePath, "utf-8");
12994
+ ensureHyvDir();
12995
+ writeCachedProfile(name, content);
12996
+ console.log(import_chalk7.default.green(`
12997
+ \u2713 Profile imported: ${name}`));
12998
+ } catch (error) {
12999
+ console.error(import_chalk7.default.red(`Error: ${error.message}`));
13000
+ process.exit(1);
13001
+ }
13002
+ });
13003
+ }
12985
13004
  function askQuestion(question) {
12986
13005
  return new Promise((resolve5) => {
12987
13006
  const readline = require("readline");
@@ -13422,6 +13441,83 @@ error: ${error.message}
13422
13441
  }
13423
13442
  });
13424
13443
  }
13444
+ function registerSayCommand(program3) {
13445
+ program3.command("say").description('natural language commands (e.g., "rename my profile to X")').argument("<input>", "natural language command").action(async (input) => {
13446
+ const trimmed = input.trim();
13447
+ if (!trimmed) {
13448
+ console.log(import_chalk11.default.red("\nerror: no input provided\n"));
13449
+ console.log(import_chalk11.default.dim(' try: hyv say "rename my profile to <name>"\n'));
13450
+ process.exit(1);
13451
+ return;
13452
+ }
13453
+ const intent = parseNaturalLanguage(trimmed);
13454
+ switch (intent.action) {
13455
+ case "rename":
13456
+ if (intent.name) {
13457
+ const token = getToken();
13458
+ if (!token) {
13459
+ console.log(import_chalk11.default.red("\nerror: you're not signed in yet\n"));
13460
+ console.log(import_chalk11.default.dim(" run: hyv init\n"));
13461
+ process.exit(1);
13462
+ return;
13463
+ }
13464
+ const response = await authenticatedRequest(
13465
+ "https://holdyourvoice.com/cli/profiles/rename",
13466
+ {
13467
+ method: "POST",
13468
+ body: { slug_or_id: "default", new_name: intent.name }
13469
+ }
13470
+ );
13471
+ if (response.status === 200) {
13472
+ const data = response.data;
13473
+ console.log(import_chalk11.default.green(`
13474
+ \u2713 profile renamed to ${data.profile?.name || intent.name}
13475
+ `));
13476
+ } else {
13477
+ console.log(import_chalk11.default.red(`
13478
+ error: server returned ${response.status}
13479
+ `));
13480
+ }
13481
+ }
13482
+ break;
13483
+ case "unknown":
13484
+ default:
13485
+ console.log(import_chalk11.default.yellow("\n! i didn't catch that\n"));
13486
+ console.log(import_chalk11.default.dim(' try: hyv say "rename my profile to <name>"'));
13487
+ console.log(import_chalk11.default.dim(" or: hyv rename <new-name>\n"));
13488
+ process.exit(1);
13489
+ break;
13490
+ }
13491
+ });
13492
+ }
13493
+ function parseNaturalLanguage(input) {
13494
+ const raw = input.trim();
13495
+ const renamePatterns = [
13496
+ /rename\s+(?:my\s+)?(?:voice\s+)?profile\s+(?:to|as)\s+(.+)/i,
13497
+ /update\s+(?:my\s+)?(?:voice\s+)?profile\s+(?:name\s+)?(?:to|as)\s+(.+)/i,
13498
+ /change\s+(?:my\s+)?(?:voice\s+)?profile\s+(?:name\s+)?(?:to|as)\s+(.+)/i,
13499
+ /call\s+(?:my\s+)?(?:voice\s+)?profile\s+(.+)/i,
13500
+ /set\s+(?:my\s+)?(?:voice\s+)?profile\s+(?:name\s+)?(?:to|as)\s+(.+)/i,
13501
+ /name\s+(?:my\s+)?(?:voice\s+)?profile\s+(.+)/i,
13502
+ /(?:voice\s+)?profile\s+(?:rename|name)\s+(?:to|as)\s+(.+)/i,
13503
+ /rename\s+(?:to|as)\s+(.+)/i,
13504
+ /update\s+(?:voice\s+)?profile\s+(?:name\s+)?(?:to|as)\s+(.+)/i
13505
+ ];
13506
+ for (const pattern of renamePatterns) {
13507
+ const match2 = raw.match(pattern);
13508
+ if (match2 && match2[1]) {
13509
+ let name = match2[1].trim();
13510
+ if (name.startsWith('"') && name.endsWith('"') || name.startsWith("'") && name.endsWith("'")) {
13511
+ name = name.slice(1, -1);
13512
+ }
13513
+ name = name.replace(/[.!?]+$/, "").trim();
13514
+ if (name.length > 0 && name.length <= 100) {
13515
+ return { action: "rename", name, raw };
13516
+ }
13517
+ }
13518
+ }
13519
+ return { action: "unknown", raw };
13520
+ }
13425
13521
 
13426
13522
  // src/mcp.ts
13427
13523
  var fs11 = __toESM(require("fs"));
@@ -14128,7 +14224,7 @@ function buildMinimalProfile(slug, body) {
14128
14224
  }
14129
14225
  function getDefaultProfileSlug() {
14130
14226
  const config = readConfig();
14131
- return config.profile;
14227
+ return config.default_profile;
14132
14228
  }
14133
14229
 
14134
14230
  // src/mcp.ts
@@ -14459,7 +14555,7 @@ async function handleRequest(line) {
14459
14555
  send(jsonRpcOk(id, {
14460
14556
  protocolVersion: "2024-11-05",
14461
14557
  capabilities: { tools: {}, prompts: {} },
14462
- serverInfo: { name: "hyv", version: "2.0.0" }
14558
+ serverInfo: { name: "hyv", version: "2.4.3" }
14463
14559
  }));
14464
14560
  break;
14465
14561
  case "notifications/initialized":
@@ -14693,7 +14789,7 @@ async function exportCommand(format, opts) {
14693
14789
 
14694
14790
  // src/index.ts
14695
14791
  var program2 = new Command();
14696
- program2.name("hyv").description("Hold Your Voice \u2014 CLI-first voice gate layer for AI workflows").version("2.0.0");
14792
+ program2.name("hyv").description("Hold Your Voice \u2014 CLI-first voice gate layer for AI workflows").version("2.4.3");
14697
14793
  registerInitCommand(program2);
14698
14794
  registerStatusCommand(program2);
14699
14795
  registerSyncCommand(program2);
@@ -14704,6 +14800,8 @@ registerPlanCommand(program2);
14704
14800
  registerScanCommand(program2);
14705
14801
  registerDoctorCommand(program2);
14706
14802
  registerRenameCommand(program2);
14803
+ registerSayCommand(program2);
14804
+ registerImportCommand(program2);
14707
14805
  program2.command("mcp").description("Start MCP server (for Claude Desktop and other MCP hosts)").option("--setup-chatgpt", "Show ChatGPT connector setup instructions").action(async (opts) => {
14708
14806
  if (opts.setupChatgpt) {
14709
14807
  console.log(import_chalk13.default.bold("\nhold your voice \u2014 chatgpt setup\n"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holdyourvoice/hyv",
3
- "version": "2.4.1",
3
+ "version": "2.4.3",
4
4
  "description": "Hold Your Voice \u2014 voice gate layer for AI workflows. make your ai agent sound exactly like you! includes 220+ AI pattern detection engine.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env python3
2
- #!/usr/bin/env python3
3
2
  """Portable Hold Your Voice helpers.
4
3
 
5
4
  This script intentionally has no third-party dependencies. It is not the Hold
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env python3
2
- #!/usr/bin/env python3
3
2
  """Push voice profile, meta, and voice.md to Cloudflare R2 for backup.
4
3
 
5
4
  Cost design: R2 has no egress fees. This script uses S3-compatible PUT only
@@ -103,6 +103,33 @@ try {
103
103
  }
104
104
  } catch {}
105
105
 
106
+ // ── Codex (AGENTS.md in current project) ──────────────────────────────────
107
+ try {
108
+ const cwd = process.cwd();
109
+ const agentsFile = path.join(cwd, 'AGENTS.md');
110
+ if (!fs.existsSync(agentsFile)) {
111
+ const src = path.join(pkgDir, 'agents', 'codex.md');
112
+ if (fs.existsSync(src)) {
113
+ fs.copyFileSync(src, agentsFile);
114
+ configured.push('codex');
115
+ }
116
+ }
117
+ } catch {}
118
+
119
+ // ── Command Code (global skills) ──────────────────────────────────────────
120
+ try {
121
+ const ccDir = path.join(home, '.commandcode', 'skills', 'hyv');
122
+ if (fs.existsSync(path.dirname(ccDir))) {
123
+ fs.mkdirSync(ccDir, { recursive: true });
124
+ const skillFile = path.join(ccDir, 'SKILL.md');
125
+ const src = path.join(pkgDir, 'agents', 'generic.md');
126
+ if (fs.existsSync(src) && !fs.existsSync(skillFile)) {
127
+ fs.copyFileSync(src, skillFile);
128
+ configured.push('command code');
129
+ }
130
+ }
131
+ } catch {}
132
+
106
133
  // ── Summary ───────────────────────────────────────────────────────────────
107
134
  if (configured.length > 0) {
108
135
  console.log(' \u2713 auto-configured: ' + configured.join(', '));