@promptscore/cli 0.1.1 → 0.2.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/dist/index.js +93 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4,32 +4,67 @@
|
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
import { readFile } from "fs/promises";
|
|
6
6
|
import { existsSync } from "fs";
|
|
7
|
+
import { dirname, resolve } from "path";
|
|
7
8
|
import {
|
|
8
9
|
analyze,
|
|
9
10
|
createDefaultRegistry,
|
|
10
11
|
format,
|
|
12
|
+
loadPromptScoreConfig,
|
|
11
13
|
ProfileLoader
|
|
12
14
|
} from "@promptscore/core";
|
|
15
|
+
|
|
16
|
+
// src/version.ts
|
|
17
|
+
var productVersion = "0.2.0";
|
|
18
|
+
|
|
19
|
+
// src/index.ts
|
|
13
20
|
var program = new Command();
|
|
14
|
-
program.name("promptscore").description("Static analysis for LLM prompts \u2014 ESLint, but for prompts.").version(
|
|
15
|
-
program.command("analyze").description("Analyze a prompt and print a report").argument("[file]", "path to a prompt file").option("-i, --inline <prompt>", "analyze an inline prompt string").option("-m, --model <model>", "model profile name (e.g. claude, gpt)", "_base").option("-f, --format <format>", "output format: text, json, markdown", "text").option("-r, --rules <rules>", "comma-separated rule ids to include").option("--llm", "include LLM-powered rules (requires API key)", false).option("--no-color", "disable colored output").action(async (file, opts) => {
|
|
21
|
+
program.name("promptscore").description("Static analysis for LLM prompts \u2014 ESLint, but for prompts.").version(productVersion);
|
|
22
|
+
program.command("analyze").description("Analyze a prompt and print a report").argument("[file]", "path to a prompt file").option("-c, --config <path>", "path to a PromptScore config file").option("-i, --inline <prompt>", "analyze an inline prompt string").option("-m, --model <model>", "model profile name (e.g. claude, gpt)", "_base").option("-f, --format <format>", "output format: text, json, markdown", "text").option("-r, --rules <rules>", "comma-separated rule ids to include").option("--fail-on <severity>", "exit non-zero on error, warning, info, or none", "error").option("--llm", "include LLM-powered rules (requires API key)", false).option("--no-color", "disable colored output").action(async (file, opts, command) => {
|
|
16
23
|
try {
|
|
24
|
+
const loadedConfig = await loadPromptScoreConfig({
|
|
25
|
+
cwd: opts.config ? process.cwd() : resolveConfigSearchDir(file),
|
|
26
|
+
configPath: opts.config
|
|
27
|
+
});
|
|
17
28
|
const prompt = await resolvePromptInput(file, opts.inline);
|
|
18
29
|
if (!prompt) {
|
|
19
30
|
process.stderr.write("No prompt provided. Pass a file path or use --inline.\n");
|
|
20
31
|
process.exit(1);
|
|
21
32
|
}
|
|
22
|
-
const
|
|
33
|
+
const model = resolveOption(command, "model", opts.model, loadedConfig.config.model, "_base");
|
|
34
|
+
const fmt = resolveOption(command, "format", opts.format, loadedConfig.config.format, "text");
|
|
35
|
+
const includeLlm = resolveOption(
|
|
36
|
+
command,
|
|
37
|
+
"llm",
|
|
38
|
+
Boolean(opts.llm),
|
|
39
|
+
loadedConfig.config.includeLlm,
|
|
40
|
+
false
|
|
41
|
+
);
|
|
42
|
+
const color = resolveOption(
|
|
43
|
+
command,
|
|
44
|
+
"color",
|
|
45
|
+
opts.color !== false,
|
|
46
|
+
loadedConfig.config.color,
|
|
47
|
+
true
|
|
48
|
+
);
|
|
49
|
+
const failOnSeverity = parseFailOnSeverity(
|
|
50
|
+
resolveOption(
|
|
51
|
+
command,
|
|
52
|
+
"failOn",
|
|
53
|
+
String(opts.failOn),
|
|
54
|
+
loadedConfig.config.failOnSeverity,
|
|
55
|
+
"error"
|
|
56
|
+
)
|
|
57
|
+
);
|
|
58
|
+
const only = optionWasProvided(command, "rules") ? parseRulesOption(opts.rules) : loadedConfig.config.rules;
|
|
23
59
|
const report = await analyze(prompt, {
|
|
24
|
-
model
|
|
60
|
+
model,
|
|
25
61
|
only,
|
|
26
|
-
includeLlm
|
|
62
|
+
includeLlm,
|
|
63
|
+
profileOptions: loadedConfig.config.profilesDir ? { profilesDir: loadedConfig.config.profilesDir } : void 0
|
|
27
64
|
});
|
|
28
|
-
const
|
|
29
|
-
const output = format(report, fmt, { color: opts.color !== false });
|
|
65
|
+
const output = format(report, normalizeFormat(fmt), { color });
|
|
30
66
|
process.stdout.write(output + "\n");
|
|
31
|
-
|
|
32
|
-
process.exit(hasErrors ? 1 : 0);
|
|
67
|
+
process.exit(getExitCode(report, failOnSeverity));
|
|
33
68
|
} catch (err) {
|
|
34
69
|
printError(err);
|
|
35
70
|
process.exit(2);
|
|
@@ -50,9 +85,15 @@ program.command("rules").description("List all available rules").option("-f, --f
|
|
|
50
85
|
`);
|
|
51
86
|
}
|
|
52
87
|
});
|
|
53
|
-
program.command("profiles").description("List available profiles").action(async () => {
|
|
88
|
+
program.command("profiles").description("List available profiles").option("-c, --config <path>", "path to a PromptScore config file").action(async (opts) => {
|
|
54
89
|
try {
|
|
55
|
-
const
|
|
90
|
+
const loadedConfig = await loadPromptScoreConfig({
|
|
91
|
+
cwd: process.cwd(),
|
|
92
|
+
configPath: opts.config
|
|
93
|
+
});
|
|
94
|
+
const loader = new ProfileLoader(
|
|
95
|
+
loadedConfig.config.profilesDir ? { profilesDir: loadedConfig.config.profilesDir } : {}
|
|
96
|
+
);
|
|
56
97
|
const names = await loader.list();
|
|
57
98
|
for (const name of names) {
|
|
58
99
|
const profile = await loader.load(name);
|
|
@@ -78,13 +119,13 @@ async function resolvePromptInput(file, inline) {
|
|
|
78
119
|
return void 0;
|
|
79
120
|
}
|
|
80
121
|
async function readStdin() {
|
|
81
|
-
return new Promise((
|
|
122
|
+
return new Promise((resolve2, reject) => {
|
|
82
123
|
let data = "";
|
|
83
124
|
process.stdin.setEncoding("utf8");
|
|
84
125
|
process.stdin.on("data", (chunk) => {
|
|
85
126
|
data += chunk;
|
|
86
127
|
});
|
|
87
|
-
process.stdin.on("end", () =>
|
|
128
|
+
process.stdin.on("end", () => resolve2(data));
|
|
88
129
|
process.stdin.on("error", reject);
|
|
89
130
|
});
|
|
90
131
|
}
|
|
@@ -92,6 +133,45 @@ function normalizeFormat(input) {
|
|
|
92
133
|
if (input === "json" || input === "markdown" || input === "text") return input;
|
|
93
134
|
return "text";
|
|
94
135
|
}
|
|
136
|
+
function resolveOption(command, optionName, cliValue, configValue, fallback) {
|
|
137
|
+
if (optionWasProvided(command, optionName)) {
|
|
138
|
+
return cliValue;
|
|
139
|
+
}
|
|
140
|
+
return configValue ?? fallback;
|
|
141
|
+
}
|
|
142
|
+
function optionWasProvided(command, optionName) {
|
|
143
|
+
return command.getOptionValueSource(optionName) === "cli";
|
|
144
|
+
}
|
|
145
|
+
function parseRulesOption(value) {
|
|
146
|
+
if (!value) return void 0;
|
|
147
|
+
return String(value).split(",").map((s) => s.trim()).filter(Boolean);
|
|
148
|
+
}
|
|
149
|
+
function parseFailOnSeverity(value) {
|
|
150
|
+
if (value === "error" || value === "warning" || value === "info" || value === "none") {
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
throw new Error(`Invalid value for --fail-on: ${value}`);
|
|
154
|
+
}
|
|
155
|
+
function getExitCode(report, failOnSeverity) {
|
|
156
|
+
if (failOnSeverity === "none") {
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
const rank = {
|
|
160
|
+
info: 1,
|
|
161
|
+
warning: 2,
|
|
162
|
+
error: 3
|
|
163
|
+
};
|
|
164
|
+
const threshold = rank[failOnSeverity];
|
|
165
|
+
const shouldFail = report.results.some((result) => {
|
|
166
|
+
if (result.passed) return false;
|
|
167
|
+
return rank[result.severity] >= threshold;
|
|
168
|
+
});
|
|
169
|
+
return shouldFail ? 1 : 0;
|
|
170
|
+
}
|
|
171
|
+
function resolveConfigSearchDir(file) {
|
|
172
|
+
if (!file) return process.cwd();
|
|
173
|
+
return dirname(resolve(file));
|
|
174
|
+
}
|
|
95
175
|
function stripRuleCheck(rule) {
|
|
96
176
|
const { check: _check, ...rest } = rule;
|
|
97
177
|
return rest;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport {\n analyze,\n createDefaultRegistry,\n format,\n ProfileLoader,\n type ReportFormat,\n} from '@promptscore/core';\n\nconst program = new Command();\n\nprogram\n .name('promptscore')\n .description('Static analysis for LLM prompts — ESLint, but for prompts.')\n .version('0.1.1');\n\nprogram\n .command('analyze')\n .description('Analyze a prompt and print a report')\n .argument('[file]', 'path to a prompt file')\n .option('-i, --inline <prompt>', 'analyze an inline prompt string')\n .option('-m, --model <model>', 'model profile name (e.g. claude, gpt)', '_base')\n .option('-f, --format <format>', 'output format: text, json, markdown', 'text')\n .option('-r, --rules <rules>', 'comma-separated rule ids to include')\n .option('--llm', 'include LLM-powered rules (requires API key)', false)\n .option('--no-color', 'disable colored output')\n .action(async (file: string | undefined, opts) => {\n try {\n const prompt = await resolvePromptInput(file, opts.inline);\n if (!prompt) {\n process.stderr.write('No prompt provided. Pass a file path or use --inline.\\n');\n process.exit(1);\n }\n\n const only = opts.rules\n ? String(opts.rules)\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n : undefined;\n\n const report = await analyze(prompt, {\n model: opts.model,\n only,\n includeLlm: Boolean(opts.llm),\n });\n\n const fmt = normalizeFormat(opts.format);\n const output = format(report, fmt, { color: opts.color !== false });\n process.stdout.write(output + '\\n');\n\n const hasErrors = report.results.some((r) => !r.passed && r.severity === 'error');\n process.exit(hasErrors ? 1 : 0);\n } catch (err) {\n printError(err);\n process.exit(2);\n }\n });\n\nprogram\n .command('rules')\n .description('List all available rules')\n .option('-f, --format <format>', 'output format: text, json', 'text')\n .action((opts) => {\n const registry = createDefaultRegistry();\n const rules = registry.all();\n if (opts.format === 'json') {\n process.stdout.write(JSON.stringify(rules.map(stripRuleCheck), null, 2) + '\\n');\n return;\n }\n for (const rule of rules) {\n process.stdout.write(`${rule.id} [${rule.category}, ${rule.defaultSeverity}]\\n`);\n process.stdout.write(` ${rule.description}\\n\\n`);\n }\n });\n\nprogram\n .command('profiles')\n .description('List available profiles')\n .action(async () => {\n try {\n const loader = new ProfileLoader();\n const names = await loader.list();\n for (const name of names) {\n const profile = await loader.load(name);\n process.stdout.write(`${profile.name} ${profile.displayName}\\n`);\n }\n } catch (err) {\n printError(err);\n process.exit(2);\n }\n });\n\nasync function resolvePromptInput(\n file: string | undefined,\n inline: string | undefined,\n): Promise<string | undefined> {\n if (inline) return inline;\n if (file) {\n if (!existsSync(file)) {\n throw new Error(`File not found: ${file}`);\n }\n return readFile(file, 'utf8');\n }\n // Try reading from stdin if piped\n if (!process.stdin.isTTY) {\n return readStdin();\n }\n return undefined;\n}\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', (chunk) => {\n data += chunk;\n });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\nfunction normalizeFormat(input: string): ReportFormat {\n if (input === 'json' || input === 'markdown' || input === 'text') return input;\n return 'text';\n}\n\nfunction stripRuleCheck<T extends { check: unknown }>(rule: T): Omit<T, 'check'> {\n const { check: _check, ...rest } = rule;\n return rest;\n}\n\nfunction printError(err: unknown): void {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`error: ${msg}\\n`);\n}\n\nprogram.parseAsync(process.argv).catch((err) => {\n printError(err);\n process.exit(2);\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/version.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport {\n analyze,\n createDefaultRegistry,\n format,\n loadPromptScoreConfig,\n ProfileLoader,\n type FailOnSeverity,\n type ReportFormat,\n} from '@promptscore/core';\nimport { productVersion } from './version.js';\n\nconst program = new Command();\n\nprogram\n .name('promptscore')\n .description('Static analysis for LLM prompts — ESLint, but for prompts.')\n .version(productVersion);\n\nprogram\n .command('analyze')\n .description('Analyze a prompt and print a report')\n .argument('[file]', 'path to a prompt file')\n .option('-c, --config <path>', 'path to a PromptScore config file')\n .option('-i, --inline <prompt>', 'analyze an inline prompt string')\n .option('-m, --model <model>', 'model profile name (e.g. claude, gpt)', '_base')\n .option('-f, --format <format>', 'output format: text, json, markdown', 'text')\n .option('-r, --rules <rules>', 'comma-separated rule ids to include')\n .option('--fail-on <severity>', 'exit non-zero on error, warning, info, or none', 'error')\n .option('--llm', 'include LLM-powered rules (requires API key)', false)\n .option('--no-color', 'disable colored output')\n .action(async (file: string | undefined, opts, command: Command) => {\n try {\n const loadedConfig = await loadPromptScoreConfig({\n cwd: opts.config ? process.cwd() : resolveConfigSearchDir(file),\n configPath: opts.config,\n });\n const prompt = await resolvePromptInput(file, opts.inline);\n if (!prompt) {\n process.stderr.write('No prompt provided. Pass a file path or use --inline.\\n');\n process.exit(1);\n }\n\n const model = resolveOption(command, 'model', opts.model, loadedConfig.config.model, '_base');\n const fmt = resolveOption(command, 'format', opts.format, loadedConfig.config.format, 'text');\n const includeLlm = resolveOption(\n command,\n 'llm',\n Boolean(opts.llm),\n loadedConfig.config.includeLlm,\n false,\n );\n const color = resolveOption(\n command,\n 'color',\n opts.color !== false,\n loadedConfig.config.color,\n true,\n );\n const failOnSeverity = parseFailOnSeverity(\n resolveOption(\n command,\n 'failOn',\n String(opts.failOn),\n loadedConfig.config.failOnSeverity,\n 'error',\n ),\n );\n const only = optionWasProvided(command, 'rules')\n ? parseRulesOption(opts.rules)\n : loadedConfig.config.rules;\n\n const report = await analyze(prompt, {\n model,\n only,\n includeLlm,\n profileOptions: loadedConfig.config.profilesDir\n ? { profilesDir: loadedConfig.config.profilesDir }\n : undefined,\n });\n\n const output = format(report, normalizeFormat(fmt), { color });\n process.stdout.write(output + '\\n');\n\n process.exit(getExitCode(report, failOnSeverity));\n } catch (err) {\n printError(err);\n process.exit(2);\n }\n });\n\nprogram\n .command('rules')\n .description('List all available rules')\n .option('-f, --format <format>', 'output format: text, json', 'text')\n .action((opts) => {\n const registry = createDefaultRegistry();\n const rules = registry.all();\n if (opts.format === 'json') {\n process.stdout.write(JSON.stringify(rules.map(stripRuleCheck), null, 2) + '\\n');\n return;\n }\n for (const rule of rules) {\n process.stdout.write(`${rule.id} [${rule.category}, ${rule.defaultSeverity}]\\n`);\n process.stdout.write(` ${rule.description}\\n\\n`);\n }\n });\n\nprogram\n .command('profiles')\n .description('List available profiles')\n .option('-c, --config <path>', 'path to a PromptScore config file')\n .action(async (opts) => {\n try {\n const loadedConfig = await loadPromptScoreConfig({\n cwd: process.cwd(),\n configPath: opts.config,\n });\n const loader = new ProfileLoader(\n loadedConfig.config.profilesDir ? { profilesDir: loadedConfig.config.profilesDir } : {},\n );\n const names = await loader.list();\n for (const name of names) {\n const profile = await loader.load(name);\n process.stdout.write(`${profile.name} ${profile.displayName}\\n`);\n }\n } catch (err) {\n printError(err);\n process.exit(2);\n }\n });\n\nasync function resolvePromptInput(\n file: string | undefined,\n inline: string | undefined,\n): Promise<string | undefined> {\n if (inline) return inline;\n if (file) {\n if (!existsSync(file)) {\n throw new Error(`File not found: ${file}`);\n }\n return readFile(file, 'utf8');\n }\n // Try reading from stdin if piped\n if (!process.stdin.isTTY) {\n return readStdin();\n }\n return undefined;\n}\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', (chunk) => {\n data += chunk;\n });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\nfunction normalizeFormat(input: string): ReportFormat {\n if (input === 'json' || input === 'markdown' || input === 'text') return input;\n return 'text';\n}\n\nfunction resolveOption<T>(\n command: Command,\n optionName: string,\n cliValue: T,\n configValue: T | undefined,\n fallback: T,\n): T {\n if (optionWasProvided(command, optionName)) {\n return cliValue;\n }\n return configValue ?? fallback;\n}\n\nfunction optionWasProvided(command: Command, optionName: string): boolean {\n return command.getOptionValueSource(optionName) === 'cli';\n}\n\nfunction parseRulesOption(value: string | undefined): string[] | undefined {\n if (!value) return undefined;\n return String(value)\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n}\n\nfunction parseFailOnSeverity(value: string): FailOnSeverity {\n if (value === 'error' || value === 'warning' || value === 'info' || value === 'none') {\n return value;\n }\n throw new Error(`Invalid value for --fail-on: ${value}`);\n}\n\nfunction getExitCode(\n report: Awaited<ReturnType<typeof analyze>>,\n failOnSeverity: FailOnSeverity,\n): number {\n if (failOnSeverity === 'none') {\n return 0;\n }\n\n const rank: Record<Exclude<FailOnSeverity, 'none'>, number> = {\n info: 1,\n warning: 2,\n error: 3,\n };\n const threshold = rank[failOnSeverity];\n\n const shouldFail = report.results.some((result) => {\n if (result.passed) return false;\n return rank[result.severity] >= threshold;\n });\n\n return shouldFail ? 1 : 0;\n}\n\nfunction resolveConfigSearchDir(file: string | undefined): string {\n if (!file) return process.cwd();\n return dirname(resolve(file));\n}\n\nfunction stripRuleCheck<T extends { check: unknown }>(rule: T): Omit<T, 'check'> {\n const { check: _check, ...rest } = rule;\n return rest;\n}\n\nfunction printError(err: unknown): void {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`error: ${msg}\\n`);\n}\n\nprogram.parseAsync(process.argv).catch((err) => {\n printError(err);\n process.exit(2);\n});\n","// This file is generated by scripts/sync-release-version.mjs.\n// Do not edit by hand.\n\nexport const productVersion = '0.2.0';\nexport const productVersionLabel = 'v0.2.0';\n"],"mappings":"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","names":["resolve"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@promptscore/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CLI for PromptScore — static analysis for LLM prompts.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Riccardo Merenda",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"clean": "rimraf dist .turbo"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@promptscore/core": "^0.
|
|
36
|
+
"@promptscore/core": "^0.2.0",
|
|
37
37
|
"commander": "^12.1.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|