oh-my-knowledge 0.26.0 → 0.28.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/README.md +105 -346
- package/README.zh.md +142 -375
- package/dist/src/analysis/report-diagnostics.d.ts +2 -2
- package/dist/src/analysis/report-diagnostics.js +2 -2
- package/dist/src/analysis/sample-diagnostics.d.ts +3 -3
- package/dist/src/analysis/sample-diagnostics.js +3 -3
- package/dist/src/authoring/generator.d.ts.map +1 -1
- package/dist/src/authoring/generator.js +9 -8
- package/dist/src/authoring/generator.js.map +1 -1
- package/dist/src/cli/cli-exit.d.ts +15 -0
- package/dist/src/cli/cli-exit.d.ts.map +1 -0
- package/dist/src/cli/cli-exit.js +19 -0
- package/dist/src/cli/cli-exit.js.map +1 -0
- package/dist/src/cli/commands/_shared.d.ts +12 -0
- package/dist/src/cli/commands/_shared.d.ts.map +1 -0
- package/dist/src/cli/commands/_shared.js +26 -0
- package/dist/src/cli/commands/_shared.js.map +1 -0
- package/dist/src/cli/commands/doctor.d.ts +2 -0
- package/dist/src/cli/commands/doctor.d.ts.map +1 -0
- package/dist/src/cli/commands/doctor.js +174 -0
- package/dist/src/cli/commands/doctor.js.map +1 -0
- package/dist/src/cli/commands/eval-gold.d.ts +2 -0
- package/dist/src/cli/commands/eval-gold.d.ts.map +1 -0
- package/dist/src/cli/commands/eval-gold.js +137 -0
- package/dist/src/cli/commands/eval-gold.js.map +1 -0
- package/dist/src/cli/commands/eval-runner.d.ts +2 -0
- package/dist/src/cli/commands/eval-runner.d.ts.map +1 -0
- package/dist/src/cli/commands/eval-runner.js +299 -0
- package/dist/src/cli/commands/eval-runner.js.map +1 -0
- package/dist/src/cli/commands/eval.d.ts +2 -0
- package/dist/src/cli/commands/eval.d.ts.map +1 -0
- package/dist/src/cli/commands/eval.js +11 -0
- package/dist/src/cli/commands/eval.js.map +1 -0
- package/dist/src/cli/commands/evolve.d.ts +2 -0
- package/dist/src/cli/commands/evolve.d.ts.map +1 -0
- package/dist/src/cli/commands/evolve.js +115 -0
- package/dist/src/cli/commands/evolve.js.map +1 -0
- package/dist/src/cli/commands/init.d.ts +2 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -0
- package/dist/src/cli/commands/init.js +110 -0
- package/dist/src/cli/commands/init.js.map +1 -0
- package/dist/src/cli/commands/observe.d.ts +2 -0
- package/dist/src/cli/commands/observe.d.ts.map +1 -0
- package/dist/src/cli/commands/observe.js +77 -0
- package/dist/src/cli/commands/observe.js.map +1 -0
- package/dist/src/cli/commands/registry.d.ts +11 -0
- package/dist/src/cli/commands/registry.d.ts.map +1 -0
- package/dist/src/cli/commands/registry.js +24 -0
- package/dist/src/cli/commands/registry.js.map +1 -0
- package/dist/src/cli/commands/sample.d.ts +2 -0
- package/dist/src/cli/commands/sample.d.ts.map +1 -0
- package/dist/src/cli/commands/sample.js +121 -0
- package/dist/src/cli/commands/sample.js.map +1 -0
- package/dist/src/cli/commands/studio.d.ts +2 -0
- package/dist/src/cli/commands/studio.d.ts.map +1 -0
- package/dist/src/cli/commands/studio.js +76 -0
- package/dist/src/cli/commands/studio.js.map +1 -0
- package/dist/src/cli/i18n-dict.d.ts +2 -4
- package/dist/src/cli/i18n-dict.d.ts.map +1 -1
- package/dist/src/cli/i18n-dict.js +461 -675
- package/dist/src/cli/i18n-dict.js.map +1 -1
- package/dist/src/cli/index.js +43 -1516
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/parse-run-config.d.ts +3 -4
- package/dist/src/cli/parse-run-config.d.ts.map +1 -1
- package/dist/src/cli/parse-run-config.js +5 -5
- package/dist/src/cli/parse-run-config.js.map +1 -1
- package/dist/src/cli/parse-strict.d.ts +0 -13
- package/dist/src/cli/parse-strict.d.ts.map +1 -1
- package/dist/src/cli/parse-strict.js +2 -1
- package/dist/src/cli/parse-strict.js.map +1 -1
- package/dist/src/doctor/health/builtin-dimensions.d.ts +11 -0
- package/dist/src/doctor/health/builtin-dimensions.d.ts.map +1 -0
- package/dist/src/doctor/health/builtin-dimensions.js +94 -0
- package/dist/src/doctor/health/builtin-dimensions.js.map +1 -0
- package/dist/src/doctor/health/composer.d.ts +19 -0
- package/dist/src/doctor/health/composer.d.ts.map +1 -0
- package/dist/src/doctor/health/composer.js +289 -0
- package/dist/src/doctor/health/composer.js.map +1 -0
- package/dist/src/doctor/health/dimension-registry.d.ts +13 -0
- package/dist/src/doctor/health/dimension-registry.d.ts.map +1 -0
- package/dist/src/doctor/health/dimension-registry.js +28 -0
- package/dist/src/doctor/health/dimension-registry.js.map +1 -0
- package/dist/src/doctor/health/dimension-spec.d.ts +46 -0
- package/dist/src/doctor/health/dimension-spec.d.ts.map +1 -0
- package/dist/src/doctor/health/dimension-spec.js +12 -0
- package/dist/src/doctor/health/dimension-spec.js.map +1 -0
- package/dist/src/doctor/health/parser.d.ts +27 -0
- package/dist/src/doctor/health/parser.d.ts.map +1 -0
- package/dist/src/doctor/health/parser.js +190 -0
- package/dist/src/doctor/health/parser.js.map +1 -0
- package/dist/src/doctor/health/prompt-builder.d.ts +22 -0
- package/dist/src/doctor/health/prompt-builder.d.ts.map +1 -0
- package/dist/src/doctor/health/prompt-builder.js +162 -0
- package/dist/src/doctor/health/prompt-builder.js.map +1 -0
- package/dist/src/doctor/health/register.d.ts +13 -0
- package/dist/src/doctor/health/register.d.ts.map +1 -0
- package/dist/src/doctor/health/register.js +20 -0
- package/dist/src/doctor/health/register.js.map +1 -0
- package/dist/src/doctor/html-renderer.d.ts +20 -0
- package/dist/src/doctor/html-renderer.d.ts.map +1 -0
- package/dist/src/doctor/html-renderer.js +366 -0
- package/dist/src/doctor/html-renderer.js.map +1 -0
- package/dist/src/doctor/index.d.ts +1 -1
- package/dist/src/doctor/index.d.ts.map +1 -1
- package/dist/src/doctor/index.js +57 -8
- package/dist/src/doctor/index.js.map +1 -1
- package/dist/src/doctor/preflight.d.ts +2 -2
- package/dist/src/doctor/preflight.js +2 -2
- package/dist/src/doctor/renderer.d.ts +4 -0
- package/dist/src/doctor/renderer.d.ts.map +1 -1
- package/dist/src/doctor/renderer.js +72 -18
- package/dist/src/doctor/renderer.js.map +1 -1
- package/dist/src/doctor/rules.d.ts +6 -5
- package/dist/src/doctor/rules.d.ts.map +1 -1
- package/dist/src/doctor/rules.js +4 -3
- package/dist/src/doctor/rules.js.map +1 -1
- package/dist/src/eval-core/fact-checker.js +1 -1
- package/dist/src/eval-core/fact-checker.js.map +1 -1
- package/dist/src/eval-core/layer-gates.d.ts +1 -1
- package/dist/src/eval-core/layer-gates.js +1 -1
- package/dist/src/eval-core/verdict.d.ts +4 -4
- package/dist/src/eval-core/verdict.d.ts.map +1 -1
- package/dist/src/eval-core/verdict.js +2 -2
- package/dist/src/eval-workflows/batch-evaluation-workflow.d.ts +15 -2
- package/dist/src/eval-workflows/batch-evaluation-workflow.d.ts.map +1 -1
- package/dist/src/eval-workflows/batch-evaluation-workflow.js +13 -2
- package/dist/src/eval-workflows/batch-evaluation-workflow.js.map +1 -1
- package/dist/src/eval-workflows/evaluation-pipeline.d.ts +6 -3
- package/dist/src/eval-workflows/evaluation-pipeline.d.ts.map +1 -1
- package/dist/src/eval-workflows/evaluation-pipeline.js +10 -9
- package/dist/src/eval-workflows/evaluation-pipeline.js.map +1 -1
- package/dist/src/eval-workflows/run-evaluation.d.ts +1 -1
- package/dist/src/eval-workflows/run-evaluation.d.ts.map +1 -1
- package/dist/src/eval-workflows/run-evaluation.js +13 -6
- package/dist/src/eval-workflows/run-evaluation.js.map +1 -1
- package/dist/src/executors/script.d.ts.map +1 -1
- package/dist/src/executors/script.js +16 -3
- package/dist/src/executors/script.js.map +1 -1
- package/dist/src/grading/debias-validate.d.ts +2 -2
- package/dist/src/grading/debias-validate.js +2 -2
- package/dist/src/grading/gold-cli.d.ts +2 -5
- package/dist/src/grading/gold-cli.d.ts.map +1 -1
- package/dist/src/grading/gold-cli.js +4 -8
- package/dist/src/grading/gold-cli.js.map +1 -1
- package/dist/src/grading/judge.d.ts +1 -1
- package/dist/src/renderer/html-renderer.js +1 -1
- package/dist/src/renderer/layout.js +5 -5
- package/dist/src/renderer/layout.js.map +1 -1
- package/dist/src/renderer/skill-health-renderer.d.ts +1 -1
- package/dist/src/renderer/skill-health-renderer.js +1 -1
- package/dist/src/renderer/summary.js +8 -8
- package/dist/src/server/report-server.d.ts.map +1 -1
- package/dist/src/server/report-server.js +8 -7
- package/dist/src/server/report-server.js.map +1 -1
- package/dist/src/types/doctor.d.ts +44 -6
- package/dist/src/types/doctor.d.ts.map +1 -1
- package/dist/src/types/doctor.js +3 -0
- package/dist/src/types/doctor.js.map +1 -1
- package/dist/src/types/eval.d.ts +1 -1
- package/dist/src/types/report.d.ts +2 -2
- package/dist/src/types/report.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/src/cli/coverage-renderer.d.ts +0 -15
- package/dist/src/cli/coverage-renderer.d.ts.map +0 -1
- package/dist/src/cli/coverage-renderer.js +0 -74
- package/dist/src/cli/coverage-renderer.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../../src/doctor/health/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;AAO1E,iEAAiE;AACjE,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,UAAU,GAAyB,EAAE,CAAC;IAC5C,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACrC,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,MAAM;QACxB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC;QACb,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,IAAI,MAAM,EAAE,CAAC;gBAAC,MAAM,GAAG,KAAK,CAAC;gBAAC,SAAS;YAAC,CAAC;YACzC,IAAI,QAAQ,EAAE,CAAC;gBACb,IAAI,CAAC,KAAK,IAAI;oBAAE,MAAM,GAAG,IAAI,CAAC;qBACzB,IAAI,CAAC,KAAK,GAAG;oBAAE,QAAQ,GAAG,KAAK,CAAC;gBACrC,SAAS;YACX,CAAC;YACD,IAAI,CAAC,KAAK,GAAG;gBAAE,QAAQ,GAAG,IAAI,CAAC;iBAC1B,IAAI,CAAC,KAAK,GAAG;gBAAE,KAAK,IAAI,CAAC,CAAC;iBAC1B,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;gBACnB,KAAK,IAAI,CAAC,CAAC;gBACX,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;oBAAC,GAAG,GAAG,CAAC,CAAC;oBAAC,MAAM;gBAAC,CAAC;YACtC,CAAC;QACH,CAAC;QACD,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,MAAM;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1D,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAA8B,EAAE,CAAC,CAAC;YACvE,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;QACjE,CAAC;QACD,GAAG,GAAG,KAAK,GAAG,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACrC,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,KAAK,MAAM,CAAC,IAAI,iBAAiB;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG;gBAAE,IAAI,IAAI,CAAC,CAAC;QAC7D,OAAO,IAAI,IAAI,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrD,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxB,CAAC;IACD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IACnD,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnD,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACtB,CAAC;AAED,8EAA8E;AAC9E,yBAAyB;AACzB,8EAA8E;AAE9E,SAAS,UAAU,CAAC,CAAU;IAC5B,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,KAAK,CAAC;AACjE,CAAC;AAED,SAAS,cAAc,CAAC,CAAU;IAChC,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC;AAChD,CAAC;AAED,SAAS,SAAS,CAAC,GAAY;IAC7B,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACjD,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO;QACL,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,OAAO,EAAE,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;QACvD,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;QAC1D,WAAW,EAAE,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;KACpE,CAAC;AACJ,CAAC;AAWD,gDAAgD;AAChD,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,IAA2B;IAE3B,IAAI,MAA+B,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAA4B,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,EAAE,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAiC,CAAC;IAEzD,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;QAChC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,SAAS;QACtD,MAAM,IAAI,GAAG,OAAkC,CAAC;QAChD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS,CAAC,cAAc;QAC/E,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS,CAAkC,eAAe;QAClF,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,MAAM,QAAQ,GAAoB,EAAE,CAAC;QACrC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;YAC1B,IAAI,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;QACD,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;YACjD,CAAC,CAAE,IAAI,CAAC,WAAyB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;YACnF,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,KAAK,GAAyB,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;YACxD,CAAC,CAAC,IAAI,CAAC,KAAK;YACZ,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,oBAAoB;IACpB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;QACtE,CAAC,CAAC,MAAM,CAAC,OAAO;QAChB,CAAC,CAAC,EAAE,CAA4B,CAAC;IACnC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC,CAAC;IAC/D,MAAM,UAAU,GAAG,UAAU,CAAC,cAAc,CAAC;IAC7C,MAAM,OAAO,GAAG,OAAO,UAAU,KAAK,QAAQ,IAAI,aAAa,CAAC,GAAG,CAAC,UAAmB,CAAC;QACtF,CAAC,CAAE,UAAqC;QACxC,CAAC,CAAC,IAAI,CAAC;IACT,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC;QAC9D,CAAC,CAAE,UAAU,CAAC,eAA6B,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QAC7F,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;IAExF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC;AAC7D,CAAC;AAED,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E,SAAS,cAAc,CAAC,QAAyB;IAC/C,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACzD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAA2C;IAC7E,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACjC,IAAI,CAAC,CAAC,QAAQ;YAAE,SAAS,CAAC,OAAO;QACjC,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK;YAAE,YAAY,GAAG,IAAI,CAAC;aACtC,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK;YAAE,aAAa,GAAG,IAAI,CAAC;IACnD,CAAC;IACD,IAAI,YAAY;QAAE,OAAO,MAAM,CAAC;IAChC,IAAI,aAAa;QAAE,OAAO,MAAM,CAAC;IACjC,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 健康度体检 prompt 拼装器。
|
|
3
|
+
*
|
|
4
|
+
* 4 个区块:
|
|
5
|
+
* Block 1: 任务说明 + skill 输入(固定)
|
|
6
|
+
* Block 2: 检查维度章节(动态:遍历 dims,自动加 ## N. 标题 + (id: ...))
|
|
7
|
+
* Block 3: 通用规则(同根因合并 / Finding level / 维度 level / overall_health)
|
|
8
|
+
* Block 4: JSON schema(半动态:dim_id 枚举 + checklist 项数 = dims.length)
|
|
9
|
+
*
|
|
10
|
+
* 关键约束:LLM 用 dim_id(英文)在输出中标识维度,而不是中文 displayName —
|
|
11
|
+
* displayName 翻译/重命名时不会让 parser 崩。
|
|
12
|
+
*/
|
|
13
|
+
import type { HealthDimensionSpec } from './dimension-spec.js';
|
|
14
|
+
export interface PromptInput {
|
|
15
|
+
skillName: string;
|
|
16
|
+
skillContent: string;
|
|
17
|
+
skillRoot: string | null;
|
|
18
|
+
subFiles: string[];
|
|
19
|
+
siblingSkills: string[];
|
|
20
|
+
}
|
|
21
|
+
export declare function buildHealthPrompt(input: PromptInput, dims: HealthDimensionSpec[]): string;
|
|
22
|
+
//# sourceMappingURL=prompt-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../../../../src/doctor/health/prompt-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,mBAAmB,EAAE,GAAG,MAAM,CAOzF"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 健康度体检 prompt 拼装器。
|
|
3
|
+
*
|
|
4
|
+
* 4 个区块:
|
|
5
|
+
* Block 1: 任务说明 + skill 输入(固定)
|
|
6
|
+
* Block 2: 检查维度章节(动态:遍历 dims,自动加 ## N. 标题 + (id: ...))
|
|
7
|
+
* Block 3: 通用规则(同根因合并 / Finding level / 维度 level / overall_health)
|
|
8
|
+
* Block 4: JSON schema(半动态:dim_id 枚举 + checklist 项数 = dims.length)
|
|
9
|
+
*
|
|
10
|
+
* 关键约束:LLM 用 dim_id(英文)在输出中标识维度,而不是中文 displayName —
|
|
11
|
+
* displayName 翻译/重命名时不会让 parser 崩。
|
|
12
|
+
*/
|
|
13
|
+
export function buildHealthPrompt(input, dims) {
|
|
14
|
+
return [
|
|
15
|
+
renderBlock1Header(input),
|
|
16
|
+
renderBlock2Dimensions(dims),
|
|
17
|
+
renderBlock3CommonRules(),
|
|
18
|
+
renderBlock4JsonSchema(input.skillName, dims),
|
|
19
|
+
].join('\n\n');
|
|
20
|
+
}
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Block 1: 任务 + skill 输入
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
function renderBlock1Header(input) {
|
|
25
|
+
const { skillName, skillContent, skillRoot, subFiles, siblingSkills } = input;
|
|
26
|
+
const siblingList = siblingSkills.length > 0
|
|
27
|
+
? siblingSkills.map((s) => `\`${s}\``).join(', ')
|
|
28
|
+
: '(none)';
|
|
29
|
+
const subFilesList = subFiles.length > 0
|
|
30
|
+
? subFiles.map((f) => `- ${f}`).join('\n')
|
|
31
|
+
: '(no sub-files; pure SKILL.md skill)';
|
|
32
|
+
const skillRootHint = skillRoot
|
|
33
|
+
? `skill 根目录: \`${skillRoot}\`(子文件需要时用 Read 工具自取)`
|
|
34
|
+
: 'skill 是单文件 .md;没有子目录可 Read。';
|
|
35
|
+
return `你正在对 \`${skillName}\` 这个 skill 做**健康度体检**——按下面注册的所有维度逐一检查,给出 level、findings、改进建议。
|
|
36
|
+
|
|
37
|
+
# 输入
|
|
38
|
+
|
|
39
|
+
- skill 名: \`${skillName}\`
|
|
40
|
+
- ${skillRootHint}
|
|
41
|
+
- 子文件清单(仅参考,需要时用 Read 工具按路径自取):
|
|
42
|
+
${subFilesList}
|
|
43
|
+
|
|
44
|
+
# 系统 skill 列表(跨 skill 引用判断用)
|
|
45
|
+
|
|
46
|
+
${siblingList}
|
|
47
|
+
|
|
48
|
+
## SKILL.md 内容(已 inline,无需再 Read)
|
|
49
|
+
|
|
50
|
+
\`\`\`markdown
|
|
51
|
+
${skillContent}
|
|
52
|
+
\`\`\``;
|
|
53
|
+
}
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Block 2: 维度章节
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
function renderBlock2Dimensions(dims) {
|
|
58
|
+
const sections = dims.map((dim, idx) => {
|
|
59
|
+
const num = idx + 1;
|
|
60
|
+
return `## ${num}. ${dim.displayName} (id: \`${dim.id}\`)
|
|
61
|
+
${dim.promptSection.trim()}`;
|
|
62
|
+
});
|
|
63
|
+
return `# 检查维度
|
|
64
|
+
|
|
65
|
+
${sections.join('\n\n')}`;
|
|
66
|
+
}
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Block 3: 通用规则
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
function renderBlock3CommonRules() {
|
|
71
|
+
return `# 同根因合并(去重规则)
|
|
72
|
+
|
|
73
|
+
多个 finding 如果**根因相同 + 修复方式相同**,必须合并成**一条** finding(可以跨维度合并)。在 \`evidence\` 字段里把所有出现位置列全(用 \` ; \` 分隔),\`description\` 里点明"在 N 处出现"。
|
|
74
|
+
|
|
75
|
+
合并后,该 finding 的 \`level\` 取所有出现位置中**最严重的一个**。\`suggestions\` 给统一修法。
|
|
76
|
+
|
|
77
|
+
# Finding level 判定
|
|
78
|
+
|
|
79
|
+
- \`错误\`:**必须修**。包括:
|
|
80
|
+
- 在**常见用户环境 / 默认安装方式 / 不同版本号下直接跑不通**(不只是"在文档作者机子上跑不通")
|
|
81
|
+
- 硬编码绝对路径含具体版本号 / 用户名 → 换环境必失败
|
|
82
|
+
- 引用了不存在的脚本 / CLI / MCP 工具 / skill
|
|
83
|
+
- 不可逆操作没有人工确认
|
|
84
|
+
- 指令严重歧义会让 LLM 在多次执行中跑出截然不同结果
|
|
85
|
+
- \`警告\`:**应该修**。规范不符 / 可读性明显差 / 误触发风险但不会直接挂掉
|
|
86
|
+
- \`建议\`:锦上添花
|
|
87
|
+
|
|
88
|
+
# 维度 level 派生规则
|
|
89
|
+
|
|
90
|
+
- \`健康\`:0 个 finding
|
|
91
|
+
- \`亚健康\`:有警告 / 建议但无错误
|
|
92
|
+
- \`不健康\`:至少 1 个错误
|
|
93
|
+
- \`不适用\`:该维度对本 skill 无意义(谨慎使用,不要拿来回避检查)
|
|
94
|
+
|
|
95
|
+
# overall_health
|
|
96
|
+
|
|
97
|
+
- \`良好\`:所有维度都是 \`健康\` 或 \`不适用\`
|
|
98
|
+
- \`部分缺陷\`:有 \`亚健康\` 但无 \`不健康\`
|
|
99
|
+
- \`严重缺陷\`:任一维度 \`不健康\``;
|
|
100
|
+
}
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// Block 4: JSON schema
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
function renderBlock4JsonSchema(skillName, dims) {
|
|
105
|
+
const dimIdEnum = dims.map((d) => `"${d.id}"`).join(' | ');
|
|
106
|
+
const dimIdList = dims.map((d) => `\`${d.id}\``).join(', ');
|
|
107
|
+
return `# 输出 JSON schema
|
|
108
|
+
|
|
109
|
+
输出**必须是单一合法 JSON 对象**。第一字符 \`{\`,最后 \`}\`,**不要**用 \`\`\`json\`\`\` 围栏,**不要**寒暄。
|
|
110
|
+
|
|
111
|
+
{
|
|
112
|
+
"skill_name": "${skillName}",
|
|
113
|
+
"feature_points": [
|
|
114
|
+
{
|
|
115
|
+
"name": "<功能点名>",
|
|
116
|
+
"description": "<1-2 行>",
|
|
117
|
+
"simulation": [
|
|
118
|
+
{
|
|
119
|
+
"step": 1,
|
|
120
|
+
"action": "<这一步做什么>",
|
|
121
|
+
"input": "<参数>",
|
|
122
|
+
"simulated_output": "<假设返回值,**不真跑**>",
|
|
123
|
+
"derivable_from_doc": true,
|
|
124
|
+
"note": "<指令模糊处>"
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
"checklist": [
|
|
130
|
+
{
|
|
131
|
+
"dim_id": ${dimIdEnum},
|
|
132
|
+
"level": "健康 | 亚健康 | 不健康 | 不适用",
|
|
133
|
+
"findings": [
|
|
134
|
+
{
|
|
135
|
+
"level": "错误 | 警告 | 建议",
|
|
136
|
+
"subtype": "<仅 \`security\` 维度需填:不可逆操作 | 凭据硬编码 | 个人化耦合;其它维度留空字符串>",
|
|
137
|
+
"evidence": "<具体引用:SKILL.md L<行号> / 章节标题 / 文件名 / 功能点 X 第 Y 步>",
|
|
138
|
+
"description": "<一句话讲清问题>"
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"suggestions": ["<可执行的改进动作>"]
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
"summary": {
|
|
145
|
+
"overall_health": "良好 | 部分缺陷 | 严重缺陷",
|
|
146
|
+
"top_suggestions": ["<整 skill 视角下最该先改的 3 条,按优先级从高到低>"]
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# 字段约束
|
|
151
|
+
|
|
152
|
+
- \`checklist\` 必须**恰好包含 ${dims.length} 项**,\`dim_id\` 必须是以下之一,**每个 id 出现且仅出现一次**:
|
|
153
|
+
${dimIdList}
|
|
154
|
+
- \`level\` / \`subtype\` 字段值用精确中文字符串,不允许英文或别名
|
|
155
|
+
- \`evidence\` 必须有具体引用,不能笼统说"全文"
|
|
156
|
+
- 字符串里的 skill / 文件 / 命令名用反引号 \`xxx\` 包裹
|
|
157
|
+
- **不要**冒虚假 finding,宁可少报也不要把"看起来可能有问题"硬塞进来
|
|
158
|
+
- 不要输出 \`dimension_level_count\` / \`finding_count_by_level\` 字段(框架自己重算)
|
|
159
|
+
|
|
160
|
+
读 SKILL.md(已 inline)→ 模拟执行 → 出 JSON。`;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=prompt-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-builder.js","sourceRoot":"","sources":["../../../../src/doctor/health/prompt-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH,MAAM,UAAU,iBAAiB,CAAC,KAAkB,EAAE,IAA2B;IAC/E,OAAO;QACL,kBAAkB,CAAC,KAAK,CAAC;QACzB,sBAAsB,CAAC,IAAI,CAAC;QAC5B,uBAAuB,EAAE;QACzB,sBAAsB,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC;KAC9C,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjB,CAAC;AAED,8EAA8E;AAC9E,yBAAyB;AACzB,8EAA8E;AAE9E,SAAS,kBAAkB,CAAC,KAAkB;IAC5C,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IAC9E,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC;QAC1C,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACjD,CAAC,CAAC,QAAQ,CAAC;IACb,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC;QACtC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAC1C,CAAC,CAAC,qCAAqC,CAAC;IAC1C,MAAM,aAAa,GAAG,SAAS;QAC7B,CAAC,CAAC,gBAAgB,SAAS,uBAAuB;QAClD,CAAC,CAAC,6BAA6B,CAAC;IAElC,OAAO,UAAU,SAAS;;;;eAIb,SAAS;IACpB,aAAa;;EAEf,YAAY;;;;EAIZ,WAAW;;;;;EAKX,YAAY;OACP,CAAC;AACR,CAAC;AAED,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,SAAS,sBAAsB,CAAC,IAA2B;IACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;QACpB,OAAO,MAAM,GAAG,KAAK,GAAG,CAAC,WAAW,WAAW,GAAG,CAAC,EAAE;EACvD,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IACH,OAAO;;EAEP,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AAC1B,CAAC;AAED,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,SAAS,uBAAuB;IAC9B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA4Be,CAAC;AACzB,CAAC;AAED,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,SAAS,sBAAsB,CAAC,SAAiB,EAAE,IAA2B;IAC5E,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE5D,OAAO;;;;;mBAKU,SAAS;;;;;;;;;;;;;;;;;;;kBAmBV,SAAS;;;;;;;;;;;;;;;;;;;;;2BAqBA,IAAI,CAAC,MAAM;IAClC,SAAS;;;;;;;qCAOwB,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 副作用入口:把 7 个内置维度注册到 dimensionRegistry,把 composer rule
|
|
3
|
+
* 注册到 doctor customRules。
|
|
4
|
+
*
|
|
5
|
+
* CLI doctor.ts 默认动态 import 本文件 → 副作用一次性完成。
|
|
6
|
+
* `--static-only` 会在 CLI 层过滤掉 composer rule,不触发 LLM 审计。
|
|
7
|
+
* 测试 import 各 module 的具名 export 不会触发本文件,保持 registry 干净。
|
|
8
|
+
*
|
|
9
|
+
* 用户自定义维度:在自己的代码里 `registerHealthDimension(spec)`,只要在
|
|
10
|
+
* composer 跑之前注册即可(eg. 在 omk 配置 / plugin 入口里)。
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=register.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/doctor/health/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 副作用入口:把 7 个内置维度注册到 dimensionRegistry,把 composer rule
|
|
3
|
+
* 注册到 doctor customRules。
|
|
4
|
+
*
|
|
5
|
+
* CLI doctor.ts 默认动态 import 本文件 → 副作用一次性完成。
|
|
6
|
+
* `--static-only` 会在 CLI 层过滤掉 composer rule,不触发 LLM 审计。
|
|
7
|
+
* 测试 import 各 module 的具名 export 不会触发本文件,保持 registry 干净。
|
|
8
|
+
*
|
|
9
|
+
* 用户自定义维度:在自己的代码里 `registerHealthDimension(spec)`,只要在
|
|
10
|
+
* composer 跑之前注册即可(eg. 在 omk 配置 / plugin 入口里)。
|
|
11
|
+
*/
|
|
12
|
+
import { registerRule } from '../rules.js';
|
|
13
|
+
import { BUILTIN_HEALTH_DIMENSIONS } from './builtin-dimensions.js';
|
|
14
|
+
import { registerHealthDimension } from './dimension-registry.js';
|
|
15
|
+
import { makeSkillHealthComposer } from './composer.js';
|
|
16
|
+
for (const spec of BUILTIN_HEALTH_DIMENSIONS) {
|
|
17
|
+
registerHealthDimension(spec);
|
|
18
|
+
}
|
|
19
|
+
registerRule(makeSkillHealthComposer());
|
|
20
|
+
//# sourceMappingURL=register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../../src/doctor/health/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAExD,KAAK,MAAM,IAAI,IAAI,yBAAyB,EAAE,CAAC;IAC7C,uBAAuB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AACD,YAAY,CAAC,uBAAuB,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* doctor HTML 报告渲染器。
|
|
3
|
+
*
|
|
4
|
+
* 输出 single-file HTML(JSON inline,CSS/JS 内嵌,无外部依赖),双击可看,
|
|
5
|
+
* 不需 http server。专为 LLM 健康度审计报告设计 — 重点展示 composer group 内的
|
|
6
|
+
* 维度结果,但也兼容显示静态 rule 段。
|
|
7
|
+
*
|
|
8
|
+
* 排序约定:
|
|
9
|
+
* - 维度卡片按 fail → warn → pass → skipped(STATUS_RANK)排
|
|
10
|
+
* - 每个维度卡片内的 finding 按 错误 → 警告 → 建议 排
|
|
11
|
+
* - skill 级别按 outcome (failed / warnings_only / passed) 排
|
|
12
|
+
*
|
|
13
|
+
* 前端交互:
|
|
14
|
+
* - 顶部 filter pills:全部 / 仅失败 / 仅警告 / 仅通过 — 切换时 dim card 显隐
|
|
15
|
+
* - 维度卡片头部点击折叠/展开 findings 区
|
|
16
|
+
*/
|
|
17
|
+
import type { DoctorReport } from '../types/index.js';
|
|
18
|
+
import { type CliLang } from '../cli/i18n.js';
|
|
19
|
+
export declare function renderDoctorReportHtml(report: DoctorReport, lang?: CliLang): string;
|
|
20
|
+
//# sourceMappingURL=html-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-renderer.d.ts","sourceRoot":"","sources":["../../../src/doctor/html-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACV,YAAY,EAGb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAsVpD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,GAAE,OAAc,GAAG,MAAM,CA0BzF"}
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* doctor HTML 报告渲染器。
|
|
3
|
+
*
|
|
4
|
+
* 输出 single-file HTML(JSON inline,CSS/JS 内嵌,无外部依赖),双击可看,
|
|
5
|
+
* 不需 http server。专为 LLM 健康度审计报告设计 — 重点展示 composer group 内的
|
|
6
|
+
* 维度结果,但也兼容显示静态 rule 段。
|
|
7
|
+
*
|
|
8
|
+
* 排序约定:
|
|
9
|
+
* - 维度卡片按 fail → warn → pass → skipped(STATUS_RANK)排
|
|
10
|
+
* - 每个维度卡片内的 finding 按 错误 → 警告 → 建议 排
|
|
11
|
+
* - skill 级别按 outcome (failed / warnings_only / passed) 排
|
|
12
|
+
*
|
|
13
|
+
* 前端交互:
|
|
14
|
+
* - 顶部 filter pills:全部 / 仅失败 / 仅警告 / 仅通过 — 切换时 dim card 显隐
|
|
15
|
+
* - 维度卡片头部点击折叠/展开 findings 区
|
|
16
|
+
*/
|
|
17
|
+
import { CLI_DICT } from '../cli/i18n-dict.js';
|
|
18
|
+
import { tCli } from '../cli/i18n.js';
|
|
19
|
+
const STATUS_RANK = {
|
|
20
|
+
fail: 0, warn: 1, pass: 2, skipped: 3,
|
|
21
|
+
};
|
|
22
|
+
const FINDING_RANK = { '错误': 0, '警告': 1, '建议': 2 };
|
|
23
|
+
function escapeHtml(s) {
|
|
24
|
+
return s
|
|
25
|
+
.replace(/&/g, '&')
|
|
26
|
+
.replace(/</g, '<')
|
|
27
|
+
.replace(/>/g, '>')
|
|
28
|
+
.replace(/"/g, '"')
|
|
29
|
+
.replace(/'/g, ''');
|
|
30
|
+
}
|
|
31
|
+
function renderLabel(result, lang) {
|
|
32
|
+
if (result.labelKey in CLI_DICT)
|
|
33
|
+
return tCli(result.labelKey, lang);
|
|
34
|
+
return result.ruleId;
|
|
35
|
+
}
|
|
36
|
+
function getDimDetail(r) {
|
|
37
|
+
const d = (r.detail ?? {});
|
|
38
|
+
const findings = Array.isArray(d.findings) ? d.findings : [];
|
|
39
|
+
const suggestions = Array.isArray(d.suggestions)
|
|
40
|
+
? d.suggestions.filter((s) => typeof s === 'string')
|
|
41
|
+
: [];
|
|
42
|
+
return {
|
|
43
|
+
findings: [...findings].sort((a, b) => (FINDING_RANK[a.level] ?? 9) - (FINDING_RANK[b.level] ?? 9)),
|
|
44
|
+
suggestions,
|
|
45
|
+
level: typeof d.level === 'string' ? d.level : undefined,
|
|
46
|
+
missing: d.missing === true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function getSummaryDetail(r) {
|
|
50
|
+
if (!r)
|
|
51
|
+
return { topSuggestions: [] };
|
|
52
|
+
const d = (r.detail ?? {});
|
|
53
|
+
return {
|
|
54
|
+
overall: typeof d.overall === 'string' ? d.overall : undefined,
|
|
55
|
+
topSuggestions: Array.isArray(d.topSuggestions)
|
|
56
|
+
? d.topSuggestions.filter((s) => typeof s === 'string')
|
|
57
|
+
: [],
|
|
58
|
+
dimensionLevelCount: typeof d.dimensionLevelCount === 'object' && d.dimensionLevelCount !== null
|
|
59
|
+
? d.dimensionLevelCount
|
|
60
|
+
: undefined,
|
|
61
|
+
findingCountByLevel: typeof d.findingCountByLevel === 'object' && d.findingCountByLevel !== null
|
|
62
|
+
? d.findingCountByLevel
|
|
63
|
+
: undefined,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function renderDimCard(r, lang) {
|
|
67
|
+
const label = renderLabel(r, lang);
|
|
68
|
+
const status = r.status;
|
|
69
|
+
const detail = getDimDetail(r);
|
|
70
|
+
const findingsHtml = detail.findings.length === 0
|
|
71
|
+
? `<div class="empty">${lang === 'zh' ? '无 finding' : 'no findings'}</div>`
|
|
72
|
+
: detail.findings.map((f) => `
|
|
73
|
+
<div class="finding finding-${f.level === '错误' ? 'err' : f.level === '警告' ? 'warn' : 'sug'}">
|
|
74
|
+
<div class="finding-head">
|
|
75
|
+
<span class="finding-level">${escapeHtml(f.level)}</span>
|
|
76
|
+
${f.subtype ? `<span class="finding-subtype">${escapeHtml(f.subtype)}</span>` : ''}
|
|
77
|
+
<span class="finding-desc">${escapeHtml(f.description ?? '')}</span>
|
|
78
|
+
</div>
|
|
79
|
+
${f.evidence ? `<div class="finding-evidence">${escapeHtml(f.evidence)}</div>` : ''}
|
|
80
|
+
</div>`).join('');
|
|
81
|
+
const sugsHtml = detail.suggestions.length === 0 ? '' : `
|
|
82
|
+
<div class="dim-sugs">
|
|
83
|
+
<div class="sugs-title">${lang === 'zh' ? '建议' : 'suggestions'}</div>
|
|
84
|
+
<ul>${detail.suggestions.map((s) => `<li>${escapeHtml(s)}</li>`).join('')}</ul>
|
|
85
|
+
</div>`;
|
|
86
|
+
const dimIdHint = r.detail?.dimensionId ?? r.ruleId.split(':')[1] ?? '';
|
|
87
|
+
return `
|
|
88
|
+
<div class="dim-card status-${status}" data-status="${status}" data-dimid="${escapeHtml(dimIdHint)}">
|
|
89
|
+
<div class="dim-head" onclick="this.parentElement.classList.toggle('open')">
|
|
90
|
+
<span class="dim-status">${escapeHtml(detail.level ?? status)}</span>
|
|
91
|
+
<span class="dim-name">${escapeHtml(label)}</span>
|
|
92
|
+
<span class="dim-counts">
|
|
93
|
+
<span class="badge badge-err">${detail.findings.filter((f) => f.level === '错误').length}</span>
|
|
94
|
+
<span class="badge badge-warn">${detail.findings.filter((f) => f.level === '警告').length}</span>
|
|
95
|
+
<span class="badge badge-sug">${detail.findings.filter((f) => f.level === '建议').length}</span>
|
|
96
|
+
</span>
|
|
97
|
+
<span class="dim-toggle">▸</span>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="dim-body">
|
|
100
|
+
${detail.missing ? `<div class="dim-missing">⚠ ${escapeHtml(r.message)}</div>` : ''}
|
|
101
|
+
<div class="dim-findings">${findingsHtml}</div>
|
|
102
|
+
${sugsHtml}
|
|
103
|
+
</div>
|
|
104
|
+
</div>`;
|
|
105
|
+
}
|
|
106
|
+
function renderStaticRule(r, lang) {
|
|
107
|
+
return `
|
|
108
|
+
<div class="rule-row status-${r.status}">
|
|
109
|
+
<span class="rule-status">${r.status.toUpperCase()}</span>
|
|
110
|
+
<span class="rule-label">${escapeHtml(renderLabel(r, lang))}</span>
|
|
111
|
+
<span class="rule-msg">${escapeHtml(r.message)}</span>
|
|
112
|
+
${r.hint ? `<div class="rule-hint">💡 ${escapeHtml(r.hint)}</div>` : ''}
|
|
113
|
+
</div>`;
|
|
114
|
+
}
|
|
115
|
+
function segmentSkillResults(skill) {
|
|
116
|
+
const staticRules = [];
|
|
117
|
+
const groups = new Map();
|
|
118
|
+
for (const r of skill.results) {
|
|
119
|
+
if (!r.groupId) {
|
|
120
|
+
staticRules.push(r);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
let arr = groups.get(r.groupId);
|
|
124
|
+
if (!arr) {
|
|
125
|
+
arr = [];
|
|
126
|
+
groups.set(r.groupId, arr);
|
|
127
|
+
}
|
|
128
|
+
arr.push(r);
|
|
129
|
+
}
|
|
130
|
+
return { staticRules, groups };
|
|
131
|
+
}
|
|
132
|
+
function renderGroup(groupId, results, lang) {
|
|
133
|
+
const summaryRow = results.find((r) => r.ruleId.endsWith(':_summary'));
|
|
134
|
+
const dimRows = results.filter((r) => !r.ruleId.endsWith(':_summary'));
|
|
135
|
+
dimRows.sort((a, b) => STATUS_RANK[a.status] - STATUS_RANK[b.status]);
|
|
136
|
+
const groupLabel = summaryRow ? renderLabel(summaryRow, lang) : groupId;
|
|
137
|
+
const summary = getSummaryDetail(summaryRow);
|
|
138
|
+
const totalsLine = summary.dimensionLevelCount && summary.findingCountByLevel
|
|
139
|
+
? `<div class="group-totals">
|
|
140
|
+
<span>${lang === 'zh' ? '维度' : 'dims'}: ✗${summary.dimensionLevelCount['不健康'] ?? 0} ⚠${summary.dimensionLevelCount['亚健康'] ?? 0} ✓${summary.dimensionLevelCount['健康'] ?? 0} ⊙${summary.dimensionLevelCount['不适用'] ?? 0}</span>
|
|
141
|
+
<span>findings: ✗${summary.findingCountByLevel['错误'] ?? 0} ⚠${summary.findingCountByLevel['警告'] ?? 0} ·${summary.findingCountByLevel['建议'] ?? 0}</span>
|
|
142
|
+
</div>`
|
|
143
|
+
: '';
|
|
144
|
+
const topSugsHtml = summary.topSuggestions.length === 0 ? '' : `
|
|
145
|
+
<div class="group-top">
|
|
146
|
+
<div class="top-title">★ ${lang === 'zh' ? 'Top 改进建议' : 'Top suggestions'}</div>
|
|
147
|
+
<ol>${summary.topSuggestions.map((s) => `<li>${escapeHtml(s)}</li>`).join('')}</ol>
|
|
148
|
+
</div>`;
|
|
149
|
+
const cardsHtml = dimRows.map((r) => renderDimCard(r, lang)).join('');
|
|
150
|
+
return `
|
|
151
|
+
<section class="group" data-group="${escapeHtml(groupId)}">
|
|
152
|
+
<header class="group-head">
|
|
153
|
+
<h2>${escapeHtml(groupLabel)}${summary.overall ? ` <span class="group-overall">${escapeHtml(summary.overall)}</span>` : ''}</h2>
|
|
154
|
+
${totalsLine}
|
|
155
|
+
</header>
|
|
156
|
+
${topSugsHtml}
|
|
157
|
+
<div class="filter-pills">
|
|
158
|
+
<button class="pill active" data-filter="all">${lang === 'zh' ? '全部' : 'All'}</button>
|
|
159
|
+
<button class="pill" data-filter="fail">${lang === 'zh' ? '仅失败' : 'Fail only'}</button>
|
|
160
|
+
<button class="pill" data-filter="warn">${lang === 'zh' ? '仅警告' : 'Warn only'}</button>
|
|
161
|
+
<button class="pill" data-filter="pass">${lang === 'zh' ? '仅通过' : 'Pass only'}</button>
|
|
162
|
+
<button class="pill" data-filter="skipped">${lang === 'zh' ? '跳过' : 'Skipped'}</button>
|
|
163
|
+
</div>
|
|
164
|
+
<div class="dim-grid">${cardsHtml}</div>
|
|
165
|
+
</section>`;
|
|
166
|
+
}
|
|
167
|
+
function renderSkill(skill, lang) {
|
|
168
|
+
const seg = segmentSkillResults(skill);
|
|
169
|
+
const staticHtml = seg.staticRules.map((r) => renderStaticRule(r, lang)).join('');
|
|
170
|
+
const groupsHtml = [...seg.groups.entries()].map(([gid, results]) => renderGroup(gid, results, lang)).join('');
|
|
171
|
+
return `
|
|
172
|
+
<article class="skill skill-${skill.status}">
|
|
173
|
+
<header class="skill-head">
|
|
174
|
+
<h1>${escapeHtml(skill.skillName)}</h1>
|
|
175
|
+
<span class="skill-status">${skill.status.toUpperCase()}</span>
|
|
176
|
+
<span class="skill-path">${escapeHtml(skill.skillPath)}</span>
|
|
177
|
+
</header>
|
|
178
|
+
${seg.staticRules.length > 0 ? `<div class="static-rules">${staticHtml}</div>` : ''}
|
|
179
|
+
${groupsHtml}
|
|
180
|
+
</article>`;
|
|
181
|
+
}
|
|
182
|
+
function renderHeader(report, lang) {
|
|
183
|
+
const totals = report.totals;
|
|
184
|
+
const isZh = lang === 'zh';
|
|
185
|
+
return `
|
|
186
|
+
<header class="report-head">
|
|
187
|
+
<h1>${isZh ? 'omk doctor 健康检查报告' : 'omk doctor Health Check Report'}</h1>
|
|
188
|
+
<div class="meta">
|
|
189
|
+
<span class="outcome outcome-${report.outcome}">${report.outcome.toUpperCase()}</span>
|
|
190
|
+
<span>${isZh ? 'Skill 总览' : 'Skills'}: ✗${totals.fail} ⚠${totals.warn} ✓${totals.pass}</span>
|
|
191
|
+
<span>${isZh ? '生成于' : 'Generated'}: ${escapeHtml(report.timestamp)}</span>
|
|
192
|
+
<span>${isZh ? '工作目录' : 'CWD'}: <code>${escapeHtml(report.cwd)}</code></span>
|
|
193
|
+
<span>executor: ${escapeHtml(report.executorName)} / ${escapeHtml(report.model)}</span>
|
|
194
|
+
</div>
|
|
195
|
+
</header>`;
|
|
196
|
+
}
|
|
197
|
+
const CSS = `
|
|
198
|
+
:root {
|
|
199
|
+
--c-fail: #dc2626; --c-warn: #d97706; --c-pass: #16a34a; --c-skip: #6b7280;
|
|
200
|
+
--c-fail-bg: #fee2e2; --c-warn-bg: #fef3c7; --c-pass-bg: #dcfce7; --c-skip-bg: #f3f4f6;
|
|
201
|
+
--c-bg: #fafafa; --c-card: #fff; --c-border: #e5e7eb; --c-text: #111;
|
|
202
|
+
--c-muted: #6b7280;
|
|
203
|
+
}
|
|
204
|
+
* { box-sizing: border-box; }
|
|
205
|
+
body { font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
206
|
+
color: var(--c-text); background: var(--c-bg); margin: 0; padding: 0; }
|
|
207
|
+
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .92em;
|
|
208
|
+
background: #f5f5f5; padding: 1px 4px; border-radius: 3px; }
|
|
209
|
+
.container { max-width: 1100px; margin: 0 auto; padding: 24px; }
|
|
210
|
+
|
|
211
|
+
.report-head { background: var(--c-card); padding: 20px 24px; border-radius: 8px;
|
|
212
|
+
box-shadow: 0 1px 3px rgba(0,0,0,.08); margin-bottom: 20px; }
|
|
213
|
+
.report-head h1 { margin: 0 0 8px; font-size: 22px; }
|
|
214
|
+
.report-head .meta { display: flex; gap: 16px; flex-wrap: wrap; color: var(--c-muted); font-size: 13px; }
|
|
215
|
+
.outcome { font-weight: 600; padding: 2px 10px; border-radius: 4px; }
|
|
216
|
+
.outcome-failed { color: var(--c-fail); background: var(--c-fail-bg); }
|
|
217
|
+
.outcome-warnings_only { color: var(--c-warn); background: var(--c-warn-bg); }
|
|
218
|
+
.outcome-passed { color: var(--c-pass); background: var(--c-pass-bg); }
|
|
219
|
+
|
|
220
|
+
.skill { background: var(--c-card); border-radius: 8px; padding: 20px 24px;
|
|
221
|
+
margin-bottom: 16px; box-shadow: 0 1px 3px rgba(0,0,0,.06); }
|
|
222
|
+
.skill-head { display: flex; align-items: center; gap: 12px; margin-bottom: 16px;
|
|
223
|
+
border-bottom: 1px solid var(--c-border); padding-bottom: 12px; }
|
|
224
|
+
.skill-head h1 { margin: 0; font-size: 18px; }
|
|
225
|
+
.skill-status { font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 4px; }
|
|
226
|
+
.skill-fail .skill-status { background: var(--c-fail-bg); color: var(--c-fail); }
|
|
227
|
+
.skill-warn .skill-status { background: var(--c-warn-bg); color: var(--c-warn); }
|
|
228
|
+
.skill-pass .skill-status { background: var(--c-pass-bg); color: var(--c-pass); }
|
|
229
|
+
.skill-path { font-family: ui-monospace, monospace; color: var(--c-muted); font-size: 12px; }
|
|
230
|
+
|
|
231
|
+
.static-rules { margin-bottom: 16px; }
|
|
232
|
+
.rule-row { padding: 8px 12px; border-left: 3px solid; margin-bottom: 4px;
|
|
233
|
+
background: #fafafa; border-radius: 0 4px 4px 0; }
|
|
234
|
+
.rule-row.status-fail { border-color: var(--c-fail); }
|
|
235
|
+
.rule-row.status-warn { border-color: var(--c-warn); }
|
|
236
|
+
.rule-row.status-pass { border-color: var(--c-pass); }
|
|
237
|
+
.rule-row.status-skipped { border-color: var(--c-skip); }
|
|
238
|
+
.rule-status { font-weight: 700; font-size: 11px; margin-right: 8px; }
|
|
239
|
+
.rule-row.status-fail .rule-status { color: var(--c-fail); }
|
|
240
|
+
.rule-row.status-warn .rule-status { color: var(--c-warn); }
|
|
241
|
+
.rule-row.status-pass .rule-status { color: var(--c-pass); }
|
|
242
|
+
.rule-row.status-skipped .rule-status { color: var(--c-skip); }
|
|
243
|
+
.rule-label { font-weight: 600; margin-right: 8px; }
|
|
244
|
+
.rule-msg { color: var(--c-muted); }
|
|
245
|
+
.rule-hint { margin-top: 4px; font-size: 12px; color: var(--c-muted); }
|
|
246
|
+
|
|
247
|
+
.group { margin-top: 20px; padding: 16px; background: #f9fafb; border-radius: 6px; }
|
|
248
|
+
.group-head h2 { margin: 0 0 6px; font-size: 16px; }
|
|
249
|
+
.group-overall { font-size: 12px; padding: 2px 8px; border-radius: 4px;
|
|
250
|
+
background: var(--c-fail-bg); color: var(--c-fail); margin-left: 8px; }
|
|
251
|
+
.group-totals { display: flex; gap: 16px; color: var(--c-muted); font-size: 12px; margin-bottom: 12px; }
|
|
252
|
+
.group-top { background: #fff7ed; border-left: 4px solid var(--c-warn); padding: 12px 16px;
|
|
253
|
+
border-radius: 0 4px 4px 0; margin-bottom: 12px; }
|
|
254
|
+
.group-top .top-title { font-weight: 600; margin-bottom: 4px; }
|
|
255
|
+
.group-top ol { margin: 0; padding-left: 20px; }
|
|
256
|
+
|
|
257
|
+
.filter-pills { display: flex; gap: 6px; margin: 12px 0; }
|
|
258
|
+
.pill { border: 1px solid var(--c-border); background: #fff; padding: 4px 12px;
|
|
259
|
+
border-radius: 999px; cursor: pointer; font-size: 12px; }
|
|
260
|
+
.pill.active { background: var(--c-text); color: #fff; border-color: var(--c-text); }
|
|
261
|
+
|
|
262
|
+
.dim-grid { display: grid; gap: 8px; }
|
|
263
|
+
.dim-card { background: #fff; border: 1px solid var(--c-border); border-left-width: 4px;
|
|
264
|
+
border-radius: 6px; transition: box-shadow .15s; }
|
|
265
|
+
.dim-card:hover { box-shadow: 0 2px 6px rgba(0,0,0,.06); }
|
|
266
|
+
.dim-card.status-fail { border-left-color: var(--c-fail); }
|
|
267
|
+
.dim-card.status-warn { border-left-color: var(--c-warn); }
|
|
268
|
+
.dim-card.status-pass { border-left-color: var(--c-pass); }
|
|
269
|
+
.dim-card.status-skipped { border-left-color: var(--c-skip); }
|
|
270
|
+
.dim-head { display: flex; align-items: center; gap: 12px; padding: 12px 16px;
|
|
271
|
+
cursor: pointer; user-select: none; }
|
|
272
|
+
.dim-status { font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 4px;
|
|
273
|
+
background: #f3f4f6; }
|
|
274
|
+
.status-fail .dim-status { background: var(--c-fail-bg); color: var(--c-fail); }
|
|
275
|
+
.status-warn .dim-status { background: var(--c-warn-bg); color: var(--c-warn); }
|
|
276
|
+
.status-pass .dim-status { background: var(--c-pass-bg); color: var(--c-pass); }
|
|
277
|
+
.status-skipped .dim-status { background: var(--c-skip-bg); color: var(--c-skip); }
|
|
278
|
+
.dim-name { font-weight: 600; flex: 1; }
|
|
279
|
+
.dim-counts { display: flex; gap: 4px; }
|
|
280
|
+
.badge { font-size: 11px; padding: 1px 6px; border-radius: 3px; min-width: 18px;
|
|
281
|
+
text-align: center; font-weight: 600; }
|
|
282
|
+
.badge-err { background: var(--c-fail-bg); color: var(--c-fail); }
|
|
283
|
+
.badge-warn { background: var(--c-warn-bg); color: var(--c-warn); }
|
|
284
|
+
.badge-sug { background: #f3f4f6; color: var(--c-muted); }
|
|
285
|
+
.dim-toggle { color: var(--c-muted); transition: transform .15s; }
|
|
286
|
+
.dim-card.open .dim-toggle { transform: rotate(90deg); }
|
|
287
|
+
|
|
288
|
+
.dim-body { display: none; padding: 0 16px 16px; border-top: 1px solid var(--c-border); }
|
|
289
|
+
.dim-card.open .dim-body { display: block; }
|
|
290
|
+
.dim-missing { background: var(--c-warn-bg); color: var(--c-warn); padding: 8px 12px;
|
|
291
|
+
border-radius: 4px; margin: 12px 0; font-size: 13px; }
|
|
292
|
+
|
|
293
|
+
.dim-findings { margin-top: 12px; }
|
|
294
|
+
.finding { margin-bottom: 8px; padding: 10px 12px; border-radius: 4px; background: #fafafa;
|
|
295
|
+
border-left: 3px solid; }
|
|
296
|
+
.finding-err { border-color: var(--c-fail); }
|
|
297
|
+
.finding-warn { border-color: var(--c-warn); }
|
|
298
|
+
.finding-sug { border-color: var(--c-skip); }
|
|
299
|
+
.finding-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
|
300
|
+
.finding-level { font-size: 11px; font-weight: 700; padding: 1px 8px; border-radius: 3px; }
|
|
301
|
+
.finding-err .finding-level { background: var(--c-fail-bg); color: var(--c-fail); }
|
|
302
|
+
.finding-warn .finding-level { background: var(--c-warn-bg); color: var(--c-warn); }
|
|
303
|
+
.finding-sug .finding-level { background: #f3f4f6; color: var(--c-muted); }
|
|
304
|
+
.finding-subtype { font-size: 11px; padding: 1px 8px; background: #fff; border: 1px solid var(--c-border);
|
|
305
|
+
border-radius: 3px; color: var(--c-muted); }
|
|
306
|
+
.finding-desc { flex: 1; }
|
|
307
|
+
.finding-evidence { margin-top: 4px; font-family: ui-monospace, monospace; font-size: 12px;
|
|
308
|
+
color: var(--c-muted); padding-left: 8px; border-left: 2px solid var(--c-border); }
|
|
309
|
+
|
|
310
|
+
.dim-sugs { margin-top: 12px; padding: 8px 12px; background: #f0f9ff; border-radius: 4px; }
|
|
311
|
+
.dim-sugs .sugs-title { font-weight: 600; font-size: 12px; color: var(--c-muted); margin-bottom: 4px; }
|
|
312
|
+
.dim-sugs ul { margin: 0; padding-left: 20px; }
|
|
313
|
+
.dim-sugs li { font-size: 13px; }
|
|
314
|
+
|
|
315
|
+
.empty { color: var(--c-muted); font-style: italic; padding: 8px 0; }
|
|
316
|
+
`;
|
|
317
|
+
const JS = `
|
|
318
|
+
(function() {
|
|
319
|
+
// Filter pills: hide dim cards not matching filter (within same group)
|
|
320
|
+
document.querySelectorAll('.group').forEach(function(group) {
|
|
321
|
+
var pills = group.querySelectorAll('.pill');
|
|
322
|
+
pills.forEach(function(pill) {
|
|
323
|
+
pill.addEventListener('click', function() {
|
|
324
|
+
pills.forEach(function(p) { p.classList.remove('active'); });
|
|
325
|
+
pill.classList.add('active');
|
|
326
|
+
var filter = pill.getAttribute('data-filter');
|
|
327
|
+
group.querySelectorAll('.dim-card').forEach(function(card) {
|
|
328
|
+
var status = card.getAttribute('data-status');
|
|
329
|
+
card.style.display = (filter === 'all' || filter === status) ? '' : 'none';
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// Auto-open dim cards with status fail/warn (collapsed by default for pass/skipped)
|
|
336
|
+
document.querySelectorAll('.dim-card.status-fail').forEach(function(c) { c.classList.add('open'); });
|
|
337
|
+
})();
|
|
338
|
+
`;
|
|
339
|
+
export function renderDoctorReportHtml(report, lang = 'zh') {
|
|
340
|
+
// 按 outcome 排序 skill: failed > warnings > passed
|
|
341
|
+
const skillsSorted = [...report.skills].sort((a, b) => {
|
|
342
|
+
const rank = { fail: 0, warn: 1, pass: 2 };
|
|
343
|
+
return (rank[a.status] ?? 9) - (rank[b.status] ?? 9);
|
|
344
|
+
});
|
|
345
|
+
const skillsHtml = skillsSorted.map((s) => renderSkill(s, lang)).join('');
|
|
346
|
+
const dataInline = JSON.stringify(report);
|
|
347
|
+
const title = lang === 'zh' ? 'omk doctor 健康检查报告' : 'omk doctor Health Check Report';
|
|
348
|
+
return `<!DOCTYPE html>
|
|
349
|
+
<html lang="${lang}">
|
|
350
|
+
<head>
|
|
351
|
+
<meta charset="utf-8">
|
|
352
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
353
|
+
<title>${escapeHtml(title)}</title>
|
|
354
|
+
<style>${CSS}</style>
|
|
355
|
+
</head>
|
|
356
|
+
<body>
|
|
357
|
+
<div class="container">
|
|
358
|
+
${renderHeader(report, lang)}
|
|
359
|
+
${skillsHtml}
|
|
360
|
+
</div>
|
|
361
|
+
<script type="application/json" id="doctor-report-data">${escapeHtml(dataInline)}</script>
|
|
362
|
+
<script>${JS}</script>
|
|
363
|
+
</body>
|
|
364
|
+
</html>`;
|
|
365
|
+
}
|
|
366
|
+
//# sourceMappingURL=html-renderer.js.map
|