@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 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("0.1.1");
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 only = opts.rules ? String(opts.rules).split(",").map((s) => s.trim()).filter(Boolean) : void 0;
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: opts.model,
60
+ model,
25
61
  only,
26
- includeLlm: Boolean(opts.llm)
62
+ includeLlm,
63
+ profileOptions: loadedConfig.config.profilesDir ? { profilesDir: loadedConfig.config.profilesDir } : void 0
27
64
  });
28
- const fmt = normalizeFormat(opts.format);
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
- const hasErrors = report.results.some((r) => !r.passed && r.severity === "error");
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 loader = new ProfileLoader();
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((resolve, reject) => {
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", () => resolve(data));
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.1.1",
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.1.1",
36
+ "@promptscore/core": "^0.2.0",
37
37
  "commander": "^12.1.0"
38
38
  },
39
39
  "devDependencies": {