eduevidence 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +506 -0
- package/README.zh-CN.md +434 -0
- package/SKILL.md +195 -0
- package/bin/eduevidence.js +127 -0
- package/domains/education/manifest.json +183 -0
- package/domains/education/outcome_taxonomy.json +127 -0
- package/domains/manifest.json +26 -0
- package/domains/policy/frame.schema.json +234 -0
- package/domains/policy/manifest.json +10 -0
- package/domains/policy/methodology_checklist.json +109 -0
- package/domains/policy/outcome_taxonomy.json +53 -0
- package/domains/policy/references/causal-identification.md +45 -0
- package/domains/policy/references/cost-evidence.md +44 -0
- package/domains/policy/references/equity.md +42 -0
- package/domains/policy/references/evidence-hierarchy.md +41 -0
- package/domains/policy/references/implementation-evidence.md +47 -0
- package/eduevidence_cli.py +26 -0
- package/engine/__init__.py +11 -0
- package/engine/__pycache__/__init__.cpython-312.pyc +0 -0
- package/engine/__pycache__/analysis.cpython-312.pyc +0 -0
- package/engine/__pycache__/bias.cpython-312.pyc +0 -0
- package/engine/__pycache__/briefs.cpython-312.pyc +0 -0
- package/engine/__pycache__/capabilities.cpython-312.pyc +0 -0
- package/engine/__pycache__/citation_check.cpython-312.pyc +0 -0
- package/engine/__pycache__/contracts.cpython-312.pyc +0 -0
- package/engine/__pycache__/datasets.cpython-312.pyc +0 -0
- package/engine/__pycache__/events.cpython-312.pyc +0 -0
- package/engine/__pycache__/evidence_graph.cpython-312.pyc +0 -0
- package/engine/__pycache__/evidence_review.cpython-312.pyc +0 -0
- package/engine/__pycache__/evidencecore.cpython-312.pyc +0 -0
- package/engine/__pycache__/gap_lens.cpython-312.pyc +0 -0
- package/engine/__pycache__/gaps.cpython-312.pyc +0 -0
- package/engine/__pycache__/graph_store.cpython-312.pyc +0 -0
- package/engine/__pycache__/graph_validate.cpython-312.pyc +0 -0
- package/engine/__pycache__/ids.cpython-312.pyc +0 -0
- package/engine/__pycache__/library.cpython-312.pyc +0 -0
- package/engine/__pycache__/library_builtin.cpython-312.pyc +0 -0
- package/engine/__pycache__/living.cpython-312.pyc +0 -0
- package/engine/__pycache__/log.cpython-312.pyc +0 -0
- package/engine/__pycache__/meta_analysis.cpython-312.pyc +0 -0
- package/engine/__pycache__/meta_synthesis.cpython-312.pyc +0 -0
- package/engine/__pycache__/migration.cpython-312.pyc +0 -0
- package/engine/__pycache__/mode_router.cpython-312.pyc +0 -0
- package/engine/__pycache__/paths.cpython-312.pyc +0 -0
- package/engine/__pycache__/pilot.cpython-312.pyc +0 -0
- package/engine/__pycache__/planner.cpython-312.pyc +0 -0
- package/engine/__pycache__/project.cpython-312.pyc +0 -0
- package/engine/__pycache__/projections.cpython-312.pyc +0 -0
- package/engine/__pycache__/robustness.cpython-312.pyc +0 -0
- package/engine/__pycache__/run.cpython-312.pyc +0 -0
- package/engine/__pycache__/semantics.cpython-312.pyc +0 -0
- package/engine/__pycache__/study_design.cpython-312.pyc +0 -0
- package/engine/__pycache__/synthesis.cpython-312.pyc +0 -0
- package/engine/__pycache__/tribunal.cpython-312.pyc +0 -0
- package/engine/__pycache__/update.cpython-312.pyc +0 -0
- package/engine/__pycache__/versions.cpython-312.pyc +0 -0
- package/engine/analysis.py +308 -0
- package/engine/bias.py +178 -0
- package/engine/briefs.py +106 -0
- package/engine/capabilities.py +99 -0
- package/engine/citation_check.py +192 -0
- package/engine/contracts.py +117 -0
- package/engine/datasets.py +165 -0
- package/engine/events.py +67 -0
- package/engine/evidence_graph.py +571 -0
- package/engine/evidence_review.py +88 -0
- package/engine/evidencecore.py +182 -0
- package/engine/gap_lens.py +132 -0
- package/engine/gaps.py +169 -0
- package/engine/graph_store.py +335 -0
- package/engine/graph_validate.py +87 -0
- package/engine/ids.py +77 -0
- package/engine/library.py +268 -0
- package/engine/library_builtin.py +301 -0
- package/engine/living.py +671 -0
- package/engine/log.py +39 -0
- package/engine/meta_analysis.py +333 -0
- package/engine/meta_synthesis.py +111 -0
- package/engine/migration.py +397 -0
- package/engine/mode_router.py +72 -0
- package/engine/paths.py +15 -0
- package/engine/pilot.py +368 -0
- package/engine/planner.py +126 -0
- package/engine/project.py +118 -0
- package/engine/projections.py +240 -0
- package/engine/robustness.py +109 -0
- package/engine/run.py +85 -0
- package/engine/semantics.py +135 -0
- package/engine/study_design.py +87 -0
- package/engine/synthesis.py +187 -0
- package/engine/tribunal.py +408 -0
- package/engine/update.py +113 -0
- package/engine/versions.py +12 -0
- package/install.sh +510 -0
- package/integrations/__init__.py +1 -0
- package/integrations/__pycache__/__init__.cpython-312.pyc +0 -0
- package/integrations/__pycache__/agent_mcp.cpython-312.pyc +0 -0
- package/integrations/__pycache__/smart_web_fetch.cpython-312.pyc +0 -0
- package/integrations/agent_mcp.py +856 -0
- package/integrations/smart_web_fetch.py +59 -0
- package/package.json +50 -0
- package/pyproject.toml +55 -0
- package/references/applicability-policy.md +88 -0
- package/references/education-framing.md +132 -0
- package/references/effect_size_formulas.md +35 -0
- package/references/evaluation-design.md +111 -0
- package/references/evidence-quality.md +79 -0
- package/references/grade_framework.md +29 -0
- package/references/intervention-design.md +98 -0
- package/references/methodology-audit.md +103 -0
- package/references/outcome-taxonomy.md +106 -0
- package/references/retrieval-protocol.md +142 -0
- package/references/skeptic-protocol.md +93 -0
- package/references/social_science_pitfalls.md +48 -0
- package/references/source-validity.md +140 -0
- package/references/tribunal-policy.md +112 -0
- package/references/wwc_standards.md +29 -0
- package/retrieval/__init__.py +1 -0
- package/retrieval/__pycache__/__init__.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/corpus_store.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/dedupe.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/failures.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/fetch.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/search.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/source.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/validate.cpython-312.pyc +0 -0
- package/retrieval/corpus_store.py +181 -0
- package/retrieval/dedupe.py +127 -0
- package/retrieval/failures.py +90 -0
- package/retrieval/fetch.py +435 -0
- package/retrieval/search.py +493 -0
- package/retrieval/source.py +160 -0
- package/retrieval/validate.py +257 -0
- package/schemas/agent-mcp-approval.schema.json +57 -0
- package/schemas/chart-spec.schema.json +88 -0
- package/schemas/cross-model-review.schema.json +28 -0
- package/schemas/education-frame.schema.json +106 -0
- package/schemas/evaluation.schema.json +35 -0
- package/schemas/evidence.schema.json +81 -0
- package/schemas/fetch-result.schema.json +119 -0
- package/schemas/intervention.schema.json +46 -0
- package/schemas/methodology.schema.json +102 -0
- package/schemas/report-result.schema.json +381 -0
- package/schemas/report-spec.schema.json +130 -0
- package/schemas/source.schema.json +311 -0
- package/schemas/v2/analysis-plan.schema.json +28 -0
- package/schemas/v2/analysis-run.schema.json +33 -0
- package/schemas/v2/claim.schema.json +26 -0
- package/schemas/v2/dataset-asset.schema.json +40 -0
- package/schemas/v2/decision-snapshot.schema.json +53 -0
- package/schemas/v2/evidence-link.schema.json +38 -0
- package/schemas/v2/finding.schema.json +47 -0
- package/schemas/v2/graph-revision.schema.json +30 -0
- package/schemas/v2/knowledge-gap.schema.json +40 -0
- package/schemas/v2/methodology-audit.schema.json +30 -0
- package/schemas/v2/outcome.schema.json +18 -0
- package/schemas/v2/project.schema.json +31 -0
- package/schemas/v2/research-intent.schema.json +24 -0
- package/schemas/v2/run.schema.json +43 -0
- package/schemas/v2/source.schema.json +24 -0
- package/schemas/v2/study-design.schema.json +67 -0
- package/schemas/v2/study.schema.json +37 -0
- package/schemas/v3/pilot-outcome.schema.json +132 -0
- package/schemas/v3/run-manifest.schema.json +193 -0
- package/schemas/v3/synthesis.schema.json +86 -0
- package/schemas/v4/drift-report.schema.json +66 -0
- package/schemas/v4/evidence-library.schema.json +42 -0
- package/schemas/v4/living-subscription.schema.json +55 -0
- package/schemas/v4/meta-analysis.schema.json +152 -0
- package/schemas/verdict.schema.json +56 -0
- package/scripts/__init__.py +0 -0
- package/scripts/__pycache__/__init__.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_evaluator.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_judge.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_routing.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_v2.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_v3.cpython-312.pyc +0 -0
- package/scripts/__pycache__/build_result.cpython-312.pyc +0 -0
- package/scripts/__pycache__/claim_audit.cpython-312.pyc +0 -0
- package/scripts/__pycache__/complexity_gate.cpython-312.pyc +0 -0
- package/scripts/__pycache__/compute_confidence.cpython-312.pyc +0 -0
- package/scripts/__pycache__/dashboard_server.cpython-312.pyc +0 -0
- package/scripts/__pycache__/did_regression.cpython-312.pyc +0 -0
- package/scripts/__pycache__/effect_calculator.cpython-312.pyc +0 -0
- package/scripts/__pycache__/evidence_matrix.cpython-312.pyc +0 -0
- package/scripts/__pycache__/evidence_score.cpython-312.pyc +0 -0
- package/scripts/__pycache__/evidence_semantics.cpython-312.pyc +0 -0
- package/scripts/__pycache__/fetch_benchmark.cpython-312.pyc +0 -0
- package/scripts/__pycache__/lint_report_layout.cpython-312.pyc +0 -0
- package/scripts/__pycache__/orchestrator.cpython-312.pyc +0 -0
- package/scripts/__pycache__/pre_verdict_gate.cpython-312.pyc +0 -0
- package/scripts/__pycache__/recompute_demo_quality.cpython-312.pyc +0 -0
- package/scripts/__pycache__/render_report.cpython-312.pyc +0 -0
- package/scripts/__pycache__/render_report_html.cpython-312.pyc +0 -0
- package/scripts/__pycache__/run_workspace.cpython-312.pyc +0 -0
- package/scripts/__pycache__/skill_lint.cpython-312.pyc +0 -0
- package/scripts/__pycache__/startup_probe.cpython-312.pyc +0 -0
- package/scripts/__pycache__/sync_killer_demo_report.cpython-312.pyc +0 -0
- package/scripts/__pycache__/test_adversarial_empirical.cpython-312-pytest-9.0.2.pyc +0 -0
- package/scripts/__pycache__/test_adversarial_empirical.cpython-312-pytest-9.1.1.pyc +0 -0
- package/scripts/__pycache__/validate_schema.cpython-312.pyc +0 -0
- package/scripts/audit_dois.py +292 -0
- package/scripts/bake_pack.sh +37 -0
- package/scripts/benchmark.py +183 -0
- package/scripts/benchmark_evaluator.py +371 -0
- package/scripts/benchmark_judge.py +535 -0
- package/scripts/benchmark_routing.py +120 -0
- package/scripts/benchmark_v2.py +304 -0
- package/scripts/benchmark_v3.py +552 -0
- package/scripts/build_esl_artifacts.py +1921 -0
- package/scripts/build_evidence_library.py +307 -0
- package/scripts/build_killer_demo.py +295 -0
- package/scripts/build_result.py +311 -0
- package/scripts/check_version_consistency.py +96 -0
- package/scripts/citation_check.py +123 -0
- package/scripts/claim_audit.py +157 -0
- package/scripts/complexity_gate.py +180 -0
- package/scripts/compute_confidence.py +176 -0
- package/scripts/dashboard_server.py +536 -0
- package/scripts/did_regression.py +315 -0
- package/scripts/effect_calculator.py +99 -0
- package/scripts/enrich_projects_human_and_lieflat.py +315 -0
- package/scripts/evidence_matrix.py +129 -0
- package/scripts/evidence_score.py +234 -0
- package/scripts/evidence_semantics.py +87 -0
- package/scripts/fetch_benchmark.py +177 -0
- package/scripts/generate_metrics.py +99 -0
- package/scripts/generate_new_projects.py +686 -0
- package/scripts/generate_promo.py +192 -0
- package/scripts/lint_report_layout.py +182 -0
- package/scripts/orchestrator.py +1456 -0
- package/scripts/pre_verdict_gate.py +513 -0
- package/scripts/quickstart.py +121 -0
- package/scripts/rebake_all_5themes.py +88 -0
- package/scripts/recompute_demo_quality.py +205 -0
- package/scripts/render_report.py +270 -0
- package/scripts/render_report_html.py +356 -0
- package/scripts/retraction_watch.py +110 -0
- package/scripts/run_workspace.py +337 -0
- package/scripts/serve_web.py +54 -0
- package/scripts/skill_lint.py +150 -0
- package/scripts/startup_probe.py +265 -0
- package/scripts/sync_killer_demo_report.py +270 -0
- package/scripts/test_adversarial_empirical.py +541 -0
- package/scripts/validate_schema.py +256 -0
- package/skill/agents/education-planner.md +80 -0
- package/skill/agents/evaluation-designer.md +74 -0
- package/skill/agents/evidence-analyst.md +106 -0
- package/skill/agents/evidence-judge.md +111 -0
- package/skill/agents/evidence-retriever.md +80 -0
- package/skill/agents/intervention-designer.md +82 -0
- package/skill/agents/method-reviewer.md +104 -0
- package/skill/agents/skeptic.md +89 -0
- package/skill/sub-skills/aihot-trend-analysis/SKILL.md +31 -0
- package/skill/sub-skills/contradiction-analysis/SKILL.md +17 -0
- package/skill/sub-skills/data-analysis/SKILL.md +23 -0
- package/skill/sub-skills/ethics-review/SKILL.md +25 -0
- package/skill/sub-skills/evidence-extraction/SKILL.md +19 -0
- package/skill/sub-skills/evidence-review/SKILL.md +18 -0
- package/skill/sub-skills/gap-analysis/SKILL.md +25 -0
- package/skill/sub-skills/literature-review/SKILL.md +21 -0
- package/skill/sub-skills/methodology-audit/SKILL.md +20 -0
- package/skill/sub-skills/report-generation/SKILL.md +51 -0
- package/skill/sub-skills/research-planning/SKILL.md +21 -0
- package/skill/sub-skills/study-design/SKILL.md +16 -0
- package/skill/task-briefs/adjudicate.md +17 -0
- package/skill/task-briefs/audit.md +15 -0
- package/skill/task-briefs/challenge.md +15 -0
- package/skill/task-briefs/evaluate.md +13 -0
- package/skill/task-briefs/extract.md +16 -0
- package/skill/task-briefs/frame.md +17 -0
- package/skill/task-briefs/intervene.md +14 -0
- package/skill/task-briefs/present.md +16 -0
- package/skill/task-briefs/retrieve.md +15 -0
- package/visualization/eduevidence-report/assets/base.css +337 -0
- package/visualization/eduevidence-report/motion/motion.css +157 -0
- package/visualization/eduevidence-report/motion/motion.js +107 -0
- package/visualization/eduevidence-report/references/bilingual-style.md +7 -0
- package/visualization/eduevidence-report/references/component-catalog.md +145 -0
- package/visualization/eduevidence-report/references/evidence-expansion.md +65 -0
- package/visualization/eduevidence-report/references/full-report-outline.md +86 -0
- package/visualization/eduevidence-report/references/layout-constraints.md +63 -0
- package/visualization/eduevidence-report/references/lieflat-composition.md +79 -0
- package/visualization/eduevidence-report/references/motion-system.md +31 -0
- package/visualization/eduevidence-report/schemas/adapter-envelope.schema.json +22 -0
- package/visualization/eduevidence-report/schemas/visual-layout.schema.json +87 -0
- package/visualization/eduevidence-report/scripts/__pycache__/adapter_contract.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_artifact_manifest.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_charts.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_figures.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_infographics.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_report.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/charts_data.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/lieflat_engine.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/zh_labels.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/adapter_contract.py +72 -0
- package/visualization/eduevidence-report/scripts/build_artifact_manifest.py +70 -0
- package/visualization/eduevidence-report/scripts/build_charts.py +283 -0
- package/visualization/eduevidence-report/scripts/build_figures.py +515 -0
- package/visualization/eduevidence-report/scripts/build_infographics.py +268 -0
- package/visualization/eduevidence-report/scripts/build_report.py +3211 -0
- package/visualization/eduevidence-report/scripts/charts_data.py +617 -0
- package/visualization/eduevidence-report/scripts/check_mobile_layout.js +220 -0
- package/visualization/eduevidence-report/scripts/lieflat_engine.py +852 -0
- package/visualization/eduevidence-report/scripts/zh_labels.py +245 -0
- package/visualization/eduevidence-report/themes/academic.css +94 -0
- package/visualization/eduevidence-report/themes/claude.css +96 -0
- package/visualization/eduevidence-report/themes/datalab-dark.css +147 -0
- package/visualization/eduevidence-report/themes/datalab.css +151 -0
- package/visualization/eduevidence-report/themes/presentation.css +140 -0
package/engine/update.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Close the Full Research Cycle: validated project analysis → graph evidence.
|
|
2
|
+
|
|
3
|
+
One atomic mutation: a project-local Source (portable project:// locator,
|
|
4
|
+
derived from DatasetAsset + AnalysisRun provenance), one Study, its
|
|
5
|
+
Findings, MethodologyAudit, and contextual Claims/Links commit in ONE graph
|
|
6
|
+
revision — never one revision per Finding.
|
|
7
|
+
|
|
8
|
+
AnalysisRun.status must be `validated`; otherwise ANALYSIS_INVALID is
|
|
9
|
+
returned and the graph stays unchanged. The engine derives the Source; the
|
|
10
|
+
caller supplies schema-valid Study/Findings/Audit/Claims/Links.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from datetime import datetime, timezone
|
|
16
|
+
|
|
17
|
+
from engine.contracts import validate_record
|
|
18
|
+
from engine.graph_store import GraphStore, GraphMutation, GraphRevision
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _now_iso() -> str:
|
|
22
|
+
return datetime.now(timezone.utc).isoformat()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def project_study_mutation(*, project: ProjectWorkspace,
|
|
26
|
+
design: dict,
|
|
27
|
+
dataset_asset: dict,
|
|
28
|
+
analysis_run: dict,
|
|
29
|
+
study: dict,
|
|
30
|
+
findings: list[dict],
|
|
31
|
+
methodology_audit: dict,
|
|
32
|
+
claims: list[dict],
|
|
33
|
+
links: list[dict]) -> GraphMutation:
|
|
34
|
+
"""Build the bundle mutation; raises ValueError on invalid inputs.
|
|
35
|
+
|
|
36
|
+
The derived project-local Source carries a portable `project://` locator
|
|
37
|
+
referencing the dataset; raw filesystem paths stay provenance metadata.
|
|
38
|
+
"""
|
|
39
|
+
if analysis_run.get("status") != "validated":
|
|
40
|
+
raise ValueError(
|
|
41
|
+
f"ANALYSIS_INVALID: AnalysisRun {analysis_run.get('analysis_run_id')} "
|
|
42
|
+
f"status {analysis_run.get('status')!r} is not 'validated'; graph "
|
|
43
|
+
f"unchanged")
|
|
44
|
+
|
|
45
|
+
source_id = f"SRC-{dataset_asset['dataset_id']}"
|
|
46
|
+
source = {
|
|
47
|
+
"source_id": source_id,
|
|
48
|
+
"origin": "project",
|
|
49
|
+
"source_type": "project_study",
|
|
50
|
+
"canonical_locator": (
|
|
51
|
+
f"project://{project.project_id}/datasets/{dataset_asset['dataset_id']}"),
|
|
52
|
+
"validation_status": "valid",
|
|
53
|
+
"content_hash": dataset_asset["content_hash"],
|
|
54
|
+
"extensions": {
|
|
55
|
+
"dataset_id": dataset_asset["dataset_id"],
|
|
56
|
+
"design_id": design["design_id"],
|
|
57
|
+
"analysis_run_id": analysis_run["analysis_run_id"],
|
|
58
|
+
"provenance": {
|
|
59
|
+
"provider": (analysis_run.get("extensions") or {}).get("provider"),
|
|
60
|
+
"software": (analysis_run.get("extensions") or {}).get("software"),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
errors = validate_record("source", source)
|
|
65
|
+
if errors:
|
|
66
|
+
raise ValueError(f"derived project source invalid: {errors}")
|
|
67
|
+
|
|
68
|
+
# validate the whole bundle before touching the store
|
|
69
|
+
for label, schema, rec in (
|
|
70
|
+
("study", "study", study),
|
|
71
|
+
("audit", "methodology-audit", methodology_audit),
|
|
72
|
+
):
|
|
73
|
+
errs = validate_record(schema, rec)
|
|
74
|
+
if errs:
|
|
75
|
+
raise ValueError(f"{label} invalid: {errs}")
|
|
76
|
+
for f in findings:
|
|
77
|
+
errs = validate_record("finding", f)
|
|
78
|
+
if errs:
|
|
79
|
+
raise ValueError(f"finding {f.get('finding_id')} invalid: {errs}")
|
|
80
|
+
for c in claims:
|
|
81
|
+
errs = validate_record("claim", c)
|
|
82
|
+
if errs:
|
|
83
|
+
raise ValueError(f"claim {c.get('claim_id')} invalid: {errs}")
|
|
84
|
+
for l in links:
|
|
85
|
+
errs = validate_record("evidence-link", l)
|
|
86
|
+
if errs:
|
|
87
|
+
raise ValueError(f"evidence_link {l.get('evidence_link_id')} invalid: {errs}")
|
|
88
|
+
|
|
89
|
+
return GraphMutation(
|
|
90
|
+
upserts={
|
|
91
|
+
"sources": [source],
|
|
92
|
+
"studies": [study],
|
|
93
|
+
"findings": findings,
|
|
94
|
+
"audits": [methodology_audit],
|
|
95
|
+
"claims": claims,
|
|
96
|
+
"evidence_links": links,
|
|
97
|
+
},
|
|
98
|
+
retire_ids={},
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def commit_project_study(*, store: GraphStore, run_id: str,
|
|
103
|
+
design: dict, dataset_asset: dict,
|
|
104
|
+
analysis_run: dict, study: dict,
|
|
105
|
+
findings: list[dict], methodology_audit: dict,
|
|
106
|
+
claims: list[dict], links: list[dict]) -> GraphRevision:
|
|
107
|
+
"""Validate the bundle and commit it as exactly ONE graph revision."""
|
|
108
|
+
mutation = project_study_mutation(
|
|
109
|
+
project=store.project, design=design, dataset_asset=dataset_asset,
|
|
110
|
+
analysis_run=analysis_run, study=study, findings=findings,
|
|
111
|
+
methodology_audit=methodology_audit, claims=claims, links=links)
|
|
112
|
+
return store.commit(run_id=run_id, reason="project study evidence",
|
|
113
|
+
mutation=mutation)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Version pins for the V2 Research Engine.
|
|
2
|
+
|
|
3
|
+
Policy versions are frozen identifiers, not free-form strings: changing a
|
|
4
|
+
policy requires a new version, never silent mutation of an existing one.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
ENGINE_VERSION = "5.2.0"
|
|
8
|
+
GRAPH_SCHEMA_VERSION = "2.0"
|
|
9
|
+
SOURCE_VALIDATION_POLICY_VERSION = "2026-08-12.v2"
|
|
10
|
+
METHODOLOGY_POLICY_VERSION = "2026-08-12.v2"
|
|
11
|
+
CONFIDENCE_POLICY_VERSION = "2026-08-12.v3"
|
|
12
|
+
REPORT_CONTRACT_VERSION = "3.0"
|
package/install.sh
ADDED
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# EduEvidence 一键安装脚本(macOS / Linux)
|
|
3
|
+
#
|
|
4
|
+
# 供应链提示(E7):远程执行请优先走「clone + 本地审阅」路径——
|
|
5
|
+
# git clone --depth 1 https://github.com/37chengshan/eduevidence
|
|
6
|
+
# cd eduevidence && bash install.sh
|
|
7
|
+
# 若必须 curl 直跑,建议固定到具体 commit 并先人工审阅:
|
|
8
|
+
# curl -fsSL https://raw.githubusercontent.com/37chengshan/eduevidence/<commit>/install.sh -o install.sh
|
|
9
|
+
#
|
|
10
|
+
# 副作用披露:本脚本会 (a) 创建 Python venv 并安装依赖;
|
|
11
|
+
# (b) 写入 $HOME/.eduevidence/env(AGENT_MCP_INSTALLED=1 声明);
|
|
12
|
+
# (c) --skill 模式在所选宿主目录写入 skill 文件(覆盖前自动备份)。
|
|
13
|
+
#
|
|
14
|
+
# 用法:
|
|
15
|
+
# bash install.sh # 本地安装:venv + 依赖 + 自检 + 测试(等价 --dev)
|
|
16
|
+
# bash install.sh --dev # 同上(向后兼容,默认行为)
|
|
17
|
+
# bash install.sh --skill # 交互式安装为 AI Agent Skill(选择宿主 Agent)
|
|
18
|
+
# bash install.sh --list-hosts # 显示支持的宿主 Agent 与 Skill 落点
|
|
19
|
+
# bash install.sh --dry-run # 只预览将执行的变更,不写入任何文件
|
|
20
|
+
# bash install.sh --skill --dry-run # 预览 Skill 安装(仍会交互选择宿主)
|
|
21
|
+
# bash install.sh --skill --host claude # 非交互:安装到指定宿主
|
|
22
|
+
# bash install.sh --skill --host all # 非交互:安装到全部宿主
|
|
23
|
+
# bash install.sh --skill --dest ~/.cursor/skills # 非交互:自定义 skill 根目录
|
|
24
|
+
# bash install.sh --skill --skill-only --host claude # 仅复制 Skill,跳过 venv/pytest
|
|
25
|
+
set -euo pipefail
|
|
26
|
+
|
|
27
|
+
REPO_URL="https://github.com/37chengshan/eduevidence"
|
|
28
|
+
SKILL_NAME="eduevidence"
|
|
29
|
+
# Skill 本体(运行协议 + 确定性脚本 + 检索/集成层 + 展示层)。
|
|
30
|
+
# retrieval/ 与 integrations/ 会被 scripts/ 直接 import;visualization/ 负责最终 HTML 渲染。
|
|
31
|
+
SKILL_PAYLOAD=(SKILL.md engine domains skill references schemas scripts retrieval integrations visualization)
|
|
32
|
+
# Agent MCP 声明文件:安装完成后写入 AGENT_MCP_INSTALLED=1,供
|
|
33
|
+
# integrations/agent_mcp.py 作为 env 后备来源读取(真实环境变量优先于该文件)。
|
|
34
|
+
AGENT_MCP_ENV_FILE="${AGENT_MCP_ENV_FILE:-$HOME/.eduevidence/env}"
|
|
35
|
+
|
|
36
|
+
# ---------- curl 远程执行支持 ----------
|
|
37
|
+
# 用法: bash -c "$(curl -fsSL https://raw.githubusercontent.com/37chengshan/eduevidence/main/install.sh)"
|
|
38
|
+
# 脚本不在仓库内运行时(无 SKILL.md),自动 clone 仓库到 ./eduevidence 并进入。
|
|
39
|
+
if [ ! -f "SKILL.md" ]; then
|
|
40
|
+
echo "==> 未在 EduEvidence 仓库内,自动克隆仓库…"
|
|
41
|
+
if command -v git >/dev/null 2>&1; then
|
|
42
|
+
git clone --depth 1 "$REPO_URL" eduevidence
|
|
43
|
+
cd eduevidence
|
|
44
|
+
else
|
|
45
|
+
echo "ERROR: 未找到 git,请先安装 git 或手动 clone 仓库" >&2
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# ---------- 参数解析 ----------
|
|
51
|
+
INSTALL_DEV=""
|
|
52
|
+
HAS_DEV_FLAG=0
|
|
53
|
+
MODE="local" # local | skill | list
|
|
54
|
+
DRY_RUN=0
|
|
55
|
+
HOST_CHOICE=""
|
|
56
|
+
DEST_ROOT=""
|
|
57
|
+
SKILL_ONLY=0
|
|
58
|
+
while [ $# -gt 0 ]; do
|
|
59
|
+
case "$1" in
|
|
60
|
+
--dev) INSTALL_DEV="--dev"; HAS_DEV_FLAG=1; shift ;;
|
|
61
|
+
--skill) MODE="skill"; shift ;;
|
|
62
|
+
--skill-only) SKILL_ONLY=1; MODE="skill"; shift ;;
|
|
63
|
+
--list-hosts) MODE="list"; shift ;;
|
|
64
|
+
--dry-run) DRY_RUN=1; shift ;;
|
|
65
|
+
--host)
|
|
66
|
+
HOST_CHOICE="${2:-}"
|
|
67
|
+
if [ -z "$HOST_CHOICE" ]; then
|
|
68
|
+
echo "ERROR: --host 需要参数(如 claude / codex / all)" >&2
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
MODE="skill"
|
|
72
|
+
shift 2
|
|
73
|
+
;;
|
|
74
|
+
--dest)
|
|
75
|
+
DEST_ROOT="${2:-}"
|
|
76
|
+
if [ -z "$DEST_ROOT" ]; then
|
|
77
|
+
echo "ERROR: --dest 需要 skill 根目录参数" >&2
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
DEST_ROOT="${DEST_ROOT%/}"
|
|
81
|
+
DEST_ROOT="${DEST_ROOT/#\~/$HOME}"
|
|
82
|
+
MODE="skill"
|
|
83
|
+
shift 2
|
|
84
|
+
;;
|
|
85
|
+
*) echo "ERROR: 未知参数: $1" >&2; exit 1 ;;
|
|
86
|
+
esac
|
|
87
|
+
done
|
|
88
|
+
# 向后兼容:裸 `bash install.sh` 等价于 `bash install.sh --dev`
|
|
89
|
+
if [ "$MODE" = "local" ] && [ "$HAS_DEV_FLAG" -eq 0 ]; then
|
|
90
|
+
INSTALL_DEV="--dev"
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# ---------- 宿主 Agent 表 ----------
|
|
94
|
+
HOSTS=(claude codex cursor omp opencode kimi zcode openclaw harness grok copilot cline)
|
|
95
|
+
|
|
96
|
+
# 探测宿主是否已安装(尽力而为;未探测到不阻塞安装,只做提示)
|
|
97
|
+
host_detect() {
|
|
98
|
+
case "$1" in
|
|
99
|
+
claude) [ -d "$HOME/.claude" ] || [ -f "$HOME/.claude.json" ] ;;
|
|
100
|
+
codex) [ -d "$HOME/.codex" ] || command -v codex >/dev/null 2>&1 ;;
|
|
101
|
+
cursor) [ -d "$HOME/.cursor" ] ;;
|
|
102
|
+
omp) [ -d "$HOME/.omp" ] ;;
|
|
103
|
+
opencode) [ -d "$HOME/.config/opencode" ] || command -v opencode >/dev/null 2>&1 ;;
|
|
104
|
+
kimi) [ -d "${KIMI_CODE_HOME:-$HOME/.kimi-code}" ] || command -v kimi >/dev/null 2>&1 ;;
|
|
105
|
+
zcode) [ -d "$HOME/.zcode" ] ;;
|
|
106
|
+
openclaw) [ -d "$HOME/.openclaw" ] ;;
|
|
107
|
+
harness) [ -d "$HOME/.harness" ] ;;
|
|
108
|
+
grok) [ -d "$HOME/.grok" ] ;;
|
|
109
|
+
copilot) [ -d "$HOME/.copilot" ] || command -v copilot >/dev/null 2>&1 ;;
|
|
110
|
+
cline) [ -d "$HOME/.cline" ] || [ -d "$HOME/.config/cline" ] ;;
|
|
111
|
+
*) return 1 ;;
|
|
112
|
+
esac
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# 返回某宿主的 skill 根目录(eduevidence/ 会创建为其子目录)
|
|
116
|
+
host_skill_root() {
|
|
117
|
+
case "$1" in
|
|
118
|
+
claude)
|
|
119
|
+
if [ -d "$HOME/.claude/skills" ] || [ -d "$HOME/.claude" ]; then
|
|
120
|
+
echo "$HOME/.claude/skills" # 用户级配置存在 → 用户级落点
|
|
121
|
+
else
|
|
122
|
+
echo "$PWD/.claude/skills" # 否则装到项目级 .claude/skills/
|
|
123
|
+
fi
|
|
124
|
+
;;
|
|
125
|
+
codex)
|
|
126
|
+
# 官方标准 ~/.agents/skills,兼容 ~/.codex/skills 与 ~/.codex/prompts,按探测顺序取
|
|
127
|
+
if [ -d "$HOME/.agents/skills" ]; then
|
|
128
|
+
echo "$HOME/.agents/skills"
|
|
129
|
+
elif [ -d "$HOME/.codex/skills" ]; then
|
|
130
|
+
echo "$HOME/.codex/skills"
|
|
131
|
+
elif [ -d "$HOME/.codex/prompts" ]; then
|
|
132
|
+
echo "$HOME/.codex/prompts"
|
|
133
|
+
else
|
|
134
|
+
echo "$HOME/.agents/skills"
|
|
135
|
+
fi
|
|
136
|
+
;;
|
|
137
|
+
cursor) echo "$HOME/.cursor/skills" ;;
|
|
138
|
+
omp) echo "$HOME/.omp/agent/skills" ;;
|
|
139
|
+
opencode) echo "$HOME/.config/opencode/skills" ;;
|
|
140
|
+
kimi) echo "${KIMI_CODE_HOME:-$HOME/.kimi-code}/skills" ;;
|
|
141
|
+
zcode) echo "$HOME/.zcode/skills" ;;
|
|
142
|
+
openclaw) echo "$HOME/.openclaw/skills" ;;
|
|
143
|
+
harness) echo "$HOME/.harness/skills" ;;
|
|
144
|
+
grok) echo "$HOME/.grok/skills" ;;
|
|
145
|
+
copilot) echo "$HOME/.copilot/skills" ;;
|
|
146
|
+
cline) echo "$HOME/.cline/skills" ;;
|
|
147
|
+
esac
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# ---------- 通用提示词(方式三:宿主不在支持列表时交给任意 AI) ----------
|
|
151
|
+
UNIVERSAL_PROMPT="请把 https://github.com/37chengshan/eduevidence 仓库中的 EduEvidence 安装为 skill:
|
|
152
|
+
1. 将仓库根目录的 SKILL.md、skill/、references/、schemas/、scripts/、retrieval/、integrations/、visualization/ 复制到你的 skill 目录
|
|
153
|
+
(如 ~/.claude/skills/eduevidence/、~/.omp/agent/skills/eduevidence/、~/.agents/skills/eduevidence/ 等),
|
|
154
|
+
或按你的 skill 装载机制导入;
|
|
155
|
+
2. 安装完成后确认能读取 SKILL.md,并能运行 scripts/ 下的确定性脚本;
|
|
156
|
+
3. 告诉我安装结果。"
|
|
157
|
+
|
|
158
|
+
print_universal_prompt() {
|
|
159
|
+
echo ""
|
|
160
|
+
echo "============================================================"
|
|
161
|
+
echo "方式三:通用提示词(宿主 Agent 不在支持列表时使用)"
|
|
162
|
+
echo "============================================================"
|
|
163
|
+
echo "把下面这段提示词原样交给任意支持 skill / 自定义指令的 AI:"
|
|
164
|
+
echo ""
|
|
165
|
+
echo "$UNIVERSAL_PROMPT"
|
|
166
|
+
echo ""
|
|
167
|
+
echo "============================================================"
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
# ---------- 安装完成后的提示(仅提示,不自动执行任何 star 操作) ----------
|
|
171
|
+
star_prompt() {
|
|
172
|
+
echo ""
|
|
173
|
+
echo "==> If EduEvidence helps, consider starring ⭐ ${REPO_URL}(仅提示,不会自动点 star)"
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
# ---------- Agent MCP 声明(~/.eduevidence/env) ----------
|
|
177
|
+
# 安装完成后写入 AGENT_MCP_INSTALLED=1,供 integrations/agent_mcp.py 读取。
|
|
178
|
+
# 只写「已安装」声明,不安装 agent-mcp daemon:detect 仍要求 daemon 可达
|
|
179
|
+
# (声明但 daemon 未起 -> state: unavailable;daemon 起但未声明 ->
|
|
180
|
+
# state: daemon_reachable_undeclared)。
|
|
181
|
+
write_agent_mcp_env() {
|
|
182
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
183
|
+
echo " [dry-run] 将写入 $AGENT_MCP_ENV_FILE: AGENT_MCP_INSTALLED=1"
|
|
184
|
+
return 0
|
|
185
|
+
fi
|
|
186
|
+
mkdir -p "$(dirname "$AGENT_MCP_ENV_FILE")"
|
|
187
|
+
touch "$AGENT_MCP_ENV_FILE"
|
|
188
|
+
if grep -q '^AGENT_MCP_INSTALLED=' "$AGENT_MCP_ENV_FILE" 2>/dev/null; then
|
|
189
|
+
# 幂等更新(兼容 macOS/BSD 与 GNU sed:不用 -i)
|
|
190
|
+
local tmp
|
|
191
|
+
tmp="$(mktemp)"
|
|
192
|
+
sed 's/^AGENT_MCP_INSTALLED=.*/AGENT_MCP_INSTALLED=1/' \
|
|
193
|
+
"$AGENT_MCP_ENV_FILE" > "$tmp"
|
|
194
|
+
mv "$tmp" "$AGENT_MCP_ENV_FILE"
|
|
195
|
+
else
|
|
196
|
+
printf 'AGENT_MCP_INSTALLED=1\n' >> "$AGENT_MCP_ENV_FILE"
|
|
197
|
+
fi
|
|
198
|
+
echo " ✅ 已写入 ${AGENT_MCP_ENV_FILE}(AGENT_MCP_INSTALLED=1)"
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
# ---------- 本地安装:Python 检查 + venv + 依赖 + 自检(--dev 时含 pytest) ----------
|
|
202
|
+
local_setup() {
|
|
203
|
+
local PYTHON_BIN="${PYTHON:-python3}"
|
|
204
|
+
|
|
205
|
+
echo "==> EduEvidence 安装开始"
|
|
206
|
+
|
|
207
|
+
# 1. 检查 Python >= 3.10
|
|
208
|
+
if ! command -v "$PYTHON_BIN" >/dev/null 2>&1; then
|
|
209
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
210
|
+
echo " [dry-run] Python 版本检查将失败:未找到 ${PYTHON_BIN}(需要 3.10+)"
|
|
211
|
+
echo " [dry-run] 预览结束(本环境不会真正安装)"
|
|
212
|
+
exit 0
|
|
213
|
+
fi
|
|
214
|
+
echo "ERROR: 未找到 ${PYTHON_BIN},请先安装 Python 3.10+ (https://www.python.org/downloads/)" >&2
|
|
215
|
+
exit 1
|
|
216
|
+
fi
|
|
217
|
+
PY_VERSION="$("$PYTHON_BIN" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')"
|
|
218
|
+
PY_MAJOR="${PY_VERSION%%.*}"
|
|
219
|
+
PY_MINOR="${PY_VERSION#*.}"
|
|
220
|
+
if [ "$PY_MAJOR" -lt 3 ] || { [ "$PY_MAJOR" -eq 3 ] && [ "$PY_MINOR" -lt 10 ]; }; then
|
|
221
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
222
|
+
echo " [dry-run] Python 版本检查将失败:需要 3.10+,当前 $PY_VERSION"
|
|
223
|
+
echo " [dry-run] 预览结束(本环境不会真正安装)"
|
|
224
|
+
exit 0
|
|
225
|
+
fi
|
|
226
|
+
echo "ERROR: 需要 Python 3.10+,当前 $PY_VERSION" >&2
|
|
227
|
+
exit 1
|
|
228
|
+
fi
|
|
229
|
+
echo " Python $PY_VERSION OK"
|
|
230
|
+
|
|
231
|
+
# 2. 创建 venv(如不存在)
|
|
232
|
+
if [ ! -d ".venv" ]; then
|
|
233
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
234
|
+
echo " [dry-run] 将创建虚拟环境 .venv"
|
|
235
|
+
else
|
|
236
|
+
echo "==> 创建虚拟环境 .venv"
|
|
237
|
+
"$PYTHON_BIN" -m venv .venv
|
|
238
|
+
fi
|
|
239
|
+
fi
|
|
240
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
241
|
+
echo " [dry-run] 将激活 .venv 并安装依赖(pip install -e .)"
|
|
242
|
+
echo " [dry-run] 将运行自检:Schema 校验 + 渲染双语 HTML 报告"
|
|
243
|
+
write_agent_mcp_env
|
|
244
|
+
return 0
|
|
245
|
+
fi
|
|
246
|
+
# shellcheck disable=SC1091
|
|
247
|
+
source .venv/bin/activate
|
|
248
|
+
echo " venv: $(command -v python)"
|
|
249
|
+
|
|
250
|
+
# 3. 安装依赖(EduEvidence 核心零依赖;--dev 额外安装 pytest)
|
|
251
|
+
if [ "$INSTALL_DEV" = "--dev" ]; then
|
|
252
|
+
echo "==> 安装开发依赖(pytest)"
|
|
253
|
+
pip install --quiet --upgrade pip
|
|
254
|
+
pip install --quiet -e '.[dev]'
|
|
255
|
+
else
|
|
256
|
+
echo "==> 安装核心(零第三方依赖)"
|
|
257
|
+
pip install --quiet --upgrade pip
|
|
258
|
+
pip install --quiet -e .
|
|
259
|
+
fi
|
|
260
|
+
|
|
261
|
+
# 4. 可选:matplotlib 用于学术图 PNG/PDF 导出(非必需)
|
|
262
|
+
if python -c "import matplotlib" 2>/dev/null; then
|
|
263
|
+
echo " matplotlib: 已安装(学术图 PNG/PDF 可用)"
|
|
264
|
+
else
|
|
265
|
+
echo " matplotlib: 未安装(学术图仍可输出 SVG;PNG/PDF 导出需要 pip install matplotlib)"
|
|
266
|
+
fi
|
|
267
|
+
|
|
268
|
+
# 5. 自检:Schema 校验 + 报告渲染
|
|
269
|
+
echo "==> 自检:Schema 校验"
|
|
270
|
+
python scripts/validate_schema.py --schema schemas/verdict.schema.json \
|
|
271
|
+
--data examples/ai-coding-assistant/verdict.json
|
|
272
|
+
python scripts/validate_schema.py --schema schemas/evidence.schema.json \
|
|
273
|
+
--data examples/ai-coding-assistant/evidence.jsonl
|
|
274
|
+
|
|
275
|
+
echo "==> 自检:渲染双语 HTML 报告"
|
|
276
|
+
python visualization/eduevidence-report/scripts/build_report.py \
|
|
277
|
+
--result examples/ai-coding-assistant/result.json \
|
|
278
|
+
--out /tmp/eduevidence-smoke.html
|
|
279
|
+
rm -f /tmp/eduevidence-smoke.html
|
|
280
|
+
|
|
281
|
+
# 6. 运行测试(仅 dev 模式)
|
|
282
|
+
if [ "$INSTALL_DEV" = "--dev" ]; then
|
|
283
|
+
echo "==> 运行测试"
|
|
284
|
+
pytest -q
|
|
285
|
+
fi
|
|
286
|
+
|
|
287
|
+
# 7. Agent MCP 声明:写入 AGENT_MCP_INSTALLED=1(~/.eduevidence/env)
|
|
288
|
+
write_agent_mcp_env
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
local_finish() {
|
|
292
|
+
echo ""
|
|
293
|
+
echo "安装完成。下一步:"
|
|
294
|
+
echo " 1. 查看示例报告: open examples/ai-coding-assistant/EduEvidence_Report.html"
|
|
295
|
+
echo " 2. 渲染自己的 result.json(需同时准备 result.zh.json 中文平行数据):"
|
|
296
|
+
echo " python visualization/eduevidence-report/scripts/build_report.py \\"
|
|
297
|
+
echo " --result <你的 result.json> --out REPORT.html"
|
|
298
|
+
echo " 3. Agent MCP: 已写入 ${AGENT_MCP_ENV_FILE}(AGENT_MCP_INSTALLED=1),"
|
|
299
|
+
echo " 安装并启动 agent-mcp daemon 后 detect 即报 state: available"
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
# ---------- Skill 安装 ----------
|
|
303
|
+
# 复制 Skill 本体到指定目录(写前自动备份:cp -r 到 .bak-时间戳)
|
|
304
|
+
install_to_dir() {
|
|
305
|
+
local dest="$1"
|
|
306
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
307
|
+
echo " [dry-run] 将备份已有目录: $dest → $dest.bak-<时间戳>(如存在)"
|
|
308
|
+
echo " [dry-run] 将复制: ${SKILL_PAYLOAD[*]} → $dest/"
|
|
309
|
+
return 0
|
|
310
|
+
fi
|
|
311
|
+
if [ -e "$dest" ]; then
|
|
312
|
+
local bak="${dest}.bak-$(date +%Y%m%d%H%M%S)"
|
|
313
|
+
cp -r "$dest" "$bak"
|
|
314
|
+
echo " 已备份: $dest → $bak"
|
|
315
|
+
rm -rf "$dest"
|
|
316
|
+
fi
|
|
317
|
+
mkdir -p "$dest"
|
|
318
|
+
cp -R "${SKILL_PAYLOAD[@]}" "$dest"/
|
|
319
|
+
echo " ✅ 已安装: $dest"
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
# 安装到单个宿主
|
|
323
|
+
install_one_host() {
|
|
324
|
+
local host="$1"
|
|
325
|
+
local dest
|
|
326
|
+
dest="$(host_skill_root "$host")/$SKILL_NAME"
|
|
327
|
+
echo ""
|
|
328
|
+
echo "==> 安装 Skill 到 $host"
|
|
329
|
+
echo " 目标目录: $dest"
|
|
330
|
+
install_to_dir "$dest"
|
|
331
|
+
echo " 提示: 重启 $host 会话后 Skill 即可自动发现(或按宿主机制手动装载)"
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
# custom:手动指定 skill 根目录
|
|
335
|
+
custom_install() {
|
|
336
|
+
local dir=""
|
|
337
|
+
read -r -p "请输入 skill 根目录(将创建 <目录>/$SKILL_NAME/): " dir || true
|
|
338
|
+
dir="${dir%/}"
|
|
339
|
+
dir="${dir/#\~/$HOME}" # 展开 ~
|
|
340
|
+
if [ -z "$dir" ]; then
|
|
341
|
+
echo "ERROR: 未输入目录,取消安装。" >&2
|
|
342
|
+
exit 1
|
|
343
|
+
fi
|
|
344
|
+
echo "==> 安装 Skill 到自定义目录"
|
|
345
|
+
echo " 目标目录: $dir/$SKILL_NAME"
|
|
346
|
+
install_to_dir "$dir/$SKILL_NAME"
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
# 非交互:--host / --dest 指定落点
|
|
350
|
+
skill_install_noninteractive() {
|
|
351
|
+
local choice="$1"
|
|
352
|
+
case "$choice" in
|
|
353
|
+
all)
|
|
354
|
+
for h in "${HOSTS[@]}"; do install_one_host "$h"; done
|
|
355
|
+
print_universal_prompt
|
|
356
|
+
;;
|
|
357
|
+
local)
|
|
358
|
+
echo "==> 仅本地安装:安装 pytest 并运行测试"
|
|
359
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
360
|
+
echo " [dry-run] 将执行: pip install -e '.[dev]' && pytest -q"
|
|
361
|
+
else
|
|
362
|
+
pip install --quiet -e '.[dev]'
|
|
363
|
+
pytest -q
|
|
364
|
+
fi
|
|
365
|
+
write_agent_mcp_env
|
|
366
|
+
;;
|
|
367
|
+
custom)
|
|
368
|
+
echo "ERROR: 非交互模式请使用 --dest <skill根目录>" >&2
|
|
369
|
+
exit 1
|
|
370
|
+
;;
|
|
371
|
+
*)
|
|
372
|
+
local found=0 h
|
|
373
|
+
for h in "${HOSTS[@]}"; do
|
|
374
|
+
[ "$h" = "$choice" ] && found=1
|
|
375
|
+
done
|
|
376
|
+
if [ "$found" -eq 0 ]; then
|
|
377
|
+
echo "ERROR: 无效宿主: $choice(bash install.sh --list-hosts 查看列表)" >&2
|
|
378
|
+
exit 1
|
|
379
|
+
fi
|
|
380
|
+
install_one_host "$choice"
|
|
381
|
+
print_universal_prompt
|
|
382
|
+
;;
|
|
383
|
+
esac
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
# 交互式选择宿主并安装 Skill
|
|
387
|
+
skill_install() {
|
|
388
|
+
if [ -n "$DEST_ROOT" ]; then
|
|
389
|
+
echo "==> 安装 Skill 到自定义目录"
|
|
390
|
+
echo " 目标目录: $DEST_ROOT/$SKILL_NAME"
|
|
391
|
+
install_to_dir "$DEST_ROOT/$SKILL_NAME"
|
|
392
|
+
print_universal_prompt
|
|
393
|
+
return 0
|
|
394
|
+
fi
|
|
395
|
+
if [ -n "$HOST_CHOICE" ]; then
|
|
396
|
+
echo " 已选择: $HOST_CHOICE"
|
|
397
|
+
skill_install_noninteractive "$HOST_CHOICE"
|
|
398
|
+
return 0
|
|
399
|
+
fi
|
|
400
|
+
|
|
401
|
+
local i=1 choice="" mark=""
|
|
402
|
+
echo ""
|
|
403
|
+
echo "==> 选择安装到哪个宿主 Agent(Skill 落点见: bash install.sh --list-hosts):"
|
|
404
|
+
for h in "${HOSTS[@]}"; do
|
|
405
|
+
if host_detect "$h"; then mark="✓ 已探测到"; else mark="未探测到"; fi
|
|
406
|
+
printf ' %2d) %-9s %s\n' "$i" "$h" "$mark"
|
|
407
|
+
i=$((i + 1))
|
|
408
|
+
done
|
|
409
|
+
printf ' %2d) %-9s 安装到全部 Agent\n' "$i" "all"
|
|
410
|
+
i=$((i + 1))
|
|
411
|
+
printf ' %2d) %-9s 手动指定 skill 目录\n' "$i" "custom"
|
|
412
|
+
i=$((i + 1))
|
|
413
|
+
printf ' %2d) %-9s 只装本地(venv + pytest + 自检)\n' "$i" "local"
|
|
414
|
+
|
|
415
|
+
read -r -p "请输入编号或名称 [claude]: " choice || true
|
|
416
|
+
choice="${choice:-claude}"
|
|
417
|
+
|
|
418
|
+
# 数字编号 → 名称
|
|
419
|
+
if [[ "$choice" =~ ^[0-9]+$ ]]; then
|
|
420
|
+
local idx=$((choice - 1))
|
|
421
|
+
if [ "$idx" -lt "${#HOSTS[@]}" ]; then
|
|
422
|
+
choice="${HOSTS[$idx]}"
|
|
423
|
+
else
|
|
424
|
+
case "$idx" in
|
|
425
|
+
11) choice="all" ;;
|
|
426
|
+
12) choice="custom" ;;
|
|
427
|
+
13) choice="local" ;;
|
|
428
|
+
*) echo "ERROR: 无效编号" >&2; exit 1 ;;
|
|
429
|
+
esac
|
|
430
|
+
fi
|
|
431
|
+
fi
|
|
432
|
+
# 名称校验
|
|
433
|
+
case "$choice" in
|
|
434
|
+
all|local|custom) ;;
|
|
435
|
+
*)
|
|
436
|
+
local found=0 h
|
|
437
|
+
for h in "${HOSTS[@]}"; do
|
|
438
|
+
[ "$h" = "$choice" ] && found=1
|
|
439
|
+
done
|
|
440
|
+
if [ "$found" -eq 0 ]; then
|
|
441
|
+
echo "ERROR: 无效选择: $choice" >&2
|
|
442
|
+
exit 1
|
|
443
|
+
fi
|
|
444
|
+
;;
|
|
445
|
+
esac
|
|
446
|
+
echo " 已选择: $choice"
|
|
447
|
+
|
|
448
|
+
case "$choice" in
|
|
449
|
+
local)
|
|
450
|
+
echo "==> 仅本地安装:安装 pytest 并运行测试"
|
|
451
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
452
|
+
echo " [dry-run] 将执行: pip install -e '.[dev]' && pytest -q"
|
|
453
|
+
else
|
|
454
|
+
pip install --quiet -e '.[dev]'
|
|
455
|
+
pytest -q
|
|
456
|
+
fi
|
|
457
|
+
write_agent_mcp_env
|
|
458
|
+
;;
|
|
459
|
+
all)
|
|
460
|
+
for h in "${HOSTS[@]}"; do install_one_host "$h"; done
|
|
461
|
+
print_universal_prompt
|
|
462
|
+
;;
|
|
463
|
+
custom)
|
|
464
|
+
custom_install
|
|
465
|
+
print_universal_prompt
|
|
466
|
+
;;
|
|
467
|
+
*)
|
|
468
|
+
install_one_host "$choice"
|
|
469
|
+
print_universal_prompt
|
|
470
|
+
;;
|
|
471
|
+
esac
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
# ---------- --list-hosts:显示支持列表与落点 ----------
|
|
475
|
+
list_hosts() {
|
|
476
|
+
echo "==> EduEvidence 支持的宿主 Agent 与 Skill 落点"
|
|
477
|
+
printf ' %-10s %-12s %s\n' "宿主" "探测" "Skill 安装落点"
|
|
478
|
+
printf ' %-10s %-12s %s\n' "----" "----" "----------------"
|
|
479
|
+
for h in "${HOSTS[@]}"; do
|
|
480
|
+
if host_detect "$h"; then mark="✓ 已探测到"; else mark="未探测到"; fi
|
|
481
|
+
printf ' %-10s %-12s %s/%s/\n' "$h" "$mark" "$(host_skill_root "$h")" "$SKILL_NAME"
|
|
482
|
+
done
|
|
483
|
+
echo ""
|
|
484
|
+
echo " 选择 all 安装到全部 Agent;custom 手动指定目录;local 只装本地。"
|
|
485
|
+
echo " 未列出的 Agent(方式三):用通用提示词手动安装,详见 README「安装为 Skill」。"
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
# ---------- 主流程 ----------
|
|
489
|
+
case "$MODE" in
|
|
490
|
+
list)
|
|
491
|
+
list_hosts
|
|
492
|
+
;;
|
|
493
|
+
skill)
|
|
494
|
+
if [ "$SKILL_ONLY" -eq 1 ] || [ -n "$HOST_CHOICE" ] || [ -n "$DEST_ROOT" ]; then
|
|
495
|
+
echo "==> Skill-only 安装(跳过 venv / pytest)"
|
|
496
|
+
write_agent_mcp_env
|
|
497
|
+
else
|
|
498
|
+
local_setup
|
|
499
|
+
fi
|
|
500
|
+
skill_install
|
|
501
|
+
star_prompt
|
|
502
|
+
;;
|
|
503
|
+
local)
|
|
504
|
+
local_setup
|
|
505
|
+
local_finish
|
|
506
|
+
star_prompt
|
|
507
|
+
;;
|
|
508
|
+
esac
|
|
509
|
+
echo ""
|
|
510
|
+
echo "完成。"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""EduEvidence integration modules."""
|
|
Binary file
|
|
Binary file
|
|
Binary file
|