opencode-skills-collection 4.0.69 → 4.0.70
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/bundled-skills/.antigravity-install-manifest.json +39 -1
- package/bundled-skills/api-integration-architect/SKILL.md +241 -0
- package/bundled-skills/apify-generate-output-schema/SKILL.md +438 -0
- package/bundled-skills/apify-integration-development/SKILL.md +168 -0
- package/bundled-skills/apify-integration-development/references/ai-framework-package.md +158 -0
- package/bundled-skills/apify-integration-development/references/ai-harness-plugin.md +192 -0
- package/bundled-skills/apify-integration-development/references/sdk-integration.md +236 -0
- package/bundled-skills/apify-integration-development/references/workflow-automation.md +163 -0
- package/bundled-skills/architecture-review/README.md +42 -0
- package/bundled-skills/architecture-review/SKILL.md +77 -0
- package/bundled-skills/architecture-review/examples.md +11 -0
- package/bundled-skills/architecture-review/reference/best-practices.md +7 -0
- package/bundled-skills/architecture-review/reference/capabilities.md +20 -0
- package/bundled-skills/architecture-review/reference/fallbacks.md +11 -0
- package/bundled-skills/architecture-review/reference/graph.md +15 -0
- package/bundled-skills/architecture-review/reference/mcp.md +14 -0
- package/bundled-skills/architecture-review/reference/workflow.md +15 -0
- package/bundled-skills/architecture-review/templates/architecture-review.md +21 -0
- package/bundled-skills/code-review-sensei/SKILL.md +177 -0
- package/bundled-skills/codebase-onboarding/README.md +42 -0
- package/bundled-skills/codebase-onboarding/SKILL.md +77 -0
- package/bundled-skills/codebase-onboarding/examples.md +11 -0
- package/bundled-skills/codebase-onboarding/reference/best-practices.md +7 -0
- package/bundled-skills/codebase-onboarding/reference/capabilities.md +20 -0
- package/bundled-skills/codebase-onboarding/reference/fallbacks.md +11 -0
- package/bundled-skills/codebase-onboarding/reference/graph.md +15 -0
- package/bundled-skills/codebase-onboarding/reference/mcp.md +14 -0
- package/bundled-skills/codebase-onboarding/reference/workflow.md +15 -0
- package/bundled-skills/codebase-onboarding/templates/repository-onboarding.md +21 -0
- package/bundled-skills/connection-auth-rules/SKILL.md +199 -0
- package/bundled-skills/connection-auth-rules/fetch_schema.py +320 -0
- package/bundled-skills/dependency-analysis/README.md +42 -0
- package/bundled-skills/dependency-analysis/SKILL.md +76 -0
- package/bundled-skills/dependency-analysis/examples.md +11 -0
- package/bundled-skills/dependency-analysis/reference/best-practices.md +7 -0
- package/bundled-skills/dependency-analysis/reference/capabilities.md +20 -0
- package/bundled-skills/dependency-analysis/reference/fallbacks.md +11 -0
- package/bundled-skills/dependency-analysis/reference/graph.md +15 -0
- package/bundled-skills/dependency-analysis/reference/mcp.md +14 -0
- package/bundled-skills/dependency-analysis/reference/workflow.md +15 -0
- package/bundled-skills/dependency-analysis/templates/dependency-review.md +21 -0
- package/bundled-skills/devops-pipeline-builder/SKILL.md +200 -0
- package/bundled-skills/eas-app-stores/SKILL.md +197 -0
- package/bundled-skills/eas-app-stores/agents/openai.yaml +4 -0
- package/bundled-skills/eas-app-stores/references/app-store-metadata.md +497 -0
- package/bundled-skills/eas-app-stores/references/ios-app-store.md +376 -0
- package/bundled-skills/eas-app-stores/references/native-ios.md +167 -0
- package/bundled-skills/eas-app-stores/references/play-store.md +244 -0
- package/bundled-skills/eas-app-stores/references/testflight.md +62 -0
- package/bundled-skills/eas-app-stores/references/workflows.md +120 -0
- package/bundled-skills/eas-hosting/SKILL.md +448 -0
- package/bundled-skills/eas-hosting/agents/openai.yaml +4 -0
- package/bundled-skills/eas-observe/SKILL.md +75 -0
- package/bundled-skills/eas-observe/agents/openai.yaml +4 -0
- package/bundled-skills/eas-observe/references/metrics.md +98 -0
- package/bundled-skills/eas-observe/references/queries.md +403 -0
- package/bundled-skills/eas-observe/references/setup.md +476 -0
- package/bundled-skills/eas-observe/references/third-party.md +136 -0
- package/bundled-skills/eas-simulator/SKILL.md +251 -0
- package/bundled-skills/eas-simulator/agents/openai.yaml +4 -0
- package/bundled-skills/eas-simulator/references/controllers.md +135 -0
- package/bundled-skills/eas-simulator/references/run-your-app.md +240 -0
- package/bundled-skills/eas-simulator/references/troubleshooting.md +47 -0
- package/bundled-skills/eas-workflows/SKILL.md +119 -0
- package/bundled-skills/eas-workflows/agents/openai.yaml +4 -0
- package/bundled-skills/eas-workflows/scripts/fetch.js +109 -0
- package/bundled-skills/expo-animation/LICENSE +21 -0
- package/bundled-skills/expo-animation/RECIPES.md +385 -0
- package/bundled-skills/expo-animation/SKILL.md +295 -0
- package/bundled-skills/expo-animation/agents/openai.yaml +4 -0
- package/bundled-skills/fact-check-x-unified/SKILL.md +178 -0
- package/bundled-skills/fact-check-x-unified/agents/openai.yaml +4 -0
- package/bundled-skills/fact-check-x-unified/references/acceptance-criteria.md +44 -0
- package/bundled-skills/fact-check-x-unified/references/contracts.md +39 -0
- package/bundled-skills/fact-check-x-unified/scripts/common.py +31 -0
- package/bundled-skills/fact-check-x-unified/scripts/fact_check_x.py +1832 -0
- package/bundled-skills/fact-check-x-unified/scripts/trusted_search_config.py +324 -0
- package/bundled-skills/fact-check-x-unified/tests/anchor_downgrade_test.py +90 -0
- package/bundled-skills/fact-check-x-unified/tests/multi_platform_test.py +369 -0
- package/bundled-skills/fact-check-x-unified/tests/smoke_test.py +740 -0
- package/bundled-skills/fact-check-x-unified/tests/stage_checkpoint_test.py +103 -0
- package/bundled-skills/fact-check-x-unified/tests/trusted_search_config_test.py +156 -0
- package/bundled-skills/gpt-taste/SKILL.md +8 -1
- package/bundled-skills/hf-cli/SKILL.md +263 -0
- package/bundled-skills/huggingface-community-evals/SKILL.md +228 -0
- package/bundled-skills/huggingface-community-evals/examples/.env.example +3 -0
- package/bundled-skills/huggingface-community-evals/examples/USAGE_EXAMPLES.md +101 -0
- package/bundled-skills/huggingface-community-evals/scripts/inspect_eval_uv.py +104 -0
- package/bundled-skills/huggingface-community-evals/scripts/inspect_vllm_uv.py +306 -0
- package/bundled-skills/huggingface-community-evals/scripts/lighteval_vllm_uv.py +297 -0
- package/bundled-skills/huggingface-datasets/SKILL.md +130 -0
- package/bundled-skills/jev-social/SKILL.md +182 -0
- package/bundled-skills/longbridge-derivatives/SKILL.md +117 -0
- package/bundled-skills/longbridge-derivatives/references/option.md +36 -0
- package/bundled-skills/longbridge-derivatives/references/options-advanced.md +101 -0
- package/bundled-skills/longbridge-derivatives/references/options-pnl.md +74 -0
- package/bundled-skills/longbridge-derivatives/references/options-strategy.md +82 -0
- package/bundled-skills/longbridge-derivatives/references/options-volatility.md +70 -0
- package/bundled-skills/longbridge-derivatives/references/warrant.md +12 -0
- package/bundled-skills/longbridge-quant/SKILL.md +151 -0
- package/bundled-skills/longbridge-quant/references/correlation.md +51 -0
- package/bundled-skills/longbridge-quant/references/execution-model.md +68 -0
- package/bundled-skills/longbridge-quant/references/factor-research.md +95 -0
- package/bundled-skills/longbridge-quant/references/factor-screen.md +101 -0
- package/bundled-skills/longbridge-quant/references/hedging.md +136 -0
- package/bundled-skills/longbridge-quant/references/ml-strategy.md +77 -0
- package/bundled-skills/longbridge-quant/references/multifactor.md +68 -0
- package/bundled-skills/longbridge-quant/references/pairs-trading.md +61 -0
- package/bundled-skills/longbridge-quant/references/quant-cli.md +133 -0
- package/bundled-skills/longbridge-quant/references/quant-stats.md +150 -0
- package/bundled-skills/longbridge-quant/references/seasonality.md +50 -0
- package/bundled-skills/longbridge-quant/references/strategy-optimizer.md +68 -0
- package/bundled-skills/longbridge-quant/references/volatility-strategy.md +52 -0
- package/bundled-skills/longbridge-research/SKILL.md +187 -0
- package/bundled-skills/longbridge-research/references/company-profile.md +96 -0
- package/bundled-skills/longbridge-research/references/company-tearsheet.md +82 -0
- package/bundled-skills/longbridge-research/references/competitive-analysis.md +81 -0
- package/bundled-skills/longbridge-research/references/consensus.md +92 -0
- package/bundled-skills/longbridge-research/references/coverage-initiation.md +76 -0
- package/bundled-skills/longbridge-research/references/defi-yield.md +60 -0
- package/bundled-skills/longbridge-research/references/finance-calendar.md +165 -0
- package/bundled-skills/longbridge-research/references/financial-planning.md +77 -0
- package/bundled-skills/longbridge-research/references/forecast-eps.md +39 -0
- package/bundled-skills/longbridge-research/references/fund-holder.md +44 -0
- package/bundled-skills/longbridge-research/references/hkipo-analysis.md +101 -0
- package/bundled-skills/longbridge-research/references/industry-peers.md +46 -0
- package/bundled-skills/longbridge-research/references/industry-rank.md +62 -0
- package/bundled-skills/longbridge-research/references/insider-trades.md +48 -0
- package/bundled-skills/longbridge-research/references/institution-rating.md +62 -0
- package/bundled-skills/longbridge-research/references/investment-ideas.md +69 -0
- package/bundled-skills/longbridge-research/references/investment-proposal.md +95 -0
- package/bundled-skills/longbridge-research/references/investors.md +87 -0
- package/bundled-skills/longbridge-research/references/onchain.md +70 -0
- package/bundled-skills/longbridge-research/references/post-investment.md +76 -0
- package/bundled-skills/longbridge-research/references/shareholder.md +72 -0
- package/bundled-skills/longbridge-research/references/short-positions.md +50 -0
- package/bundled-skills/longbridge-research/references/short-trades.md +50 -0
- package/bundled-skills/longbridge-research/references/stock-research.md +61 -0
- package/bundled-skills/longbridge-research/references/thesis-tracker.md +64 -0
- package/bundled-skills/makepad-2-0-animation/SKILL.md +318 -0
- package/bundled-skills/makepad-2-0-animation/references/animator-reference.md +433 -0
- package/bundled-skills/makepad-2-0-dsl/SKILL.md +492 -0
- package/bundled-skills/makepad-2-0-dsl/references/dsl-syntax-reference.md +511 -0
- package/bundled-skills/makepad-2-0-dsl/references/extended-guide.md +56 -0
- package/bundled-skills/makepad-2-0-dsl/references/property-system.md +757 -0
- package/bundled-skills/makepad-2-0-events/SKILL.md +497 -0
- package/bundled-skills/makepad-2-0-events/references/event-patterns.md +802 -0
- package/bundled-skills/makepad-2-0-events/references/extended-guide.md +590 -0
- package/bundled-skills/makepad-2-0-layout/SKILL.md +499 -0
- package/bundled-skills/makepad-2-0-layout/references/extended-guide.md +243 -0
- package/bundled-skills/makepad-2-0-layout/references/layout-patterns.md +881 -0
- package/bundled-skills/makepad-2-0-widgets/SKILL.md +261 -0
- package/bundled-skills/makepad-2-0-widgets/references/widget-advanced.md +648 -0
- package/bundled-skills/makepad-2-0-widgets/references/widget-catalog.md +547 -0
- package/bundled-skills/meeting-distiller-pro/SKILL.md +120 -0
- package/bundled-skills/monte-carlo-analyze-root-cause/SKILL.md +12 -1
- package/bundled-skills/monte-carlo-asset-health/SKILL.md +12 -1
- package/bundled-skills/monte-carlo-context-detection/SKILL.md +170 -0
- package/bundled-skills/monte-carlo-context-detection/references/signal-definitions.md +46 -0
- package/bundled-skills/remotion-captions/SKILL.md +57 -0
- package/bundled-skills/remotion-captions/agents/openai.yaml +7 -0
- package/bundled-skills/remotion-captions/assets/remotion-icon.svg +4 -0
- package/bundled-skills/remotion-captions/display-captions.md +190 -0
- package/bundled-skills/remotion-captions/import-srt-captions.md +73 -0
- package/bundled-skills/remotion-captions/transcribe-captions.md +70 -0
- package/bundled-skills/remotion-create/SKILL.md +106 -0
- package/bundled-skills/remotion-create/agents/openai.yaml +7 -0
- package/bundled-skills/remotion-create/assets/remotion-icon.svg +4 -0
- package/bundled-skills/remotion-create/tailwind.md +11 -0
- package/bundled-skills/remotion-create/video-layout.md +9 -0
- package/bundled-skills/remotion-docs/SKILL.md +67 -0
- package/bundled-skills/remotion-docs/agents/openai.yaml +7 -0
- package/bundled-skills/remotion-docs/assets/remotion-icon.svg +4 -0
- package/bundled-skills/remotion-interactivity/SKILL.md +270 -0
- package/bundled-skills/remotion-interactivity/agents/openai.yaml +7 -0
- package/bundled-skills/remotion-interactivity/assets/remotion-icon.svg +4 -0
- package/bundled-skills/remotion-render/SKILL.md +48 -0
- package/bundled-skills/remotion-render/agents/openai.yaml +7 -0
- package/bundled-skills/remotion-render/assets/remotion-icon.svg +4 -0
- package/bundled-skills/remotion-render/transparent-videos.md +106 -0
- package/bundled-skills/saas-pricing-strategist/SKILL.md +169 -0
- package/bundled-skills/score-eval/SKILL.md +35 -0
- package/bundled-skills/writing-guidelines/SKILL.md +60 -0
- package/package.json +1 -1
- package/skills_index.json +980 -3
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import ssl
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
import urllib.error
|
|
11
|
+
import urllib.request
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
PROVIDER_URL = "https://platform.dknowc.cn/auth/#/login"
|
|
16
|
+
DEFAULT_ENDPOINT = "https://open.dknowc.cn/dependable/search"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ConfigurationError(RuntimeError):
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class InvalidCredentialError(ConfigurationError):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ServiceUnavailableError(ConfigurationError):
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def trusted_search_ssl_context() -> ssl.SSLContext:
|
|
32
|
+
candidates: list[str] = []
|
|
33
|
+
try:
|
|
34
|
+
import certifi
|
|
35
|
+
|
|
36
|
+
candidates.append(certifi.where())
|
|
37
|
+
except ImportError:
|
|
38
|
+
pass
|
|
39
|
+
defaults = ssl.get_default_verify_paths()
|
|
40
|
+
candidates.extend(
|
|
41
|
+
path
|
|
42
|
+
for path in (
|
|
43
|
+
defaults.cafile,
|
|
44
|
+
"/etc/ssl/cert.pem",
|
|
45
|
+
"/opt/homebrew/etc/openssl@3/cert.pem",
|
|
46
|
+
"/usr/local/etc/openssl@3/cert.pem",
|
|
47
|
+
)
|
|
48
|
+
if path
|
|
49
|
+
)
|
|
50
|
+
for candidate in dict.fromkeys(candidates):
|
|
51
|
+
if Path(candidate).is_file():
|
|
52
|
+
return ssl.create_default_context(cafile=candidate)
|
|
53
|
+
return ssl.create_default_context()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def credential_path() -> Path:
|
|
57
|
+
override = os.getenv("FACT_CHECK_X_TRUSTED_SEARCH_KEY_FILE", "").strip()
|
|
58
|
+
if override:
|
|
59
|
+
return Path(override).expanduser()
|
|
60
|
+
return Path.home() / ".fact-check-x" / "credentials" / "trusted-search-key"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _validate_key_shape(key: str) -> str:
|
|
64
|
+
normalized = key.strip()
|
|
65
|
+
if (
|
|
66
|
+
len(normalized) < 16
|
|
67
|
+
or any(character.isspace() for character in normalized)
|
|
68
|
+
or "*" in normalized
|
|
69
|
+
):
|
|
70
|
+
raise ConfigurationError("可信搜索 Key 格式不正确。")
|
|
71
|
+
return normalized
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _shared_trusted_search_key() -> str:
|
|
75
|
+
path = credential_path()
|
|
76
|
+
if not path.is_file():
|
|
77
|
+
return ""
|
|
78
|
+
if os.name != "nt" and path.stat().st_mode & 0o077:
|
|
79
|
+
raise ConfigurationError("本机可信搜索配置权限不安全,请重新执行自动配置。")
|
|
80
|
+
return _validate_key_shape(path.read_text(encoding="utf-8"))
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def trusted_search_key_candidates() -> list[tuple[str, str]]:
|
|
84
|
+
candidates = []
|
|
85
|
+
shared_key = _shared_trusted_search_key()
|
|
86
|
+
if shared_key:
|
|
87
|
+
candidates.append(("shared_local_credential", shared_key))
|
|
88
|
+
environment_key = os.getenv("TRUSTED_SEARCH_KEY", "").strip()
|
|
89
|
+
if environment_key:
|
|
90
|
+
normalized = _validate_key_shape(environment_key)
|
|
91
|
+
if all(normalized != key for _, key in candidates):
|
|
92
|
+
candidates.append(("environment", normalized))
|
|
93
|
+
return candidates
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def load_trusted_search_key() -> str:
|
|
97
|
+
candidates = trusted_search_key_candidates()
|
|
98
|
+
return candidates[0][1] if candidates else ""
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def key_source() -> str:
|
|
102
|
+
candidates = trusted_search_key_candidates()
|
|
103
|
+
return candidates[0][0] if candidates else "missing"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def clear_trusted_search_key() -> bool:
|
|
107
|
+
path = credential_path()
|
|
108
|
+
existed = path.exists()
|
|
109
|
+
path.unlink(missing_ok=True)
|
|
110
|
+
return existed
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def validate_trusted_search_key(key: str) -> None:
|
|
114
|
+
normalized = _validate_key_shape(key)
|
|
115
|
+
endpoint = os.getenv("FACTCHECK_TRUSTED_SEARCH_URL", DEFAULT_ENDPOINT).strip()
|
|
116
|
+
payload = {
|
|
117
|
+
"query": "住房公积金管理条例",
|
|
118
|
+
"segmentCount": 1,
|
|
119
|
+
"simplified": True,
|
|
120
|
+
"return_full_content": False,
|
|
121
|
+
}
|
|
122
|
+
request = urllib.request.Request(
|
|
123
|
+
endpoint,
|
|
124
|
+
data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
|
|
125
|
+
method="POST",
|
|
126
|
+
headers={"Content-Type": "application/json", "api-key": normalized},
|
|
127
|
+
)
|
|
128
|
+
try:
|
|
129
|
+
with urllib.request.urlopen(
|
|
130
|
+
request,
|
|
131
|
+
timeout=20,
|
|
132
|
+
context=trusted_search_ssl_context(),
|
|
133
|
+
) as response:
|
|
134
|
+
raw = response.read().decode("utf-8")
|
|
135
|
+
status = response.status
|
|
136
|
+
except urllib.error.HTTPError as exc:
|
|
137
|
+
if exc.code in {401, 403}:
|
|
138
|
+
raise InvalidCredentialError("MaaS 返回的 Key 无效或无可信搜索权限。") from None
|
|
139
|
+
raise ServiceUnavailableError(f"可信搜索服务暂时不可用(HTTP {exc.code})。") from None
|
|
140
|
+
except (urllib.error.URLError, TimeoutError, OSError):
|
|
141
|
+
raise ServiceUnavailableError("暂时无法连接可信搜索服务,请检查网络后重试。") from None
|
|
142
|
+
try:
|
|
143
|
+
data = json.loads(raw)
|
|
144
|
+
except json.JSONDecodeError:
|
|
145
|
+
raise ServiceUnavailableError("可信搜索服务返回异常,请稍后重试。") from None
|
|
146
|
+
code = data.get("code") if isinstance(data, dict) else None
|
|
147
|
+
if status != 200 or not isinstance(data, dict):
|
|
148
|
+
raise ServiceUnavailableError("可信搜索服务返回异常,请稍后重试。")
|
|
149
|
+
if code not in (None, 0, 200):
|
|
150
|
+
if code in (401, 403):
|
|
151
|
+
raise InvalidCredentialError("MaaS 返回的 Key 无效或无可信搜索权限。")
|
|
152
|
+
raise ServiceUnavailableError("可信搜索服务返回异常,请稍后重试。")
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def validated_trusted_search_key() -> tuple[str, str]:
|
|
156
|
+
for source, key in trusted_search_key_candidates():
|
|
157
|
+
try:
|
|
158
|
+
validate_trusted_search_key(key)
|
|
159
|
+
except ConfigurationError:
|
|
160
|
+
continue
|
|
161
|
+
return key, source
|
|
162
|
+
return "", "missing"
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def trusted_search_key_for_execution() -> tuple[str, str, str]:
|
|
166
|
+
transient_candidate: tuple[str, str] | None = None
|
|
167
|
+
for source, key in trusted_search_key_candidates():
|
|
168
|
+
try:
|
|
169
|
+
validate_trusted_search_key(key)
|
|
170
|
+
except ServiceUnavailableError:
|
|
171
|
+
if transient_candidate is None:
|
|
172
|
+
transient_candidate = (source, key)
|
|
173
|
+
continue
|
|
174
|
+
except ConfigurationError:
|
|
175
|
+
continue
|
|
176
|
+
return key, source, "valid"
|
|
177
|
+
if transient_candidate is not None:
|
|
178
|
+
source, key = transient_candidate
|
|
179
|
+
return key, source, "service_unavailable"
|
|
180
|
+
return "", "missing", "missing"
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def onboarding_script_candidates() -> list[Path]:
|
|
184
|
+
script_root = Path(__file__).resolve().parent
|
|
185
|
+
skill_root = script_root.parent
|
|
186
|
+
candidates = [
|
|
187
|
+
skill_root
|
|
188
|
+
/ "modules"
|
|
189
|
+
/ "llm-answer-reference-compare"
|
|
190
|
+
/ "assets"
|
|
191
|
+
/ "tool"
|
|
192
|
+
/ "dist"
|
|
193
|
+
/ "trusted-search-onboarding.js",
|
|
194
|
+
skill_root.parent
|
|
195
|
+
/ "llm-answer-reference-compare"
|
|
196
|
+
/ "assets"
|
|
197
|
+
/ "tool"
|
|
198
|
+
/ "dist"
|
|
199
|
+
/ "trusted-search-onboarding.js",
|
|
200
|
+
]
|
|
201
|
+
output = []
|
|
202
|
+
for candidate in candidates:
|
|
203
|
+
resolved = candidate.resolve()
|
|
204
|
+
if resolved not in output:
|
|
205
|
+
output.append(resolved)
|
|
206
|
+
return output
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def locate_onboarding_script() -> Path:
|
|
210
|
+
for candidate in onboarding_script_candidates():
|
|
211
|
+
if candidate.is_file():
|
|
212
|
+
return candidate
|
|
213
|
+
searched = "、".join(str(path) for path in onboarding_script_candidates())
|
|
214
|
+
raise ConfigurationError(f"未找到可信搜索自动配置组件;已检查:{searched}")
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def run_onboarding(*, force: bool = False) -> dict:
|
|
218
|
+
script = locate_onboarding_script()
|
|
219
|
+
command = [
|
|
220
|
+
"node",
|
|
221
|
+
str(script),
|
|
222
|
+
"--credential-file",
|
|
223
|
+
str(credential_path()),
|
|
224
|
+
"--provider-url",
|
|
225
|
+
PROVIDER_URL,
|
|
226
|
+
]
|
|
227
|
+
if force:
|
|
228
|
+
command.append("--force")
|
|
229
|
+
process = subprocess.run(
|
|
230
|
+
command,
|
|
231
|
+
text=True,
|
|
232
|
+
capture_output=True,
|
|
233
|
+
check=False,
|
|
234
|
+
env=os.environ.copy(),
|
|
235
|
+
)
|
|
236
|
+
lines = [line for line in process.stdout.splitlines() if line.strip()]
|
|
237
|
+
result = {}
|
|
238
|
+
if lines:
|
|
239
|
+
try:
|
|
240
|
+
result = json.loads(lines[-1])
|
|
241
|
+
except json.JSONDecodeError:
|
|
242
|
+
result = {}
|
|
243
|
+
if process.returncode or result.get("status") not in {
|
|
244
|
+
"configured",
|
|
245
|
+
"already_configured",
|
|
246
|
+
}:
|
|
247
|
+
message = str(result.get("error") or "").strip()
|
|
248
|
+
if not message:
|
|
249
|
+
message = "可信搜索自动配置未完成,请保持浏览器打开并完成登录。"
|
|
250
|
+
raise ConfigurationError(message)
|
|
251
|
+
load_trusted_search_key()
|
|
252
|
+
return {
|
|
253
|
+
"status": result["status"],
|
|
254
|
+
"providerUrl": PROVIDER_URL,
|
|
255
|
+
"validated": True,
|
|
256
|
+
"source": str(result.get("source") or "maas_console"),
|
|
257
|
+
"created": bool(result.get("created")),
|
|
258
|
+
"message": (
|
|
259
|
+
"检测到已有有效配置,已跳过 MaaS 登录。"
|
|
260
|
+
if result["status"] == "already_configured"
|
|
261
|
+
else "MaaS 登录与可信搜索配置已完成,流水线可以自动继续。"
|
|
262
|
+
),
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def configure() -> dict:
|
|
267
|
+
existing, source, validation = trusted_search_key_for_execution()
|
|
268
|
+
if existing:
|
|
269
|
+
return {
|
|
270
|
+
"status": "already_configured",
|
|
271
|
+
"providerUrl": PROVIDER_URL,
|
|
272
|
+
"validated": validation == "valid",
|
|
273
|
+
"validation": validation,
|
|
274
|
+
"source": source,
|
|
275
|
+
"created": False,
|
|
276
|
+
"message": (
|
|
277
|
+
"检测到已有有效可信搜索配置,已跳过 MaaS 登录。"
|
|
278
|
+
if validation == "valid"
|
|
279
|
+
else "检测到已有可信搜索配置;服务暂时不可达,已保留配置且不会要求重复登录。"
|
|
280
|
+
),
|
|
281
|
+
}
|
|
282
|
+
return run_onboarding(force=True)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def parser() -> argparse.ArgumentParser:
|
|
286
|
+
root = argparse.ArgumentParser(description="Fact-Check-X 可信搜索跨载体自动配置。")
|
|
287
|
+
commands = root.add_subparsers(dest="command", required=True)
|
|
288
|
+
commands.add_parser("configure", help="登录 MaaS 后自动获取或创建 Key 并完成配置")
|
|
289
|
+
commands.add_parser("status", help="检查共享配置,不显示 Key")
|
|
290
|
+
commands.add_parser("clear", help="清除本机共享的可信搜索 Key")
|
|
291
|
+
return root
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def main() -> int:
|
|
295
|
+
args = parser().parse_args()
|
|
296
|
+
try:
|
|
297
|
+
if args.command == "configure":
|
|
298
|
+
print(json.dumps(configure(), ensure_ascii=False))
|
|
299
|
+
return 0
|
|
300
|
+
if args.command == "clear":
|
|
301
|
+
print(json.dumps({
|
|
302
|
+
"status": "cleared",
|
|
303
|
+
"removed": clear_trusted_search_key(),
|
|
304
|
+
}, ensure_ascii=False))
|
|
305
|
+
return 0
|
|
306
|
+
configured = bool(load_trusted_search_key())
|
|
307
|
+
print(json.dumps({
|
|
308
|
+
"status": "configured" if configured else "configuration_required",
|
|
309
|
+
"configured": configured,
|
|
310
|
+
"source": key_source(),
|
|
311
|
+
"providerUrl": PROVIDER_URL,
|
|
312
|
+
}, ensure_ascii=False))
|
|
313
|
+
return 0 if configured else 3
|
|
314
|
+
except (ConfigurationError, OSError) as exc:
|
|
315
|
+
print(json.dumps({
|
|
316
|
+
"status": "failed",
|
|
317
|
+
"error": str(exc),
|
|
318
|
+
"providerUrl": PROVIDER_URL,
|
|
319
|
+
}, ensure_ascii=False))
|
|
320
|
+
return 1
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
if __name__ == "__main__":
|
|
324
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""锚点模式门禁的非对称性回归。
|
|
3
|
+
|
|
4
|
+
比较阶段依据引用池认定「免搜索」,核验阶段可能独立判定该锚点撑不住主张而改走
|
|
5
|
+
可信搜索。多搜一次是保守方向,必须放行(否则整条流水线死锁);反过来把本应搜索
|
|
6
|
+
的知识点降级成免搜索属于洗白,必须继续拦住。
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import sys
|
|
12
|
+
import tempfile
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
16
|
+
sys.path.insert(0, str(ROOT / "scripts"))
|
|
17
|
+
from common import PipelineError
|
|
18
|
+
from fact_check_x import merge_verification
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def comparison_for(anchor: dict) -> dict:
|
|
22
|
+
return {
|
|
23
|
+
"knowledgePoints": [
|
|
24
|
+
{
|
|
25
|
+
"id": "K1",
|
|
26
|
+
"role": "direct",
|
|
27
|
+
"statement": "示例主张",
|
|
28
|
+
"trustedAnchor": anchor,
|
|
29
|
+
"claims": {"alpha": {"covered": True}},
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def authority(search_mode: str, request_count: int) -> dict:
|
|
36
|
+
return {
|
|
37
|
+
"schemaVersion": "fact-check-x/authority-result@1",
|
|
38
|
+
"requestId": "K1",
|
|
39
|
+
"searchMode": search_mode,
|
|
40
|
+
"requestCount": request_count,
|
|
41
|
+
"authoritativeFinding": "示例权威结论",
|
|
42
|
+
"verdicts": {"alpha": {"verdict": "supported", "category": "direct_accurate"}},
|
|
43
|
+
"evidenceGaps": [],
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
GOV_ANCHOR = {"eligible": True, "sourcePolicy": "gov_cn_reference"}
|
|
48
|
+
NO_ANCHOR: dict = {}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def run(anchor: dict, search_mode: str, request_count: int) -> dict:
|
|
52
|
+
with tempfile.TemporaryDirectory(prefix="fcx-anchor-") as raw:
|
|
53
|
+
results_dir = Path(raw)
|
|
54
|
+
(results_dir / "K1.json").write_text(
|
|
55
|
+
json.dumps(authority(search_mode, request_count), ensure_ascii=False),
|
|
56
|
+
encoding="utf-8",
|
|
57
|
+
)
|
|
58
|
+
return merge_verification(comparison_for(anchor), results_dir)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# 1. 期望免搜 + 核验阶段判锚点无效改走可信搜索:放行并留痕
|
|
62
|
+
# 修复前这里直接 PipelineError,整条流水线停在合并阶段,第四步出不来
|
|
63
|
+
downgraded = run(GOV_ANCHOR, "trusted_search", 1)
|
|
64
|
+
assert downgraded["govExemptCount"] == 0, downgraded["govExemptCount"]
|
|
65
|
+
assert downgraded["trustedSearchRequestCount"] == 1
|
|
66
|
+
assert downgraded["anchorDowngrades"] == ["K1"], downgraded["anchorDowngrades"]
|
|
67
|
+
|
|
68
|
+
# 2. 期望免搜 + 实际免搜:正常,不留降级记录
|
|
69
|
+
ok = run(GOV_ANCHOR, "gov_exempt", 0)
|
|
70
|
+
assert ok["govExemptCount"] == 1, ok["govExemptCount"]
|
|
71
|
+
assert ok["anchorDowngrades"] == [], ok["anchorDowngrades"]
|
|
72
|
+
|
|
73
|
+
# 3. 期望搜索 + 实际降级成免搜索:洗白,必须继续拒绝
|
|
74
|
+
for forged_mode in ("gov_exempt", "dknow_exempt"):
|
|
75
|
+
try:
|
|
76
|
+
run(NO_ANCHOR, forged_mode, 0)
|
|
77
|
+
except PipelineError:
|
|
78
|
+
pass
|
|
79
|
+
else:
|
|
80
|
+
raise AssertionError(f"{forged_mode} 降级未被拦截")
|
|
81
|
+
|
|
82
|
+
# 4. 模式相符但请求数对不上:仍然拒绝
|
|
83
|
+
try:
|
|
84
|
+
run(GOV_ANCHOR, "gov_exempt", 3)
|
|
85
|
+
except PipelineError:
|
|
86
|
+
pass
|
|
87
|
+
else:
|
|
88
|
+
raise AssertionError("免搜模式下的异常请求数未被拦截")
|
|
89
|
+
|
|
90
|
+
print("PASS 锚点门禁非对称:多搜放行、洗白拦截")
|