@holdyourvoice/hyv 2.2.0 → 2.3.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/assets/voice-dna-template.md +88 -0
- package/dist/index.js +209 -97
- package/package.json +1 -1
- package/scripts/postinstall 2.js +110 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Voice DNA
|
|
2
|
+
|
|
3
|
+
## Writing Rules
|
|
4
|
+
- Write like a sharp human, not a language model.
|
|
5
|
+
- Use contractions naturally (don't, can't, won't).
|
|
6
|
+
- Short paragraphs. 1-3 sentences max.
|
|
7
|
+
- Get to the point. No throat-clearing, no preamble.
|
|
8
|
+
- If making a claim, be specific. Use numbers, names, concrete details.
|
|
9
|
+
- Vary sentence length. Mix short punchy lines with longer ones.
|
|
10
|
+
- Use natural transitions, not mechanical ones ("Furthermore," "Additionally").
|
|
11
|
+
- When uncertain, say so plainly ("I think," "probably," "kinda"). Hedging is human.
|
|
12
|
+
- Never pad output to seem more thorough. Shorter and accurate beats longer and fluffy.
|
|
13
|
+
- Use physical verbs for abstract processes: "sanded down" not "improved," "bolted on" not "added," "stripped back" not "simplified."
|
|
14
|
+
- Humor comes from specificity, not from jokes. Be unexpectedly precise.
|
|
15
|
+
- Parenthetical asides are good. Use them for editorial commentary, honest reactions, quick tangents, and deflating your own seriousness (like this).
|
|
16
|
+
- Write the way you talk. Naturally.
|
|
17
|
+
- Use short words, short sentences, short paragraphs.
|
|
18
|
+
- Never use jargon. Pretend the reader is smart but unfamiliar with the topic.
|
|
19
|
+
- Read every sentence aloud in your head. If you'd stumble saying it, rewrite it.
|
|
20
|
+
- Be crystal clear about what you want the reader to do next.
|
|
21
|
+
|
|
22
|
+
## Formatting Rules
|
|
23
|
+
- Short paragraphs (1-2 sentences default, 3 max).
|
|
24
|
+
- Numbers as digits.
|
|
25
|
+
- Contractions always.
|
|
26
|
+
- NO em dashes ever. Use commas, periods, colons, semicolons, or parentheses.
|
|
27
|
+
- Bold sparingly, 1-2 key moments per section.
|
|
28
|
+
- Code blocks for specific prompts, commands, or tool outputs.
|
|
29
|
+
|
|
30
|
+
## Banned Phrases
|
|
31
|
+
|
|
32
|
+
### Dead AI Language
|
|
33
|
+
- "In today's [anything]..."
|
|
34
|
+
- "It's important to note that..." / "It's worth noting..."
|
|
35
|
+
- "Delve" / "Dive into" / "Unpack"
|
|
36
|
+
- "Harness" / "Leverage" / "Utilize"
|
|
37
|
+
- "Landscape" / "Realm" / "Robust"
|
|
38
|
+
- "Game-changer" / "Cutting-edge" / "State-of-the-art"
|
|
39
|
+
- "Straightforward"
|
|
40
|
+
- "I'd be happy to help"
|
|
41
|
+
- "In order to"
|
|
42
|
+
|
|
43
|
+
### Dead Transitions
|
|
44
|
+
- "Furthermore" / "Additionally" / "Moreover"
|
|
45
|
+
- "Moving forward" / "At the end of the day"
|
|
46
|
+
- "To put this in perspective..."
|
|
47
|
+
- "What makes this particularly interesting is..."
|
|
48
|
+
- "The implications here are..."
|
|
49
|
+
- "In other words..."
|
|
50
|
+
- "It goes without saying..."
|
|
51
|
+
|
|
52
|
+
### Engagement Bait
|
|
53
|
+
- "Let that sink in" / "Read that again" / "Full stop"
|
|
54
|
+
- "This changes everything"
|
|
55
|
+
- "Are you paying attention?"
|
|
56
|
+
- "You're not ready for this"
|
|
57
|
+
|
|
58
|
+
### AI Cringe
|
|
59
|
+
- "Supercharge" / "Unlock" / "Future-proof"
|
|
60
|
+
- "10x your productivity"
|
|
61
|
+
- "The AI revolution"
|
|
62
|
+
- "In the age of AI"
|
|
63
|
+
|
|
64
|
+
### Generic Insider Claims
|
|
65
|
+
- "Here's the part nobody's talking about"
|
|
66
|
+
- "What nobody tells you"
|
|
67
|
+
- Anything with "nobody" or "most people don't realize"
|
|
68
|
+
|
|
69
|
+
### The Big One (FATAL)
|
|
70
|
+
- "This isn't X. This is Y." and ALL variations.
|
|
71
|
+
- "Not X. Y."
|
|
72
|
+
- "Forget X. This is Y."
|
|
73
|
+
- "Less X, more Y."
|
|
74
|
+
- ANY sentence that negates one framing then asserts a corrected one.
|
|
75
|
+
- If even ONE of these appears, the output fails. Delete the negation, just state the positive claim.
|
|
76
|
+
|
|
77
|
+
### Business Jargon (Ogilvy Rule)
|
|
78
|
+
- "Utilize" / "Leverage" / "Synergy"
|
|
79
|
+
- "Circle back" / "Touch base" / "Take it offline"
|
|
80
|
+
- "Low-hanging fruit" / "Move the needle" / "Bandwidth"
|
|
81
|
+
- "Deep dive" / "Boil the ocean"
|
|
82
|
+
|
|
83
|
+
## Writing Samples
|
|
84
|
+
|
|
85
|
+
<!-- Paste your writing here. The more you give, the better the voice match.
|
|
86
|
+
Google docs, emails, blog posts, Slack messages, reports.
|
|
87
|
+
Pre-AI writing is best — your voice before it blended with AI defaults. -->
|
|
88
|
+
|
package/dist/index.js
CHANGED
|
@@ -5062,6 +5062,164 @@ var require_open = __commonJS({
|
|
|
5062
5062
|
}
|
|
5063
5063
|
});
|
|
5064
5064
|
|
|
5065
|
+
// src/lib/patterns.ts
|
|
5066
|
+
function scanLine(line, lineNum, filePath) {
|
|
5067
|
+
const findings = [];
|
|
5068
|
+
for (const pat of ALL_PATTERNS) {
|
|
5069
|
+
pat.regex.lastIndex = 0;
|
|
5070
|
+
let match2;
|
|
5071
|
+
while ((match2 = pat.regex.exec(line)) !== null) {
|
|
5072
|
+
findings.push({
|
|
5073
|
+
file: filePath,
|
|
5074
|
+
line: lineNum,
|
|
5075
|
+
column: match2.index + 1,
|
|
5076
|
+
pattern: pat.id,
|
|
5077
|
+
category: pat.category,
|
|
5078
|
+
severity: pat.severity,
|
|
5079
|
+
excerpt: highlightMatch(line.trim(), match2.index, match2[0].length),
|
|
5080
|
+
suggestion: pat.suggestion
|
|
5081
|
+
});
|
|
5082
|
+
}
|
|
5083
|
+
}
|
|
5084
|
+
return findings;
|
|
5085
|
+
}
|
|
5086
|
+
function highlightMatch(line, start, len) {
|
|
5087
|
+
const before = line.slice(0, start);
|
|
5088
|
+
const match2 = line.slice(start, start + len);
|
|
5089
|
+
const after = line.slice(start + len);
|
|
5090
|
+
return `${before}\xAB${match2}\xBB${after}`.slice(0, 120);
|
|
5091
|
+
}
|
|
5092
|
+
var AI_OVERUSED, FORMULAIC, HEDGING, STRUCTURE, ENGAGEMENT_BAIT, AI_CRINGE, INSIDER_CLAIMS, FORMATTING, OGILVY, ALL_PATTERNS;
|
|
5093
|
+
var init_patterns = __esm({
|
|
5094
|
+
"src/lib/patterns.ts"() {
|
|
5095
|
+
"use strict";
|
|
5096
|
+
AI_OVERUSED = [
|
|
5097
|
+
{ id: "ai.delve", category: "ai-slop", severity: "red", regex: /\bdelve\b/gi, suggestion: "use a specific verb: dig, explore, look at" },
|
|
5098
|
+
{ id: "ai.leverage", category: "ai-slop", severity: "red", regex: /\bleverage\b/gi, suggestion: "use: use, apply, build on" },
|
|
5099
|
+
{ id: "ai.utilize", category: "ai-slop", severity: "red", regex: /\butilize\b/gi, suggestion: "use: use" },
|
|
5100
|
+
{ id: "ai.tapestry", category: "ai-slop", severity: "red", regex: /\btapestry\b/gi, suggestion: "be specific about what you mean" },
|
|
5101
|
+
{ id: "ai.holistic", category: "ai-slop", severity: "red", regex: /\bholistic\b/gi, suggestion: "describe the actual approach" },
|
|
5102
|
+
{ id: "ai.robust", category: "ai-slop", severity: "yellow", regex: /\brobust\b/gi, suggestion: "say what actually makes it strong" },
|
|
5103
|
+
{ id: "ai.pivotal", category: "ai-slop", severity: "yellow", regex: /\bpivotal\b/gi, suggestion: "say why it matters specifically" },
|
|
5104
|
+
{ id: "ai.foster", category: "ai-slop", severity: "yellow", regex: /\bfoster\b/gi, suggestion: "use: build, grow, encourage, support" },
|
|
5105
|
+
{ id: "ai.harness", category: "ai-slop", severity: "yellow", regex: /\bharness\b/gi, suggestion: "use: use, apply, work with" },
|
|
5106
|
+
{ id: "ai.illuminate", category: "ai-slop", severity: "yellow", regex: /\billuminate\b/gi, suggestion: "use: show, explain, highlight" },
|
|
5107
|
+
{ id: "ai.ever-evolving", category: "ai-slop", severity: "red", regex: /\b(?:ever[\s-]evolving|ever[\s-]changing)\b/gi, suggestion: "cut this \u2014 it says nothing" },
|
|
5108
|
+
{ id: "ai.fast-paced", category: "ai-slop", severity: "red", regex: /\bfast[\s-]paced\b/gi, suggestion: "cut this \u2014 every industry says this" },
|
|
5109
|
+
{ id: "ai.game-changer", category: "ai-slop", severity: "red", regex: /\bgame[\s-]changer\b/gi, suggestion: "explain what actually changed" },
|
|
5110
|
+
{ id: "ai.paradigm", category: "ai-slop", severity: "red", regex: /\bparadigm\b/gi, suggestion: "describe the actual shift" },
|
|
5111
|
+
{ id: "ai.synergy", category: "ai-slop", severity: "red", regex: /\bsynergy\b/gi, suggestion: "describe what works together and why" },
|
|
5112
|
+
{ id: "ai.ecosystem", category: "ai-slop", severity: "yellow", regex: /\becosystem\b/gi, suggestion: "name the specific tools/partners/platforms" },
|
|
5113
|
+
{ id: "ai.seamless", category: "ai-slop", severity: "yellow", regex: /\bseamless\b/gi, suggestion: "describe how it actually works" },
|
|
5114
|
+
{ id: "ai.actionable", category: "ai-slop", severity: "yellow", regex: /\bactionable\b/gi, suggestion: "just give the action, don't label it" },
|
|
5115
|
+
{ id: "ai.granular", category: "ai-slop", severity: "yellow", regex: /\bgranular\b/gi, suggestion: "say: specific, detailed, or name the level" },
|
|
5116
|
+
{ id: "ai.impactful", category: "ai-slop", severity: "yellow", regex: /\bimpactful\b/gi, suggestion: "describe the actual impact" },
|
|
5117
|
+
{ id: "ai.landscape", category: "ai-slop", severity: "red", regex: /\blandscape\b/gi, suggestion: "name the specific market/field/area" },
|
|
5118
|
+
{ id: "ai.realm", category: "ai-slop", severity: "red", regex: /\brealm\b/gi, suggestion: "name the specific domain" },
|
|
5119
|
+
{ id: "ai.straightforward", category: "ai-slop", severity: "yellow", regex: /\bstraightforward\b/gi, suggestion: "just explain it directly" }
|
|
5120
|
+
];
|
|
5121
|
+
FORMULAIC = [
|
|
5122
|
+
{ id: "formula.firstly", category: "ai-slop", severity: "yellow", regex: /\bfirstly\b/gi, suggestion: 'just start \u2014 "firstly" is filler' },
|
|
5123
|
+
{ id: "formula.secondly", category: "ai-slop", severity: "yellow", regex: /\bsecondly\b/gi, suggestion: 'just continue \u2014 "secondly" is filler' },
|
|
5124
|
+
{ id: "formula.lastly", category: "ai-slop", severity: "yellow", regex: /\blastly\b/gi, suggestion: 'just end \u2014 "lastly" is filler' },
|
|
5125
|
+
{ id: "formula.moreover", category: "ai-slop", severity: "yellow", regex: /\bmoreover\b/gi, suggestion: "just add the point" },
|
|
5126
|
+
{ id: "formula.furthermore", category: "ai-slop", severity: "yellow", regex: /\bfurthermore\b/gi, suggestion: "just add the point" },
|
|
5127
|
+
{ id: "formula.in-conclusion", category: "ai-slop", severity: "red", regex: /\bin conclusion\b/gi, suggestion: "just end. readers know it's the end." },
|
|
5128
|
+
{ id: "formula.in-summary", category: "ai-slop", severity: "red", regex: /\bin summary\b/gi, suggestion: "just summarize. the label is redundant." },
|
|
5129
|
+
{ id: "formula.it-is-important", category: "ai-slop", severity: "yellow", regex: /\bit is important to note\b/gi, suggestion: "just note it. skip the preamble." },
|
|
5130
|
+
{ id: "formula.at-the-end", category: "ai-slop", severity: "yellow", regex: /\bat the end of the day\b/gi, suggestion: "cut this \u2014 it means nothing" },
|
|
5131
|
+
{ id: "formula.needless-to-say", category: "ai-slop", severity: "yellow", regex: /\bneedless to say\b/gi, suggestion: "if it's needless, don't say it" },
|
|
5132
|
+
{ id: "formula.it-goes-without", category: "ai-slop", severity: "yellow", regex: /\bit goes without saying\b/gi, suggestion: "then don't say it" },
|
|
5133
|
+
{ id: "formula.in-today", category: "ai-slop", severity: "red", regex: /\bin today'?s\b/gi, suggestion: "start with your actual point instead" },
|
|
5134
|
+
{ id: "formula.lets-dive", category: "ai-slop", severity: "red", regex: /\blet'?s (?:dive|jump|dig|delve)\b/gi, suggestion: "just start. no diving needed." },
|
|
5135
|
+
{ id: "formula.without-further", category: "ai-slop", severity: "red", regex: /\bwithout further ado\b/gi, suggestion: "cut this \u2014 just get to it" },
|
|
5136
|
+
{ id: "formula.its-worth-noting", category: "ai-slop", severity: "yellow", regex: /\bit'?s worth noting\b/gi, suggestion: "just note it directly" },
|
|
5137
|
+
{ id: "formula.moving-forward", category: "ai-slop", severity: "yellow", regex: /\bmoving forward\b/gi, suggestion: "just say what happens next" },
|
|
5138
|
+
{ id: "formula.to-put-in-perspective", category: "ai-slop", severity: "yellow", regex: /\bto put this in perspective\b/gi, suggestion: "just give the perspective directly" },
|
|
5139
|
+
{ id: "formula.what-makes-interesting", category: "ai-slop", severity: "yellow", regex: /\bwhat makes this particularly interesting\b/gi, suggestion: "just say the interesting thing" },
|
|
5140
|
+
{ id: "formula.implications", category: "ai-slop", severity: "yellow", regex: /\bthe implications here are\b/gi, suggestion: "state the implications directly" },
|
|
5141
|
+
{ id: "formula.in-other-words", category: "ai-slop", severity: "red", regex: /\bin other words\b/gi, suggestion: "say it once, well" }
|
|
5142
|
+
];
|
|
5143
|
+
HEDGING = [
|
|
5144
|
+
{ id: "hedge.some-might", category: "voice-drift", severity: "yellow", regex: /\bsome might say\b/gi, suggestion: "commit to the claim or drop it" },
|
|
5145
|
+
{ id: "hedge.arguably", category: "voice-drift", severity: "yellow", regex: /\barguably\b/gi, suggestion: "commit. say it or don't." },
|
|
5146
|
+
{ id: "hedge.worth-noting", category: "voice-drift", severity: "yellow", regex: /\bit'?s worth noting\b/gi, suggestion: "just note it directly" },
|
|
5147
|
+
{ id: "hedge.to-some-extent", category: "voice-drift", severity: "yellow", regex: /\bto some extent\b/gi, suggestion: "be specific about the extent" },
|
|
5148
|
+
{ id: "hedge.perhaps", category: "voice-drift", severity: "yellow", regex: /\bperhaps\b/gi, suggestion: "commit or cut" },
|
|
5149
|
+
{ id: "hedge.it-seems", category: "voice-drift", severity: "yellow", regex: /\bit seems\b/gi, suggestion: "state it directly" }
|
|
5150
|
+
];
|
|
5151
|
+
STRUCTURE = [
|
|
5152
|
+
{ id: "struct.antithesis", category: "structure", severity: "yellow", regex: /\bnot (?:just|only) .{3,50}, but .{3,50}/gi, suggestion: "this antithesis pattern is an AI tell \u2014 restructure" },
|
|
5153
|
+
{ id: "struct.more-than-just", category: "structure", severity: "yellow", regex: /\bmore than just\b/gi, suggestion: "say what it IS, not what it isn't" },
|
|
5154
|
+
{ id: "struct.in-order-to", category: "structure", severity: "yellow", regex: /\bin order to\b/gi, suggestion: 'just use "to"' },
|
|
5155
|
+
{ id: "struct.due-to-the-fact", category: "structure", severity: "yellow", regex: /\bdue to the fact that\b/gi, suggestion: 'use "because"' },
|
|
5156
|
+
{ id: "struct.for-the-purpose", category: "structure", severity: "yellow", regex: /\bfor the purpose of\b/gi, suggestion: 'use "to"' },
|
|
5157
|
+
{ id: "struct.which-is-another", category: "structure", severity: "red", regex: /\bwhich is another way of saying\b/gi, suggestion: "just say the thing directly" },
|
|
5158
|
+
{ id: "struct.this-is-why", category: "structure", severity: "yellow", regex: /\bthis is (?:also )?(?:why|how|where|what\b)/gi, suggestion: "signpost claims are AI tells \u2014 just make the point" },
|
|
5159
|
+
{ id: "struct.heres-where", category: "structure", severity: "yellow", regex: /\bhere'?s (?:where|why|what|the part|the (?:harder|real|actual|main|bigger) problem)\b/gi, suggestion: "just make the point without the signpost" },
|
|
5160
|
+
{ id: "struct.rhetorical-truth", category: "structure", severity: "yellow", regex: /\b(?:the\s+)?(?:uncomfortable|hard|harsh|brutal|real|honest)\s+(?:truth|reality)\b/gi, suggestion: "state the fact directly, skip the framing" },
|
|
5161
|
+
{ id: "struct.lesson-setup", category: "structure", severity: "yellow", regex: /\bhere'?s what .{3,60} taught\b/gi, suggestion: "just share the lesson" },
|
|
5162
|
+
// THE BIG ONE — antithesis negation pattern (Voice DNA: FATAL)
|
|
5163
|
+
{ id: "struct.this-isnt-x-this-is-y", category: "structure", severity: "red", regex: /\bthis isn'?t .{2,40}\.?\s*(?:this is|it'?s) .{2,40}/gi, suggestion: "FATAL: delete the negation, just state the positive claim" },
|
|
5164
|
+
{ id: "struct.not-x-y", category: "structure", severity: "red", regex: /\bnot .{2,30}\.?\s*.{2,30}\b/gi, suggestion: 'the "Not X. Y." pattern is an AI tell \u2014 just state Y' },
|
|
5165
|
+
{ id: "struct.forget-x", category: "structure", severity: "red", regex: /\bforget .{2,40}\.?\s*(?:this is|it'?s|you need)/gi, suggestion: "don't negate \u2014 just state what you mean" }
|
|
5166
|
+
];
|
|
5167
|
+
ENGAGEMENT_BAIT = [
|
|
5168
|
+
{ id: "bait.let-that-sink", category: "engagement-bait", severity: "red", regex: /\blet that sink in\b/gi, suggestion: "cut the sink. make your point and move on." },
|
|
5169
|
+
{ id: "bait.read-that-again", category: "engagement-bait", severity: "red", regex: /\bread that again\b/gi, suggestion: "if it needs repeating, repeat it yourself" },
|
|
5170
|
+
{ id: "bait.full-stop", category: "engagement-bait", severity: "red", regex: /\bfull stop\b/gi, suggestion: "the period already does this job" },
|
|
5171
|
+
{ id: "bait.this-changes-everything", category: "engagement-bait", severity: "red", regex: /\bthis changes everything\b/gi, suggestion: "prove it with specifics" },
|
|
5172
|
+
{ id: "bait.paying-attention", category: "engagement-bait", severity: "red", regex: /\bare you paying attention\b/gi, suggestion: "don't patronize the reader" },
|
|
5173
|
+
{ id: "bait.not-ready", category: "engagement-bait", severity: "red", regex: /\byou'?re not ready for this\b/gi, suggestion: "just deliver the content" }
|
|
5174
|
+
];
|
|
5175
|
+
AI_CRINGE = [
|
|
5176
|
+
{ id: "cringe.supercharge", category: "ai-cringe", severity: "red", regex: /\bsupercharge\b/gi, suggestion: "describe what it actually does" },
|
|
5177
|
+
{ id: "cringe.unlock", category: "ai-cringe", severity: "yellow", regex: /\bunlock\b/gi, suggestion: "describe what they get access to" },
|
|
5178
|
+
{ id: "cringe.future-proof", category: "ai-cringe", severity: "red", regex: /\bfuture[\s-]proof\b/gi, suggestion: "explain what specifically makes it durable" },
|
|
5179
|
+
{ id: "cringe.10x", category: "ai-cringe", severity: "red", regex: /\b10x\b/gi, suggestion: "use the actual numbers" },
|
|
5180
|
+
{ id: "cringe.ai-revolution", category: "ai-cringe", severity: "red", regex: /\bthe ai revolution\b/gi, suggestion: "describe the specific change" },
|
|
5181
|
+
{ id: "cringe.age-of-ai", category: "ai-cringe", severity: "red", regex: /\bin the age of ai\b/gi, suggestion: "just talk about what's happening now" },
|
|
5182
|
+
{ id: "cringe.happy-to-help", category: "ai-cringe", severity: "red", regex: /\bi'?d be happy to help\b/gi, suggestion: "just help. don't announce it." }
|
|
5183
|
+
];
|
|
5184
|
+
INSIDER_CLAIMS = [
|
|
5185
|
+
{ id: "insider.nobody-talking", category: "insider-claim", severity: "red", regex: /\bhere'?s the part nobody'?s? talking about\b/gi, suggestion: "just say the thing. the framing is noise." },
|
|
5186
|
+
{ id: "insider.nobody-tells", category: "insider-claim", severity: "red", regex: /\bwhat nobody tells you\b/gi, suggestion: "just tell them." },
|
|
5187
|
+
{ id: "insider.most-people", category: "insider-claim", severity: "yellow", regex: /\bmost people don'?t realize\b/gi, suggestion: "just explain it. skip the setup." },
|
|
5188
|
+
{ id: "insider.nobody-realizes", category: "insider-claim", severity: "red", regex: /\bnobody (?:realizes|talks about|mentions)\b/gi, suggestion: "if nobody talks about it, just talk about it" }
|
|
5189
|
+
];
|
|
5190
|
+
FORMATTING = [
|
|
5191
|
+
{ id: "format.em-dash", category: "formatting", severity: "red", regex: /\u2014/g, suggestion: "NO em dashes. use commas, periods, colons, semicolons, or parentheses." }
|
|
5192
|
+
];
|
|
5193
|
+
OGILVY = [
|
|
5194
|
+
// Jargon — words that hide lack of understanding
|
|
5195
|
+
{ id: "ogilvy.jargon-utilize", category: "ai-slop", severity: "red", regex: /\butilize[sd]?\b/gi, suggestion: 'Ogilvy: use "use" instead' },
|
|
5196
|
+
{ id: "ogilvy.jargon-leverage", category: "ai-slop", severity: "red", regex: /\bleverage[ds]?\b/gi, suggestion: "Ogilvy: say what you actually mean" },
|
|
5197
|
+
{ id: "ogilvy.jargon-synergy", category: "ai-slop", severity: "red", regex: /\bsynerg(?:y|ies|istic)\b/gi, suggestion: "Ogilvy: describe what works together and why" },
|
|
5198
|
+
{ id: "ogilvy.jargon-bandwidth", category: "ai-slop", severity: "yellow", regex: /\bbandwidth\b/gi, suggestion: 'Ogilvy: say "time" or "capacity"' },
|
|
5199
|
+
{ id: "ogilvy.jargon-circle-back", category: "ai-slop", severity: "red", regex: /\bcircle back\b/gi, suggestion: 'Ogilvy: say "follow up" or "talk later"' },
|
|
5200
|
+
{ id: "ogilvy.jargon-low-hanging", category: "ai-slop", severity: "red", regex: /\blow-hanging fruit\b/gi, suggestion: "Ogilvy: name the specific easy win" },
|
|
5201
|
+
{ id: "ogilvy.jargon-move-the-needle", category: "ai-slop", severity: "red", regex: /\bmove the needle\b/gi, suggestion: "Ogilvy: describe the actual impact" },
|
|
5202
|
+
{ id: "ogilvy.jargon-touch-base", category: "ai-slop", severity: "red", regex: /\btouch base\b/gi, suggestion: 'Ogilvy: say "talk" or "meet"' },
|
|
5203
|
+
{ id: "ogilvy.jargon-take-it-offline", category: "ai-slop", severity: "red", regex: /\btake it offline\b/gi, suggestion: 'Ogilvy: say "discuss later"' },
|
|
5204
|
+
{ id: "ogilvy.jargon-deep-dive", category: "ai-slop", severity: "yellow", regex: /\bdeep dive\b/gi, suggestion: 'Ogilvy: say "look closely at" or "examine"' },
|
|
5205
|
+
// Throat-clearing openers
|
|
5206
|
+
{ id: "ogilvy.preamble-i-want-to", category: "voice-drift", severity: "yellow", regex: /^\s*i want to (?:share|talk about|discuss|mention)\b/gi, suggestion: "Ogilvy: just say it. skip the preamble." },
|
|
5207
|
+
{ id: "ogilvy.preamble-just-wanted", category: "voice-drift", severity: "yellow", regex: /^\s*(?:i just wanted|i wanted to)\b/gi, suggestion: "Ogilvy: just say it." }
|
|
5208
|
+
];
|
|
5209
|
+
ALL_PATTERNS = [
|
|
5210
|
+
...AI_OVERUSED,
|
|
5211
|
+
...FORMULAIC,
|
|
5212
|
+
...HEDGING,
|
|
5213
|
+
...STRUCTURE,
|
|
5214
|
+
...ENGAGEMENT_BAIT,
|
|
5215
|
+
...AI_CRINGE,
|
|
5216
|
+
...INSIDER_CLAIMS,
|
|
5217
|
+
...FORMATTING,
|
|
5218
|
+
...OGILVY
|
|
5219
|
+
];
|
|
5220
|
+
}
|
|
5221
|
+
});
|
|
5222
|
+
|
|
5065
5223
|
// src/lib/api.ts
|
|
5066
5224
|
var api_exports = {};
|
|
5067
5225
|
__export(api_exports, {
|
|
@@ -11376,87 +11534,6 @@ var init_esm6 = __esm({
|
|
|
11376
11534
|
}
|
|
11377
11535
|
});
|
|
11378
11536
|
|
|
11379
|
-
// src/lib/patterns.ts
|
|
11380
|
-
function scanLine(line, lineNum, filePath) {
|
|
11381
|
-
const findings = [];
|
|
11382
|
-
for (const pat of ALL_PATTERNS) {
|
|
11383
|
-
pat.regex.lastIndex = 0;
|
|
11384
|
-
let match2;
|
|
11385
|
-
while ((match2 = pat.regex.exec(line)) !== null) {
|
|
11386
|
-
findings.push({
|
|
11387
|
-
file: filePath,
|
|
11388
|
-
line: lineNum,
|
|
11389
|
-
column: match2.index + 1,
|
|
11390
|
-
pattern: pat.id,
|
|
11391
|
-
category: pat.category,
|
|
11392
|
-
severity: pat.severity,
|
|
11393
|
-
excerpt: highlightMatch2(line.trim(), match2.index, match2[0].length),
|
|
11394
|
-
suggestion: pat.suggestion
|
|
11395
|
-
});
|
|
11396
|
-
}
|
|
11397
|
-
}
|
|
11398
|
-
return findings;
|
|
11399
|
-
}
|
|
11400
|
-
function highlightMatch2(line, start, len) {
|
|
11401
|
-
const before = line.slice(0, start);
|
|
11402
|
-
const match2 = line.slice(start, start + len);
|
|
11403
|
-
const after = line.slice(start + len);
|
|
11404
|
-
return `${before}\xAB${match2}\xBB${after}`.slice(0, 120);
|
|
11405
|
-
}
|
|
11406
|
-
var AI_OVERUSED2, FORMULAIC2, HEDGING2, STRUCTURE2, ALL_PATTERNS;
|
|
11407
|
-
var init_patterns = __esm({
|
|
11408
|
-
"src/lib/patterns.ts"() {
|
|
11409
|
-
"use strict";
|
|
11410
|
-
AI_OVERUSED2 = [
|
|
11411
|
-
{ id: "ai.delve", category: "ai-slop", severity: "red", regex: /\bdelve\b/gi, suggestion: "use a specific verb: dig, explore, look at" },
|
|
11412
|
-
{ id: "ai.leverage", category: "ai-slop", severity: "red", regex: /\bleverage\b/gi, suggestion: "use: use, apply, build on" },
|
|
11413
|
-
{ id: "ai.tapestry", category: "ai-slop", severity: "red", regex: /\btapestry\b/gi, suggestion: "be specific about what you mean" },
|
|
11414
|
-
{ id: "ai.holistic", category: "ai-slop", severity: "red", regex: /\bholistic\b/gi, suggestion: "describe the actual approach" },
|
|
11415
|
-
{ id: "ai.robust", category: "ai-slop", severity: "yellow", regex: /\brobust\b/gi, suggestion: "say what actually makes it strong" },
|
|
11416
|
-
{ id: "ai.pivotal", category: "ai-slop", severity: "yellow", regex: /\bpivotal\b/gi, suggestion: "say why it matters specifically" },
|
|
11417
|
-
{ id: "ai.foster", category: "ai-slop", severity: "yellow", regex: /\bfoster\b/gi, suggestion: "use: build, grow, encourage, support" },
|
|
11418
|
-
{ id: "ai.harness", category: "ai-slop", severity: "yellow", regex: /\bharness\b/gi, suggestion: "use: use, apply, work with" },
|
|
11419
|
-
{ id: "ai.illuminate", category: "ai-slop", severity: "yellow", regex: /\billuminate\b/gi, suggestion: "use: show, explain, highlight" },
|
|
11420
|
-
{ id: "ai.ever-evolving", category: "ai-slop", severity: "red", regex: /\b(?:ever[\s-]evolving|ever[\s-]changing)\b/gi, suggestion: "cut this \u2014 it says nothing" },
|
|
11421
|
-
{ id: "ai.fast-paced", category: "ai-slop", severity: "red", regex: /\bfast[\s-]paced\b/gi, suggestion: "cut this \u2014 every industry says this" },
|
|
11422
|
-
{ id: "ai.game-changer", category: "ai-slop", severity: "red", regex: /\bgame[\s-]changer\b/gi, suggestion: "explain what actually changed" },
|
|
11423
|
-
{ id: "ai.paradigm", category: "ai-slop", severity: "red", regex: /\bparadigm\b/gi, suggestion: "describe the actual shift" },
|
|
11424
|
-
{ id: "ai.synergy", category: "ai-slop", severity: "red", regex: /\bsynergy\b/gi, suggestion: "describe what works together and why" },
|
|
11425
|
-
{ id: "ai.ecosystem", category: "ai-slop", severity: "yellow", regex: /\becosystem\b/gi, suggestion: "name the specific tools/partners/platforms" },
|
|
11426
|
-
{ id: "ai.seamless", category: "ai-slop", severity: "yellow", regex: /\bseamless\b/gi, suggestion: "describe how it actually works" },
|
|
11427
|
-
{ id: "ai.actionable", category: "ai-slop", severity: "yellow", regex: /\bactionable\b/gi, suggestion: "just give the action, don't label it" },
|
|
11428
|
-
{ id: "ai.granular", category: "ai-slop", severity: "yellow", regex: /\bgranular\b/gi, suggestion: "say: specific, detailed, or name the level" },
|
|
11429
|
-
{ id: "ai.impactful", category: "ai-slop", severity: "yellow", regex: /\bimpactful\b/gi, suggestion: "describe the actual impact" }
|
|
11430
|
-
];
|
|
11431
|
-
FORMULAIC2 = [
|
|
11432
|
-
{ id: "formula.firstly", category: "ai-slop", severity: "yellow", regex: /\bfirstly\b/gi, suggestion: 'just start \u2014 "firstly" is filler' },
|
|
11433
|
-
{ id: "formula.in-conclusion", category: "ai-slop", severity: "red", regex: /\bin conclusion\b/gi, suggestion: "just end. readers know it's the end." },
|
|
11434
|
-
{ id: "formula.it-is-important", category: "ai-slop", severity: "yellow", regex: /\bit is important to note\b/gi, suggestion: "just note it. skip the preamble." },
|
|
11435
|
-
{ id: "formula.at-the-end", category: "ai-slop", severity: "yellow", regex: /\bat the end of the day\b/gi, suggestion: "cut this \u2014 it means nothing" },
|
|
11436
|
-
{ id: "formula.needless-to-say", category: "ai-slop", severity: "yellow", regex: /\bneedless to say\b/gi, suggestion: "if it's needless, don't say it" },
|
|
11437
|
-
{ id: "formula.it-goes-without", category: "ai-slop", severity: "yellow", regex: /\bit goes without saying\b/gi, suggestion: "then don't say it" },
|
|
11438
|
-
{ id: "formula.in-today", category: "ai-slop", severity: "red", regex: /\bin today'?s\b/gi, suggestion: "start with your actual point instead" },
|
|
11439
|
-
{ id: "formula.lets-dive", category: "ai-slop", severity: "red", regex: /\blet'?s (?:dive|jump|dig|delve)\b/gi, suggestion: "just start. no diving needed." },
|
|
11440
|
-
{ id: "formula.without-further", category: "ai-slop", severity: "red", regex: /\bwithout further ado\b/gi, suggestion: "cut this \u2014 just get to it" }
|
|
11441
|
-
];
|
|
11442
|
-
HEDGING2 = [
|
|
11443
|
-
{ id: "hedge.some-might", category: "voice-drift", severity: "yellow", regex: /\bsome might say\b/gi, suggestion: "commit to the claim or drop it" },
|
|
11444
|
-
{ id: "hedge.arguably", category: "voice-drift", severity: "yellow", regex: /\barguably\b/gi, suggestion: "commit. say it or don't." },
|
|
11445
|
-
{ id: "hedge.worth-noting", category: "voice-drift", severity: "yellow", regex: /\bit'?s worth noting\b/gi, suggestion: "just note it directly" },
|
|
11446
|
-
{ id: "hedge.to-some-extent", category: "voice-drift", severity: "yellow", regex: /\bto some extent\b/gi, suggestion: "be specific about the extent" }
|
|
11447
|
-
];
|
|
11448
|
-
STRUCTURE2 = [
|
|
11449
|
-
{ id: "struct.antithesis", category: "structure", severity: "yellow", regex: /\bnot (?:just|only) .{3,50}, but .{3,50}/gi, suggestion: "this antithesis pattern is an AI tell \u2014 restructure" },
|
|
11450
|
-
{ id: "struct.more-than-just", category: "structure", severity: "yellow", regex: /\bmore than just\b/gi, suggestion: "say what it IS, not what it isn't" },
|
|
11451
|
-
{ id: "struct.in-order-to", category: "structure", severity: "yellow", regex: /\bin order to\b/gi, suggestion: 'just use "to"' },
|
|
11452
|
-
{ id: "struct.due-to-the-fact", category: "structure", severity: "yellow", regex: /\bdue to the fact that\b/gi, suggestion: 'use "because"' },
|
|
11453
|
-
{ id: "struct.for-the-purpose", category: "structure", severity: "yellow", regex: /\bfor the purpose of\b/gi, suggestion: 'use "to"' },
|
|
11454
|
-
{ id: "struct.which-is-another", category: "structure", severity: "red", regex: /\bwhich is another way of saying\b/gi, suggestion: "just say the thing directly" }
|
|
11455
|
-
];
|
|
11456
|
-
ALL_PATTERNS = [...AI_OVERUSED2, ...FORMULAIC2, ...HEDGING2, ...STRUCTURE2];
|
|
11457
|
-
}
|
|
11458
|
-
});
|
|
11459
|
-
|
|
11460
11537
|
// src/lib/scanner.ts
|
|
11461
11538
|
var scanner_exports = {};
|
|
11462
11539
|
__export(scanner_exports, {
|
|
@@ -12050,6 +12127,7 @@ var path3 = __toESM(require("path"));
|
|
|
12050
12127
|
init_config();
|
|
12051
12128
|
|
|
12052
12129
|
// src/lib/scan.ts
|
|
12130
|
+
init_patterns();
|
|
12053
12131
|
var AI_PATTERN_RULES = [
|
|
12054
12132
|
{
|
|
12055
12133
|
id: "ai_antithesis",
|
|
@@ -12210,10 +12288,16 @@ function scanText(text) {
|
|
|
12210
12288
|
}
|
|
12211
12289
|
const lines = safeText.split("\n");
|
|
12212
12290
|
for (let i = 0; i < lines.length; i++) {
|
|
12213
|
-
const
|
|
12291
|
+
const lineNum = i + 1;
|
|
12292
|
+
const lineText = lines[i];
|
|
12293
|
+
const patternHits = scanLine(lineText, lineNum, "inline");
|
|
12294
|
+
for (const hit of patternHits) {
|
|
12295
|
+
hits.push({ line: hit.line, rule: hit.pattern, severity: hit.severity, phrase: hit.excerpt || "", text: lineText.trim().slice(0, 120) });
|
|
12296
|
+
}
|
|
12297
|
+
const lineHits = lineStyleHits(lineText);
|
|
12214
12298
|
for (const hit of lineHits) {
|
|
12215
|
-
hit.line =
|
|
12216
|
-
hit.text =
|
|
12299
|
+
hit.line = lineNum;
|
|
12300
|
+
hit.text = lineText.trim().slice(0, 240);
|
|
12217
12301
|
hits.push(hit);
|
|
12218
12302
|
}
|
|
12219
12303
|
}
|
|
@@ -12282,9 +12366,37 @@ Rules:
|
|
|
12282
12366
|
- Preserve unflagged lines exactly by not returning them.
|
|
12283
12367
|
- Preserve the original argument and local meaning.
|
|
12284
12368
|
- Use the voice profile as the benchmark when present.
|
|
12285
|
-
- Remove AI cadence, polished founder cadence, abstract strategy-deck language, and generic lesson shapes.
|
|
12286
12369
|
- Do not add new sections, hooks, CTAs, markdown, bullets, or commentary.
|
|
12287
12370
|
|
|
12371
|
+
## Style Rules (always apply)
|
|
12372
|
+
- Write like a sharp human, not a language model.
|
|
12373
|
+
- Use contractions naturally (don't, can't, won't).
|
|
12374
|
+
- Short paragraphs. 1-3 sentences max.
|
|
12375
|
+
- Get to the point. No throat-clearing, no preamble.
|
|
12376
|
+
- If making a claim, be specific. Use numbers, names, concrete details.
|
|
12377
|
+
- Vary sentence length. Mix short punchy lines with longer ones.
|
|
12378
|
+
- Use natural transitions, not mechanical ones (no "Furthermore," "Additionally").
|
|
12379
|
+
- Use physical verbs for abstract processes: "sanded down" not "improved," "bolted on" not "added."
|
|
12380
|
+
- Humor comes from specificity, not from jokes. Be unexpectedly precise.
|
|
12381
|
+
- Parenthetical asides are good for editorial commentary and deflating seriousness.
|
|
12382
|
+
- Write the way you talk. Naturally.
|
|
12383
|
+
- Use short words, short sentences, short paragraphs.
|
|
12384
|
+
- Never use jargon. Pretend the reader is smart but unfamiliar with the topic.
|
|
12385
|
+
- Read every sentence aloud in your head. If you'd stumble saying it, rewrite it.
|
|
12386
|
+
- Be crystal clear about what you want the reader to do next.
|
|
12387
|
+
|
|
12388
|
+
## Formatting Rules
|
|
12389
|
+
- NO em dashes ever. Use commas, periods, colons, semicolons, or parentheses.
|
|
12390
|
+
- Numbers as digits.
|
|
12391
|
+
- Contractions always.
|
|
12392
|
+
- Bold sparingly, 1-2 key moments per section.
|
|
12393
|
+
|
|
12394
|
+
## The Big One (FATAL \u2014 delete the negation, just state the positive claim)
|
|
12395
|
+
- "This isn't X. This is Y." is banned. Just state Y.
|
|
12396
|
+
- "Not X. Y." is banned. Just state Y.
|
|
12397
|
+
- "Forget X. This is Y." is banned. Just state Y.
|
|
12398
|
+
- ANY sentence that negates one framing then asserts a corrected one fails.
|
|
12399
|
+
|
|
12288
12400
|
Voice profile:
|
|
12289
12401
|
{profile_block}
|
|
12290
12402
|
|
|
@@ -13317,7 +13429,7 @@ var path12 = __toESM(require("path"));
|
|
|
13317
13429
|
var os4 = __toESM(require("os"));
|
|
13318
13430
|
|
|
13319
13431
|
// src/lib/signals.ts
|
|
13320
|
-
var
|
|
13432
|
+
var AI_OVERUSED2 = [
|
|
13321
13433
|
{ id: "ai.delve", category: "ai-slop", severity: "red", regex: /\bdelve\b/gi, suggestion: "use a specific verb: dig, explore, look at", autoFixable: true },
|
|
13322
13434
|
{ id: "ai.leverage", category: "ai-slop", severity: "red", regex: /\bleverage\b/gi, suggestion: "use: use, apply, build on", autoFixable: true },
|
|
13323
13435
|
{ id: "ai.tapestry", category: "ai-slop", severity: "red", regex: /\btapestry\b/gi, suggestion: "be specific about what you mean", autoFixable: true },
|
|
@@ -13350,7 +13462,7 @@ var AI_OVERUSED = [
|
|
|
13350
13462
|
{ id: "ai.world-class", category: "ai-slop", severity: "red", regex: /\bworld[\s-]class\b/gi, suggestion: "prove it with specifics", autoFixable: true },
|
|
13351
13463
|
{ id: "ai.second-to-none", category: "ai-slop", severity: "red", regex: /\bsecond[\s-]to[\s-]none\b/gi, suggestion: "drop the superlative, show the work", autoFixable: true }
|
|
13352
13464
|
];
|
|
13353
|
-
var
|
|
13465
|
+
var FORMULAIC2 = [
|
|
13354
13466
|
{ id: "formula.firstly", category: "ai-slop", severity: "yellow", regex: /\bfirstly\b/gi, suggestion: 'just start \u2014 "firstly" is filler', autoFixable: true },
|
|
13355
13467
|
{ id: "formula.secondly", category: "ai-slop", severity: "yellow", regex: /\bsecondly\b/gi, suggestion: 'just continue \u2014 "secondly" is filler', autoFixable: true },
|
|
13356
13468
|
{ id: "formula.lastly", category: "ai-slop", severity: "yellow", regex: /\blastly\b/gi, suggestion: 'just end \u2014 "lastly" is filler', autoFixable: true },
|
|
@@ -13367,7 +13479,7 @@ var FORMULAIC = [
|
|
|
13367
13479
|
{ id: "formula.without-further", category: "ai-slop", severity: "red", regex: /\bwithout further ado\b/gi, suggestion: "cut this \u2014 just get to it", autoFixable: true },
|
|
13368
13480
|
{ id: "formula.its-worth-noting", category: "ai-slop", severity: "yellow", regex: /\bit'?s worth noting\b/gi, suggestion: "just note it directly", autoFixable: true }
|
|
13369
13481
|
];
|
|
13370
|
-
var
|
|
13482
|
+
var HEDGING2 = [
|
|
13371
13483
|
{ id: "hedge.some-might", category: "voice-drift", severity: "yellow", regex: /\bsome might say\b/gi, suggestion: "commit to the claim or drop it", autoFixable: true },
|
|
13372
13484
|
{ id: "hedge.arguably", category: "voice-drift", severity: "yellow", regex: /\barguably\b/gi, suggestion: "commit. say it or don't.", autoFixable: true },
|
|
13373
13485
|
{ id: "hedge.worth-noting", category: "voice-drift", severity: "yellow", regex: /\bit'?s worth noting\b/gi, suggestion: "just note it directly", autoFixable: true },
|
|
@@ -13379,7 +13491,7 @@ var HEDGING = [
|
|
|
13379
13491
|
{ id: "hedge.i-think", category: "voice-drift", severity: "yellow", regex: /\bi think\b/gi, suggestion: 'just say it. the "i think" is implied.', autoFixable: true },
|
|
13380
13492
|
{ id: "hedge.in-my-opinion", category: "voice-drift", severity: "yellow", regex: /\bin my opinion\b/gi, suggestion: "just state it. it's your article.", autoFixable: true }
|
|
13381
13493
|
];
|
|
13382
|
-
var
|
|
13494
|
+
var STRUCTURE2 = [
|
|
13383
13495
|
{ id: "struct.antithesis", category: "structure", severity: "yellow", regex: /\bnot (?:just|only) .{3,50}, but .{3,50}/gi, suggestion: "this antithesis pattern is an AI tell \u2014 restructure", autoFixable: false },
|
|
13384
13496
|
{ id: "struct.not-just-but-also", category: "structure", severity: "yellow", regex: /\bnot\s+just\b.{3,80}\bbut\s+(?:also\s+)?/gi, suggestion: "say what it IS, not what it isn't", autoFixable: false },
|
|
13385
13497
|
{ id: "struct.more-than-just", category: "structure", severity: "yellow", regex: /\bmore\s+than\s+just\b/gi, suggestion: "say what it IS, not what it isn't", autoFixable: false },
|
|
@@ -13403,10 +13515,10 @@ var PUNCTUATION = [
|
|
|
13403
13515
|
{ id: "punct.em-dash", category: "ai-slop", severity: "yellow", regex: /—/g, suggestion: "em dashes are an AI tell \u2014 use a period, comma, or parentheses", autoFixable: false }
|
|
13404
13516
|
];
|
|
13405
13517
|
var ALL_STATIC_PATTERNS = [
|
|
13406
|
-
...
|
|
13407
|
-
...
|
|
13408
|
-
...
|
|
13409
|
-
...
|
|
13518
|
+
...AI_OVERUSED2,
|
|
13519
|
+
...FORMULAIC2,
|
|
13520
|
+
...HEDGING2,
|
|
13521
|
+
...STRUCTURE2,
|
|
13410
13522
|
...PUNCTUATION
|
|
13411
13523
|
];
|
|
13412
13524
|
var WORD_SWAPS = {
|
|
@@ -13688,7 +13800,7 @@ function extractSignals(text, profile) {
|
|
|
13688
13800
|
// downgrade if drift-accepted
|
|
13689
13801
|
rule: pat.suggestion,
|
|
13690
13802
|
match: match2[0],
|
|
13691
|
-
excerpt:
|
|
13803
|
+
excerpt: highlightMatch2(line.trim(), match2.index, match2[0].length),
|
|
13692
13804
|
suggestion: pat.suggestion,
|
|
13693
13805
|
autoFixable: pat.autoFixable,
|
|
13694
13806
|
driftAccepted: isDriftAccepted
|
|
@@ -13740,7 +13852,7 @@ function scoreCadence(text, profileCadence) {
|
|
|
13740
13852
|
}
|
|
13741
13853
|
return score;
|
|
13742
13854
|
}
|
|
13743
|
-
function
|
|
13855
|
+
function highlightMatch2(line, start, len) {
|
|
13744
13856
|
const before = line.slice(0, start);
|
|
13745
13857
|
const match2 = line.slice(start, start + len);
|
|
13746
13858
|
const after = line.slice(start + len);
|
|
@@ -14282,7 +14394,7 @@ ${result.issues.map((i) => ` - ${i}`).join("\n")}`);
|
|
|
14282
14394
|
var TOOLS = [
|
|
14283
14395
|
{
|
|
14284
14396
|
name: "hyv_rewrite",
|
|
14285
|
-
description: "Rewrite text to match the user's voice profile. Auto-fixes AI patterns
|
|
14397
|
+
description: "Rewrite text to match the user's voice profile using Voice DNA rules (natural voice, short paragraphs, no jargon, no em-dashes, physical verbs, specificity over jokes) and Ogilvy principles (write like you talk, short words, clear action). Auto-fixes 80+ AI patterns including engagement bait, insider claims, antithesis negation, and dead transitions. ALWAYS use this tool when: the user asks to write, rewrite, edit, draft, or improve any text. Trigger on: make this better, fix the tone, clean this up, make it sound like me, rewrite in my voice, or any writing/editing request. Do NOT wait for the user to say hyv.",
|
|
14286
14398
|
inputSchema: {
|
|
14287
14399
|
type: "object",
|
|
14288
14400
|
properties: {
|
|
@@ -14294,7 +14406,7 @@ var TOOLS = [
|
|
|
14294
14406
|
},
|
|
14295
14407
|
{
|
|
14296
14408
|
name: "hyv_scan",
|
|
14297
|
-
description: "Scan text for AI writing patterns and
|
|
14409
|
+
description: "Scan text for 80+ AI writing patterns, voice drift, engagement bait, jargon, and Ogilvy violations. ALWAYS use this tool before finalizing any written content \u2014 emails, posts, docs, messages. Detects: dead AI language, formulaic connectors, hedging, antithesis negation, insider claims, AI cringe, business jargon, and em-dashes. Returns issues with severity, line numbers, and suggested fixes.",
|
|
14298
14410
|
inputSchema: {
|
|
14299
14411
|
type: "object",
|
|
14300
14412
|
properties: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holdyourvoice/hyv",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
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": {
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
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
|
+
*/
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
|
|
12
|
+
const home = os.homedir();
|
|
13
|
+
const isWin = process.platform === 'win32';
|
|
14
|
+
const pkgDir = path.resolve(__dirname, '..');
|
|
15
|
+
|
|
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('');
|
|
26
|
+
|
|
27
|
+
const configured = [];
|
|
28
|
+
|
|
29
|
+
// ── Claude Desktop ─────────────────────────────────────────────────────────
|
|
30
|
+
try {
|
|
31
|
+
const claudeDir = isWin
|
|
32
|
+
? path.join(home, 'AppData', 'Roaming', 'Claude')
|
|
33
|
+
: path.join(home, 'Library', 'Application Support', 'Claude');
|
|
34
|
+
const configFile = path.join(claudeDir, 'claude_desktop_config.json');
|
|
35
|
+
|
|
36
|
+
if (fs.existsSync(claudeDir)) {
|
|
37
|
+
let config = {};
|
|
38
|
+
if (fs.existsSync(configFile)) {
|
|
39
|
+
try { config = JSON.parse(fs.readFileSync(configFile, 'utf-8')); } catch {}
|
|
40
|
+
}
|
|
41
|
+
if (!config.mcpServers) config.mcpServers = {};
|
|
42
|
+
if (!config.mcpServers.hyv) {
|
|
43
|
+
config.mcpServers.hyv = { command: 'hyv', args: ['mcp'] };
|
|
44
|
+
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
|
|
45
|
+
configured.push('claude desktop');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
} catch {}
|
|
49
|
+
|
|
50
|
+
// ── Claude Code (global commands) ──────────────────────────────────────────
|
|
51
|
+
try {
|
|
52
|
+
const cmdDir = path.join(home, '.claude', 'commands');
|
|
53
|
+
if (fs.existsSync(path.dirname(cmdDir))) {
|
|
54
|
+
fs.mkdirSync(cmdDir, { recursive: true });
|
|
55
|
+
const cmdFile = path.join(cmdDir, 'hyv.md');
|
|
56
|
+
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
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} catch {}
|
|
63
|
+
|
|
64
|
+
// ── Cursor (global rules) ─────────────────────────────────────────────────
|
|
65
|
+
try {
|
|
66
|
+
const cursorDir = path.join(home, '.cursor');
|
|
67
|
+
if (fs.existsSync(cursorDir)) {
|
|
68
|
+
const rulesFile = path.join(cursorDir, 'rules', 'hyv.md');
|
|
69
|
+
fs.mkdirSync(path.dirname(rulesFile), { recursive: true });
|
|
70
|
+
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
|
+
}
|
|
75
|
+
}
|
|
76
|
+
} catch {}
|
|
77
|
+
|
|
78
|
+
// ── Windsurf (global rules) ───────────────────────────────────────────────
|
|
79
|
+
try {
|
|
80
|
+
const wsDir = isWin
|
|
81
|
+
? path.join(home, 'AppData', 'Roaming', 'Windsurf')
|
|
82
|
+
: path.join(home, '.windsurf');
|
|
83
|
+
if (fs.existsSync(wsDir)) {
|
|
84
|
+
const rulesFile = path.join(wsDir, 'rules', 'hyv.md');
|
|
85
|
+
fs.mkdirSync(path.dirname(rulesFile), { recursive: true });
|
|
86
|
+
const src = path.join(pkgDir, 'agents', 'windsurf.md');
|
|
87
|
+
if (fs.existsSync(src) && !fs.existsSync(rulesFile)) {
|
|
88
|
+
fs.copyFileSync(src, rulesFile);
|
|
89
|
+
configured.push('windsurf');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} catch {}
|
|
93
|
+
|
|
94
|
+
// ── ChatGPT (custom instructions file) ────────────────────────────────────
|
|
95
|
+
try {
|
|
96
|
+
const chatgptDir = path.join(home, '.chatgpt');
|
|
97
|
+
if (!fs.existsSync(chatgptDir)) fs.mkdirSync(chatgptDir, { recursive: true });
|
|
98
|
+
const instrFile = path.join(chatgptDir, 'hyv-instructions.txt');
|
|
99
|
+
const src = path.join(pkgDir, 'agents', 'chatgpt.md');
|
|
100
|
+
if (fs.existsSync(src) && !fs.existsSync(instrFile)) {
|
|
101
|
+
fs.copyFileSync(src, instrFile);
|
|
102
|
+
configured.push('chatgpt');
|
|
103
|
+
}
|
|
104
|
+
} catch {}
|
|
105
|
+
|
|
106
|
+
// ── Summary ───────────────────────────────────────────────────────────────
|
|
107
|
+
if (configured.length > 0) {
|
|
108
|
+
console.log(' \u2713 auto-configured: ' + configured.join(', '));
|
|
109
|
+
console.log('');
|
|
110
|
+
}
|