@hone-ai/cli 1.8.1 → 1.9.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/hone-cli.js +87 -3
- package/package.json +1 -1
package/hone-cli.js
CHANGED
|
@@ -362,10 +362,16 @@ program
|
|
|
362
362
|
console.log('Running setup-ai-pipeline.sh v3.1...');
|
|
363
363
|
console.log('');
|
|
364
364
|
|
|
365
|
+
// Auto-detect non-TTY (CI, piped, Claude Code) and add --non-interactive
|
|
366
|
+
const isNonInteractive = opts.nonInteractive || !process.stdin.isTTY;
|
|
367
|
+
if (isNonInteractive && !opts.nonInteractive) {
|
|
368
|
+
console.log(' (non-TTY detected — running in non-interactive mode)');
|
|
369
|
+
}
|
|
370
|
+
|
|
365
371
|
const flags = [
|
|
366
372
|
`--source "${path.join(tmpDir, 'enterprise-github')}"`,
|
|
367
|
-
opts.dryRun
|
|
368
|
-
|
|
373
|
+
opts.dryRun ? '--dry-run' : '',
|
|
374
|
+
isNonInteractive ? '--non-interactive' : '',
|
|
369
375
|
].filter(Boolean).join(' ');
|
|
370
376
|
|
|
371
377
|
try {
|
|
@@ -4144,6 +4150,7 @@ program
|
|
|
4144
4150
|
.option('--contracts', 'Run contract validation between pipeline agents')
|
|
4145
4151
|
.option('--snapshot', 'Save current eval + contract results as regression baseline')
|
|
4146
4152
|
.option('--regression', 'Compare current results against saved baseline (detect drift)')
|
|
4153
|
+
.option('--judge', 'Run LLM-as-judge scenarios (requires ANTHROPIC_API_KEY, costs tokens)')
|
|
4147
4154
|
.action(async (opts) => {
|
|
4148
4155
|
const path = require('path');
|
|
4149
4156
|
const fs = require('fs');
|
|
@@ -4205,7 +4212,84 @@ program
|
|
|
4205
4212
|
process.exit(results.failed > 0 ? 1 : 0);
|
|
4206
4213
|
}
|
|
4207
4214
|
|
|
4208
|
-
//
|
|
4215
|
+
// LLM-judge mode (HC-019i / #268)
|
|
4216
|
+
if (opts.judge) {
|
|
4217
|
+
const { loadScenarios, formatResults } = require('./lib/eval-runner');
|
|
4218
|
+
const { runJudgeScenario } = require('./lib/eval-llm-judge');
|
|
4219
|
+
|
|
4220
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
4221
|
+
if (!apiKey) {
|
|
4222
|
+
console.error('ANTHROPIC_API_KEY required for --judge mode. Set: export ANTHROPIC_API_KEY=sk-ant-...');
|
|
4223
|
+
process.exit(1);
|
|
4224
|
+
}
|
|
4225
|
+
|
|
4226
|
+
const scenarios = loadScenarios({
|
|
4227
|
+
evalDir, agent: opts.agent, tag: opts.tag, scenarioId: opts.scenario,
|
|
4228
|
+
readFile: (p) => fs.readFileSync(p, 'utf8'),
|
|
4229
|
+
listDir: (p) => fs.readdirSync(p), isDir: (p) => fs.statSync(p).isDirectory(),
|
|
4230
|
+
parseYaml: (text) => yaml.load(text),
|
|
4231
|
+
});
|
|
4232
|
+
|
|
4233
|
+
const judgeScenarios = scenarios.filter(s => s.grading?.mode === 'llm-judge');
|
|
4234
|
+
if (judgeScenarios.length === 0) {
|
|
4235
|
+
console.log('No llm-judge scenarios found. Add grading.mode: llm-judge to eval YAML files.');
|
|
4236
|
+
process.exit(0);
|
|
4237
|
+
}
|
|
4238
|
+
|
|
4239
|
+
// LLM call function using Anthropic API
|
|
4240
|
+
async function callLLM(systemPrompt, userPrompt) {
|
|
4241
|
+
const { data } = await axios.post('https://api.anthropic.com/v1/messages', {
|
|
4242
|
+
model: 'claude-sonnet-4-20250514',
|
|
4243
|
+
max_tokens: 2048,
|
|
4244
|
+
system: systemPrompt,
|
|
4245
|
+
messages: [{ role: 'user', content: userPrompt }],
|
|
4246
|
+
}, {
|
|
4247
|
+
headers: {
|
|
4248
|
+
'x-api-key': apiKey,
|
|
4249
|
+
'anthropic-version': '2023-06-01',
|
|
4250
|
+
'content-type': 'application/json',
|
|
4251
|
+
},
|
|
4252
|
+
timeout: 60000,
|
|
4253
|
+
});
|
|
4254
|
+
return data.content?.[0]?.text || '';
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4257
|
+
console.log(`Running ${judgeScenarios.length} LLM-judge scenario(s)...`);
|
|
4258
|
+
console.log('');
|
|
4259
|
+
|
|
4260
|
+
const results = [];
|
|
4261
|
+
for (const scenario of judgeScenarios) {
|
|
4262
|
+
const agentName = scenario.evalAgent || scenario.agent;
|
|
4263
|
+
const promptText = AGENT_PROMPTS[agentName];
|
|
4264
|
+
if (!promptText) {
|
|
4265
|
+
results.push({ id: scenario.id, agent: agentName, result: 'error',
|
|
4266
|
+
checks: 0, checks_passed: 0, failures: [{ type: 'missing_prompt', passed: false, detail: `agent "${agentName}" not found` }] });
|
|
4267
|
+
continue;
|
|
4268
|
+
}
|
|
4269
|
+
try {
|
|
4270
|
+
const result = await runJudgeScenario({ scenario, agentPrompt: promptText, callLLM });
|
|
4271
|
+
results.push(result);
|
|
4272
|
+
} catch (e) {
|
|
4273
|
+
results.push({ id: scenario.id, agent: agentName, result: 'error',
|
|
4274
|
+
checks: 0, checks_passed: 0, failures: [{ type: 'llm_error', passed: false, detail: e.message }] });
|
|
4275
|
+
}
|
|
4276
|
+
|
|
4277
|
+
if (opts.failFast && results[results.length - 1].result !== 'pass') break;
|
|
4278
|
+
}
|
|
4279
|
+
|
|
4280
|
+
const summary = {
|
|
4281
|
+
total: results.length,
|
|
4282
|
+
passed: results.filter(r => r.result === 'pass').length,
|
|
4283
|
+
failed: results.filter(r => r.result === 'fail').length,
|
|
4284
|
+
errors: results.filter(r => r.result === 'error').length,
|
|
4285
|
+
scenarios: results,
|
|
4286
|
+
};
|
|
4287
|
+
|
|
4288
|
+
console.log(formatResults(summary, opts.format));
|
|
4289
|
+
process.exit(summary.failed + summary.errors > 0 ? 1 : 0);
|
|
4290
|
+
}
|
|
4291
|
+
|
|
4292
|
+
// Scenario evaluation mode (deterministic)
|
|
4209
4293
|
const { loadScenarios, runAllScenarios, formatResults } = require('./lib/eval-runner');
|
|
4210
4294
|
|
|
4211
4295
|
if (!fs.existsSync(evalDir)) {
|