@holdyourvoice/hyv 3.3.5 → 3.4.1
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/Readme.md +66 -116
- package/dist/agents/catalog.js +118 -0
- package/dist/agents/catalog.test.js +60 -0
- package/dist/agents/emit.js +42 -0
- package/dist/agents/emit.test.js +64 -0
- package/dist/agents/index.js +4 -0
- package/dist/agents/load.js +184 -0
- package/dist/agents/load.test.js +149 -0
- package/dist/agents/types.js +18 -0
- package/dist/cli.js +464 -317
- package/dist/cli.test.js +76 -0
- package/dist/fact-linter.js +107 -98
- package/dist/mcp.js +43 -192
- package/dist/rebuild-task.test.js +1 -1
- package/dist/release-audit.test.js +5 -1
- package/dist/stage1-evaluation.js +74 -48
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/skills/hyv-analyze/SKILL.md +24 -0
- package/skills/hyv-analyze/agent.json +49 -0
- package/skills/hyv-analyze/agents/openai.yaml +4 -0
- package/skills/hyv-apply-hidden-text-policy/SKILL.md +24 -0
- package/skills/hyv-apply-hidden-text-policy/agent.json +49 -0
- package/skills/hyv-apply-hidden-text-policy/agents/openai.yaml +4 -0
- package/skills/hyv-apply-rebuild/SKILL.md +24 -0
- package/skills/hyv-apply-rebuild/agent.json +49 -0
- package/skills/hyv-apply-rebuild/agents/openai.yaml +4 -0
- package/skills/hyv-apply-rewrite/SKILL.md +24 -0
- package/skills/hyv-apply-rewrite/agent.json +48 -0
- package/skills/hyv-apply-rewrite/agents/openai.yaml +4 -0
- package/skills/hyv-batch-analyze/SKILL.md +24 -0
- package/skills/hyv-batch-analyze/agent.json +45 -0
- package/skills/hyv-batch-analyze/agents/openai.yaml +4 -0
- package/skills/hyv-fact-lint/SKILL.md +24 -0
- package/skills/hyv-fact-lint/agent.json +50 -0
- package/skills/hyv-fact-lint/agents/openai.yaml +4 -0
- package/skills/hyv-final-check/SKILL.md +24 -0
- package/skills/hyv-final-check/agent.json +43 -0
- package/skills/hyv-final-check/agents/openai.yaml +4 -0
- package/skills/hyv-hygiene/SKILL.md +24 -0
- package/skills/hyv-hygiene/agent.json +50 -0
- package/skills/hyv-hygiene/agents/openai.yaml +4 -0
- package/skills/hyv-inspect-hidden-text/SKILL.md +24 -0
- package/skills/hyv-inspect-hidden-text/agent.json +48 -0
- package/skills/hyv-inspect-hidden-text/agents/openai.yaml +4 -0
- package/skills/hyv-learning/SKILL.md +24 -0
- package/skills/hyv-learning/agent.json +48 -0
- package/skills/hyv-learning/agents/openai.yaml +4 -0
- package/skills/hyv-lifecycle/SKILL.md +24 -0
- package/skills/hyv-lifecycle/agent.json +48 -0
- package/skills/hyv-lifecycle/agents/openai.yaml +4 -0
- package/skills/hyv-logic-lint/SKILL.md +24 -0
- package/skills/hyv-logic-lint/agent.json +47 -0
- package/skills/hyv-logic-lint/agents/openai.yaml +4 -0
- package/skills/hyv-mcp/SKILL.md +24 -0
- package/skills/hyv-mcp/agent.json +43 -0
- package/skills/hyv-mcp/agents/openai.yaml +4 -0
- package/skills/hyv-patterns/SKILL.md +24 -0
- package/skills/hyv-patterns/agent.json +43 -0
- package/skills/hyv-patterns/agents/openai.yaml +4 -0
- package/skills/hyv-prepare-judgment/SKILL.md +24 -0
- package/skills/hyv-prepare-judgment/agent.json +52 -0
- package/skills/hyv-prepare-judgment/agents/openai.yaml +4 -0
- package/skills/hyv-prepare-rebuild/SKILL.md +24 -0
- package/skills/hyv-prepare-rebuild/agent.json +54 -0
- package/skills/hyv-prepare-rebuild/agents/openai.yaml +4 -0
- package/skills/hyv-prepare-rewrite/SKILL.md +24 -0
- package/skills/hyv-prepare-rewrite/agent.json +51 -0
- package/skills/hyv-prepare-rewrite/agents/openai.yaml +4 -0
- package/skills/hyv-profile/SKILL.md +24 -0
- package/skills/hyv-profile/agent.json +50 -0
- package/skills/hyv-profile/agents/openai.yaml +4 -0
- package/skills/hyv-rebuild-writer-request/SKILL.md +24 -0
- package/skills/hyv-rebuild-writer-request/agent.json +47 -0
- package/skills/hyv-rebuild-writer-request/agents/openai.yaml +4 -0
- package/skills/hyv-reduce-judgment/SKILL.md +24 -0
- package/skills/hyv-reduce-judgment/agent.json +45 -0
- package/skills/hyv-reduce-judgment/agents/openai.yaml +4 -0
- package/skills/hyv-rewrite-prompt/SKILL.md +24 -0
- package/skills/hyv-rewrite-prompt/agent.json +48 -0
- package/skills/hyv-rewrite-prompt/agents/openai.yaml +4 -0
- package/skills/hyv-verify/SKILL.md +24 -0
- package/skills/hyv-verify/agent.json +49 -0
- package/skills/hyv-verify/agents/openai.yaml +4 -0
- package/skills/hyv-verify-spec/SKILL.md +24 -0
- package/skills/hyv-verify-spec/agent.json +50 -0
- package/skills/hyv-verify-spec/agents/openai.yaml +4 -0
package/dist/cli.js
CHANGED
|
@@ -19,7 +19,8 @@ import { buildProfile } from './voice-dna.js';
|
|
|
19
19
|
import { loadApprovalContext } from './approval-context.js';
|
|
20
20
|
import { formatFactLintReport, lintFacts } from './fact-linter.js';
|
|
21
21
|
import { lintLogic } from './logic-linter.js';
|
|
22
|
-
|
|
22
|
+
import { loadAll, validateAll, validateId, sortedIds, describe, emitJson, emitPrompt } from './agents/index.js';
|
|
23
|
+
const usage = 'Commands: agent, profile, analyze, hygiene, inspect-hidden-text, apply-hidden-text-policy, final-check, fact-lint, logic-lint, batch-analyze, rewrite-prompt, prepare-rewrite, apply-rewrite, prepare-judgment, reduce-judgment, prepare-rebuild, rebuild-writer-request, apply-rebuild, verify, verify-spec, lifecycle, learning, patterns, mcp';
|
|
23
24
|
function input(path) {
|
|
24
25
|
return path === '-' ? readFileSync(0, 'utf8') : readFileSync(path, 'utf8');
|
|
25
26
|
}
|
|
@@ -198,6 +199,9 @@ function json(value) {
|
|
|
198
199
|
console.log(JSON.stringify(value, null, 2));
|
|
199
200
|
}
|
|
200
201
|
function canonical(value) { process.stdout.write(`${canonicalJson(value)}\n`); }
|
|
202
|
+
function writeJson(path, value) {
|
|
203
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
204
|
+
}
|
|
201
205
|
function profileArguments(args) {
|
|
202
206
|
const [output, ...rest] = args;
|
|
203
207
|
const samples = [];
|
|
@@ -269,348 +273,491 @@ function writeNewFileAtomically(path, text) {
|
|
|
269
273
|
if (primaryError)
|
|
270
274
|
throw primaryError;
|
|
271
275
|
}
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
276
|
+
function agentFlags(args) {
|
|
277
|
+
const values = [];
|
|
278
|
+
let host = 'generic';
|
|
279
|
+
let mode;
|
|
280
|
+
let output;
|
|
281
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
282
|
+
const argument = args[index];
|
|
283
|
+
if (argument === '--host') {
|
|
284
|
+
const value = args[index + 1];
|
|
285
|
+
if (!value || value.startsWith('--'))
|
|
286
|
+
throw new Error('Usage: hyv agent --host HOST requires a value.');
|
|
287
|
+
host = value;
|
|
288
|
+
index += 1;
|
|
289
|
+
}
|
|
290
|
+
else if (argument.startsWith('--host=')) {
|
|
291
|
+
const value = argument.slice('--host='.length);
|
|
292
|
+
if (!value)
|
|
293
|
+
throw new Error('Usage: hyv agent --host HOST requires a value.');
|
|
294
|
+
host = value;
|
|
295
|
+
}
|
|
296
|
+
else if (argument === '--mode') {
|
|
297
|
+
const value = args[index + 1];
|
|
298
|
+
if (value !== 'prompt' && value !== 'json')
|
|
299
|
+
throw new Error('Usage: hyv agent --mode prompt|json requires a mode.');
|
|
300
|
+
mode = value;
|
|
301
|
+
index += 1;
|
|
302
|
+
}
|
|
303
|
+
else if (argument.startsWith('--mode=')) {
|
|
304
|
+
const value = argument.slice('--mode='.length);
|
|
305
|
+
if (value !== 'prompt' && value !== 'json')
|
|
306
|
+
throw new Error('Usage: hyv agent --mode prompt|json requires a mode.');
|
|
307
|
+
mode = value;
|
|
308
|
+
}
|
|
309
|
+
else if (argument === '--output') {
|
|
310
|
+
const value = args[index + 1];
|
|
311
|
+
if (!value || value.startsWith('--'))
|
|
312
|
+
throw new Error('Usage: hyv agent --output FILE requires a value.');
|
|
313
|
+
output = value;
|
|
314
|
+
index += 1;
|
|
315
|
+
}
|
|
316
|
+
else if (argument.startsWith('--output=')) {
|
|
317
|
+
const value = argument.slice('--output='.length);
|
|
318
|
+
if (!value)
|
|
319
|
+
throw new Error('Usage: hyv agent --output FILE requires a value.');
|
|
320
|
+
output = value;
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
values.push(argument);
|
|
294
324
|
}
|
|
295
|
-
const outputPath = output ?? cleanedPath(path);
|
|
296
|
-
if (resolve(outputPath) === resolve(path))
|
|
297
|
-
throw new Error('Hygiene output must differ from the input path.');
|
|
298
|
-
const result = cleanHygiene(text);
|
|
299
|
-
writeNewFileAtomically(outputPath, result.cleaned);
|
|
300
|
-
json({ ...result.report, changed: result.changed, changes: result.changes, outputPath });
|
|
301
|
-
return 0;
|
|
302
325
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
326
|
+
return { values, host, mode, output };
|
|
327
|
+
}
|
|
328
|
+
function runAgent(args) {
|
|
329
|
+
const [subcommand, ...subargs] = args;
|
|
330
|
+
if (subcommand === 'list') {
|
|
331
|
+
if (subargs.length)
|
|
332
|
+
throw new Error('Usage: hyv agent list');
|
|
333
|
+
const packages = loadAll();
|
|
334
|
+
const ids = sortedIds(packages);
|
|
335
|
+
json(ids.map((id) => {
|
|
336
|
+
const descriptor = packages.get(id).descriptor;
|
|
337
|
+
return { id, role: descriptor.role, workflow_phase: descriptor.workflow_phase, description: descriptor.description };
|
|
338
|
+
}));
|
|
308
339
|
return 0;
|
|
309
340
|
}
|
|
310
|
-
if (
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
json({
|
|
341
|
+
if (subcommand === 'validate') {
|
|
342
|
+
if (subargs.length > 1)
|
|
343
|
+
throw new Error('Usage: hyv agent validate [id]');
|
|
344
|
+
const packages = loadAll();
|
|
345
|
+
const id = subargs[0];
|
|
346
|
+
if (id !== undefined)
|
|
347
|
+
validateId(packages, id);
|
|
348
|
+
validateAll(packages);
|
|
349
|
+
json({ schema_version: '1.0.0', status: 'PASS', agent: id ?? 'all' });
|
|
319
350
|
return 0;
|
|
320
351
|
}
|
|
321
|
-
if (
|
|
322
|
-
const
|
|
323
|
-
if (
|
|
324
|
-
throw new Error('Usage: hyv
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
return 2;
|
|
329
|
-
}
|
|
330
|
-
if (result.changed)
|
|
331
|
-
console.error(JSON.stringify({ changed: true, changes: result.changes }, null, 2));
|
|
332
|
-
process.stdout.write(result.output);
|
|
352
|
+
if (subcommand === 'describe') {
|
|
353
|
+
const { values, host, mode, output } = agentFlags(subargs);
|
|
354
|
+
if (values.length !== 1 || mode !== undefined || output !== undefined)
|
|
355
|
+
throw new Error('Usage: hyv agent describe <id> [--host HOST]');
|
|
356
|
+
const packages = loadAll();
|
|
357
|
+
validateId(packages, values[0]);
|
|
358
|
+
json(describe(packages.get(values[0]), host));
|
|
333
359
|
return 0;
|
|
334
360
|
}
|
|
335
|
-
if (
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
continue;
|
|
351
|
-
}
|
|
352
|
-
if (option.startsWith('--source=')) {
|
|
353
|
-
const value = option.slice('--source='.length);
|
|
354
|
-
const separator = value.indexOf(':');
|
|
355
|
-
const id = value.slice(0, separator).trim();
|
|
356
|
-
const path = value.slice(separator + 1);
|
|
357
|
-
if (separator < 1 || !id || !path)
|
|
358
|
-
throw new Error('Sources must use --source=id:path.');
|
|
359
|
-
sources.push({ id, text: input(path) });
|
|
360
|
-
continue;
|
|
361
|
-
}
|
|
362
|
-
if (option.startsWith('--metadata=')) {
|
|
363
|
-
metadata = JSON.parse(input(option.slice('--metadata='.length)));
|
|
364
|
-
continue;
|
|
365
|
-
}
|
|
366
|
-
throw new Error('Usage: hyv fact-lint <draft|-> --source=id:path [--source=id:path] [--metadata=metadata.json] [--strict] [--human]');
|
|
361
|
+
if (subcommand === 'emit') {
|
|
362
|
+
const { values, host, mode, output } = agentFlags(subargs);
|
|
363
|
+
if (values.length !== 1)
|
|
364
|
+
throw new Error('Usage: hyv agent emit <id> --mode prompt|json [--host HOST] [--output FILE]');
|
|
365
|
+
if (!mode)
|
|
366
|
+
throw new Error('Usage: hyv agent emit <id> --mode prompt|json [--host HOST] [--output FILE]');
|
|
367
|
+
const packages = loadAll();
|
|
368
|
+
validateId(packages, values[0]);
|
|
369
|
+
const pkg = packages.get(values[0]);
|
|
370
|
+
const body = mode === 'prompt' ? emitPrompt(pkg, host) : `${emitJson(pkg, host)}\n`;
|
|
371
|
+
if (output !== undefined) {
|
|
372
|
+
writeFileSync(output, body, { encoding: 'utf8', flag: 'wx' });
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
process.stdout.write(body);
|
|
367
376
|
}
|
|
368
|
-
const report = lintFacts({ sources, draft: input(draftPath), metadata });
|
|
369
|
-
if (human)
|
|
370
|
-
console.log(formatFactLintReport(report));
|
|
371
|
-
else
|
|
372
|
-
json(report);
|
|
373
|
-
return strict && report.findings.some((item) => item.severity === 'error') ? 2 : 0;
|
|
374
|
-
}
|
|
375
|
-
if (command === 'logic-lint') {
|
|
376
|
-
const [draftPath, briefPath, ...extra] = rest;
|
|
377
|
-
if (!draftPath || extra.length)
|
|
378
|
-
throw new Error('Usage: hyv logic-lint <draft|-> [writing-brief.json]');
|
|
379
|
-
const report = lintLogic(input(draftPath), readBrief(briefPath));
|
|
380
|
-
json(report);
|
|
381
|
-
return report.passed ? 0 : 2;
|
|
382
|
-
}
|
|
383
|
-
if (command === 'batch-analyze') {
|
|
384
|
-
if (rest.length < 2)
|
|
385
|
-
throw new Error('Usage: hyv batch-analyze draft-a.md draft-b.md [draft-c.md]');
|
|
386
|
-
json(analyzeBatch(rest.map(input)));
|
|
387
377
|
return 0;
|
|
388
378
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
379
|
+
throw new Error('Usage: hyv agent <list|validate|describe|emit> ...');
|
|
380
|
+
}
|
|
381
|
+
function runProfile(args) {
|
|
382
|
+
const { output, samples, avoid } = profileArguments(args);
|
|
383
|
+
writeJson(output, buildProfile(samples.map(input), avoid));
|
|
384
|
+
return 0;
|
|
385
|
+
}
|
|
386
|
+
function runAnalyze(args) {
|
|
387
|
+
const [draft, profilePath, briefPath] = args;
|
|
388
|
+
if (!draft || !profilePath)
|
|
389
|
+
throw new Error('Usage: hyv analyze draft.md profile.json [writing-brief.json]');
|
|
390
|
+
json(analyze(input(draft), readProfile(profilePath), readBrief(briefPath)));
|
|
391
|
+
return 0;
|
|
392
|
+
}
|
|
393
|
+
function runHygiene(args) {
|
|
394
|
+
const { path, fix, output } = hygieneArguments(args);
|
|
395
|
+
if (fix && path === '-')
|
|
396
|
+
throw new Error('hyv hygiene --fix requires a file path so the original can be preserved.');
|
|
397
|
+
const text = input(path);
|
|
398
|
+
if (!fix) {
|
|
399
|
+
json(inspectHygiene(text));
|
|
395
400
|
return 0;
|
|
396
401
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
402
|
+
const outputPath = output ?? cleanedPath(path);
|
|
403
|
+
if (resolve(outputPath) === resolve(path))
|
|
404
|
+
throw new Error('Hygiene output must differ from the input path.');
|
|
405
|
+
const result = cleanHygiene(text);
|
|
406
|
+
writeNewFileAtomically(outputPath, result.cleaned);
|
|
407
|
+
json({ ...result.report, changed: result.changed, changes: result.changes, outputPath });
|
|
408
|
+
return 0;
|
|
409
|
+
}
|
|
410
|
+
function runInspectHiddenText(args) {
|
|
411
|
+
const [path, policyPath, ...extra] = args;
|
|
412
|
+
if (!path || extra.length)
|
|
413
|
+
throw new Error('Usage: hyv inspect-hidden-text draft.md [policy.json]');
|
|
414
|
+
json(inspectHiddenText(input(path), policyPath ? parseHiddenTextPolicy(readJson(policyPath)) : undefined));
|
|
415
|
+
return 0;
|
|
416
|
+
}
|
|
417
|
+
function runApplyHiddenTextPolicy(args) {
|
|
418
|
+
const [path, policyPath, output, ...extra] = args;
|
|
419
|
+
if (!path || !policyPath || !output || extra.length)
|
|
420
|
+
throw new Error('Usage: hyv apply-hidden-text-policy draft.md policy.json output.md');
|
|
421
|
+
if (path === '-' || resolve(path) === resolve(output))
|
|
422
|
+
throw new Error('Hidden-text output must differ from the input path.');
|
|
423
|
+
const result = applyHiddenTextPolicy(input(path), parseHiddenTextPolicy(readJson(policyPath)));
|
|
424
|
+
writeNewFileAtomically(output, result.output);
|
|
425
|
+
json({ ...result, outputPath: output });
|
|
426
|
+
return 0;
|
|
427
|
+
}
|
|
428
|
+
function runFinalCheck(args) {
|
|
429
|
+
const [path, ...options] = args;
|
|
430
|
+
if (!path || options.length)
|
|
431
|
+
throw new Error('Usage: hyv final-check <path|->');
|
|
432
|
+
const result = finalOutputCheck(input(path));
|
|
433
|
+
if (!result.accepted) {
|
|
434
|
+
console.error(JSON.stringify(result, null, 2));
|
|
435
|
+
return 2;
|
|
436
|
+
}
|
|
437
|
+
if (result.changed)
|
|
438
|
+
console.error(JSON.stringify({ changed: true, changes: result.changes }, null, 2));
|
|
439
|
+
process.stdout.write(result.output);
|
|
440
|
+
return 0;
|
|
441
|
+
}
|
|
442
|
+
function runFactLint(args) {
|
|
443
|
+
const [draftPath, ...options] = args;
|
|
444
|
+
const sources = [];
|
|
445
|
+
let metadata;
|
|
446
|
+
let strict = false;
|
|
447
|
+
let human = false;
|
|
448
|
+
if (!draftPath)
|
|
449
|
+
throw new Error('Usage: hyv fact-lint <draft|-> --source=id:path [--source=id:path] [--metadata=metadata.json] [--strict] [--human]');
|
|
450
|
+
for (const option of options) {
|
|
451
|
+
if (option === '--strict') {
|
|
452
|
+
strict = true;
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
if (option === '--human') {
|
|
456
|
+
human = true;
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
if (option.startsWith('--source=')) {
|
|
460
|
+
const value = option.slice('--source='.length);
|
|
461
|
+
const separator = value.indexOf(':');
|
|
462
|
+
const id = value.slice(0, separator).trim();
|
|
463
|
+
const path = value.slice(separator + 1);
|
|
464
|
+
if (separator < 1 || !id || !path)
|
|
465
|
+
throw new Error('Sources must use --source=id:path.');
|
|
466
|
+
sources.push({ id, text: input(path) });
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
if (option.startsWith('--metadata=')) {
|
|
470
|
+
metadata = JSON.parse(input(option.slice('--metadata='.length)));
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
throw new Error('Usage: hyv fact-lint <draft|-> --source=id:path [--source=id:path] [--metadata=metadata.json] [--strict] [--human]');
|
|
406
474
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
475
|
+
const report = lintFacts({ sources, draft: input(draftPath), metadata });
|
|
476
|
+
if (human)
|
|
477
|
+
console.log(formatFactLintReport(report));
|
|
478
|
+
else
|
|
479
|
+
json(report);
|
|
480
|
+
return strict && report.findings.some((item) => item.severity === 'error') ? 2 : 0;
|
|
481
|
+
}
|
|
482
|
+
function runLogicLint(args) {
|
|
483
|
+
const [draftPath, briefPath, ...extra] = args;
|
|
484
|
+
if (!draftPath || extra.length)
|
|
485
|
+
throw new Error('Usage: hyv logic-lint <draft|-> [writing-brief.json]');
|
|
486
|
+
const report = lintLogic(input(draftPath), readBrief(briefPath));
|
|
487
|
+
json(report);
|
|
488
|
+
return report.passed ? 0 : 2;
|
|
489
|
+
}
|
|
490
|
+
function runBatchAnalyze(args) {
|
|
491
|
+
if (args.length < 2)
|
|
492
|
+
throw new Error('Usage: hyv batch-analyze draft-a.md draft-b.md [draft-c.md]');
|
|
493
|
+
json(analyzeBatch(args.map(input)));
|
|
494
|
+
return 0;
|
|
495
|
+
}
|
|
496
|
+
function runRewritePrompt(args) {
|
|
497
|
+
const [draft, profilePath, briefPath] = args;
|
|
498
|
+
if (!draft || !profilePath)
|
|
499
|
+
throw new Error('Usage: hyv rewrite-prompt draft.md profile.json [writing-brief.json]');
|
|
500
|
+
const profile = readProfile(profilePath);
|
|
501
|
+
console.log(rewritePrompt(input(draft), profile, composeLearning(profile), readBrief(briefPath)));
|
|
502
|
+
return 0;
|
|
503
|
+
}
|
|
504
|
+
function runPrepareRewrite(args) {
|
|
505
|
+
const [draft, profilePath, output, ...contextPaths] = args;
|
|
506
|
+
if (!draft || !profilePath || !output)
|
|
507
|
+
throw new Error('Usage: hyv prepare-rewrite draft.md profile.json task.json [copy-spec.json] [writing-brief.json]');
|
|
508
|
+
const context = prepareContext(contextPaths);
|
|
509
|
+
const task = prepareRewriteTask(input(draft), readProfile(profilePath), context.copySpec, context.writingBrief);
|
|
510
|
+
writeJson(output, task);
|
|
511
|
+
json({ version: task.version, fingerprint: task.fingerprint, eligibleSentenceIds: task.eligibleSentenceIds });
|
|
512
|
+
return 0;
|
|
513
|
+
}
|
|
514
|
+
function runApplyRewrite(args) {
|
|
515
|
+
const [taskPath, responsePath, profilePath] = args;
|
|
516
|
+
if (!taskPath || !responsePath || !profilePath)
|
|
517
|
+
throw new Error('Usage: hyv apply-rewrite task.json response.json profile.json');
|
|
518
|
+
const result = evaluateRewriteResponse(parseRewriteTask(JSON.parse(input(taskPath))), input(responsePath), readProfile(profilePath));
|
|
519
|
+
json(result);
|
|
520
|
+
return result.status === 'accepted' ? 0 : 2;
|
|
521
|
+
}
|
|
522
|
+
function runPrepareJudgment(args) {
|
|
523
|
+
const [stage, kind, draft, profilePath, output, candidatePath] = args;
|
|
524
|
+
if (!stage || !kind || !draft || !profilePath || !output)
|
|
525
|
+
throw new Error('Usage: hyv prepare-judgment pre-edit|post-candidate kind draft.md profile.json task.json [candidate.md]');
|
|
526
|
+
if (stage === 'post-candidate' && !candidatePath)
|
|
527
|
+
throw new Error('Usage: hyv prepare-judgment post-candidate kind draft.md profile.json task.json candidate.md');
|
|
528
|
+
const profile = readProfile(profilePath);
|
|
529
|
+
const task = stage === 'pre-edit'
|
|
530
|
+
? preparePreEditJudgment(input(draft), profile, kind)
|
|
531
|
+
: preparePostCandidateJudgment(input(draft), input(candidatePath ?? ''), profile, kind);
|
|
532
|
+
writeJson(output, task);
|
|
533
|
+
json({ version: task.version, stage: task.stage, judgmentType: task.judgmentType, taskFingerprint: task.taskFingerprint });
|
|
534
|
+
return 0;
|
|
535
|
+
}
|
|
536
|
+
function runReduceJudgment(args) {
|
|
537
|
+
if (args.length < 3)
|
|
538
|
+
throw new Error('Usage: hyv reduce-judgment envelope.json envelope.json [envelope.json...]');
|
|
539
|
+
const envelopes = args.map((path) => parseJudgmentEnvelope(JSON.parse(input(path))));
|
|
540
|
+
json(envelopes[0]?.stage === 'pre-edit' ? reducePreEdit(envelopes) : reducePostCandidate(envelopes));
|
|
541
|
+
return 0;
|
|
542
|
+
}
|
|
543
|
+
function runPrepareRebuild(args) {
|
|
544
|
+
const { values, capability, recompositionPolicy } = rebuildArguments(args);
|
|
545
|
+
const [draft, profilePath, reductionPath, specPath, output, briefPath] = values;
|
|
546
|
+
if (!draft || !profilePath || !reductionPath || !specPath || !output || !capability) {
|
|
547
|
+
throw new Error('Usage: hyv prepare-rebuild draft.md profile.json reduction.json copy-spec.json task.json [writing-brief.json] [--recomposition-policy policy.json] (--capability-stdin|--capability-file path)');
|
|
548
|
+
}
|
|
549
|
+
const context = loadApprovalContext();
|
|
550
|
+
const task = prepareRebuildTask(input(draft), readProfile(profilePath), readJson(reductionPath), parseCopySpec(JSON.parse(input(specPath))), capability, context.trustStore, context.now, briefPath ? parseWritingBrief(JSON.parse(input(briefPath))) : undefined, recompositionPolicy);
|
|
551
|
+
writeJson(output, task);
|
|
552
|
+
json({ version: task.version, fingerprint: task.fingerprint, recommendationFingerprint: task.recommendationFingerprint, authorizationFingerprint: task.authorizationFingerprint, ...(task.recompositionPolicy ? { recompositionPolicy: task.recompositionPolicy } : {}) });
|
|
553
|
+
return 0;
|
|
554
|
+
}
|
|
555
|
+
function runApplyRebuild(args) {
|
|
556
|
+
const { values, capability } = capabilityArguments(args);
|
|
557
|
+
const [taskPath, responsePath, profilePath, ...extra] = values;
|
|
558
|
+
if (!taskPath || !responsePath || !profilePath || extra.length || !capability)
|
|
559
|
+
throw new Error('Usage: hyv apply-rebuild task.json response.json profile.json (--capability-stdin|--capability-file path)');
|
|
560
|
+
const context = loadApprovalContext();
|
|
561
|
+
const result = evaluateRebuildResponse(parseRebuildTask(JSON.parse(input(taskPath))), input(responsePath), readProfile(profilePath), capability, context.trustStore, context.now);
|
|
562
|
+
json(result);
|
|
563
|
+
return result.status === 'accepted' ? 0 : 2;
|
|
564
|
+
}
|
|
565
|
+
function runRebuildWriterRequest(args) {
|
|
566
|
+
const [taskPath, output, ...extra] = args;
|
|
567
|
+
if (!taskPath || !output || extra.length)
|
|
568
|
+
throw new Error('Usage: hyv rebuild-writer-request task.json writer-request.json');
|
|
569
|
+
const request = writerRequestForRebuild(parseRebuildTask(JSON.parse(input(taskPath))));
|
|
570
|
+
writeJson(output, request);
|
|
571
|
+
json({ version: request.version, taskFingerprint: request.taskFingerprint, copySpecFingerprint: request.copySpecFingerprint, ...(request.recompositionPolicyFingerprint ? { recompositionPolicyFingerprint: request.recompositionPolicyFingerprint } : {}) });
|
|
572
|
+
return 0;
|
|
573
|
+
}
|
|
574
|
+
function runVerify(args) {
|
|
575
|
+
const [original, candidate, profilePath, briefPath] = args;
|
|
576
|
+
if (!original || !candidate || !profilePath)
|
|
577
|
+
throw new Error('Usage: hyv verify original.md candidate.md profile.json [writing-brief.json]');
|
|
578
|
+
const profile = readProfile(profilePath);
|
|
579
|
+
const originalText = input(original);
|
|
580
|
+
const candidateText = input(candidate);
|
|
581
|
+
const result = verify(originalText, candidateText, profile, readBrief(briefPath));
|
|
582
|
+
json(result);
|
|
583
|
+
return result.passed ? 0 : 2;
|
|
584
|
+
}
|
|
585
|
+
function runVerifySpec(args) {
|
|
586
|
+
const [original, candidate, profilePath, specPath, briefPath] = args;
|
|
587
|
+
if (!original || !candidate || !profilePath || !specPath)
|
|
588
|
+
throw new Error('Usage: hyv verify-spec original.md candidate.md profile.json copy-spec.json [writing-brief.json]');
|
|
589
|
+
const profile = readProfile(profilePath);
|
|
590
|
+
const candidateText = input(candidate);
|
|
591
|
+
const result = verifyWithCopySpec(input(original), candidateText, profile, parseCopySpec(JSON.parse(input(specPath))), readBrief(briefPath));
|
|
592
|
+
json(result);
|
|
593
|
+
return result.passed ? 0 : 2;
|
|
594
|
+
}
|
|
595
|
+
function runLifecycle(args) {
|
|
596
|
+
const [action, ...raw] = args;
|
|
597
|
+
if (action === 'prepare-semantic')
|
|
598
|
+
return prepareSemanticLifecycle(raw);
|
|
599
|
+
if (action === 'submit-verdict')
|
|
600
|
+
return submitLifecycleVerdict(raw);
|
|
601
|
+
if (action === 'inspect')
|
|
602
|
+
return inspectLifecycleArtifact(raw);
|
|
603
|
+
if (action === 'validate-final-approval' || action === 'finalize')
|
|
604
|
+
return finishLifecycle(action, raw);
|
|
605
|
+
throw new Error('Usage: hyv lifecycle <prepare-semantic|submit-verdict|inspect|validate-final-approval|finalize> ...');
|
|
606
|
+
}
|
|
607
|
+
function prepareSemanticLifecycle(args) {
|
|
608
|
+
const [deterministicPath, bindingPath, receiptPath, policy, violationsPath, output, ...extra] = args;
|
|
609
|
+
if (!deterministicPath || !bindingPath || !receiptPath || !policy || !violationsPath || !output || extra.length || !['normal', 'high_assurance'].includes(policy))
|
|
610
|
+
throw new Error('Usage: hyv lifecycle prepare-semantic deterministic.json binding.json receipt.json <normal|high_assurance> violations.json output.json');
|
|
611
|
+
if (policy === 'high_assurance')
|
|
612
|
+
throw new Error('High-assurance semantic review requires a trusted embedding.');
|
|
613
|
+
const result = prepareLifecycle(readJson(deterministicPath), readJson(bindingPath), readJson(receiptPath), policy, readJson(violationsPath));
|
|
614
|
+
const serialized = canonicalJson(result);
|
|
615
|
+
writeFileSync(output, `${serialized}\n`, { encoding: 'utf8', flag: 'wx', mode: 0o600 });
|
|
616
|
+
process.stdout.write(`${serialized}\n`);
|
|
617
|
+
return 0;
|
|
618
|
+
}
|
|
619
|
+
function submitLifecycleVerdict(args) {
|
|
620
|
+
const [artifactPath, taskPath, evaluatorId, verdictPath, ...extra] = args;
|
|
621
|
+
if (!artifactPath || !taskPath || !evaluatorId || !verdictPath || extra.length)
|
|
622
|
+
throw new Error('Usage: hyv lifecycle submit-verdict artifact.json task.json evaluator-id verdict.json');
|
|
623
|
+
const artifact = readJson(artifactPath);
|
|
624
|
+
const task = readJson(taskPath);
|
|
625
|
+
if (task.policy !== 'normal')
|
|
626
|
+
throw new Error('High-assurance semantic review requires a trusted embedding.');
|
|
627
|
+
const result = submitSemanticVerdict(artifact, task, evaluatorId, readJson(verdictPath), loadApprovalContext());
|
|
628
|
+
canonical(result.ok ? result.artifact : { error: result.error });
|
|
629
|
+
return result.ok && result.artifact.status === 'ready_for_human_review' ? 0 : 2;
|
|
630
|
+
}
|
|
631
|
+
function inspectLifecycleArtifact(args) {
|
|
632
|
+
const [artifactPath, ...extra] = args;
|
|
633
|
+
if (!artifactPath || extra.length)
|
|
634
|
+
throw new Error('Usage: hyv lifecycle inspect artifact.json');
|
|
635
|
+
canonical(inspectLifecycle(readJson(artifactPath)));
|
|
636
|
+
return 0;
|
|
637
|
+
}
|
|
638
|
+
function finishLifecycle(action, args) {
|
|
639
|
+
const { values, capability } = capabilityArguments(args);
|
|
640
|
+
if (action === 'validate-final-approval') {
|
|
641
|
+
const [artifactPath, ...extra] = values;
|
|
642
|
+
if (!artifactPath || extra.length || !capability)
|
|
643
|
+
throw new Error('Usage: hyv lifecycle validate-final-approval artifact.json (--capability-stdin|--capability-file path)');
|
|
644
|
+
const result = validateFinalApproval(readJson(artifactPath), capability, loadApprovalContext());
|
|
645
|
+
canonical(result);
|
|
646
|
+
return result.ok ? 0 : 2;
|
|
647
|
+
}
|
|
648
|
+
const [artifactPath, decisionPath, ...extra] = values;
|
|
649
|
+
if (!artifactPath || !decisionPath || extra.length)
|
|
650
|
+
throw new Error('Usage: hyv lifecycle finalize artifact.json decision.json [--capability-stdin|--capability-file path]');
|
|
651
|
+
const decision = readJson(decisionPath);
|
|
652
|
+
if (decision.decision === 'approve' && !capability)
|
|
653
|
+
throw new Error('Approval requires a capability.');
|
|
654
|
+
if (decision.decision === 'reject' && capability)
|
|
655
|
+
throw new Error('Rejection does not accept a capability.');
|
|
656
|
+
const result = finalizeLifecycle(readJson(artifactPath), decision, loadApprovalContext(), capability);
|
|
657
|
+
canonical(result.ok ? result.artifact : { error: result.error });
|
|
658
|
+
return result.ok && result.artifact.status === 'approved' ? 0 : 2;
|
|
659
|
+
}
|
|
660
|
+
function runLearning(args) {
|
|
661
|
+
const [action, ...raw] = args;
|
|
662
|
+
if (action === 'record-approved')
|
|
663
|
+
return runRecordApprovedLearning(raw);
|
|
664
|
+
const { values, options } = learningArguments(raw);
|
|
665
|
+
const [profilePath, ...operands] = values;
|
|
666
|
+
if (!action || !profilePath)
|
|
667
|
+
throw new Error('Usage: hyv learning <show|inspect|add|record|ratify|supersede|migrate|clear> profile.json [value] [options]');
|
|
668
|
+
const profile = readProfile(profilePath);
|
|
669
|
+
if (action === 'show') {
|
|
670
|
+
json({ profile: profileFingerprint(profile), preferences: composeLearning(profile, options) });
|
|
427
671
|
return 0;
|
|
428
672
|
}
|
|
429
|
-
if (
|
|
430
|
-
if (
|
|
431
|
-
throw new Error('Usage: hyv
|
|
432
|
-
|
|
433
|
-
const stage = envelopes[0]?.stage;
|
|
434
|
-
json(stage === 'pre-edit' ? reducePreEdit(envelopes) : reducePostCandidate(envelopes));
|
|
673
|
+
if (action === 'inspect') {
|
|
674
|
+
if (Object.keys(options).length)
|
|
675
|
+
throw new Error('Usage: hyv learning inspect profile.json');
|
|
676
|
+
json(inspectLearning(profile));
|
|
435
677
|
return 0;
|
|
436
678
|
}
|
|
437
|
-
if (
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}
|
|
443
|
-
const context = loadApprovalContext();
|
|
444
|
-
const task = prepareRebuildTask(input(draft), readProfile(profilePath), readJson(reductionPath), parseCopySpec(JSON.parse(input(specPath))), capability, context.trustStore, context.now, briefPath ? parseWritingBrief(JSON.parse(input(briefPath))) : undefined, recompositionPolicy);
|
|
445
|
-
writeFileSync(output, `${JSON.stringify(task, null, 2)}\n`);
|
|
446
|
-
json({ version: task.version, fingerprint: task.fingerprint, recommendationFingerprint: task.recommendationFingerprint, authorizationFingerprint: task.authorizationFingerprint, ...(task.recompositionPolicy ? { recompositionPolicy: task.recompositionPolicy } : {}) });
|
|
679
|
+
if (action === 'add' || action === 'record') {
|
|
680
|
+
const text = operands.join(' ').trim();
|
|
681
|
+
if (!text)
|
|
682
|
+
throw new Error('Usage: hyv learning record profile.json "instruction" [options]');
|
|
683
|
+
const result = recordLearningInstruction(profile, text, options);
|
|
684
|
+
json(action === 'add' ? { added: result.status === 'recorded' } : result);
|
|
447
685
|
return 0;
|
|
448
686
|
}
|
|
449
|
-
if (
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
const context = loadApprovalContext();
|
|
455
|
-
const result = evaluateRebuildResponse(parseRebuildTask(JSON.parse(input(taskPath))), input(responsePath), readProfile(profilePath), capability, context.trustStore, context.now);
|
|
456
|
-
json(result);
|
|
457
|
-
return result.status === 'accepted' ? 0 : 2;
|
|
458
|
-
}
|
|
459
|
-
if (command === 'rebuild-writer-request') {
|
|
460
|
-
const [taskPath, output, ...extra] = rest;
|
|
461
|
-
if (!taskPath || !output || extra.length)
|
|
462
|
-
throw new Error('Usage: hyv rebuild-writer-request task.json writer-request.json');
|
|
463
|
-
const request = writerRequestForRebuild(parseRebuildTask(JSON.parse(input(taskPath))));
|
|
464
|
-
writeFileSync(output, `${JSON.stringify(request, null, 2)}\n`);
|
|
465
|
-
json({ version: request.version, taskFingerprint: request.taskFingerprint, copySpecFingerprint: request.copySpecFingerprint, ...(request.recompositionPolicyFingerprint ? { recompositionPolicyFingerprint: request.recompositionPolicyFingerprint } : {}) });
|
|
687
|
+
if (action === 'ratify' || action === 'supersede') {
|
|
688
|
+
const [eventId, ...extra] = operands;
|
|
689
|
+
if (!eventId || extra.length)
|
|
690
|
+
throw new Error(`Usage: hyv learning ${action} profile.json event-id [options]`);
|
|
691
|
+
json(action === 'ratify' ? ratifyLearningEvent(requireProfileV3(profile), eventId, options) : supersedeLearningEvent(requireProfileV3(profile), eventId, options));
|
|
466
692
|
return 0;
|
|
467
693
|
}
|
|
468
|
-
if (
|
|
469
|
-
const [
|
|
470
|
-
if (!
|
|
471
|
-
throw new Error('Usage: hyv
|
|
472
|
-
|
|
473
|
-
const originalText = input(original);
|
|
474
|
-
const candidateText = input(candidate);
|
|
475
|
-
const result = verify(originalText, candidateText, profile, readBrief(briefPath));
|
|
476
|
-
json(result);
|
|
477
|
-
return result.passed ? 0 : 2;
|
|
478
|
-
}
|
|
479
|
-
if (command === 'verify-spec') {
|
|
480
|
-
const [original, candidate, profilePath, specPath, briefPath] = rest;
|
|
481
|
-
if (!original || !candidate || !profilePath || !specPath)
|
|
482
|
-
throw new Error('Usage: hyv verify-spec original.md candidate.md profile.json copy-spec.json [writing-brief.json]');
|
|
483
|
-
const profile = readProfile(profilePath);
|
|
484
|
-
const candidateText = input(candidate);
|
|
485
|
-
const result = verifyWithCopySpec(input(original), candidateText, profile, parseCopySpec(JSON.parse(input(specPath))), readBrief(briefPath));
|
|
486
|
-
json(result);
|
|
487
|
-
return result.passed ? 0 : 2;
|
|
488
|
-
}
|
|
489
|
-
if (command === 'lifecycle') {
|
|
490
|
-
const [action, ...raw] = rest;
|
|
491
|
-
if (action === 'prepare-semantic') {
|
|
492
|
-
const [deterministicPath, bindingPath, receiptPath, policy, violationsPath, output, ...extra] = raw;
|
|
493
|
-
if (!deterministicPath || !bindingPath || !receiptPath || !policy || !violationsPath || !output || extra.length || !['normal', 'high_assurance'].includes(policy))
|
|
494
|
-
throw new Error('Usage: hyv lifecycle prepare-semantic deterministic.json binding.json receipt.json <normal|high_assurance> violations.json output.json');
|
|
495
|
-
if (policy === 'high_assurance')
|
|
496
|
-
throw new Error('High-assurance semantic review requires a trusted embedding.');
|
|
497
|
-
const result = prepareLifecycle(readJson(deterministicPath), readJson(bindingPath), readJson(receiptPath), policy, readJson(violationsPath));
|
|
498
|
-
const serialized = canonicalJson(result);
|
|
499
|
-
writeFileSync(output, `${serialized}\n`, { encoding: 'utf8', flag: 'wx', mode: 0o600 });
|
|
500
|
-
process.stdout.write(`${serialized}\n`);
|
|
501
|
-
return 0;
|
|
502
|
-
}
|
|
503
|
-
if (action === 'submit-verdict') {
|
|
504
|
-
const [artifactPath, taskPath, evaluatorId, verdictPath, ...extra] = raw;
|
|
505
|
-
if (!artifactPath || !taskPath || !evaluatorId || !verdictPath || extra.length)
|
|
506
|
-
throw new Error('Usage: hyv lifecycle submit-verdict artifact.json task.json evaluator-id verdict.json');
|
|
507
|
-
const artifact = readJson(artifactPath);
|
|
508
|
-
const task = readJson(taskPath);
|
|
509
|
-
if (task.policy !== 'normal')
|
|
510
|
-
throw new Error('High-assurance semantic review requires a trusted embedding.');
|
|
511
|
-
const result = submitSemanticVerdict(artifact, task, evaluatorId, readJson(verdictPath), loadApprovalContext());
|
|
512
|
-
canonical(result.ok ? result.artifact : { error: result.error });
|
|
513
|
-
return result.ok && result.artifact.status === 'ready_for_human_review' ? 0 : 2;
|
|
514
|
-
}
|
|
515
|
-
if (action === 'inspect') {
|
|
516
|
-
const [artifactPath, ...extra] = raw;
|
|
517
|
-
if (!artifactPath || extra.length)
|
|
518
|
-
throw new Error('Usage: hyv lifecycle inspect artifact.json');
|
|
519
|
-
canonical(inspectLifecycle(readJson(artifactPath)));
|
|
520
|
-
return 0;
|
|
521
|
-
}
|
|
522
|
-
if (action === 'validate-final-approval' || action === 'finalize') {
|
|
523
|
-
const { values, capability } = capabilityArguments(raw);
|
|
524
|
-
if (action === 'validate-final-approval') {
|
|
525
|
-
const [artifactPath, ...extra] = values;
|
|
526
|
-
if (!artifactPath || extra.length || !capability)
|
|
527
|
-
throw new Error('Usage: hyv lifecycle validate-final-approval artifact.json (--capability-stdin|--capability-file path)');
|
|
528
|
-
const result = validateFinalApproval(readJson(artifactPath), capability, loadApprovalContext());
|
|
529
|
-
canonical(result);
|
|
530
|
-
return result.ok ? 0 : 2;
|
|
531
|
-
}
|
|
532
|
-
const [artifactPath, decisionPath, ...extra] = values;
|
|
533
|
-
if (!artifactPath || !decisionPath || extra.length)
|
|
534
|
-
throw new Error('Usage: hyv lifecycle finalize artifact.json decision.json [--capability-stdin|--capability-file path]');
|
|
535
|
-
const decision = readJson(decisionPath);
|
|
536
|
-
if (decision.decision === 'approve' && !capability)
|
|
537
|
-
throw new Error('Approval requires a capability.');
|
|
538
|
-
if (decision.decision === 'reject' && capability)
|
|
539
|
-
throw new Error('Rejection does not accept a capability.');
|
|
540
|
-
const result = finalizeLifecycle(readJson(artifactPath), decision, loadApprovalContext(), capability);
|
|
541
|
-
canonical(result.ok ? result.artifact : { error: result.error });
|
|
542
|
-
return result.ok && result.artifact.status === 'approved' ? 0 : 2;
|
|
543
|
-
}
|
|
544
|
-
throw new Error('Usage: hyv lifecycle <prepare-semantic|submit-verdict|inspect|validate-final-approval|finalize> ...');
|
|
545
|
-
}
|
|
546
|
-
if (command === 'learning') {
|
|
547
|
-
const [action, ...raw] = rest;
|
|
548
|
-
if (action === 'record-approved') {
|
|
549
|
-
const { values, capability } = capabilityArguments(raw);
|
|
550
|
-
const [readyPath, approvedPath, originalPath, candidatePath, profilePath, decisionPath, ...contextPaths] = values;
|
|
551
|
-
if (!readyPath || !approvedPath || !originalPath || !candidatePath || !profilePath || !decisionPath || !capability)
|
|
552
|
-
throw new Error('Usage: hyv learning record-approved ready.json approved.json original.md candidate.md profile.json decision.json [copy-spec.json] [writing-brief.json] (--capability-stdin|--capability-file path)');
|
|
553
|
-
const context = prepareContext(contextPaths);
|
|
554
|
-
const status = recordApprovedLearning({ ready: readJson(readyPath), approved: readJson(approvedPath), decision: readJson(decisionPath), capability, source: input(originalPath), candidate: input(candidatePath), profile: readProfile(profilePath), context: loadApprovalContext(), copySpec: context.copySpec, writingBrief: context.writingBrief });
|
|
555
|
-
canonical({ status });
|
|
556
|
-
return status === 'write_failed' ? 2 : 0;
|
|
557
|
-
}
|
|
558
|
-
const { values, options } = learningArguments(raw);
|
|
559
|
-
const [profilePath, ...operands] = values;
|
|
560
|
-
if (!action || !profilePath)
|
|
561
|
-
throw new Error('Usage: hyv learning <show|inspect|add|record|ratify|supersede|migrate|clear> profile.json [value] [options]');
|
|
562
|
-
const profile = readProfile(profilePath);
|
|
563
|
-
if (action === 'show') {
|
|
564
|
-
json({ profile: profileFingerprint(profile), preferences: composeLearning(profile, options) });
|
|
565
|
-
return 0;
|
|
566
|
-
}
|
|
567
|
-
if (action === 'inspect') {
|
|
568
|
-
if (Object.keys(options).length)
|
|
569
|
-
throw new Error('Usage: hyv learning inspect profile.json');
|
|
570
|
-
json(inspectLearning(profile));
|
|
571
|
-
return 0;
|
|
572
|
-
}
|
|
573
|
-
if (action === 'add' || action === 'record') {
|
|
574
|
-
const text = operands.join(' ').trim();
|
|
575
|
-
if (!text)
|
|
576
|
-
throw new Error('Usage: hyv learning record profile.json "instruction" [options]');
|
|
577
|
-
const result = recordLearningInstruction(profile, text, options);
|
|
578
|
-
json(action === 'add' ? { added: result.status === 'recorded' } : result);
|
|
579
|
-
return 0;
|
|
580
|
-
}
|
|
581
|
-
if (action === 'ratify' || action === 'supersede') {
|
|
582
|
-
const [eventId, ...extra] = operands;
|
|
583
|
-
if (!eventId || extra.length)
|
|
584
|
-
throw new Error(`Usage: hyv learning ${action} profile.json event-id [options]`);
|
|
585
|
-
json(action === 'ratify' ? ratifyLearningEvent(requireProfileV3(profile), eventId, options) : supersedeLearningEvent(requireProfileV3(profile), eventId, options));
|
|
586
|
-
return 0;
|
|
587
|
-
}
|
|
588
|
-
if (action === 'migrate') {
|
|
589
|
-
const [targetPath, ...extra] = operands;
|
|
590
|
-
if (!targetPath || extra.length || profile.version !== '2')
|
|
591
|
-
throw new Error('Usage: hyv learning migrate source-v2.json target-v3.json [options]');
|
|
592
|
-
json(migrateLearningV2ToV3(profile, requireProfileV3(readProfile(targetPath)), options));
|
|
593
|
-
return 0;
|
|
594
|
-
}
|
|
595
|
-
if (action === 'clear') {
|
|
596
|
-
if (operands.length || Object.keys(options).length)
|
|
597
|
-
throw new Error('Usage: hyv learning clear profile.json');
|
|
598
|
-
json({ cleared: clearLearning(profile) });
|
|
599
|
-
return 0;
|
|
600
|
-
}
|
|
601
|
-
throw new Error('Usage: hyv learning <show|inspect|add|record|ratify|supersede|migrate|clear> profile.json [value] [options]');
|
|
602
|
-
}
|
|
603
|
-
if (command === 'patterns') {
|
|
604
|
-
json({ version: RULESET_VERSION, rules: serializedRules() });
|
|
694
|
+
if (action === 'migrate') {
|
|
695
|
+
const [targetPath, ...extra] = operands;
|
|
696
|
+
if (!targetPath || extra.length || profile.version !== '2')
|
|
697
|
+
throw new Error('Usage: hyv learning migrate source-v2.json target-v3.json [options]');
|
|
698
|
+
json(migrateLearningV2ToV3(profile, requireProfileV3(readProfile(targetPath)), options));
|
|
605
699
|
return 0;
|
|
606
700
|
}
|
|
607
|
-
if (
|
|
608
|
-
if (
|
|
609
|
-
throw new Error('Usage: hyv
|
|
610
|
-
|
|
701
|
+
if (action === 'clear') {
|
|
702
|
+
if (operands.length || Object.keys(options).length)
|
|
703
|
+
throw new Error('Usage: hyv learning clear profile.json');
|
|
704
|
+
json({ cleared: clearLearning(profile) });
|
|
611
705
|
return 0;
|
|
612
706
|
}
|
|
613
|
-
throw new Error(
|
|
707
|
+
throw new Error('Usage: hyv learning <show|inspect|add|record|ratify|supersede|migrate|clear> profile.json [value] [options]');
|
|
708
|
+
}
|
|
709
|
+
function runRecordApprovedLearning(args) {
|
|
710
|
+
const { values, capability } = capabilityArguments(args);
|
|
711
|
+
const [readyPath, approvedPath, originalPath, candidatePath, profilePath, decisionPath, ...contextPaths] = values;
|
|
712
|
+
if (!readyPath || !approvedPath || !originalPath || !candidatePath || !profilePath || !decisionPath || !capability)
|
|
713
|
+
throw new Error('Usage: hyv learning record-approved ready.json approved.json original.md candidate.md profile.json decision.json [copy-spec.json] [writing-brief.json] (--capability-stdin|--capability-file path)');
|
|
714
|
+
const context = prepareContext(contextPaths);
|
|
715
|
+
const status = recordApprovedLearning({ ready: readJson(readyPath), approved: readJson(approvedPath), decision: readJson(decisionPath), capability, source: input(originalPath), candidate: input(candidatePath), profile: readProfile(profilePath), context: loadApprovalContext(), copySpec: context.copySpec, writingBrief: context.writingBrief });
|
|
716
|
+
canonical({ status });
|
|
717
|
+
return status === 'write_failed' ? 2 : 0;
|
|
718
|
+
}
|
|
719
|
+
function runPatterns() {
|
|
720
|
+
json({ version: RULESET_VERSION, rules: serializedRules() });
|
|
721
|
+
return 0;
|
|
722
|
+
}
|
|
723
|
+
async function runMcp(args) {
|
|
724
|
+
if (args.length > 0)
|
|
725
|
+
throw new Error('Usage: hyv mcp');
|
|
726
|
+
await import('./mcp.js');
|
|
727
|
+
return 0;
|
|
728
|
+
}
|
|
729
|
+
const commandHandlers = {
|
|
730
|
+
agent: runAgent,
|
|
731
|
+
profile: runProfile,
|
|
732
|
+
analyze: runAnalyze,
|
|
733
|
+
hygiene: runHygiene,
|
|
734
|
+
'inspect-hidden-text': runInspectHiddenText,
|
|
735
|
+
'apply-hidden-text-policy': runApplyHiddenTextPolicy,
|
|
736
|
+
'final-check': runFinalCheck,
|
|
737
|
+
'fact-lint': runFactLint,
|
|
738
|
+
'logic-lint': runLogicLint,
|
|
739
|
+
'batch-analyze': runBatchAnalyze,
|
|
740
|
+
'rewrite-prompt': runRewritePrompt,
|
|
741
|
+
'prepare-rewrite': runPrepareRewrite,
|
|
742
|
+
'apply-rewrite': runApplyRewrite,
|
|
743
|
+
'prepare-judgment': runPrepareJudgment,
|
|
744
|
+
'reduce-judgment': runReduceJudgment,
|
|
745
|
+
'prepare-rebuild': runPrepareRebuild,
|
|
746
|
+
'apply-rebuild': runApplyRebuild,
|
|
747
|
+
'rebuild-writer-request': runRebuildWriterRequest,
|
|
748
|
+
verify: runVerify,
|
|
749
|
+
'verify-spec': runVerifySpec,
|
|
750
|
+
lifecycle: runLifecycle,
|
|
751
|
+
learning: runLearning,
|
|
752
|
+
patterns: runPatterns,
|
|
753
|
+
mcp: runMcp,
|
|
754
|
+
};
|
|
755
|
+
export async function runCli(args) {
|
|
756
|
+
const [command, ...rest] = args;
|
|
757
|
+
const handler = command ? commandHandlers[command] : undefined;
|
|
758
|
+
if (!handler)
|
|
759
|
+
throw new Error(`${usage}.`);
|
|
760
|
+
return handler(rest);
|
|
614
761
|
}
|
|
615
762
|
void (async () => {
|
|
616
763
|
try {
|