master-skill 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.cursor-plugin/plugin.json +1 -1
  4. package/README.md +48 -55
  5. package/README_EN.md +72 -59
  6. package/bin/cli.mjs +12 -7
  7. package/gemini-extension.json +1 -1
  8. package/hooks/session-start +68 -77
  9. package/hooks/session_start.py +152 -0
  10. package/package.json +5 -2
  11. package/prebuilt/compare-masters/SKILL.md +21 -2
  12. package/prebuilt/master-ajahn-chah/meta.json +6 -0
  13. package/prebuilt/master-ajahn-chah/tests/fidelity.jsonl +6 -6
  14. package/prebuilt/master-atisha/tests/fidelity.jsonl +4 -4
  15. package/prebuilt/master-curriculum/references/tiantai.md +1 -1
  16. package/prebuilt/master-debate/SKILL.md +14 -2
  17. package/prebuilt/master-fazang/tests/fidelity.jsonl +2 -2
  18. package/prebuilt/master-help/SKILL.md +9 -1
  19. package/prebuilt/master-huineng/tests/fidelity.jsonl +4 -4
  20. package/prebuilt/master-kumarajiva/tests/fidelity.jsonl +3 -3
  21. package/prebuilt/master-mahasi-sayadaw/tests/fidelity.jsonl +4 -4
  22. package/prebuilt/master-milarepa/tests/fidelity.jsonl +3 -3
  23. package/prebuilt/master-nagarjuna/tests/fidelity.jsonl +6 -6
  24. package/prebuilt/master-ouyi/meta.json +5 -0
  25. package/prebuilt/master-ouyi/references/teaching.md +3 -3
  26. package/prebuilt/master-ouyi/tests/fidelity.jsonl +3 -3
  27. package/prebuilt/master-tsongkhapa/meta.json +6 -0
  28. package/prebuilt/master-tsongkhapa/tests/fidelity.jsonl +2 -2
  29. package/prebuilt/master-xuanzang/tests/fidelity.jsonl +3 -3
  30. package/prebuilt/master-xuyun/tests/fidelity.jsonl +6 -6
  31. package/prebuilt/master-zhiyi/meta.json +2 -2
  32. package/prebuilt/master-zhiyi/tests/fidelity.jsonl +2 -2
  33. package/scripts/check-audit-ignores.py +105 -0
  34. package/scripts/check-eval-sdk-surface.py +142 -0
  35. package/scripts/check-gate-liveness.py +205 -6
  36. package/scripts/reaudit-report.py +163 -0
  37. package/scripts/regrade-report.py +157 -0
  38. package/scripts/smoke-eval-sdk.py +174 -0
  39. package/scripts/test-fidelity.py +684 -52
  40. package/scripts/validate-citation-references.py +150 -0
  41. package/scripts/validate-citation-templates.py +176 -0
  42. package/scripts/validate-fixture-terms.py +127 -0
  43. package/scripts/verify-adjudication.py +316 -0
  44. package/scripts/verify_citations.py +739 -39
  45. package/tools/cross_reference.py +44 -10
  46. package/tools/fojin-known-absent.json +14 -0
  47. package/tools/fojin_bridge.py +138 -8
  48. package/tools/rag_query.py +45 -2
  49. package/tools/skill_writer.py +50 -7
  50. package/tools/verify_sources.py +240 -15
  51. package/hooks/tests/test_run_hook.sh +0 -114
  52. package/hooks/tests/test_run_hook_cmd.sh +0 -94
  53. package/hooks/tests/test_session_start.sh +0 -149
  54. package/scripts/tests/test_check_gate_liveness.py +0 -232
  55. package/scripts/tests/test_check_manifest_versions.py +0 -217
  56. package/scripts/tests/test_check_response.py +0 -190
  57. package/scripts/tests/test_debate_protocol.py +0 -159
  58. package/scripts/tests/test_fidelity_providers.py +0 -202
  59. package/scripts/tests/test_injection_hardening.py +0 -174
  60. package/scripts/tests/test_select_fidelity_smoke.py +0 -142
  61. package/scripts/tests/test_validate.py +0 -145
  62. package/scripts/tests/test_validate_citation_contract.py +0 -408
  63. package/scripts/tests/test_validate_cross_critique.py +0 -149
  64. package/scripts/tests/test_validate_curriculum_sources.py +0 -144
  65. package/scripts/tests/test_validate_fidelity.py +0 -59
  66. package/scripts/tests/test_validate_lore_triggers_content.py +0 -372
  67. package/scripts/tests/test_validate_persona_fidelity.py +0 -317
  68. package/scripts/tests/test_validate_promptfoo_configs.py +0 -386
  69. package/scripts/tests/test_validate_workflow.py +0 -284
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env python3
2
+ """Keyless end-to-end smoke for the pinned eval SDKs.
3
+
4
+ `check-eval-sdk-surface.py` reads signatures. That catches a renamed keyword,
5
+ not a changed wire format, a response model that parses differently, or a
6
+ client that stops honouring its base URL. And the real path —
7
+ `scripts/test-fidelity.py` — never runs in CI, because grading needs an API
8
+ key and there is none. So every Dependabot bump of `anthropic` or `openai`
9
+ arrived green having exercised nothing, which `requirements-eval.txt` says in
10
+ as many words.
11
+
12
+ This runs that real path without a key or a network. A local HTTP server
13
+ answers in each provider's own wire format; `test-fidelity.py` builds its
14
+ request, the pinned SDK sends and parses it, and the answer goes through
15
+ grading and the citation audit exactly as in a sweep. Then it checks what
16
+ arrived at the server and what came back.
17
+
18
+ python3 scripts/smoke-eval-sdk.py # must exit 0
19
+ python3 scripts/smoke-eval-sdk.py --break # must exit 1
20
+
21
+ `--break` makes the server return a reply with no answer text while every
22
+ assertion stays the same. CI runs both: a smoke that cannot fail is a green
23
+ tick, not a check.
24
+
25
+ First written 2026-09-14 to verify anthropic 1.4.0 → 1.5.0 and openai
26
+ 3.10.0 → 3.13.0 (#174, #175).
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import contextlib
32
+ import importlib.util
33
+ import io
34
+ import json
35
+ import os
36
+ import sys
37
+ import threading
38
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
39
+ from pathlib import Path
40
+
41
+ REPO = Path(__file__).resolve().parent.parent
42
+ ANSWER = "菩提自性,本来清净,但用此心,直了成佛。【《六祖大师法宝坛经》行由品,T48n2008】"
43
+ CACHE_CREATED = 6700
44
+
45
+
46
+ def _server(broken: bool, received: list) -> ThreadingHTTPServer:
47
+ class Handler(BaseHTTPRequestHandler):
48
+ def log_message(self, *args): # keep CI logs quiet
49
+ pass
50
+
51
+ def do_POST(self):
52
+ length = int(self.headers.get("content-length", 0))
53
+ body = json.loads(self.rfile.read(length) or b"{}")
54
+ headers = {k.lower(): v for k, v in self.headers.items()}
55
+ received.append((self.path, body, headers))
56
+ if self.path.endswith("/messages"):
57
+ reply = {
58
+ "id": "msg_smoke", "type": "message", "role": "assistant",
59
+ "model": body.get("model"),
60
+ "content": [] if broken else [{"type": "text", "text": ANSWER}],
61
+ "stop_reason": "end_turn", "stop_sequence": None,
62
+ "usage": {
63
+ "input_tokens": 21, "output_tokens": 40,
64
+ "cache_creation_input_tokens": CACHE_CREATED,
65
+ "cache_read_input_tokens": 0,
66
+ },
67
+ }
68
+ else:
69
+ reply = {
70
+ "id": "chatcmpl-smoke", "object": "chat.completion", "created": 1,
71
+ "model": body.get("model"),
72
+ "choices": [{
73
+ "index": 0, "finish_reason": "stop",
74
+ "message": {"role": "assistant", "content": None if broken else ANSWER},
75
+ }],
76
+ "usage": {"prompt_tokens": 21, "completion_tokens": 40, "total_tokens": 61},
77
+ }
78
+ data = json.dumps(reply).encode()
79
+ self.send_response(200)
80
+ self.send_header("content-type", "application/json")
81
+ self.send_header("content-length", str(len(data)))
82
+ self.end_headers()
83
+ self.wfile.write(data)
84
+
85
+ return ThreadingHTTPServer(("127.0.0.1", 0), Handler)
86
+
87
+
88
+ def main(argv: list[str]) -> int:
89
+ broken = "--break" in argv
90
+ try:
91
+ import anthropic
92
+ import openai
93
+ except ImportError as error:
94
+ # Missing is a failure, not a skip: this only runs where
95
+ # requirements-eval.txt is installed, and silence here is how a bump
96
+ # used to pass.
97
+ print(f"✗ eval SDK not importable: {error} (pip install -r requirements-eval.txt)")
98
+ return 1
99
+
100
+ received: list = []
101
+ server = _server(broken, received)
102
+ port = server.server_address[1]
103
+ threading.Thread(target=server.serve_forever, daemon=True).start()
104
+
105
+ # A proxy variable would send 127.0.0.1 somewhere else; a real key must
106
+ # never be read by a smoke that is supposed to cost nothing.
107
+ for key in ("HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "http_proxy", "https_proxy", "all_proxy"):
108
+ os.environ.pop(key, None)
109
+ os.environ.update({
110
+ "ANTHROPIC_API_KEY": "sk-ant-smoke",
111
+ "DEEPSEEK_API_KEY": "sk-smoke",
112
+ "ANTHROPIC_BASE_URL": f"http://127.0.0.1:{port}",
113
+ "NO_PROXY": "127.0.0.1,localhost",
114
+ })
115
+ os.chdir(REPO)
116
+ sys.path.insert(0, str(REPO / "scripts"))
117
+ spec = importlib.util.spec_from_file_location("test_fidelity", REPO / "scripts" / "test-fidelity.py")
118
+ fidelity = importlib.util.module_from_spec(spec)
119
+ spec.loader.exec_module(fidelity)
120
+ fidelity.PROVIDERS["deepseek"]["base_url"] = f"http://127.0.0.1:{port}/v1"
121
+
122
+ print(f"eval SDK smoke — anthropic {anthropic.__version__}, openai {openai.__version__}"
123
+ f"{' (--break: server returns no answer text)' if broken else ''}")
124
+ failures = 0
125
+
126
+ def check(label: str, ok: bool) -> None:
127
+ nonlocal failures
128
+ print(f" {'✓' if ok else '✗'} {label}")
129
+ failures += 0 if ok else 1
130
+
131
+ for provider, extra in (("anthropic", []), ("deepseek", ["--model", "deepseek-v4-flash"])):
132
+ received.clear()
133
+ sys.argv = ["test-fidelity.py", "--master", "master-huineng", "--provider", provider,
134
+ "--max-tests", "1", "--concurrency", "1", "--json", *extra]
135
+ out = io.StringIO()
136
+ with contextlib.redirect_stdout(out), contextlib.redirect_stderr(io.StringIO()):
137
+ fidelity.main()
138
+ suite = json.loads(out.getvalue())[0]
139
+ result = suite["results"][0]
140
+ print(f"── {provider}: {result.get('status')}")
141
+
142
+ check("the request reached the local server, not the internet", bool(received))
143
+ if not received:
144
+ continue
145
+ path, body, headers = received[0]
146
+ check("the reply was graded, not recorded as api_error",
147
+ result.get("status") in ("PASS", "FAIL"))
148
+ check("the answer text survived SDK parsing intact", result.get("response") == ANSWER)
149
+ check("the citation audit ran on it",
150
+ (suite.get("audit") or {}).get("citations_checked", 0) >= 1)
151
+ check("model, max_tokens and messages were sent",
152
+ {"model", "max_tokens", "messages"} <= set(body))
153
+ if provider == "anthropic":
154
+ check(f"sent to /v1/messages (got {path})", path == "/v1/messages")
155
+ check("the persona prompt carries cache_control",
156
+ (body.get("system") or [{}])[0].get("cache_control") == {"type": "ephemeral"})
157
+ check("cache token usage was read back",
158
+ (suite.get("cache") or {}).get("created") == CACHE_CREATED)
159
+ check("the pinned SDK is the one that sent it",
160
+ anthropic.__version__ in headers.get("user-agent", ""))
161
+ else:
162
+ check(f"sent to /v1/chat/completions (got {path})", path == "/v1/chat/completions")
163
+ check("the key went in the Authorization header",
164
+ headers.get("authorization") == "Bearer sk-smoke")
165
+ check("the pinned SDK is the one that sent it",
166
+ openai.__version__ in headers.get("user-agent", ""))
167
+
168
+ server.shutdown()
169
+ print(f"{'✓ eval SDK path intact' if not failures else f'✗ {failures} check(s) failed'}")
170
+ return 1 if failures else 0
171
+
172
+
173
+ if __name__ == "__main__":
174
+ sys.exit(main(sys.argv[1:]))