@cyning/harness 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cli.js CHANGED
@@ -19,6 +19,13 @@ import {
19
19
  GraphYamlError,
20
20
  yamlPathFor,
21
21
  } from './graph-yaml.js';
22
+ import {
23
+ buildSnapshot,
24
+ checkAxioms,
25
+ ingestRepoIdempotent,
26
+ loadEvents,
27
+ writeSnapshot,
28
+ } from './graph-hgm.js';
22
29
 
23
30
  function usage(version = 'unknown') {
24
31
  console.log(`@cyning/harness · cyning-harness CLI (v${version})
@@ -38,6 +45,9 @@ function usage(version = 'unknown') {
38
45
  npx @cyning/harness graph yaml check --graph-id ID [--input DIR] [--graph-json FILE]
39
46
  npx @cyning/harness graph yaml compile --all [--input DIR]
40
47
  npx @cyning/harness graph yaml check --all [--input DIR] [--graph-json FILE]
48
+ npx @cyning/harness graph ingest [--target PATH] [--actor ACTOR] [--dry-run]
49
+ npx @cyning/harness graph snapshot [--target PATH]
50
+ npx @cyning/harness graph axioms check [--target PATH] [--json]
41
51
 
42
52
  说明:
43
53
  init 首次接入 · 内部调用 wizard/install.sh + harness-sync.sh apply
@@ -48,7 +58,10 @@ function usage(version = 'unknown') {
48
58
  verify 30 前聚合:gate-check + audit D5 + S5 warn + 可选 --graph
49
59
  sync index 生成 .cyning-harness/invoke_index.json
50
60
  task check 校验 task.harness.v1.json sidecar · --no-circular 检测 depends_on 环
51
- graph yaml Inform 图谱 YAML 编译 / 校验(v1.1+)
61
+ graph yaml Inform 图谱 YAML 编译 / 校验(v1.1+)
62
+ graph ingest 扫描业务仓 → 追加 HGM 事件(v2.0+)
63
+ graph snapshot 事件重放 → graph/snapshot.json(v2.0+)
64
+ graph axioms 跑 HGM 公理检查(v2.0+)
52
65
 
53
66
  环境:
54
67
  CYNING_HARNESS 覆盖产品包根(维护者本地 clone 开发)
@@ -514,31 +527,54 @@ async function cmdTask(args) {
514
527
 
515
528
  async function cmdGraph(args) {
516
529
  if (args.includes('--help') || args.includes('-h')) {
517
- console.log(`用法: npx @cyning/harness graph yaml compile|check [选项]
530
+ console.log(`用法: npx @cyning/harness graph <子命令> [选项]
518
531
 
519
532
  子命令:
520
533
  graph yaml compile --graph-id ID [--input DIR] [--output FILE]
521
534
  graph yaml compile --all [--input DIR]
522
535
  graph yaml check --graph-id ID [--input DIR] [--graph-json FILE]
523
536
  graph yaml check --all [--input DIR] [--graph-json FILE]
537
+ graph ingest [--target PATH] [--actor ACTOR] [--dry-run]
538
+ graph snapshot [--target PATH]
539
+ graph axioms check [--target PATH] [--json]
524
540
 
525
541
  选项:
526
- --input DIR 输入目录(默认 target/docs/_tech_graph)
527
- --output FILE 输出 MD 路径(仅单图 compile)
528
- --graph-json FILE 对比的 graph.json 路径(默认 input/graph.json)
529
- --all 处理目录下所有 *.graph.yaml
542
+ --input DIR graph yaml 输入目录(默认 target/docs/_tech_graph)
543
+ --output FILE graph yaml 输出 MD 路径(仅单图 compile)
544
+ --graph-json FILE graph yaml 对比的 graph.json 路径
545
+ --target PATH 业务仓根目录(默认当前目录)
546
+ --actor ACTOR ingest actor(默认 system)
547
+ --dry-run ingest 仅输出事件数 · 不写入
548
+ --json axioms 输出 JSON
530
549
  `);
531
550
  return;
532
551
  }
533
552
 
534
553
  const [sub, ...subRest] = args;
535
- if (sub !== 'yaml') {
536
- const err = new Error(`graph 子命令未知: ${sub ?? '(空)'}`);
537
- err.exitCode = 1;
538
- throw err;
554
+ if (sub === 'yaml') {
555
+ await cmdGraphYaml(subRest);
556
+ return;
557
+ }
558
+ if (sub === 'ingest') {
559
+ await cmdGraphIngest(subRest);
560
+ return;
561
+ }
562
+ if (sub === 'snapshot') {
563
+ await cmdGraphSnapshot(subRest);
564
+ return;
565
+ }
566
+ if (sub === 'axioms') {
567
+ await cmdGraphAxioms(subRest);
568
+ return;
539
569
  }
540
570
 
541
- const [action, ...actionRest] = subRest;
571
+ const err = new Error(`graph 子命令未知: ${sub ?? '(空)'}`);
572
+ err.exitCode = 1;
573
+ throw err;
574
+ }
575
+
576
+ async function cmdGraphYaml(args) {
577
+ const [action, ...actionRest] = args;
542
578
  if (action !== 'compile' && action !== 'check') {
543
579
  const err = new Error(`graph yaml 动作未知: ${action ?? '(空)'}`);
544
580
  err.exitCode = 1;
@@ -638,3 +674,97 @@ async function cmdGraph(args) {
638
674
  throw err;
639
675
  }
640
676
  }
677
+
678
+ async function cmdGraphIngest(args) {
679
+ let rest = args;
680
+ const { value: targetArg, rest: r1 } = takeOption(rest, '--target');
681
+ rest = r1;
682
+ const { value: actor, rest: r2 } = takeOption(rest, '--actor');
683
+ rest = r2;
684
+ const dryRun = rest.includes('--dry-run');
685
+ rest = rest.filter((a) => a !== '--dry-run');
686
+
687
+ if (rest.length > 0) {
688
+ const err = new Error(`graph ingest 未知参数: ${rest.join(' ')}`);
689
+ err.exitCode = 1;
690
+ throw err;
691
+ }
692
+
693
+ const target = resolveTarget(process.cwd(), targetArg);
694
+ const result = ingestRepoIdempotent(target, {
695
+ actor: actor || 'system',
696
+ source: 'cli',
697
+ dryRun,
698
+ });
699
+
700
+ console.log(`目标: ${target}`);
701
+ console.log(`新事件: ${result.count}`);
702
+ console.log(`跳过(已存在): ${result.skipped}`);
703
+ if (dryRun) {
704
+ console.log('mode: dry-run(未写入)');
705
+ }
706
+ }
707
+
708
+ async function cmdGraphSnapshot(args) {
709
+ let rest = args;
710
+ const { value: targetArg, rest: r1 } = takeOption(rest, '--target');
711
+ rest = r1;
712
+
713
+ if (rest.length > 0) {
714
+ const err = new Error(`graph snapshot 未知参数: ${rest.join(' ')}`);
715
+ err.exitCode = 1;
716
+ throw err;
717
+ }
718
+
719
+ const target = resolveTarget(process.cwd(), targetArg);
720
+ const events = loadEvents(target);
721
+ const snapshot = buildSnapshot(events);
722
+ const out = writeSnapshot(target, snapshot);
723
+
724
+ console.log(`events: ${events.length}`);
725
+ console.log(`nodes: ${Object.keys(snapshot.nodes).length}`);
726
+ console.log(`edges: ${snapshot.edges.length}`);
727
+ console.log(`snapshot: ${out}`);
728
+ }
729
+
730
+ async function cmdGraphAxioms(args) {
731
+ const [sub, ...rest] = args;
732
+ if (sub !== 'check') {
733
+ const err = new Error(`graph axioms 动作未知: ${sub ?? '(空)'}`);
734
+ err.exitCode = 1;
735
+ throw err;
736
+ }
737
+
738
+ let remaining = rest;
739
+ const { value: targetArg, rest: r1 } = takeOption(remaining, '--target');
740
+ remaining = r1;
741
+ const json = remaining.includes('--json');
742
+ remaining = remaining.filter((a) => a !== '--json');
743
+
744
+ if (remaining.length > 0) {
745
+ const err = new Error(`graph axioms check 未知参数: ${remaining.join(' ')}`);
746
+ err.exitCode = 1;
747
+ throw err;
748
+ }
749
+
750
+ const target = resolveTarget(process.cwd(), targetArg);
751
+ const events = loadEvents(target);
752
+ const snapshot = buildSnapshot(events);
753
+ const result = checkAxioms(snapshot);
754
+
755
+ if (json) {
756
+ console.log(JSON.stringify(result, null, 2));
757
+ } else {
758
+ console.log(`axioms: ${result.ok ? 'PASS' : 'FAIL'}`);
759
+ console.log(`violations: ${result.violations.length}`);
760
+ for (const v of result.violations) {
761
+ console.log(` [${v.axiom}/${v.severity}] ${v.message}`);
762
+ }
763
+ }
764
+
765
+ if (!result.ok) {
766
+ const err = new Error('HGM axioms 未通过');
767
+ err.exitCode = 2;
768
+ throw err;
769
+ }
770
+ }