promptvet-core 1.0.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.
Files changed (94) hide show
  1. package/README.md +278 -0
  2. package/dist/cli/index.d.ts +3 -0
  3. package/dist/cli/index.d.ts.map +1 -0
  4. package/dist/cli/index.js +273 -0
  5. package/dist/cli/index.js.map +1 -0
  6. package/dist/layers/heuristics/actionVerbs.d.ts +4 -0
  7. package/dist/layers/heuristics/actionVerbs.d.ts.map +1 -0
  8. package/dist/layers/heuristics/actionVerbs.js +9 -0
  9. package/dist/layers/heuristics/actionVerbs.js.map +1 -0
  10. package/dist/layers/heuristics/browserApiRisk.d.ts +2 -0
  11. package/dist/layers/heuristics/browserApiRisk.d.ts.map +1 -0
  12. package/dist/layers/heuristics/browserApiRisk.js +18 -0
  13. package/dist/layers/heuristics/browserApiRisk.js.map +1 -0
  14. package/dist/layers/heuristics/frustrationSignal.d.ts +2 -0
  15. package/dist/layers/heuristics/frustrationSignal.d.ts.map +1 -0
  16. package/dist/layers/heuristics/frustrationSignal.js +26 -0
  17. package/dist/layers/heuristics/frustrationSignal.js.map +1 -0
  18. package/dist/layers/heuristics/geoFlakeRisk.d.ts +2 -0
  19. package/dist/layers/heuristics/geoFlakeRisk.d.ts.map +1 -0
  20. package/dist/layers/heuristics/geoFlakeRisk.js +14 -0
  21. package/dist/layers/heuristics/geoFlakeRisk.js.map +1 -0
  22. package/dist/layers/heuristics/missingFramework.d.ts +2 -0
  23. package/dist/layers/heuristics/missingFramework.d.ts.map +1 -0
  24. package/dist/layers/heuristics/missingFramework.js +16 -0
  25. package/dist/layers/heuristics/missingFramework.js.map +1 -0
  26. package/dist/layers/heuristics/missingMockStrategy.d.ts +2 -0
  27. package/dist/layers/heuristics/missingMockStrategy.d.ts.map +1 -0
  28. package/dist/layers/heuristics/missingMockStrategy.js +17 -0
  29. package/dist/layers/heuristics/missingMockStrategy.js.map +1 -0
  30. package/dist/layers/heuristics/missingOutputFormat.d.ts +2 -0
  31. package/dist/layers/heuristics/missingOutputFormat.d.ts.map +1 -0
  32. package/dist/layers/heuristics/missingOutputFormat.js +31 -0
  33. package/dist/layers/heuristics/missingOutputFormat.js.map +1 -0
  34. package/dist/layers/heuristics/missingScope.d.ts +2 -0
  35. package/dist/layers/heuristics/missingScope.d.ts.map +1 -0
  36. package/dist/layers/heuristics/missingScope.js +11 -0
  37. package/dist/layers/heuristics/missingScope.js.map +1 -0
  38. package/dist/layers/heuristics/noActionableIntent.d.ts +2 -0
  39. package/dist/layers/heuristics/noActionableIntent.d.ts.map +1 -0
  40. package/dist/layers/heuristics/noActionableIntent.js +14 -0
  41. package/dist/layers/heuristics/noActionableIntent.js.map +1 -0
  42. package/dist/layers/linguistic/bloatDetector.d.ts +2 -0
  43. package/dist/layers/linguistic/bloatDetector.d.ts.map +1 -0
  44. package/dist/layers/linguistic/bloatDetector.js +91 -0
  45. package/dist/layers/linguistic/bloatDetector.js.map +1 -0
  46. package/dist/layers/linguistic/chainedIntent.d.ts +3 -0
  47. package/dist/layers/linguistic/chainedIntent.d.ts.map +1 -0
  48. package/dist/layers/linguistic/chainedIntent.js +26 -0
  49. package/dist/layers/linguistic/chainedIntent.js.map +1 -0
  50. package/dist/layers/linguistic/hedgeDetector.d.ts +2 -0
  51. package/dist/layers/linguistic/hedgeDetector.d.ts.map +1 -0
  52. package/dist/layers/linguistic/hedgeDetector.js +12 -0
  53. package/dist/layers/linguistic/hedgeDetector.js.map +1 -0
  54. package/dist/layers/linguistic/negationDensity.d.ts +2 -0
  55. package/dist/layers/linguistic/negationDensity.d.ts.map +1 -0
  56. package/dist/layers/linguistic/negationDensity.js +8 -0
  57. package/dist/layers/linguistic/negationDensity.js.map +1 -0
  58. package/dist/layers/linguistic/passiveVoice.d.ts +2 -0
  59. package/dist/layers/linguistic/passiveVoice.d.ts.map +1 -0
  60. package/dist/layers/linguistic/passiveVoice.js +8 -0
  61. package/dist/layers/linguistic/passiveVoice.js.map +1 -0
  62. package/dist/layers/linguistic/pronounAmbiguity.d.ts +2 -0
  63. package/dist/layers/linguistic/pronounAmbiguity.d.ts.map +1 -0
  64. package/dist/layers/linguistic/pronounAmbiguity.js +25 -0
  65. package/dist/layers/linguistic/pronounAmbiguity.js.map +1 -0
  66. package/dist/layers/linguistic/tokenCount.d.ts +2 -0
  67. package/dist/layers/linguistic/tokenCount.d.ts.map +1 -0
  68. package/dist/layers/linguistic/tokenCount.js +6 -0
  69. package/dist/layers/linguistic/tokenCount.js.map +1 -0
  70. package/dist/layers/semantic/classifier.d.ts +7 -0
  71. package/dist/layers/semantic/classifier.d.ts.map +1 -0
  72. package/dist/layers/semantic/classifier.js +40 -0
  73. package/dist/layers/semantic/classifier.js.map +1 -0
  74. package/dist/layers/syscan/auditor.d.ts +12 -0
  75. package/dist/layers/syscan/auditor.d.ts.map +1 -0
  76. package/dist/layers/syscan/auditor.js +108 -0
  77. package/dist/layers/syscan/auditor.js.map +1 -0
  78. package/dist/layers/syscan/qePersona.d.ts +2 -0
  79. package/dist/layers/syscan/qePersona.d.ts.map +1 -0
  80. package/dist/layers/syscan/qePersona.js +45 -0
  81. package/dist/layers/syscan/qePersona.js.map +1 -0
  82. package/dist/scorer/fixSuggestions.d.ts +2 -0
  83. package/dist/scorer/fixSuggestions.d.ts.map +1 -0
  84. package/dist/scorer/fixSuggestions.js +18 -0
  85. package/dist/scorer/fixSuggestions.js.map +1 -0
  86. package/dist/scorer/scorer.d.ts +23 -0
  87. package/dist/scorer/scorer.d.ts.map +1 -0
  88. package/dist/scorer/scorer.js +122 -0
  89. package/dist/scorer/scorer.js.map +1 -0
  90. package/dist/types/index.d.ts +5 -0
  91. package/dist/types/index.d.ts.map +1 -0
  92. package/dist/types/index.js +2 -0
  93. package/dist/types/index.js.map +1 -0
  94. package/package.json +43 -0
package/README.md ADDED
@@ -0,0 +1,278 @@
1
+ <div align="center">
2
+
3
+ # PromptVet
4
+
5
+ ### Catch a bad prompt before it costs you tokens — not after.
6
+
7
+ [![npm](https://img.shields.io/npm/v/%40promptvet%2Fcore?color=cb3837)](https://www.npmjs.com/package/@promptvet/core)
8
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
9
+ [![Node](https://img.shields.io/badge/node-22-339933?logo=node.js&logoColor=white)](https://nodejs.org)
10
+ [![No API Key](https://img.shields.io/badge/API%20key-not%20required-success)](#architecture)
11
+ [![TDD Built](https://img.shields.io/badge/built%20with-TDD-blueviolet)](CLAUDE.md)
12
+
13
+ ```bash
14
+ npx @promptvet/core scan "your prompt here"
15
+ ```
16
+
17
+ *No install. No API key. No account. Nothing leaves your machine.*
18
+
19
+ </div>
20
+
21
+ ---
22
+
23
+ ## ⚡ See It In Action
24
+
25
+ ```bash
26
+ $ promptvet scan "write tests for my app"
27
+ ```
28
+
29
+ ```diff
30
+ PromptVet Analysis
31
+ ──────────────────
32
+ Overall Score: 59/100
33
+
34
+ Issues Found:
35
+ - ✗ [CRITICAL] MISSING_SCOPE: 'my app' isn't specific enough.
36
+
37
+ Suggested Fixes:
38
+ + Name the specific file, function, or component instead
39
+ + of using vague references like 'my app' or 'this feature'.
40
+ ```
41
+
42
+ ---
43
+
44
+ ## 🧠 The One Thing Regex Can't Catch — But This Does
45
+
46
+ Pattern-matching alone misses prompts that are **grammatically perfect but semantically empty.** That's the gap PromptVet's two-layer engine is built to close.
47
+
48
+ <table>
49
+ <tr>
50
+ <td width="50%" valign="top">
51
+
52
+ **❌ Looks fine. Isn't.**
53
+ ```bash
54
+ $ promptvet scan "improve error handling"
55
+
56
+ Running deeper analysis...
57
+ ✗ [CRITICAL] SEMANTIC_LOW_QUALITY
58
+ Too vague for a model to identify
59
+ a clear instruction.
60
+ ```
61
+
62
+ </td>
63
+ <td width="50%" valign="top">
64
+
65
+ **✅ Same shape. Actually specific.**
66
+ ```bash
67
+ $ promptvet scan "optimize the login
68
+ query in UserRepository.ts"
69
+
70
+ Overall Score: 100/100
71
+ ```
72
+
73
+ </td>
74
+ </tr>
75
+ </table>
76
+
77
+ Same sentence structure. Same grammar. One ships, one wastes a round trip. No regex on earth tells those apart — that's why PromptVet has two layers, not one.
78
+
79
+ ---
80
+
81
+ ## 🏗️ How It Works
82
+
83
+ ```
84
+ ┌─────────────────────────────────────────────────────┐
85
+ │ 1. LINGUISTIC + HEURISTICS → milliseconds │
86
+ │ Deterministic. Pattern-based. Zero cost. │
87
+ │ Catches ~90% of bad prompts instantly. │
88
+ └───────────────────────┬───────────────────────────────┘
89
+ │ clean but short & generic?
90
+
91
+ ┌─────────────────────────────────────────────────────┐
92
+ │ 2. SEMANTIC LAYER → a couple of seconds │
93
+ │ Local model inference. Runs on YOUR machine. │
94
+ │ Only triggers when layer 1 can't decide. │
95
+ │ Always tells you when it's running. No surprises. │
96
+ └─────────────────────────────────────────────────────┘
97
+ ```
98
+
99
+ Most scans never reach layer 2 — they're caught instantly. The semantic layer is the safety net for prompts that *look* fine and aren't.
100
+
101
+ ---
102
+
103
+ ## 🚀 Quick Start
104
+
105
+ ```bash
106
+ # Inline string
107
+ promptvet scan "write unit tests for my geolocation feature"
108
+
109
+ # A file
110
+ promptvet scan prompt.txt
111
+
112
+ # Machine-readable, for scripts/CI/editor integrations
113
+ promptvet scan "your prompt" --json
114
+
115
+ # Stricter pass bar (default: 60)
116
+ promptvet scan "your prompt" --threshold 70
117
+ ```
118
+
119
+ | Exit Code | Meaning |
120
+ |:---:|---|
121
+ | `0` | Passed — score above threshold, no critical issues |
122
+ | `1` | Failed — low score, **or** a critical issue (even if the score looks fine) |
123
+
124
+ ---
125
+
126
+ ## 🔍 What It Catches
127
+
128
+ <details open>
129
+ <summary><b>Pattern-based checks — instant, free, deterministic</b></summary>
130
+ <br>
131
+
132
+ | Check | Catches |
133
+ |---|---|
134
+ | `geoFlakeRisk` / `browserApiRisk` | Unit-testing browser-only APIs — a known flake trap |
135
+ | `missingFramework` | No test framework named — JS/TS, **pytest, JUnit, RSpec, go test, PHPUnit** & more |
136
+ | `missingMockStrategy` | External dependency (API/DB/ORM) with no mocking plan |
137
+ | `missingOutputFormat` | Generation request with no format specified |
138
+ | `missingScope` | "my app", "this feature" — vague reference, nothing named |
139
+ | `noActionableIntent` | No real instruction at all — *but bug reports are exempted, see below* |
140
+ | `frustrationSignal` | Profanity / visible frustration — a nudge that stressed prompts skip details |
141
+ | `hedgeDetector` `passiveVoice` `pronounAmbiguity` `negationDensity` `chainedIntent` `bloatDetector` | Hedge words, passive voice, unresolved pronouns, filler, chained requests |
142
+
143
+ </details>
144
+
145
+ <details>
146
+ <summary><b>Semantic check — only when pattern-matching can't decide</b></summary>
147
+ <br>
148
+
149
+ A local model classifies whether a short, pattern-clean prompt is actually specific enough to act on. This is what catches `"improve error handling"` above — nothing else in the engine can.
150
+
151
+ </details>
152
+
153
+ > **Worth knowing:** `noActionableIntent` doesn't punish bug reports. *"The rest timer resets after clicking increment"* has no action verb — but it's a perfectly good prompt, the fix is implied. PromptVet recognizes the shape of a bug report and lets it through.
154
+
155
+ ---
156
+
157
+ ## 📦 Sample JSON Output
158
+
159
+ ```json
160
+ {
161
+ "overall": 63.5,
162
+ "dimensions": {
163
+ "ambiguity": 70,
164
+ "tokenBloat": 100,
165
+ "clarity": 75,
166
+ "riskSignals": 0
167
+ },
168
+ "issues": [
169
+ {
170
+ "severity": "critical",
171
+ "code": "FLAKE_RISK_GEO",
172
+ "message": "Geolocation APIs are browser-dependent — unit testing is flake-prone."
173
+ }
174
+ ],
175
+ "suggestedFixes": [
176
+ "Consider integration or E2E tests instead of unit tests for browser-dependent APIs."
177
+ ]
178
+ }
179
+ ```
180
+
181
+ Every issue maps to a pre-written fix from a deterministic lookup table — pattern-based suggestions aren't generated, they're looked up.
182
+
183
+ ---
184
+
185
+ ## 🏛️ Architecture
186
+
187
+ | | |
188
+ |---|---|
189
+ | 🔑 **Zero API keys** | Not optional, not configurable, never will be |
190
+ | 👤 **Zero accounts** | None needed, none planned |
191
+ | 🔒 **Local-first** | The semantic layer runs on your machine — prompts never leave it |
192
+ | 🧪 **TDD-built** | Every detector has a failing test before it has an implementation |
193
+ | 🧬 **Pure functions** | The pattern-matching layers have nothing to mock, because there's nothing impure to mock |
194
+ | 📘 **TypeScript strict**, Node 22, ESM only | |
195
+ | ⏱️ **Honest about cost** | Pattern-matching is near-instant. The semantic layer takes a couple of seconds and always says so first. We'd rather be transparent than pretend to be magic. |
196
+
197
+ ---
198
+
199
+ ## 🗺️ Roadmap
200
+
201
+ **V4 (planned):** Claude Code hook integration — `@promptvet/hook`. A `PreToolUse` hook that intercepts your prompt before Claude Code fires any tool, runs `scan` automatically, and blocks on critical issues. Ambient enforcement without remembering to run it manually. Separate package, separate install.
202
+
203
+ ---
204
+
205
+ ## 💡 Getting the Best Results
206
+
207
+ ### For `scan`
208
+
209
+ Use file input for long or complex prompts — especially anything with
210
+ special characters like `[`, `]`, `*`, or `@`:
211
+
212
+ ```bash
213
+ promptvet scan prompt.txt
214
+ ```
215
+
216
+ **The iteration loop:** PromptVet works best as a feedback cycle, not
217
+ a one-shot check. Scan → fix what it flags → scan again. The tool
218
+ found issues in its own Claude instruction prompt and helped refine it
219
+ to 100/100 in three iterations.
220
+
221
+ ### For `syscan`
222
+
223
+ **Best results with well-structured, standard agent prompts** — role
224
+ definition, scope, constraints, under ~300-400 words:
225
+
226
+ ```bash
227
+ # Works well
228
+ promptvet syscan customer-support-agent.txt
229
+ promptvet syscan coding-assistant.txt
230
+ promptvet syscan content-moderator.txt
231
+ ```
232
+
233
+ **Known limitation — complex editorial specifications:** very long
234
+ prompts (500+ words) with dense rule sets, custom output markers, or
235
+ deeply nested constraints may produce unreliable results. The local
236
+ 1.5B model can be overwhelmed by constraint density — the same
237
+ complexity that confuses the model also makes the prompt harder for
238
+ humans to maintain.
239
+
240
+ If `syscan` finds the same false gap on repeated runs, that's a signal
241
+ the prompt itself may be too complex — consider simplifying before
242
+ re-auditing.
243
+
244
+ **Use file input for system prompts** — system prompts routinely
245
+ contain special characters that shells interpret as glob patterns:
246
+
247
+ ```bash
248
+ promptvet syscan system-prompt.txt # always use file input for syscan
249
+ ```
250
+
251
+ ### The Full Pre-Flight Check
252
+
253
+ Run both commands together for complete coverage:
254
+
255
+ ```bash
256
+ # Check your dev-task prompt for clarity
257
+ promptvet scan "write unit tests for the auth module"
258
+
259
+ # Check your system prompt for coverage gaps
260
+ promptvet syscan system-prompt.txt
261
+ ```
262
+
263
+ `scan` catches what's unclear in a single instruction.
264
+ `syscan` catches what's missing from a production spec.
265
+
266
+ ---
267
+
268
+ ## 🤝 Contributing
269
+
270
+ Read [`CLAUDE.md`](CLAUDE.md) first — it's the real contract this project is built against: TDD rules, architecture boundaries, and what's explicitly out of scope. PRs that don't follow it won't merge.
271
+
272
+ ---
273
+
274
+ <div align="center">
275
+
276
+ **MIT Licensed** · Built prompt by prompt, bug by bug, on real projects.
277
+
278
+ </div>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,273 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { score } from '../scorer/scorer.js';
5
+ import { fixSuggestions } from '../scorer/fixSuggestions.js';
6
+ import { DEFAULT_MODEL } from '../layers/syscan/auditor.js';
7
+ const program = new Command();
8
+ program
9
+ .name('promptvet')
10
+ .description('Analyze LLM prompts before they are sent to any AI');
11
+ program
12
+ .command('scan <prompt>')
13
+ .description('Scan a prompt string or file for quality issues')
14
+ .option('--json', 'Output results as JSON')
15
+ .option('--threshold <number>', 'Pass/fail score threshold (0-100)', '60')
16
+ .action(async (input, options) => {
17
+ const jsonMode = options.json === true;
18
+ const threshold = parseInt(options.threshold, 10);
19
+ // Only treat input as a file path if it ends with a known extension.
20
+ // Single-word or no-space strings without an extension are inline prompts.
21
+ const FILE_EXTENSIONS = ['.txt', '.md'];
22
+ let rawPrompt = input;
23
+ if (FILE_EXTENSIONS.some((ext) => input.endsWith(ext))) {
24
+ if (!existsSync(input)) {
25
+ emitError('FILE_NOT_FOUND', `File not found: ${input}`, jsonMode);
26
+ process.exit(1);
27
+ }
28
+ rawPrompt = readFileSync(input, 'utf-8');
29
+ }
30
+ const result = score(rawPrompt);
31
+ if ('error' in result) {
32
+ emitError(result.code, result.message, jsonMode);
33
+ process.exit(1);
34
+ }
35
+ // Semantic layer: only when heuristics+linguistic found zero issues AND prompt is short.
36
+ // Short vague prompts (e.g. "fix all things") can score 100/100 on heuristics yet be
37
+ // meaningless — this is the gap the classifier is designed to catch.
38
+ const wordCount = rawPrompt.trim().split(/\s+/).length;
39
+ let semanticDispose = null;
40
+ if (result.issues.length === 0 && wordCount < 8) {
41
+ process.stderr.write('Running deeper analysis...\n');
42
+ const { classifyIntent, disposeClassifier } = await import('../layers/semantic/classifier.js');
43
+ semanticDispose = disposeClassifier;
44
+ const semantic = await classifyIntent(rawPrompt);
45
+ if (!semantic.isMeaningful) {
46
+ result.issues.push({
47
+ severity: 'critical',
48
+ code: 'SEMANTIC_LOW_QUALITY',
49
+ message: 'This prompt appears too vague or unclear for the model to identify a clear instruction.',
50
+ });
51
+ result.overall = Math.min(result.overall, 59);
52
+ const fix = fixSuggestions['SEMANTIC_LOW_QUALITY'];
53
+ if (fix)
54
+ result.suggestedFixes.push(fix);
55
+ }
56
+ }
57
+ const hasCritical = result.issues.some((i) => i.severity === 'critical');
58
+ const passed = result.overall >= threshold && !hasCritical;
59
+ if (jsonMode) {
60
+ write(JSON.stringify({
61
+ overall: result.overall,
62
+ dimensions: result.dimensions,
63
+ issues: result.issues,
64
+ suggestedFixes: result.suggestedFixes,
65
+ }));
66
+ }
67
+ else {
68
+ write(humanFormat(result));
69
+ }
70
+ if (semanticDispose)
71
+ await semanticDispose();
72
+ process.exit(passed ? 0 : 1);
73
+ });
74
+ program
75
+ .command('syscan <prompt>')
76
+ .description('Deep audit of a system prompt for coverage gaps')
77
+ .option('--json', 'Output results as JSON')
78
+ .option('--model <modelUri>', 'Model to use: hf: URI or local .gguf path', DEFAULT_MODEL)
79
+ .action(async (input, options) => {
80
+ const jsonMode = options.json === true;
81
+ const modelUri = options.model;
82
+ if (!modelUri.startsWith('hf:') && !modelUri.endsWith('.gguf')) {
83
+ emitError('INVALID_MODEL', 'Invalid model: must be an hf: URI (e.g. hf:bartowski/SmolLM3-3B-GGUF:Q4_K_M) or a local .gguf file path.', jsonMode);
84
+ process.exit(1);
85
+ }
86
+ const FILE_EXTENSIONS = ['.txt', '.md'];
87
+ let rawPrompt = input;
88
+ if (FILE_EXTENSIONS.some((ext) => input.endsWith(ext))) {
89
+ if (!existsSync(input)) {
90
+ emitError('FILE_NOT_FOUND', `File not found: ${input}`, jsonMode);
91
+ process.exit(1);
92
+ }
93
+ rawPrompt = readFileSync(input, 'utf-8');
94
+ }
95
+ if (!rawPrompt || rawPrompt.trim() === '') {
96
+ emitError('EMPTY_PROMPT', 'Prompt must not be empty.', jsonMode);
97
+ process.exit(1);
98
+ }
99
+ if (rawPrompt.trim().split(/\s+/).length < 3) {
100
+ emitError('PROMPT_TOO_SHORT', 'Prompt must be at least 3 words.', jsonMode);
101
+ process.exit(1);
102
+ }
103
+ const stopSpinner = startSpinner('Running deep system-prompt audit...');
104
+ const { auditSystemPrompt } = await import('../layers/syscan/auditor.js');
105
+ const result = await auditSystemPrompt(rawPrompt, modelUri);
106
+ const elapsed = stopSpinner();
107
+ if (jsonMode) {
108
+ write(JSON.stringify({ gaps: result.gaps, raw: result.raw }));
109
+ }
110
+ else {
111
+ write(syscanHumanFormat(result.gaps, elapsed));
112
+ }
113
+ process.exit(0);
114
+ });
115
+ await program.parseAsync();
116
+ // ── spinner ───────────────────────────────────────────────────────────────────
117
+ function startSpinner(message) {
118
+ const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
119
+ const CLEAR_WIDTH = message.length + 16;
120
+ let frameIdx = 0;
121
+ const startTime = Date.now();
122
+ const render = () => {
123
+ const elapsed = Math.floor((Date.now() - startTime) / 1000);
124
+ process.stderr.write(`\r${frames[frameIdx % frames.length]} ${message} ${elapsed}s`);
125
+ frameIdx++;
126
+ };
127
+ render();
128
+ const interval = setInterval(render, 100);
129
+ return () => {
130
+ clearInterval(interval);
131
+ const elapsed = Math.floor((Date.now() - startTime) / 1000);
132
+ process.stderr.write('\r' + ' '.repeat(CLEAR_WIDTH) + '\r');
133
+ return elapsed;
134
+ };
135
+ }
136
+ // ── syscan output ─────────────────────────────────────────────────────────────
137
+ function syscanHumanFormat(gaps, elapsed) {
138
+ const lines = [
139
+ `PromptVet System Audit (${elapsed}s)`,
140
+ '───────────────────────',
141
+ '',
142
+ `Gaps Found (${gaps.length}):`,
143
+ ];
144
+ if (gaps.length === 0) {
145
+ lines.push('', ' No gaps detected in this run.');
146
+ }
147
+ else {
148
+ for (let i = 0; i < gaps.length; i++) {
149
+ const gap = gaps[i];
150
+ if (!gap)
151
+ continue;
152
+ lines.push('', ` ${i + 1}. ${gap.summary}`);
153
+ if (gap.detail)
154
+ lines.push(` ${gap.detail}`);
155
+ }
156
+ }
157
+ lines.push('', 'Note: There maybe false positives. Please verify each gap before treating it as confirmed.', '');
158
+ return lines.join('\n');
159
+ }
160
+ // ── output helpers ────────────────────────────────────────────────────────────
161
+ function emitError(code, message, jsonMode) {
162
+ if (jsonMode) {
163
+ write(JSON.stringify({ error: true, code, message }));
164
+ }
165
+ else {
166
+ write(`✗ Error [${code}]: ${message}`);
167
+ }
168
+ }
169
+ function write(text) {
170
+ process.stdout.write(text + '\n');
171
+ }
172
+ function bar(n) {
173
+ const filled = Math.round(n / 10);
174
+ return '█'.repeat(filled) + '░'.repeat(10 - filled);
175
+ }
176
+ function dimIcon(n) {
177
+ if (n >= 80)
178
+ return '✓';
179
+ if (n >= 60)
180
+ return '⚠';
181
+ return '✗';
182
+ }
183
+ function score3(n) {
184
+ return String(n).padStart(3);
185
+ }
186
+ function dimLabel(dim, v) {
187
+ if (dim === 'ambiguity') {
188
+ if (v === 0)
189
+ return 'Zero ambiguity';
190
+ if (v <= 25)
191
+ return 'Very low ambiguity';
192
+ if (v <= 50)
193
+ return 'Some ambiguity';
194
+ if (v <= 75)
195
+ return 'High ambiguity';
196
+ if (v < 100)
197
+ return 'Very high ambiguity';
198
+ return 'Maximum ambiguity';
199
+ }
200
+ if (dim === 'tokenBloat') {
201
+ if (v === 0)
202
+ return 'Zero bloated tokens';
203
+ if (v <= 25)
204
+ return 'Very low token bloat';
205
+ if (v <= 50)
206
+ return 'Some token bloat';
207
+ if (v <= 75)
208
+ return 'High token bloat';
209
+ if (v < 100)
210
+ return 'Heavy token bloat';
211
+ return 'Maximum token bloat';
212
+ }
213
+ if (dim === 'clarity') {
214
+ if (v === 100)
215
+ return 'Perfect linguistic quality';
216
+ if (v >= 75)
217
+ return 'Good linguistic quality';
218
+ if (v >= 50)
219
+ return 'Moderate linguistic quality';
220
+ if (v >= 25)
221
+ return 'Low linguistic quality';
222
+ if (v > 0)
223
+ return 'Very poor linguistic quality';
224
+ return 'No linguistic quality detected';
225
+ }
226
+ // riskSignals
227
+ if (v === 0)
228
+ return 'Zero structural risk';
229
+ if (v <= 25)
230
+ return 'Very low structural risk';
231
+ if (v <= 50)
232
+ return 'Some structural risk';
233
+ if (v <= 75)
234
+ return 'High structural risk';
235
+ if (v < 100)
236
+ return 'Severe structural risk';
237
+ return 'Maximum structural risk';
238
+ }
239
+ function humanFormat(result) {
240
+ const { overall, dimensions, issues, suggestedFixes } = result;
241
+ const dispAmbiguity = 100 - dimensions.ambiguity;
242
+ const dispTokenBloat = 100 - dimensions.tokenBloat;
243
+ const dispRiskSignals = 100 - dimensions.riskSignals;
244
+ const dispClarity = dimensions.clarity;
245
+ const lines = [
246
+ 'PromptVet Analysis',
247
+ '──────────────────',
248
+ `Overall Score: ${overall}/100`,
249
+ '',
250
+ 'Dimensions:',
251
+ ` Ambiguity ${bar(dispAmbiguity)} ${score3(dispAmbiguity)}/100 ${dimIcon(dimensions.ambiguity)} (${dimLabel('ambiguity', dispAmbiguity)})`,
252
+ ` Token Bloat ${bar(dispTokenBloat)} ${score3(dispTokenBloat)}/100 ${dimIcon(dimensions.tokenBloat)} (${dimLabel('tokenBloat', dispTokenBloat)})`,
253
+ ` Linguistic Quality ${bar(dispClarity)} ${score3(dispClarity)}/100 ${dimIcon(dimensions.clarity)} (${dimLabel('clarity', dispClarity)})`,
254
+ ` Risk Signals ${bar(dispRiskSignals)} ${score3(dispRiskSignals)}/100 ${dimIcon(dimensions.riskSignals)} (${dimLabel('riskSignals', dispRiskSignals)})`,
255
+ ];
256
+ if (issues.length > 0) {
257
+ lines.push('', 'Issues Found:');
258
+ for (const issue of issues) {
259
+ const sym = issue.severity === 'critical' ? '✗' : '⚠';
260
+ const tag = issue.severity === 'critical' ? '[CRITICAL]' : '[WARNING] ';
261
+ lines.push(` ${sym} ${tag} ${issue.code}: ${issue.message}`);
262
+ }
263
+ }
264
+ if (suggestedFixes.length > 0) {
265
+ lines.push('', 'Suggested Fixes:');
266
+ for (const fix of suggestedFixes) {
267
+ lines.push(` - ${fix}`);
268
+ }
269
+ }
270
+ lines.push('');
271
+ return lines.join('\n');
272
+ }
273
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare const GENERATION_VERBS: string[];
2
+ export declare const FIX_VERBS: string[];
3
+ export declare const ACTION_VERBS: string[];
4
+ //# sourceMappingURL=actionVerbs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actionVerbs.d.ts","sourceRoot":"","sources":["../../../src/layers/heuristics/actionVerbs.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,UAG5B,CAAA;AAED,eAAO,MAAM,SAAS,UAA8D,CAAA;AAKpF,eAAO,MAAM,YAAY,UAA6D,CAAA"}
@@ -0,0 +1,9 @@
1
+ export const GENERATION_VERBS = [
2
+ 'generate', 'write', 'create', 'produce', 'summarize', 'summarise',
3
+ 'draft', 'compose', 'build', 'make', 'explain', 'describe', 'list',
4
+ ];
5
+ export const FIX_VERBS = ['fix', 'debug', 'refactor', 'resolve', 'patch', 'correct'];
6
+ // Additional action verbs not used by missingOutputFormat's fix-request exemption
7
+ const MODIFICATION_VERBS = ['add', 'update', 'remove', 'implement', 'test', 'analyze', 'analyse', 'improve', 'optimize'];
8
+ export const ACTION_VERBS = [...GENERATION_VERBS, ...FIX_VERBS, ...MODIFICATION_VERBS];
9
+ //# sourceMappingURL=actionVerbs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actionVerbs.js","sourceRoot":"","sources":["../../../src/layers/heuristics/actionVerbs.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW;IAClE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM;CACnE,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CAAA;AAEpF,kFAAkF;AAClF,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;AAExH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAG,gBAAgB,EAAE,GAAG,SAAS,EAAE,GAAG,kBAAkB,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare function browserApiRisk(prompt: string): boolean;
2
+ //# sourceMappingURL=browserApiRisk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browserApiRisk.d.ts","sourceRoot":"","sources":["../../../src/layers/heuristics/browserApiRisk.ts"],"names":[],"mappings":"AAWA,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAKtD"}
@@ -0,0 +1,18 @@
1
+ const BROWSER_API_KEYWORDS = [
2
+ 'navigator', 'window', 'document', 'localstorage', 'sessionstorage',
3
+ 'cachestorage', 'cache storage', 'storagebuckets', 'storage buckets',
4
+ 'indexeddb', 'cookies', 'cookie',
5
+ 'pushmessaging', 'push messaging', 'pushmanager',
6
+ 'reportingapi', 'reporting api', 'reportingobserver',
7
+ 'extensions', 'chrome.runtime', 'browser.runtime',
8
+ 'getusermedia', 'matchmedia', 'mediarecorder',
9
+ ];
10
+ const UNIT_TEST_PATTERN = /\bunit tests?\b/i;
11
+ export function browserApiRisk(prompt) {
12
+ if (!prompt)
13
+ return false;
14
+ const lower = prompt.toLowerCase();
15
+ const hasBrowserApi = BROWSER_API_KEYWORDS.some(api => lower.includes(api));
16
+ return hasBrowserApi && UNIT_TEST_PATTERN.test(prompt);
17
+ }
18
+ //# sourceMappingURL=browserApiRisk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browserApiRisk.js","sourceRoot":"","sources":["../../../src/layers/heuristics/browserApiRisk.ts"],"names":[],"mappings":"AAAA,MAAM,oBAAoB,GAAG;IAC3B,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB;IACnE,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB;IACpE,WAAW,EAAE,SAAS,EAAE,QAAQ;IAChC,eAAe,EAAE,gBAAgB,EAAE,aAAa;IAChD,cAAc,EAAE,eAAe,EAAE,mBAAmB;IACpD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB;IACjD,cAAc,EAAE,YAAY,EAAE,eAAe;CAC9C,CAAC;AACF,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAE7C,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,MAAM,aAAa,GAAG,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5E,OAAO,aAAa,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function frustrationSignal(prompt: string): boolean;
2
+ //# sourceMappingURL=frustrationSignal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frustrationSignal.d.ts","sourceRoot":"","sources":["../../../src/layers/heuristics/frustrationSignal.ts"],"names":[],"mappings":"AAuBA,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAKzD"}
@@ -0,0 +1,26 @@
1
+ const PROFANITY = [
2
+ /\bfuck\b/i,
3
+ /\bshit\b/i,
4
+ /\bdamn\b/i,
5
+ /\bwtf\b/i,
6
+ /\bffs\b/i,
7
+ ];
8
+ const FRUSTRATION_PHRASES = [
9
+ /this is ridiculous/i,
10
+ /i give up/i,
11
+ /nothing works/i,
12
+ /nothing is working/i,
13
+ /why isn't this working/i,
14
+ /why is this happening/i,
15
+ /why does this keep/i,
16
+ /why won't this/i,
17
+ /this makes no sense/i,
18
+ /still broken/i,
19
+ /still not working/i,
20
+ /i've tried everything/i,
21
+ ];
22
+ export function frustrationSignal(prompt) {
23
+ return (PROFANITY.some((re) => re.test(prompt)) ||
24
+ FRUSTRATION_PHRASES.some((re) => re.test(prompt)));
25
+ }
26
+ //# sourceMappingURL=frustrationSignal.js.map