@holdyourvoice/hyv 2.7.0 → 2.8.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holdyourvoice/hyv",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "Hold Your Voice — 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": {
@@ -9,11 +9,17 @@
9
9
  },
10
10
  "scripts": {
11
11
  "build": "esbuild src/index.ts --bundle --platform=node --target=node18 --outfile=dist/index.js --format=cjs --banner:js='#!/usr/bin/env node'",
12
+ "build:debug": "esbuild src/index.ts --bundle --platform=node --target=node18 --outfile=dist/index.js --format=cjs --sourcemap --banner:js='#!/usr/bin/env node'",
12
13
  "dev": "npm run build && node dist/index.js",
13
- "prepublishOnly": "node scripts/check-no-duplicates.js && npm run build",
14
+ "validate:publish": "npm run build && node scripts/validate-publish.js",
15
+ "prepublishOnly": "npm run validate:publish",
14
16
  "postinstall": "node scripts/postinstall.js",
15
17
  "test": "vitest run",
16
- "test:watch": "vitest"
18
+ "test:smoke": "npm run build && bash scripts/smoke-test.sh",
19
+ "test:watch": "vitest",
20
+ "release:patch": "npm version patch && npm publish --access public",
21
+ "release:minor": "npm version minor && npm publish --access public",
22
+ "release:major": "npm version major && npm publish --access public"
17
23
  },
18
24
  "keywords": [
19
25
  "voice",
@@ -43,12 +49,14 @@
43
49
  "node": ">=18"
44
50
  },
45
51
  "files": [
46
- "dist",
47
- "scripts/",
52
+ "dist/",
53
+ "scripts/postinstall.js",
54
+ "scripts/check-no-duplicates.js",
48
55
  "assets/",
49
56
  "skills/",
57
+ "agents/",
50
58
  "README.md",
51
- "agents/"
59
+ "CHANGELOG.md"
52
60
  ],
53
61
  "repository": {
54
62
  "type": "git",
@@ -1,28 +1,43 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * postinstall.js — auto-configure MCP + agent instructions after npm install.
4
- *
5
- * Configures: Claude Desktop, Claude Code, Cursor, Windsurf, ChatGPT
6
- * Fails silently for apps that aren't installed.
7
4
  */
8
5
  const fs = require('fs');
9
6
  const path = require('path');
10
7
  const os = require('os');
8
+ const readline = require('readline');
11
9
 
12
10
  const home = os.homedir();
13
11
  const isWin = process.platform === 'win32';
14
12
  const pkgDir = path.resolve(__dirname, '..');
13
+ const quiet = process.env.HYV_POSTINSTALL_QUIET === '1' || process.argv.includes('--quiet');
14
+ const hyvDir = path.join(home, '.hyv');
15
+ const agentsMarker = path.join(hyvDir, 'agents-version.json');
16
+ const { readPkgVersion, copyAgent, writeAgentsMarker } = require('./postinstall-lib');
15
17
 
16
- // Print branded message
17
- console.log('');
18
- console.log(' make your ai agent sound exactly like you!');
19
- console.log('');
20
- console.log(' to get started:');
21
- console.log(' hyv init \u2192 sign in');
22
- console.log(' hyv new my-voice \u2192 create your voice profile');
23
- console.log('');
24
- console.log(' first month is just $1.');
25
- console.log('');
18
+ const pkgVersion = readPkgVersion(pkgDir);
19
+
20
+ function installAgent(src, dest) {
21
+ const result = copyAgent(src, dest, agentsMarker, pkgVersion);
22
+ return result.copied;
23
+ }
24
+
25
+ function print(msg) {
26
+ if (!quiet) console.log(msg);
27
+ }
28
+
29
+ print('');
30
+ print(' make your ai agent sound exactly like you!');
31
+ print(' ✓ Free local scan engine ready (works offline)');
32
+ print('');
33
+ print(' Try instantly:');
34
+ print(' hyv scan your-draft.md');
35
+ print(' hyv fix your-draft.md');
36
+ print(' hyv check "your text here"');
37
+ print(' npx @holdyourvoice/hyv welcome');
38
+ print('');
39
+ print(' Profiles + learning (paid power): hyv init');
40
+ print('');
26
41
 
27
42
  const configured = [];
28
43
 
@@ -47,51 +62,40 @@ try {
47
62
  }
48
63
  } catch {}
49
64
 
50
- // ── Claude Code (global commands) ──────────────────────────────────────────
65
+ // ── Claude Code ──────────────────────────────────────────────────────────────
51
66
  try {
52
67
  const cmdDir = path.join(home, '.claude', 'commands');
53
68
  if (fs.existsSync(path.dirname(cmdDir))) {
54
69
  fs.mkdirSync(cmdDir, { recursive: true });
55
70
  const cmdFile = path.join(cmdDir, 'hyv.md');
56
71
  const src = path.join(pkgDir, 'agents', 'claude-code.md');
57
- if (fs.existsSync(src) && !fs.existsSync(cmdFile)) {
58
- fs.copyFileSync(src, cmdFile);
59
- configured.push('claude code');
60
- }
72
+ if (installAgent(src, cmdFile)) configured.push('claude code');
61
73
  }
62
74
  } catch {}
63
75
 
64
- // ── Cursor (global rules) ─────────────────────────────────────────────────
76
+ // ── Cursor ─────────────────────────────────────────────────────────────────
65
77
  try {
66
78
  const cursorDir = path.join(home, '.cursor');
67
79
  if (fs.existsSync(cursorDir)) {
68
80
  const rulesFile = path.join(cursorDir, 'rules', 'hyv.md');
69
81
  fs.mkdirSync(path.dirname(rulesFile), { recursive: true });
70
82
  const src = path.join(pkgDir, 'agents', 'cursor.md');
71
- if (fs.existsSync(src) && !fs.existsSync(rulesFile)) {
72
- fs.copyFileSync(src, rulesFile);
73
- configured.push('cursor');
74
- }
83
+ if (installAgent(src, rulesFile)) configured.push('cursor');
75
84
  }
76
85
  } catch {}
77
86
 
78
- // ── Windsurf (global rules) ───────────────────────────────────────────────
87
+ // ── Windsurf ───────────────────────────────────────────────────────────────
79
88
  try {
80
89
  const wsDirs = [
81
- isWin
82
- ? path.join(home, 'AppData', 'Roaming', 'Windsurf')
83
- : path.join(home, '.windsurf'),
84
- isWin
85
- ? null
86
- : path.join(home, 'Library', 'Application Support', 'Windsurf'),
90
+ isWin ? path.join(home, 'AppData', 'Roaming', 'Windsurf') : path.join(home, '.windsurf'),
91
+ isWin ? null : path.join(home, 'Library', 'Application Support', 'Windsurf'),
87
92
  ].filter(Boolean);
88
93
  for (const wsDir of wsDirs) {
89
94
  if (fs.existsSync(wsDir)) {
90
95
  const rulesFile = path.join(wsDir, 'rules', 'hyv.md');
91
96
  fs.mkdirSync(path.dirname(rulesFile), { recursive: true });
92
97
  const src = path.join(pkgDir, 'agents', 'windsurf.md');
93
- if (fs.existsSync(src) && !fs.existsSync(rulesFile)) {
94
- fs.copyFileSync(src, rulesFile);
98
+ if (installAgent(src, rulesFile)) {
95
99
  configured.push('windsurf');
96
100
  break;
97
101
  }
@@ -99,20 +103,37 @@ try {
99
103
  }
100
104
  } catch {}
101
105
 
102
- // ── ChatGPT (custom instructions file) ────────────────────────────────────
106
+ // ── ChatGPT ──────────────────────────────────────────────────────────────────
103
107
  try {
104
108
  const chatgptDir = path.join(home, '.chatgpt');
105
109
  if (!fs.existsSync(chatgptDir)) fs.mkdirSync(chatgptDir, { recursive: true });
106
110
  const instrFile = path.join(chatgptDir, 'hyv-instructions.txt');
107
111
  const src = path.join(pkgDir, 'agents', 'chatgpt.md');
108
- if (fs.existsSync(src) && !fs.existsSync(instrFile)) {
109
- fs.copyFileSync(src, instrFile);
110
- configured.push('chatgpt');
111
- }
112
+ if (installAgent(src, instrFile)) configured.push('chatgpt');
112
113
  } catch {}
113
114
 
114
- // ── Summary ───────────────────────────────────────────────────────────────
115
+ writeAgentsMarker(hyvDir, pkgVersion);
116
+
115
117
  if (configured.length > 0) {
116
- console.log(' \u2713 auto-configured: ' + configured.join(', '));
117
- console.log('');
118
+ print(' auto-configured: ' + configured.join(', '));
119
+ print('');
118
120
  }
121
+
122
+ // Optional interactive demo (TTY only, non-quiet)
123
+ if (!quiet && process.stdin.isTTY) {
124
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
125
+ rl.question(' See quick free demo? (y/N) ', (answer) => {
126
+ rl.close();
127
+ if (answer.trim().toLowerCase() === 'y') {
128
+ try {
129
+ const { execSync } = require('child_process');
130
+ execSync('node "' + path.join(pkgDir, 'dist', 'index.js') + '" welcome', {
131
+ stdio: 'inherit',
132
+ env: process.env,
133
+ });
134
+ } catch {
135
+ print(' (run: hyv welcome)');
136
+ }
137
+ }
138
+ });
139
+ }