mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-10 18:23:12 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b847406dc | ||
|
|
613a196501 | ||
|
|
ef0c55c40f |
@@ -1,4 +1,4 @@
|
||||
**Language:** English | [Português (Brasil)](docs/pt-BR/README.md) | [简体中文](README.zh-CN.md) | [繁體中文](docs/zh-TW/README.md) | [日本語](docs/ja-JP/README.md) | [한국어](docs/ko-KR/README.md) | [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md)
|
||||
**Language:** English | [Português (Brasil)](docs/pt-BR/README.md) | [简体中文](README.zh-CN.md) | [繁體中文](docs/zh-TW/README.md) | [日本語](docs/ja-JP/README.md) | [한국어](docs/ko-KR/README.md) | [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md) | [Deutsch](docs/de-DE/README.md)
|
||||
|
||||
# ECC
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
**Language / 语言 / 語言 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](README.md) | [Português (Brasil)](docs/pt-BR/README.md) | [简体中文](README.zh-CN.md) | [繁體中文](docs/zh-TW/README.md) | [日本語](docs/ja-JP/README.md) | [한국어](docs/ko-KR/README.md)
|
||||
| [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md)
|
||||
| [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md) | [Deutsch](docs/de-DE/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
**Language / 语言 / 語言 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](README.md) | [Português (Brasil)](docs/pt-BR/README.md) | [简体中文](README.zh-CN.md) | [繁體中文](docs/zh-TW/README.md) | [日本語](docs/ja-JP/README.md) | [한국어](docs/ko-KR/README.md) | [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md)
|
||||
[**English**](README.md) | [Português (Brasil)](docs/pt-BR/README.md) | [简体中文](README.zh-CN.md) | [繁體中文](docs/zh-TW/README.md) | [日本語](docs/ja-JP/README.md) | [한국어](docs/ko-KR/README.md) | [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md) | [Deutsch](docs/de-DE/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
67
docs/de-DE/GLOSSARY.md
Normal file
67
docs/de-DE/GLOSSARY.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Glossar / Glossary
|
||||
|
||||
Einheitliches Terminologie-Glossar für die deutsche (de-DE) Übersetzung von ECC.
|
||||
|
||||
Leitlinie: Etablierte englische Fachbegriffe und ECC-Oberflächennamen (`agents/`, `skills/`,
|
||||
`commands/`, `hooks/`, `rules/`) bleiben **englisch** — sie sind im deutschsprachigen
|
||||
Entwickleralltag Standard und entsprechen Verzeichnis-/Befehlsnamen im Repo. Begriffe mit
|
||||
einer klaren, gebräuchlichen deutschen Entsprechung werden **übersetzt**.
|
||||
|
||||
| English | Deutsch | Notiz |
|
||||
|---------|---------|-------|
|
||||
| Agent | Agent | bleibt englisch — ECC-Oberfläche (`agents/`) |
|
||||
| Skill | Skill | bleibt englisch — ECC-Oberfläche (`skills/`) |
|
||||
| Hook | Hook | bleibt englisch — ECC-Oberfläche (`hooks/`) |
|
||||
| Command | Command | bleibt englisch als ECC-Oberfläche (`commands/`); generisch sonst „Befehl“ |
|
||||
| Rule | Rule | bleibt englisch als ECC-Oberfläche (`rules/`); generisch sonst „Regel“ |
|
||||
| Harness | Harness | bleibt englisch — keine etablierte deutsche Entsprechung |
|
||||
| Instinct | Instinct | bleibt englisch — ECC-Begriff aus Continuous Learning |
|
||||
| Plugin | Plugin | bleibt englisch |
|
||||
| Marketplace | Marketplace | bleibt englisch — Anthropic-Produktbegriff |
|
||||
| Worktree | Worktree | bleibt englisch — Git-Fachbegriff |
|
||||
| Subagent | Subagent | bleibt englisch |
|
||||
| Frontmatter | Frontmatter | bleibt englisch; YAML-Feldnamen bleiben englisch |
|
||||
| Continuous Learning | Continuous Learning | ECC-Feature-Name bleibt englisch; beschreibend „kontinuierliches Lernen“ |
|
||||
| Memory | Memory | als ECC-Konzept englisch; generisch „Speicher“ |
|
||||
| Context window | Kontextfenster | |
|
||||
| Token | Token | |
|
||||
| Coverage | Coverage | „Testabdeckung“, wo beschreibend |
|
||||
| Test-Driven Development | testgetriebene Entwicklung | Kürzel TDD beibehalten |
|
||||
| Code review | Code-Review | |
|
||||
| Refactoring | Refactoring | |
|
||||
| Pull request | Pull Request | |
|
||||
| Commit | Commit | |
|
||||
| Branch | Branch | |
|
||||
| Merge | Merge / zusammenführen | je nach Kontext |
|
||||
| Build | Build | |
|
||||
| Deploy | Deployment / deployen | |
|
||||
| Pipeline | Pipeline | |
|
||||
| Orchestration | Orchestrierung | |
|
||||
| Repository | Repository | kurz „Repo“ zulässig |
|
||||
| Dependency | Abhängigkeit | |
|
||||
| Edge case | Grenzfall | |
|
||||
| Best practice | Best Practice | |
|
||||
| Anti-pattern | Anti-Pattern | |
|
||||
| Middleware | Middleware | |
|
||||
| Endpoint | Endpoint | |
|
||||
| Schema | Schema | |
|
||||
| Payload | Payload | |
|
||||
| Callback | Callback | |
|
||||
| Checkpoint | Checkpoint | |
|
||||
| Linter | Linter | |
|
||||
| Formatter | Formatter | |
|
||||
| Staging | Staging | |
|
||||
| Production | Produktion / Produktivumgebung | je nach Kontext |
|
||||
| Debugging | Debugging | |
|
||||
| Logging | Logging | |
|
||||
| Monitoring | Monitoring | |
|
||||
| Rate limit | Rate-Limit | |
|
||||
| Retry | Retry / Wiederholung | |
|
||||
| Fallback | Fallback | |
|
||||
| Graceful degradation | Graceful Degradation | |
|
||||
| Sandboxing | Sandboxing | |
|
||||
| Sanitization | Sanitisierung | |
|
||||
| Selective install | selektive Installation | |
|
||||
| Profile | Profil | Installationsprofil |
|
||||
| Component | Komponente | Installationskomponente |
|
||||
| Module | Modul | Installationsmodul |
|
||||
1762
docs/de-DE/README.md
Normal file
1762
docs/de-DE/README.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
**言語:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
**言語:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
|
||||
# Everything Claude Code
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
**言語 / Language / 語言 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
**언어:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | 한국어 | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
**언어:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | 한국어 | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
|
||||
# Everything Claude Code
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
**Language / 语言 / 語言 / 언어 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
**Idioma:** [English](../../README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | Português (Brasil) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
**Idioma:** [English](../../README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | Português (Brasil) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
|
||||
# Everything Claude Code
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
**Idioma / Language / 语言 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](../../README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Português (Brasil)](README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
[**English**](../../README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Português (Brasil)](README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
**Язык:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | **Русский** | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
**Язык:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | **Русский** | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
|
||||
# Everything Claude Code
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
**Язык / 语言 / 語言 / Dil / Ngôn ngữ**
|
||||
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | **Русский** | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | **Русский** | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
**ภาษา:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | **ไทย**
|
||||
**ภาษา:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | **ไทย** | [Deutsch](../de-DE/README.md)
|
||||
|
||||
# Everything Claude Code
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
**ภาษา / Language / 语言 / 語言 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | **ไทย**
|
||||
[English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | **ไทย** | [Deutsch](../de-DE/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
**Dil / Language / 语言 / 語言 / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [**Türkçe**](README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [**Türkçe**](README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
**Ngôn ngữ:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | **Tiếng Việt** | [ไทย](../th/README.md)
|
||||
**Ngôn ngữ:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | **Tiếng Việt** | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
|
||||
# Everything Claude Code
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
**Ngôn ngữ / Language / 语言 / 語言 / Dil / Язык**
|
||||
|
||||
[English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | **Tiếng Việt** | [ไทย](../th/README.md)
|
||||
[English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | **Tiếng Việt** | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
**Language / 语言 / 語言 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | **繁體中文** | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | **繁體中文** | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
# AURA trust-check adapter
|
||||
|
||||
Opt-in, **read-only** counterparty reputation for agent hosts. One HTTP GET
|
||||
answers *"can I trust this agent before I delegate work or settle a payment?"*
|
||||
|
||||
- **Zero dependencies** — pure Python stdlib. Vendor the `aura/` folder, no `pip install`.
|
||||
- **Read-only** — the only network call is `GET /check?did=...`. No auth, no API key.
|
||||
- **No coupling** — does not sign, hold keys, move funds, or touch your wallet.
|
||||
- **Off by default** — nothing runs until you call it. Disabled = delete the import.
|
||||
|
||||
## Enable (opt-in)
|
||||
|
||||
It's a gate you call explicitly at a trust boundary — there is no global hook,
|
||||
no monkey-patching, no background calls. Wrap the action you want to protect:
|
||||
|
||||
```python
|
||||
from aura import before_settle, AuraUntrusted
|
||||
|
||||
def settle(counterparty_did: str, amount: float) -> None:
|
||||
try:
|
||||
before_settle(counterparty_did) # rejects high_risk + unknown
|
||||
except AuraUntrusted as e:
|
||||
log.warning("blocked: %s", e)
|
||||
return # your policy decides what to do
|
||||
pay(counterparty_did, amount) # your existing logic, untouched
|
||||
```
|
||||
|
||||
Prefer to read the verdict yourself instead of raising?
|
||||
|
||||
```python
|
||||
from aura import aura_verdict
|
||||
|
||||
v = aura_verdict(counterparty_did)
|
||||
print(v.verdict) # trusted | caution | high_risk | new | unknown
|
||||
print(v.reason) # human-readable explanation
|
||||
print(v.score) # composite 0..1, or None when there's no history
|
||||
print(v.ok) # True for trusted/caution
|
||||
|
||||
# v.dimensions tells you *which* axis is weak, not just the aggregate:
|
||||
if v.dimensions and v.dimensions.get("financial_integrity", 1) < 0.4:
|
||||
require_manual_review() # placeholder for your own policy
|
||||
```
|
||||
|
||||
> `v.ok` reflects the *verdict class* (True for `trusted`/`caution`), not the
|
||||
> outcome of `require_trust()` — the gate's default `allow` also lets `new`
|
||||
> through. Use the gate's return/raise for the decision, `v.ok` for display.
|
||||
|
||||
## Verdicts
|
||||
|
||||
| verdict | meaning | `ok` |
|
||||
|---|---|---|
|
||||
| `trusted` | strong on-chain track record (composite ≥ 0.70) | ✅ |
|
||||
| `caution` | mixed history (0.40–0.70) | ✅ |
|
||||
| `high_risk` | poor track record (< 0.40) | ❌ |
|
||||
| `new` | registered identity, no interactions yet | ❌ |
|
||||
| `unknown` | no track record — or AURA was unreachable | ❌ |
|
||||
|
||||
## Policy knobs
|
||||
|
||||
```python
|
||||
# Reject brand-new agents too (strict):
|
||||
before_settle(did, allow=("trusted", "caution"))
|
||||
|
||||
# Treat an *unreachable* AURA as a pass (fail-open). Off by default —
|
||||
# absence of evidence is not evidence of trust.
|
||||
before_settle(did, fail_open=True)
|
||||
|
||||
# Point at a self-hosted / staging gateway:
|
||||
before_settle(did, base_url="https://my-aura-mirror.example", timeout=5)
|
||||
```
|
||||
|
||||
`require_trust` is an alias of `before_settle` for non-payment call sites.
|
||||
|
||||
## Failure behavior
|
||||
|
||||
`aura_verdict()` **never raises on a network or parse error** — it returns an
|
||||
`unknown` verdict with the reason set. The gate then decides:
|
||||
|
||||
- **default (`fail_open=False`)** — `unknown` is rejected → an unreachable AURA
|
||||
blocks the action. *Fail-closed.*
|
||||
- **`fail_open=True`** — `unknown` from an unreachable endpoint is allowed
|
||||
through, so AURA can never take your flow down. *Fail-open.*
|
||||
|
||||
This keeps the trust signal **purely additive**: if you remove the adapter or
|
||||
AURA is down, your existing allow/deny logic runs exactly as before.
|
||||
|
||||
## Tests
|
||||
|
||||
Offline — every call replays a recorded `/check` body, no network:
|
||||
|
||||
```bash
|
||||
python -m pytest aura/tests -q
|
||||
```
|
||||
|
||||
Covers all five verdict classes, the gate's allow-list + `fail_open`, the
|
||||
unreachable path, and input validation. See `tests/fixtures.py` for the
|
||||
recorded response shapes.
|
||||
|
||||
## Boundary & threats
|
||||
|
||||
See [THREAT_MODEL.md](./THREAT_MODEL.md) — what the verdict does and does not
|
||||
prove, and the failure modes a verifier should account for.
|
||||
|
||||
## Carry the AURA badge
|
||||
|
||||
Show your live trust verdict in your own README — it updates automatically and
|
||||
links back to your AURA profile:
|
||||
|
||||
```markdown
|
||||
[](https://agent.auraopenprotocol.org/check?did=YOUR_DID)
|
||||
```
|
||||
|
||||
A shields-style badge colored by verdict (`trusted` green, `caution` amber,
|
||||
`high_risk` red, `new` blue, `unknown` grey). Add `&score=1` to show the
|
||||
composite score. No DID yet? The bare badge is a generic mark:
|
||||
|
||||
```markdown
|
||||
[](https://auraopenprotocol.org)
|
||||
```
|
||||
|
||||
## What's behind the verdict
|
||||
|
||||
[AURA Open Protocol](https://auraopenprotocol.org) — W3C DID identity plus 8
|
||||
on-chain reputation dimensions on Base L2 (`task_completion`, `delivery_speed`,
|
||||
`output_quality`, `honesty`, `financial_integrity`, `security_compliance`,
|
||||
`collaboration`, `dispute_history`). Docs: https://dev.auraopenprotocol.org
|
||||
@@ -1,55 +0,0 @@
|
||||
# Threat model — AURA trust-check adapter
|
||||
|
||||
A short, honest boundary statement. The verdict is **one backward-looking
|
||||
signal**, not a security guarantee. Read this before treating `trusted` as a
|
||||
green light for anything irreversible.
|
||||
|
||||
## What the verdict proves
|
||||
|
||||
- The DID has (or lacks) an on-chain interaction history on AURA, summarized
|
||||
into a composite score and per-dimension breakdown.
|
||||
- It is **backward-looking**: a statement about past recorded behavior, not a
|
||||
prediction or an authorization for the *current* proposed action.
|
||||
|
||||
## What it explicitly does NOT prove
|
||||
|
||||
- **Not action-safety.** A `trusted` agent can still propose a malicious or
|
||||
buggy transaction. Pair this with a forward-looking action-risk check
|
||||
(contract simulation, policy engine) and keep the two signals separate so
|
||||
the policy decision stays auditable.
|
||||
- **Not execution quality.** It says nothing about whether *this* call will
|
||||
succeed.
|
||||
- **Not identity proof of the live caller.** It checks a DID's reputation, not
|
||||
that the entity you're talking to controls that DID (see "Spoofed DID").
|
||||
|
||||
## Failure modes a caller must account for
|
||||
|
||||
| # | Threat | Mitigation in this adapter | Residual risk owned by caller |
|
||||
|---|---|---|---|
|
||||
| 1 | **Endpoint unreachable / timeout** | Returns `unknown` (never raises). Gate is fail-closed by default. | Choose `fail_open` deliberately; pick a sane `timeout`. |
|
||||
| 2 | **Spoofed DID** — caller claims a DID it doesn't control | Out of scope: adapter checks reputation, not control of the key. | Verify DID control (signature challenge / auth) **before** trusting the verdict. |
|
||||
| 3 | **Stale verdict** — score lags very recent bad behavior | Each call is live (no caching here). | If you cache the result, bound the TTL; don't reuse a verdict across sessions. |
|
||||
| 4 | **Endpoint MITM / response tampering** | HTTPS to a pinned host (`agent.auraopenprotocol.org`). Verdict strings are validated against a fixed allow-list; unknown values collapse to `unknown`. | Don't point `base_url` at an untrusted mirror. Consider TLS pinning if your runtime supports it. |
|
||||
| 5 | **Score gaming / Sybil** — cheap DIDs farming a `trusted` score | Inherited from AURA's on-chain cost + dispute dimension; not solvable in the adapter. | Weight `dimensions` (e.g. require non-trivial `interactions` / `dispute_history`) for high-value actions rather than trusting the aggregate alone. |
|
||||
| 6 | **Over-trust** — using the verdict as sole gate for irreversible value | `new`/`unknown` rejected by default; `dimensions` exposed. | For high-value settlement, combine with action-risk + escrow + manual review. |
|
||||
|
||||
## Data handled
|
||||
|
||||
- **Sent:** only the counterparty DID, as a query parameter to `/check`. No
|
||||
PII, no payloads, no secrets, no keys.
|
||||
- **Stored:** nothing. The adapter is stateless; it holds the DID only for the
|
||||
duration of the call.
|
||||
- **Received:** the public `/check` JSON body. Surfaced verbatim on `.raw`.
|
||||
|
||||
## Trust boundary summary
|
||||
|
||||
```
|
||||
your host --(DID only, HTTPS GET)--> AURA /check --> verdict
|
||||
| |
|
||||
| forward-looking action-risk check (separate, yours) |
|
||||
v v
|
||||
policy decision (auditable, your code)
|
||||
```
|
||||
|
||||
The adapter sits on the read-only reputation edge. Signing, fund movement,
|
||||
and the final allow/deny decision stay in your code, where they can be audited.
|
||||
@@ -1,36 +0,0 @@
|
||||
"""
|
||||
AURA trust-check adapter — opt-in, read-only counterparty reputation.
|
||||
|
||||
from aura import before_settle, AuraUntrusted
|
||||
|
||||
try:
|
||||
before_settle(counterparty_did)
|
||||
settle_payment(counterparty_did, amount)
|
||||
except AuraUntrusted as e:
|
||||
abort(str(e))
|
||||
|
||||
Zero dependencies (pure stdlib). Does not sign, hold keys, or move funds.
|
||||
See README.md for the enable section and THREAT_MODEL.md for the boundary.
|
||||
"""
|
||||
|
||||
from .adapter import (
|
||||
DEFAULT_ALLOW,
|
||||
DEFAULT_BASE_URL,
|
||||
AuraUntrusted,
|
||||
AuraVerdict,
|
||||
aura_verdict,
|
||||
before_settle,
|
||||
require_trust,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"aura_verdict",
|
||||
"before_settle",
|
||||
"require_trust",
|
||||
"AuraVerdict",
|
||||
"AuraUntrusted",
|
||||
"DEFAULT_BASE_URL",
|
||||
"DEFAULT_ALLOW",
|
||||
]
|
||||
|
||||
__version__ = "0.1.0"
|
||||
@@ -1,206 +0,0 @@
|
||||
"""
|
||||
AURA trust-check adapter — a zero-dependency, read-only reputation lookup.
|
||||
|
||||
Drop this module into any agent/host project to gate a sensitive action
|
||||
(settlement, delegation, tool execution) behind a backward-looking trust
|
||||
verdict for the *counterparty* agent. It does NOT sign, hold keys, move
|
||||
funds, or touch your wallet. It makes one HTTP GET and returns a verdict.
|
||||
|
||||
Design boundary (intentional):
|
||||
- read-only: the only network call is GET /check?did=...
|
||||
- no auth: /check is a public endpoint; no API key, no secret
|
||||
- no coupling: pure stdlib (urllib). No third-party imports, no SDK.
|
||||
- fail-closed: on network failure the verdict is `unknown`, and the
|
||||
default gate (before_settle) rejects `unknown` — so an
|
||||
unreachable AURA never silently waves a counterparty
|
||||
through. Flip `fail_open=True` to invert that.
|
||||
|
||||
Public API:
|
||||
aura_verdict(did) -> AuraVerdict (never raises on network)
|
||||
before_settle(did, allow=...) -> AuraVerdict (raises AuraUntrusted)
|
||||
require_trust = before_settle (alias)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
__all__ = [
|
||||
"aura_verdict",
|
||||
"before_settle",
|
||||
"require_trust",
|
||||
"AuraVerdict",
|
||||
"AuraUntrusted",
|
||||
"DEFAULT_BASE_URL",
|
||||
"DEFAULT_ALLOW",
|
||||
]
|
||||
|
||||
DEFAULT_BASE_URL = "https://agent.auraopenprotocol.org"
|
||||
DEFAULT_TIMEOUT = 8 # seconds
|
||||
|
||||
# Verdicts safe to proceed with by default. Rejects `high_risk` (poor track
|
||||
# record) and `unknown` (no verifiable history / endpoint unreachable).
|
||||
DEFAULT_ALLOW = ("trusted", "caution", "new")
|
||||
|
||||
# All verdict classes the /check endpoint can return.
|
||||
VERDICTS = ("trusted", "caution", "high_risk", "new", "unknown")
|
||||
|
||||
|
||||
class AuraUntrusted(Exception):
|
||||
"""Raised by before_settle() when a counterparty fails the trust gate."""
|
||||
|
||||
def __init__(self, verdict: "AuraVerdict") -> None:
|
||||
self.verdict = verdict
|
||||
super().__init__(
|
||||
f"trust gate rejected {verdict.did}: {verdict.verdict} — {verdict.reason}"
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AuraVerdict:
|
||||
"""
|
||||
Result of a zero-auth trust check on a counterparty DID.
|
||||
|
||||
Fields:
|
||||
did the DID that was checked
|
||||
verdict one of trusted | caution | high_risk | new | unknown
|
||||
reason human-readable explanation
|
||||
score composite 0..1, or None when there is no history
|
||||
has_history True once the agent has on-chain interactions
|
||||
dimensions per-dimension breakdown (which axis is weak), or None
|
||||
raw the untouched JSON body, for callers that want more
|
||||
"""
|
||||
|
||||
did: str
|
||||
verdict: str
|
||||
reason: str = ""
|
||||
score: Optional[float] = None
|
||||
has_history: bool = False
|
||||
dimensions: Optional[dict[str, float]] = None
|
||||
# False only when AURA could not be reached (network/parse failure) and the
|
||||
# verdict is a synthetic `unknown`. A reachable AURA that genuinely returns
|
||||
# `unknown` has reachable=True. before_settle's fail_open keys on this, not
|
||||
# on the verdict alone, so it can't wave through unverified counterparties.
|
||||
reachable: bool = True
|
||||
raw: dict[str, Any] = field(default_factory=dict, repr=False)
|
||||
|
||||
@property
|
||||
def ok(self) -> bool:
|
||||
"""True for verdicts safe to proceed with (trusted / caution)."""
|
||||
return self.verdict in ("trusted", "caution")
|
||||
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
"""The minimal {verdict, reason, score} contract, plus did/ok."""
|
||||
return {
|
||||
"did": self.did,
|
||||
"verdict": self.verdict,
|
||||
"reason": self.reason,
|
||||
"score": self.score,
|
||||
"ok": self.ok,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_payload(cls, did: str, body: dict[str, Any]) -> "AuraVerdict":
|
||||
verdict = str(body.get("verdict", "unknown"))
|
||||
if verdict not in VERDICTS:
|
||||
verdict = "unknown"
|
||||
return cls(
|
||||
did=body.get("did", did),
|
||||
verdict=verdict,
|
||||
reason=str(body.get("reason", "")),
|
||||
score=body.get("score"),
|
||||
has_history=bool(body.get("has_history", False)),
|
||||
dimensions=body.get("dimensions"),
|
||||
raw=body,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def unreachable(cls, did: str, reason: str) -> "AuraVerdict":
|
||||
"""A synthetic `unknown` verdict for network/parse failures."""
|
||||
return cls(did=did, verdict="unknown", reason=reason, reachable=False)
|
||||
|
||||
|
||||
# Indirection point so tests can inject canned responses without a network.
|
||||
# Signature: (url: str, timeout: float) -> dict (raises on transport error)
|
||||
def _http_get_json(url: str, timeout: float) -> dict[str, Any]:
|
||||
req = urllib.request.Request(url, headers={"User-Agent": "aura-adapter/1.0"})
|
||||
with urllib.request.urlopen(req, timeout=timeout) as resp: # noqa: S310 (https only)
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
|
||||
|
||||
def aura_verdict(
|
||||
did: str,
|
||||
*,
|
||||
base_url: str = DEFAULT_BASE_URL,
|
||||
timeout: float = DEFAULT_TIMEOUT,
|
||||
_fetch: Callable[[str, float], dict[str, Any]] = _http_get_json,
|
||||
) -> AuraVerdict:
|
||||
"""
|
||||
Look up the trust verdict for a counterparty DID. Never raises on a
|
||||
network/parse failure — returns an `unknown` verdict instead, leaving the
|
||||
proceed/abort decision to the caller's policy (see before_settle).
|
||||
|
||||
v = aura_verdict("did:aura:z6Mk...")
|
||||
print(v.verdict, v.reason, v.score)
|
||||
|
||||
`_fetch` is an injection seam for tests; production callers ignore it.
|
||||
"""
|
||||
if not did or not str(did).startswith("did:"):
|
||||
raise ValueError(f"invalid DID: {did!r} (must start with 'did:')")
|
||||
|
||||
url = f"{base_url.rstrip('/')}/check?" + urllib.parse.urlencode({"did": did})
|
||||
try:
|
||||
body = _fetch(url, timeout)
|
||||
except (urllib.error.URLError, TimeoutError, OSError) as e:
|
||||
return AuraVerdict.unreachable(did, f"AURA unreachable: {e}")
|
||||
except (json.JSONDecodeError, ValueError) as e:
|
||||
return AuraVerdict.unreachable(did, f"AURA returned non-JSON: {e}")
|
||||
|
||||
if not isinstance(body, dict):
|
||||
return AuraVerdict.unreachable(did, "AURA returned an unexpected shape")
|
||||
return AuraVerdict.from_payload(did, body)
|
||||
|
||||
|
||||
def before_settle(
|
||||
did: str,
|
||||
*,
|
||||
allow: tuple[str, ...] = DEFAULT_ALLOW,
|
||||
fail_open: bool = False,
|
||||
base_url: str = DEFAULT_BASE_URL,
|
||||
timeout: float = DEFAULT_TIMEOUT,
|
||||
_fetch: Callable[[str, float], dict[str, Any]] = _http_get_json,
|
||||
) -> AuraVerdict:
|
||||
"""
|
||||
Gate a sensitive action behind a trust check. Returns the verdict on pass,
|
||||
raises AuraUntrusted on fail.
|
||||
|
||||
try:
|
||||
before_settle(counterparty_did) # rejects high_risk + unknown
|
||||
settle_payment(counterparty_did, amount)
|
||||
except AuraUntrusted as e:
|
||||
abort(str(e))
|
||||
|
||||
Tighten to reject brand-new agents too:
|
||||
before_settle(did, allow=("trusted", "caution"))
|
||||
|
||||
fail_open=True makes an *unreachable* AURA pass through (transport failure
|
||||
only — a reachable AURA that returns `unknown` is still rejected). Off by
|
||||
default — absence of evidence is not evidence of trust.
|
||||
"""
|
||||
v = aura_verdict(did, base_url=base_url, timeout=timeout, _fetch=_fetch)
|
||||
|
||||
if v.verdict in allow:
|
||||
return v
|
||||
# fail_open only excuses a transport failure, never a reachable `unknown`.
|
||||
if fail_open and not v.reachable:
|
||||
return v
|
||||
raise AuraUntrusted(v)
|
||||
|
||||
|
||||
# Alias — same gate, name that reads better at non-payment call sites.
|
||||
require_trust = before_settle
|
||||
@@ -1,94 +0,0 @@
|
||||
"""
|
||||
Canned /check responses — one per verdict class.
|
||||
|
||||
These are recorded shapes of real GET /check?did=... responses, used so the
|
||||
test suite runs offline with no network. Pass `make_fetch(...)` as the
|
||||
`_fetch` argument to aura_verdict / before_settle to replay them.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Callable
|
||||
|
||||
# did -> recorded /check JSON body
|
||||
RECORDED: dict[str, dict[str, Any]] = {
|
||||
"did:aura:trusted-bot": {
|
||||
"did": "did:aura:trusted-bot",
|
||||
"verdict": "trusted",
|
||||
"reason": "strong on-chain track record (composite 0.86)",
|
||||
"has_history": True,
|
||||
"score": 0.86,
|
||||
"interactions": 142,
|
||||
"dimensions": {
|
||||
"task_completion": 0.92,
|
||||
"delivery_speed": 0.81,
|
||||
"output_quality": 0.88,
|
||||
"honesty": 0.90,
|
||||
"financial_integrity": 0.95,
|
||||
"security_compliance": 0.79,
|
||||
"collaboration": 0.84,
|
||||
"dispute_history": 0.83,
|
||||
},
|
||||
},
|
||||
"did:aura:caution-bot": {
|
||||
"did": "did:aura:caution-bot",
|
||||
"verdict": "caution",
|
||||
"reason": "mixed history (composite 0.55)",
|
||||
"has_history": True,
|
||||
"score": 0.55,
|
||||
"interactions": 31,
|
||||
"dimensions": {"financial_integrity": 0.41, "task_completion": 0.62},
|
||||
},
|
||||
"did:aura:risky-bot": {
|
||||
"did": "did:aura:risky-bot",
|
||||
"verdict": "high_risk",
|
||||
"reason": "poor track record (composite 0.22)",
|
||||
"has_history": True,
|
||||
"score": 0.22,
|
||||
"interactions": 18,
|
||||
"dimensions": {"financial_integrity": 0.12, "dispute_history": 0.20},
|
||||
},
|
||||
"did:aura:fresh-bot": {
|
||||
"did": "did:aura:fresh-bot",
|
||||
"verdict": "new",
|
||||
"reason": "registered identity, no interactions yet",
|
||||
"has_history": False,
|
||||
"score": None,
|
||||
"interactions": 0,
|
||||
},
|
||||
"did:aura:ghost-bot": {
|
||||
"did": "did:aura:ghost-bot",
|
||||
"verdict": "unknown",
|
||||
"reason": "no track record — unverified counterparty",
|
||||
"has_history": False,
|
||||
"score": None,
|
||||
"interactions": 0,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def make_fetch(
|
||||
table: dict[str, dict[str, Any]] | None = None,
|
||||
) -> Callable[[str, float], dict[str, Any]]:
|
||||
"""
|
||||
Build a `_fetch` stand-in that replays RECORDED bodies by DID parsed from
|
||||
the query string. Unknown DIDs replay the `unknown` body.
|
||||
"""
|
||||
table = RECORDED if table is None else table
|
||||
|
||||
def _fetch(url: str, timeout: float) -> dict[str, Any]:
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
did = parse_qs(urlparse(url).query).get("did", [""])[0]
|
||||
return table.get(did, RECORDED["did:aura:ghost-bot"])
|
||||
|
||||
return _fetch
|
||||
|
||||
|
||||
def raising_fetch(exc: Exception) -> Callable[[str, float], dict[str, Any]]:
|
||||
"""Build a `_fetch` that always raises — simulates an unreachable AURA."""
|
||||
|
||||
def _fetch(url: str, timeout: float) -> dict[str, Any]:
|
||||
raise exc
|
||||
|
||||
return _fetch
|
||||
@@ -1,133 +0,0 @@
|
||||
"""
|
||||
Offline tests for the AURA trust-check adapter.
|
||||
|
||||
Runs with plain `pytest` (or `python -m pytest`). No network: every call
|
||||
replays a recorded /check body via the `_fetch` injection seam.
|
||||
|
||||
Coverage:
|
||||
- one assertion per verdict class (trusted / caution / high_risk / new / unknown)
|
||||
- the before_settle gate: allow-list pass/reject, custom allow, fail_open
|
||||
- the network-failure path (fail-closed by default, pass with fail_open)
|
||||
- input validation
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import urllib.error
|
||||
|
||||
import pytest
|
||||
|
||||
from aura.adapter import AuraUntrusted, aura_verdict, before_settle
|
||||
from aura.tests.fixtures import make_fetch, raising_fetch
|
||||
|
||||
FETCH = make_fetch()
|
||||
|
||||
|
||||
# ── verdict classes ─────────────────────────────────────────────────────────
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"did,expected,ok",
|
||||
[
|
||||
("did:aura:trusted-bot", "trusted", True),
|
||||
("did:aura:caution-bot", "caution", True),
|
||||
("did:aura:risky-bot", "high_risk", False),
|
||||
("did:aura:fresh-bot", "new", False),
|
||||
("did:aura:ghost-bot", "unknown", False),
|
||||
],
|
||||
)
|
||||
def test_verdict_classes(did, expected, ok):
|
||||
v = aura_verdict(did, _fetch=FETCH)
|
||||
assert v.verdict == expected
|
||||
assert v.ok is ok
|
||||
assert v.did == did
|
||||
assert isinstance(v.reason, str) and v.reason
|
||||
|
||||
|
||||
def test_minimal_dict_contract():
|
||||
v = aura_verdict("did:aura:trusted-bot", _fetch=FETCH)
|
||||
d = v.as_dict()
|
||||
assert set(d) >= {"verdict", "reason", "score"}
|
||||
assert d["verdict"] == "trusted"
|
||||
assert d["score"] == 0.86
|
||||
|
||||
|
||||
def test_dimensions_exposed_for_history():
|
||||
v = aura_verdict("did:aura:risky-bot", _fetch=FETCH)
|
||||
assert v.has_history is True
|
||||
assert v.dimensions["financial_integrity"] == 0.12
|
||||
|
||||
|
||||
def test_new_agent_has_no_score():
|
||||
v = aura_verdict("did:aura:fresh-bot", _fetch=FETCH)
|
||||
assert v.score is None
|
||||
assert v.has_history is False
|
||||
|
||||
|
||||
# ── the before_settle gate ───────────────────────────────────────────────────
|
||||
|
||||
def test_gate_allows_trusted():
|
||||
v = before_settle("did:aura:trusted-bot", _fetch=FETCH)
|
||||
assert v.verdict == "trusted"
|
||||
|
||||
|
||||
def test_gate_allows_caution_and_new_by_default():
|
||||
assert before_settle("did:aura:caution-bot", _fetch=FETCH).verdict == "caution"
|
||||
assert before_settle("did:aura:fresh-bot", _fetch=FETCH).verdict == "new"
|
||||
|
||||
|
||||
def test_gate_rejects_high_risk():
|
||||
with pytest.raises(AuraUntrusted) as ei:
|
||||
before_settle("did:aura:risky-bot", _fetch=FETCH)
|
||||
assert ei.value.verdict.verdict == "high_risk"
|
||||
|
||||
|
||||
def test_gate_rejects_unknown_by_default():
|
||||
with pytest.raises(AuraUntrusted):
|
||||
before_settle("did:aura:ghost-bot", _fetch=FETCH)
|
||||
|
||||
|
||||
def test_strict_allow_rejects_new():
|
||||
with pytest.raises(AuraUntrusted):
|
||||
before_settle("did:aura:fresh-bot", allow=("trusted", "caution"), _fetch=FETCH)
|
||||
|
||||
|
||||
# ── network-failure path ──────────────────────────────────────────────────────
|
||||
|
||||
def test_unreachable_returns_unknown_not_raise():
|
||||
fetch = raising_fetch(urllib.error.URLError("connection refused"))
|
||||
v = aura_verdict("did:aura:trusted-bot", _fetch=fetch)
|
||||
assert v.verdict == "unknown"
|
||||
assert "unreachable" in v.reason.lower()
|
||||
|
||||
|
||||
def test_gate_fail_closed_on_unreachable():
|
||||
fetch = raising_fetch(urllib.error.URLError("connection refused"))
|
||||
with pytest.raises(AuraUntrusted):
|
||||
before_settle("did:aura:trusted-bot", _fetch=fetch)
|
||||
|
||||
|
||||
def test_gate_fail_open_passes_on_unreachable():
|
||||
fetch = raising_fetch(urllib.error.URLError("connection refused"))
|
||||
v = before_settle("did:aura:trusted-bot", fail_open=True, _fetch=fetch)
|
||||
assert v.verdict == "unknown"
|
||||
assert v.reachable is False
|
||||
|
||||
|
||||
def test_fail_open_does_not_pass_reachable_unknown():
|
||||
# A reachable AURA that returns `unknown` (ghost DID) is still rejected even
|
||||
# with fail_open — fail_open only excuses transport failures.
|
||||
with pytest.raises(AuraUntrusted):
|
||||
before_settle("did:aura:ghost-bot", fail_open=True, _fetch=FETCH)
|
||||
|
||||
|
||||
def test_reachable_verdict_marked_reachable():
|
||||
v = aura_verdict("did:aura:ghost-bot", _fetch=FETCH)
|
||||
assert v.reachable is True
|
||||
|
||||
|
||||
# ── input validation ──────────────────────────────────────────────────────────
|
||||
|
||||
@pytest.mark.parametrize("bad", ["", "not-a-did", "z6Mk-no-prefix", None])
|
||||
def test_rejects_bad_did(bad):
|
||||
with pytest.raises(ValueError):
|
||||
aura_verdict(bad, _fetch=FETCH)
|
||||
@@ -589,6 +589,14 @@
|
||||
"modules": [
|
||||
"docs-zh-tw"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "locale:de-de",
|
||||
"family": "locale",
|
||||
"description": "German (de-DE) translated reference docs installed to ~/.claude/docs/de-DE/.",
|
||||
"modules": [
|
||||
"docs-de-de"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -843,6 +843,22 @@
|
||||
"defaultInstall": false,
|
||||
"cost": "heavy",
|
||||
"stability": "stable"
|
||||
},
|
||||
{
|
||||
"id": "docs-de-de",
|
||||
"kind": "docs",
|
||||
"description": "German (de-DE) translated reference docs for agents, commands, skills, and rules.",
|
||||
"paths": [
|
||||
"docs/de-DE"
|
||||
],
|
||||
"targets": [
|
||||
"claude",
|
||||
"claude-project"
|
||||
],
|
||||
"dependencies": [],
|
||||
"defaultInstall": false,
|
||||
"cost": "heavy",
|
||||
"stability": "stable"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
"agent.yaml",
|
||||
"agents/",
|
||||
"commands/",
|
||||
"docs/de-DE/",
|
||||
"docs/ja-JP/",
|
||||
"docs/ko-KR/",
|
||||
"docs/pt-BR/",
|
||||
|
||||
@@ -14,7 +14,7 @@ const COMPONENT_FAMILY_PREFIXES = {
|
||||
skill: 'skill:',
|
||||
locale: 'locale:',
|
||||
};
|
||||
const SUPPORTED_LOCALES = Object.freeze(['ja', 'zh-CN', 'ko-KR', 'pt-BR', 'ru', 'tr', 'vi-VN', 'zh-TW']);
|
||||
const SUPPORTED_LOCALES = Object.freeze(['ja', 'zh-CN', 'ko-KR', 'pt-BR', 'ru', 'tr', 'vi-VN', 'zh-TW', 'de-DE']);
|
||||
const LOCALE_ALIAS_TO_COMPONENT_ID = Object.freeze({
|
||||
'ja': 'locale:ja',
|
||||
'ja-JP': 'locale:ja',
|
||||
@@ -29,6 +29,8 @@ const LOCALE_ALIAS_TO_COMPONENT_ID = Object.freeze({
|
||||
'vi-VN': 'locale:vi-vn',
|
||||
'vi': 'locale:vi-vn',
|
||||
'zh-TW': 'locale:zh-tw',
|
||||
'de-DE': 'locale:de-de',
|
||||
'de': 'locale:de-de',
|
||||
});
|
||||
|
||||
function listSupportedLocales() {
|
||||
|
||||
@@ -50,6 +50,7 @@ function runTests() {
|
||||
const components = listInstallComponents({ family: 'locale' });
|
||||
assert.ok(components.some(component => component.id === 'locale:ja'));
|
||||
assert.ok(components.some(component => component.id === 'locale:zh-cn'));
|
||||
assert.ok(components.some(component => component.id === 'locale:de-de'));
|
||||
assert.ok(components.every(component => component.family === 'locale'));
|
||||
})) passed++; else failed++;
|
||||
|
||||
@@ -75,6 +76,59 @@ function runTests() {
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('locale:de-de resolves to the German translated docs module', () => {
|
||||
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-plan-de-'));
|
||||
try {
|
||||
const plan = resolveInstallPlan({
|
||||
includeComponentIds: ['locale:de-de'],
|
||||
target: 'claude',
|
||||
homeDir,
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(plan.selectedModuleIds, ['docs-de-de']);
|
||||
assert.ok(
|
||||
plan.operations.some(operation => (
|
||||
normalizePlanPath(operation.sourceRelativePath) === 'docs/de-DE'
|
||||
&& normalizePlanPath(operation.destinationPath).endsWith('/.claude/docs/de-DE')
|
||||
)),
|
||||
'Should map docs/de-DE to ~/.claude/docs/de-DE'
|
||||
);
|
||||
} finally {
|
||||
fs.rmSync(homeDir, { recursive: true, force: true });
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('end-to-end: --locale de dry-run includes docs-de-de operations', () => {
|
||||
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-dry-run-de-'));
|
||||
const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-dry-run-de-project-'));
|
||||
|
||||
try {
|
||||
const output = runInstallApply([
|
||||
'--locale', 'de',
|
||||
'--dry-run',
|
||||
'--json',
|
||||
], {
|
||||
cwd: projectDir,
|
||||
env: { HOME: homeDir },
|
||||
});
|
||||
const json = JSON.parse(output);
|
||||
|
||||
assert.strictEqual(json.plan.mode, 'manifest');
|
||||
assert.deepStrictEqual(json.plan.includedComponentIds, ['locale:de-de']);
|
||||
assert.deepStrictEqual(json.plan.selectedModuleIds, ['docs-de-de']);
|
||||
assert.ok(
|
||||
json.plan.operations.some(operation => (
|
||||
normalizePlanPath(operation.sourceRelativePath) === 'docs/de-DE/README.md'
|
||||
&& normalizePlanPath(operation.destinationPath).endsWith('/.claude/docs/de-DE/README.md')
|
||||
)),
|
||||
'Should copy translated README into ~/.claude/docs/de-DE'
|
||||
);
|
||||
} finally {
|
||||
fs.rmSync(homeDir, { recursive: true, force: true });
|
||||
fs.rmSync(projectDir, { recursive: true, force: true });
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('end-to-end: --locale ja dry-run includes docs-ja-jp operations', () => {
|
||||
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-dry-run-'));
|
||||
const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-dry-run-project-'));
|
||||
|
||||
Reference in New Issue
Block a user