diff --git a/.autopilot/runs/playbooks-guidance.jsonl b/.autopilot/runs/playbooks-guidance.jsonl index 0954a6f..dd83145 100644 --- a/.autopilot/runs/playbooks-guidance.jsonl +++ b/.autopilot/runs/playbooks-guidance.jsonl @@ -1,2 +1,3 @@ {"type": "plan", "feature_id": "playbooks-guidance", "goal": "Make the Remediation Playbook editor instructional — surface the embedded default as a documented, editable starting point, add field hints and 'what's possible' affordances (allowed fields/enums, the tool-ceiling rule), and give richer validation than parse/pass. Mirrors the model-catalog feature.", "trunk": "main", "base": "develop", "autonomy": "pr_ci", "phases": [{"id": 0, "goal": "Backend: expose the embedded default playbook over HTTP and give create/update schema-aware, field-path validation.", "definition_of_done": ["cmd: cargo test -p ampel-api playbooks passes (embedded endpoint returns the default; create/update returns field-path 422s for missing/invalid fields).", "cmd: cargo test -p ampel-worker playbook passes (schema validator unit tests).", "cmd: cargo build --workspace succeeds; cargo clippy --workspace --all-targets --all-features -- -D warnings clean.", "cmd: make format-check passes.", "grep: /api/remediation/playbooks/embedded in crates/ampel-api/src/routes/mod.rs", "prose: the tool-ceiling clamp and trusted-vars/untrusted-context split are unchanged; the new endpoint is read-only and applies the same ADR-006 resolution."]}, {"id": 1, "goal": "Frontend: load/duplicate the embedded default as a starting point and surface preview metadata, so users see a concrete playbook and what it grants.", "definition_of_done": ["cmd: make test-frontend passes, incl. new vitest specs: 'Load built-in default' prefills the form from the embedded endpoint (mocked); duplicate prefills from a row; preview renders allowedTools/outputContract pills.", "cmd: make lint-frontend passes; make format-check passes.", "grep: playbooks/embedded in frontend/src/api/playbooks.ts", "grep:absent: TODO|FIXME in frontend/src/components/remediation/PlaybookEditor.tsx"]}, {"id": 2, "goal": "Frontend: per-field schema reference/hints (including the tool-ceiling narrow-only rule and the trusted-vars/untrusted-context split) plus richer inline validation, fully internationalized.", "definition_of_done": ["cmd: node scripts/i18n-coverage-report.js --check-missing reports no missing keys.", "cmd: node scripts/i18n-coverage-report.js --check --min-coverage 95 passes.", "cmd: make test-frontend passes (incl. a field-hint render + a field-path validation-error spec).", "cmd: make lint-frontend passes; make format-check passes.", "prose: no raw i18n keys render; interpolation-variable audit across locales is clean; brand/proper nouns (Claude/Gemini/Ollama/ONNX, GitHub/GitLab/Bitbucket, Ampel) are not translated; types.ts regenerated in sync."]}, {"id": 3, "goal": "Docs + end-to-end: document the playbook editing workflow and prove the guidance path with an integration test.", "definition_of_done": ["cmd: make test passes (full backend + frontend).", "cmd: make lint passes; make audit passes.", "grep: PLAYBOOKS.md in docs OR grep: Playbook in docs/features/PLAYBOOKS.md (doc exists).", "prose: docs explain the tool-ceiling narrow-only rule and how to start from the embedded default, consistent with the implemented endpoints; markdownlint clean."]}], "at": "2026-07-01T09:14:51-07:00"} {"phase": 0, "mode": "pr_ci", "verdict": "PASSED", "skipped": ["test:full-make-test-deferred-to-CI", "audit:deferred-to-CI"], "failed": [], "ci_attempts": 0, "pr": null, "accelerators": ["direct", "adversarial-review"], "marker": null, "at": "2026-07-01T09:33:01-07:00", "summary": "Backend playbook guidance. (1) GET /api/remediation/playbooks/embedded: read-only, PlaybookResponse-shaped view of the embedded default via resolver embedded_default_yaml() (synthetic row: id nil, source=builtin, scope global sentinel, epoch timestamps); route registered before /{id} (static wins in Axum 0.8). (2) Playbook::validate_yaml in ampel-worker/playbook.rs: schema-aware field-path validation (role, non-empty tasks + instructions, loop.{max_iterations,max_seconds,max_cost_usd decimal-string}, tools_policy, output_contract enum, provider_overlays known kinds + overlay enum; non-string keys and non-mapping overlays fail on their own field path) then a final strong-typed parse; wired into create/update -> 422 'invalid playbook ``: '. 27 worker unit tests + 4 Postgres-gated api tests (all green on real PG); clippy -D warnings + rustfmt clean. Tool-ceiling clamp + trusted/untrusted split unchanged. Adversarial review: 2 findings, both fixed."} +{"phase": 1, "mode": "pr_ci", "verdict": "PASSED", "skipped": [], "failed": [], "ci_attempts": 0, "pr": null, "accelerators": ["direct", "ampel-i18n-builder", "adversarial-review"], "marker": null, "at": "2026-07-01T10:03:22-07:00", "summary": "Frontend playbook guidance. PlaybookEditor: 'Load built-in default' (fetch GET .../embedded via new useLoadEmbeddedPlaybook mutation + playbooksApi.getEmbeddedPlaybook, prefill a sanitized copy: blank id/name, default YAML), per-row 'Duplicate to customize' (id=-copy, name, content, coerced scopeType), and preview capability pills (role/outputContract/allowedTools) mirroring model-catalog pills. Form refactored to a seed + key={nonce} remount so re-seeding re-initializes fields. New remediation:playbooks keys (loadDefault, loadingDefault, duplicate, meta.{role,outputContract,allowedTools,noTools}, errors.loadDefaultFailed) translated into ALL 26 locales via ampel-i18n-builder (Google/OpenAI fallback; Systran key 401); types.ts regenerated. 9 PlaybookEditor specs (3 new) + full suite 914 pass; type-check/lint/format-check clean. Adversarial review caught a bogus locale dir (from a zsh word-split slip in the translate loop) that polluted types.ts — removed + regenerated. GOTCHA phase 2: field hints + inline field-path 422s + 27-locale i18n for the NEW hint keys."} diff --git a/frontend/public/locales/ar/remediation.json b/frontend/public/locales/ar/remediation.json index f7e4f00..5de2f6c 100644 --- a/frontend/public/locales/ar/remediation.json +++ b/frontend/public/locales/ar/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "أدخل دليل YAML…", "create": "خطة عمل جديدة", "description": "قم بتخصيص مطالبات المعالجة التي يستخدمها الوكيل. تحقق من صحة دليل التشغيل لمعاينة المطالبة المعروضة بدون استدعاء النموذج.", + "duplicate": "قم بتكرارها لتخصيصها", "empty": "لا توجد خطط عمل حتى الآن. يتم استخدام خطة العمل الافتراضية المدمجة إلى حين إضافة خطة عمل جديدة.", "error": "فشل تحميل ملفات التشغيل.", "errors": { "contentRequired": "محتوى دليل التشغيل مطلوب.", + "loadDefaultFailed": "فشل تحميل ملف التشغيل الافتراضي المدمج.", "nameRequired": "الاسم مطلوب.", "playbookIdRequired": "يلزم وجود معرف دليل اللعب.", "previewFailed": "فشل عرض ملف التشغيل. تحقق من ملف YAML بحثًا عن الأخطاء.", "saveFailed": "فشل حفظ ملف التشغيل. تحقق من ملف YAML بحثًا عن الأخطاء." }, + "loadDefault": "تحميل الإعدادات الافتراضية المدمجة", + "loadingDefault": "جارٍ تحميل الإعدادات الافتراضية المدمجة...", + "meta": { + "allowedTools": "الأدوات المسموح بها", + "noTools": "لا أحد", + "outputContract": "عقد الإنتاج", + "role": "دور" + }, "name": "اسم", "namePlaceholder": "اسم سهل القراءة", "playbookId": "معرف دفتر التشغيل", @@ -346,4 +356,4 @@ "runs": "يركض" }, "title": "إصلاح الأسطول" -} +} \ No newline at end of file diff --git a/frontend/public/locales/cs/remediation.json b/frontend/public/locales/cs/remediation.json index 88db296..8baff5d 100644 --- a/frontend/public/locales/cs/remediation.json +++ b/frontend/public/locales/cs/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Vstupte do YAML scénáře…", "create": "Nová příručka", "description": "Přizpůsobte si výzvy k nápravě, které agent používá. Ověřte si playbook pro zobrazení náhledu vykreslené výzvy bez volání modelu.", + "duplicate": "Duplikovat pro přizpůsobení", "empty": "Zatím žádné playbooky. Dokud nový nepřidáte, používá se vestavěný výchozí playbook.", "error": "Načtení herních příruček se nezdařilo.", "errors": { "contentRequired": "Obsah herní příručky je povinný.", + "loadDefaultFailed": "Nepodařilo se načíst vestavěný výchozí playbook.", "nameRequired": "Je vyžadováno jméno.", "playbookIdRequired": "Je vyžadováno ID playbooku.", "previewFailed": "Nepodařilo se vykreslit playbook. Zkontrolujte YAML, zda neobsahuje chyby.", "saveFailed": "Uložení playbooku se nezdařilo. Zkontrolujte YAML, zda neobsahuje chyby." }, + "loadDefault": "Načíst vestavěné výchozí nastavení", + "loadingDefault": "Načítání vestavěného výchozího nastavení…", + "meta": { + "allowedTools": "Povolené nástroje", + "noTools": "Žádný", + "outputContract": "Výstupní smlouva", + "role": "Role" + }, "name": "Jméno", "namePlaceholder": "Člověkem čitelný název", "playbookId": "ID herního plánu", @@ -346,4 +356,4 @@ "runs": "Běhy" }, "title": "Sanace vozového parku" -} +} \ No newline at end of file diff --git a/frontend/public/locales/da/remediation.json b/frontend/public/locales/da/remediation.json index f86fe93..b9f6f76 100644 --- a/frontend/public/locales/da/remediation.json +++ b/frontend/public/locales/da/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Gå ind i YAML-håndbogen…", "create": "Ny håndbog", "description": "Tilpas de afhjælpningsprompter, som agenten bruger. Valider en playbook for at få vist en forhåndsvisning af den gengivne prompt uden modelkald.", + "duplicate": "Dupliker for at tilpasse", "empty": "Ingen playbooks endnu. Den indbyggede standard playbook bruges, indtil du tilføjer en.", "error": "Kunne ikke indlæse playbooks.", "errors": { "contentRequired": "Indhold i playbooken er påkrævet.", + "loadDefaultFailed": "Kunne ikke indlæse den indbyggede standardplaybook.", "nameRequired": "Et navn er påkrævet.", "playbookIdRequired": "Et playbook-ID er påkrævet.", "previewFailed": "Kunne ikke gengive playbooken. Tjek YAML for fejl.", "saveFailed": "Kunne ikke gemme playbooken. Tjek YAML for fejl." }, + "loadDefault": "Indlæs indbygget standard", + "loadingDefault": "Indlæser indbygget standard…", + "meta": { + "allowedTools": "Tilladte værktøjer", + "noTools": "Ingen", + "outputContract": "Outputkontrakt", + "role": "Rolle" + }, "name": "Navn", "namePlaceholder": "Menneskeligt læsbart navn", "playbookId": "Playbook-ID", @@ -346,4 +356,4 @@ "runs": "Løber" }, "title": "Flådeoprydning" -} +} \ No newline at end of file diff --git a/frontend/public/locales/de/remediation.json b/frontend/public/locales/de/remediation.json index 8bd4bba..e6c37dc 100644 --- a/frontend/public/locales/de/remediation.json +++ b/frontend/public/locales/de/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Geben Sie das Playbook-YAML ein…", "create": "Neues Drehbuch", "description": "Passen Sie die vom Agenten verwendeten Abhilfemaßnahmen an. Validieren Sie ein Playbook, um die gerenderte Absprache ohne Modellaufruf in einer Vorschau anzuzeigen.", + "duplicate": "Duplizieren, um anzupassen", "empty": "Noch keine Playbooks vorhanden. Das integrierte Standard-Playbook wird verwendet, bis Sie ein eigenes hinzufügen.", "error": "Playbooks konnten nicht geladen werden.", "errors": { "contentRequired": "Der Inhalt des Playbooks ist erforderlich.", + "loadDefaultFailed": "Das integrierte Standard-Playbook konnte nicht geladen werden.", "nameRequired": "Ein Name ist erforderlich.", "playbookIdRequired": "Eine Playbook-ID ist erforderlich.", "previewFailed": "Das Playbook konnte nicht gerendert werden. Überprüfen Sie die YAML-Datei auf Fehler.", "saveFailed": "Das Playbook konnte nicht gespeichert werden. Überprüfen Sie die YAML-Datei auf Fehler." }, + "loadDefault": "Eingebaute Standardeinstellungen laden", + "loadingDefault": "Lade integrierte Standardeinstellungen…", + "meta": { + "allowedTools": "Zulässige Werkzeuge", + "noTools": "Keiner", + "outputContract": "Output-Vertrag", + "role": "Rolle" + }, "name": "Name", "namePlaceholder": "für Menschen lesbarer Name", "playbookId": "Playbook-ID", @@ -346,4 +356,4 @@ "runs": "Läufe" }, "title": "Flottensanierung" -} +} \ No newline at end of file diff --git a/frontend/public/locales/en-GB/remediation.json b/frontend/public/locales/en-GB/remediation.json index 30cc218..711e964 100644 --- a/frontend/public/locales/en-GB/remediation.json +++ b/frontend/public/locales/en-GB/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Enter the playbook YAML…", "create": "New playbook", "description": "Customize the remediation prompts the agent uses. Validate a playbook to preview the rendered prompt with no model call.", + "duplicate": "Duplicate to customize", "empty": "No playbooks yet. The built-in default playbook is used until you add one.", "error": "Failed to load playbooks.", "errors": { "contentRequired": "Playbook content is required.", + "loadDefaultFailed": "Failed to load the built-in default playbook.", "nameRequired": "A name is required.", "playbookIdRequired": "A playbook ID is required.", "previewFailed": "Failed to render the playbook. Check the YAML for errors.", "saveFailed": "Failed to save the playbook. Check the YAML for errors." }, + "loadDefault": "Load built-in default", + "loadingDefault": "Loading built-in default…", + "meta": { + "allowedTools": "Allowed tools", + "noTools": "None", + "outputContract": "Output contract", + "role": "Role" + }, "name": "Name", "namePlaceholder": "Human-readable name", "playbookId": "Playbook ID", @@ -346,4 +356,4 @@ "runs": "Runs" }, "title": "Fleet Remediation" -} +} \ No newline at end of file diff --git a/frontend/public/locales/en/remediation.json b/frontend/public/locales/en/remediation.json index 139dd06..f3fd06e 100644 --- a/frontend/public/locales/en/remediation.json +++ b/frontend/public/locales/en/remediation.json @@ -306,6 +306,9 @@ "title": "Playbooks", "description": "Customize the remediation prompts the agent uses. Validate a playbook to preview the rendered prompt with no model call.", "create": "New playbook", + "loadDefault": "Load built-in default", + "loadingDefault": "Loading built-in default…", + "duplicate": "Duplicate to customize", "playbookId": "Playbook ID", "playbookIdPlaceholder": "e.g. custom-remediation", "name": "Name", @@ -320,6 +323,12 @@ "preview": "Validate / Preview", "previewing": "Rendering…", "renderedPrompt": "Rendered prompt", + "meta": { + "role": "Role", + "outputContract": "Output contract", + "allowedTools": "Allowed tools", + "noTools": "None" + }, "empty": "No playbooks yet. The built-in default playbook is used until you add one.", "error": "Failed to load playbooks.", "errors": { @@ -327,7 +336,8 @@ "nameRequired": "A name is required.", "contentRequired": "Playbook content is required.", "saveFailed": "Failed to save the playbook. Check the YAML for errors.", - "previewFailed": "Failed to render the playbook. Check the YAML for errors." + "previewFailed": "Failed to render the playbook. Check the YAML for errors.", + "loadDefaultFailed": "Failed to load the built-in default playbook." } }, "agentSession": { diff --git a/frontend/public/locales/es-ES/remediation.json b/frontend/public/locales/es-ES/remediation.json index a5c9106..c1bdd2d 100644 --- a/frontend/public/locales/es-ES/remediation.json +++ b/frontend/public/locales/es-ES/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Introduzca el manual de procedimientos YAML…", "create": "Nuevo manual de estrategias", "description": "Personaliza las indicaciones de corrección que utiliza el agente. Valida un playbook para previsualizar la indicación renderizada sin realizar ninguna llamada al modelo.", + "duplicate": "Duplicar para personalizar", "empty": "Aún no hay playbooks. Se utiliza el playbook predeterminado integrado hasta que añadas uno.", "error": "No se pudieron cargar los playbooks.", "errors": { "contentRequired": "El contenido del manual es obligatorio.", + "loadDefaultFailed": "No se pudo cargar el playbook predeterminado integrado.", "nameRequired": "Se requiere un nombre.", "playbookIdRequired": "Se requiere un ID de playbook.", "previewFailed": "No se pudo generar el playbook. Compruebe el archivo YAML en busca de errores.", "saveFailed": "No se pudo guardar el playbook. Compruebe el archivo YAML en busca de errores." }, + "loadDefault": "Cargar configuración predeterminada integrada", + "loadingDefault": "Cargando valores predeterminados integrados…", + "meta": { + "allowedTools": "Herramientas permitidas", + "noTools": "Ninguno", + "outputContract": "contrato de producción", + "role": "Role" + }, "name": "Nombre", "namePlaceholder": "Nombre legible para humanos", "playbookId": "ID del libro de jugadas", @@ -346,4 +356,4 @@ "runs": "Corre" }, "title": "Remediación de flotas" -} +} \ No newline at end of file diff --git a/frontend/public/locales/es-MX/remediation.json b/frontend/public/locales/es-MX/remediation.json index 797f139..465fae6 100644 --- a/frontend/public/locales/es-MX/remediation.json +++ b/frontend/public/locales/es-MX/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Introduzca el manual de procedimientos YAML…", "create": "Nuevo manual de estrategias", "description": "Personaliza las indicaciones de corrección que utiliza el agente. Valida un playbook para previsualizar la indicación renderizada sin realizar ninguna llamada al modelo.", + "duplicate": "Duplicar para personalizar", "empty": "Aún no hay playbooks. Se utiliza el playbook predeterminado integrado hasta que añadas uno.", "error": "No se pudieron cargar los playbooks.", "errors": { "contentRequired": "Se requiere el contenido del manual de jugadas.", + "loadDefaultFailed": "No se pudo cargar el playbook predeterminado integrado.", "nameRequired": "Se requiere un nombre.", "playbookIdRequired": "Se requiere un ID de playbook.", "previewFailed": "No se pudo generar el playbook. Compruebe el archivo YAML en busca de errores.", "saveFailed": "No se pudo guardar el playbook. Compruebe el archivo YAML en busca de errores." }, + "loadDefault": "Cargar configuración predeterminada integrada", + "loadingDefault": "Cargando valores predeterminados integrados…", + "meta": { + "allowedTools": "Herramientas permitidas", + "noTools": "Ninguno", + "outputContract": "contrato de producción", + "role": "Role" + }, "name": "Nombre", "namePlaceholder": "Nombre legible para humanos", "playbookId": "ID del libro de jugadas", @@ -346,4 +356,4 @@ "runs": "Corre" }, "title": "Remediación de flotas" -} +} \ No newline at end of file diff --git a/frontend/public/locales/fi/remediation.json b/frontend/public/locales/fi/remediation.json index 585cee5..d267ea8 100644 --- a/frontend/public/locales/fi/remediation.json +++ b/frontend/public/locales/fi/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Aloita YAML:n käyttöohje…", "create": "Uusi pelisuunnitelma", "description": "Mukauta agentin käyttämiä korjauskehotteita. Vahvista toimintasuunnitelma esikatsellaksesi renderöityä kehotetta ilman mallikutsua.", + "duplicate": "Kopioi muokataksesi", "empty": "Ei vielä peliohjeita. Sisäänrakennettua oletuspeliohjetta käytetään, kunnes lisäät sellaisen.", "error": "Pelikirjojen lataaminen epäonnistui.", "errors": { "contentRequired": "Käsikirjan sisältö on pakollinen.", + "loadDefaultFailed": "Sisäänrakennetun oletuspelikirjan lataaminen epäonnistui.", "nameRequired": "Nimi vaaditaan.", "playbookIdRequired": "Pelikirjan tunnus vaaditaan.", "previewFailed": "Käsikirjan renderöinti epäonnistui. Tarkista YAML-tiedostosta virheet.", "saveFailed": "Käsikirjan tallennus epäonnistui. Tarkista YAML-tiedostosta virheet." }, + "loadDefault": "Lataa sisäänrakennettu oletusarvo", + "loadingDefault": "Ladataan sisäänrakennettua oletusarvoa…", + "meta": { + "allowedTools": "Sallitut työkalut", + "noTools": "Ei mitään", + "outputContract": "Tuotantosopimus", + "role": "Rooli" + }, "name": "Nimi", "namePlaceholder": "Ihmisen luettavissa oleva nimi", "playbookId": "Pelikirjan tunnus", @@ -346,4 +356,4 @@ "runs": "Juoksut" }, "title": "Kaluston kunnostus" -} +} \ No newline at end of file diff --git a/frontend/public/locales/fr/remediation.json b/frontend/public/locales/fr/remediation.json index 294a2c4..ddd5348 100644 --- a/frontend/public/locales/fr/remediation.json +++ b/frontend/public/locales/fr/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Entrez le playbook YAML…", "create": "Nouveau manuel de jeu", "description": "Personnalisez les messages de correction utilisés par l'agent. Validez un playbook pour prévisualiser le message rendu sans appel de modèle.", + "duplicate": "Dupliquez pour personnaliser", "empty": "Aucun scénario prédéfini pour le moment. Le scénario par défaut intégré sera utilisé jusqu'à ce que vous en ajoutiez un.", "error": "Échec du chargement des playbooks.", "errors": { "contentRequired": "Le contenu du manuel de jeu est obligatoire.", + "loadDefaultFailed": "Impossible de charger le playbook par défaut intégré.", "nameRequired": "Un nom est requis.", "playbookIdRequired": "Un identifiant de playbook est requis.", "previewFailed": "Impossible de générer le playbook. Vérifiez le fichier YAML pour détecter d'éventuelles erreurs.", "saveFailed": "Impossible d'enregistrer le playbook. Vérifiez le fichier YAML pour détecter d'éventuelles erreurs." }, + "loadDefault": "Charger la valeur par défaut intégrée", + "loadingDefault": "Chargement des paramètres par défaut intégrés…", + "meta": { + "allowedTools": "Outils autorisés", + "noTools": "Aucun", + "outputContract": "Contrat de production", + "role": "Rôle" + }, "name": "Nom", "namePlaceholder": "Nom lisible par l'homme", "playbookId": "ID du playbook", @@ -346,4 +356,4 @@ "runs": "Courses" }, "title": "Remise en état de la flotte" -} +} \ No newline at end of file diff --git a/frontend/public/locales/he/remediation.json b/frontend/public/locales/he/remediation.json index cad9bcb..2b45a0a 100644 --- a/frontend/public/locales/he/remediation.json +++ b/frontend/public/locales/he/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "היכנסו לספר המשחקים של YAML…", "create": "ספר משחקים חדש", "description": "התאם אישית את הנחיות התיקון שהסוכן משתמש בהן. אמת מדריך כדי להציג תצוגה מקדימה של ההנחיה המעובדת ללא קריאה למודל.", + "duplicate": "שכפל להתאמה אישית", "empty": "אין עדיין ספרי הדרכה. ספר ההדרכה המובנה כברירת מחדל משמש עד שתוסיף אחד.", "error": "טעינת ספרי ההשמעה נכשלה.", "errors": { "contentRequired": "נדרש תוכן של ספר ההדרכה.", + "loadDefaultFailed": "נכשלה טעינת מדריך ברירת המחדל המובנה.", "nameRequired": "נדרש שם.", "playbookIdRequired": "נדרש מזהה פלייבוק.", "previewFailed": "עיבוד ספר ההדרכה נכשל. בדוק את קובץ ה-YAML לאיתור שגיאות.", "saveFailed": "שמירת ספר ההדרכה נכשלה. בדוק את קובץ ה-YAML לאיתור שגיאות." }, + "loadDefault": "טען את ברירת המחדל המובנית", + "loadingDefault": "טוען את ברירת המחדל המובנית...", + "meta": { + "allowedTools": "כלים מותרים", + "noTools": "אַף לֹא אֶחָד", + "outputContract": "חוזה פלט", + "role": "תַפְקִיד" + }, "name": "שֵׁם", "namePlaceholder": "שם קריא על ידי בני אדם", "playbookId": "מזהה Playbook", @@ -346,4 +356,4 @@ "runs": "ריצות" }, "title": "שיקום צי" -} +} \ No newline at end of file diff --git a/frontend/public/locales/hi/remediation.json b/frontend/public/locales/hi/remediation.json index e8b50ea..780ad36 100644 --- a/frontend/public/locales/hi/remediation.json +++ b/frontend/public/locales/hi/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "प्लेबुक YAML दर्ज करें…", "create": "नई रणनीति पुस्तिका", "description": "एजेंट द्वारा उपयोग किए जाने वाले सुधार संबंधी संकेतों को अनुकूलित करें। बिना मॉडल कॉल के प्रदर्शित संकेत का पूर्वावलोकन करने के लिए प्लेबुक को मान्य करें।", + "duplicate": "अनुकूलित करने के लिए डुप्लिकेट करें", "empty": "अभी तक कोई प्लेबुक उपलब्ध नहीं है। जब तक आप कोई प्लेबुक नहीं जोड़ते, तब तक अंतर्निहित डिफ़ॉल्ट प्लेबुक का उपयोग किया जाएगा।", "error": "प्लेबुक लोड करने में विफल।", "errors": { "contentRequired": "प्लेबुक सामग्री आवश्यक है।", + "loadDefaultFailed": "अंतर्निहित डिफ़ॉल्ट प्लेबुक को लोड करने में विफलता।", "nameRequired": "नाम आवश्यक है।", "playbookIdRequired": "प्लेबुक आईडी आवश्यक है।", "previewFailed": "प्लेबुक को रेंडर करने में विफलता। त्रुटियों के लिए YAML फ़ाइल की जाँच करें।", "saveFailed": "प्लेबुक को सहेजने में विफलता। त्रुटियों के लिए YAML फ़ाइल की जाँच करें।" }, + "loadDefault": "अंतर्निहित डिफ़ॉल्ट लोड करें", + "loadingDefault": "अंतर्निहित डिफ़ॉल्ट लोड हो रहा है…", + "meta": { + "allowedTools": "अनुमत उपकरण", + "noTools": "कोई नहीं", + "outputContract": "आउटपुट अनुबंध", + "role": "भूमिका" + }, "name": "नाम", "namePlaceholder": "मानव-पठनीय नाम", "playbookId": "प्लेबुक आईडी", @@ -346,4 +356,4 @@ "runs": "दौड़ें" }, "title": "बेड़ा सुधार" -} +} \ No newline at end of file diff --git a/frontend/public/locales/it/remediation.json b/frontend/public/locales/it/remediation.json index be01073..e0ba0ed 100644 --- a/frontend/public/locales/it/remediation.json +++ b/frontend/public/locales/it/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Ecco il playbook YAML…", "create": "Nuovo manuale di gioco", "description": "Personalizza i suggerimenti di correzione utilizzati dall'agente. Convalida un playbook per visualizzare in anteprima il suggerimento visualizzato senza chiamare il modello.", + "duplicate": "Duplica per personalizzare", "empty": "Nessun playbook ancora disponibile. Verrà utilizzato il playbook predefinito integrato finché non ne aggiungerai uno.", "error": "Impossibile caricare i playbook.", "errors": { "contentRequired": "È necessario il contenuto del manuale di gioco.", + "loadDefaultFailed": "Impossibile caricare il playbook predefinito integrato.", "nameRequired": "È necessario inserire un nome.", "playbookIdRequired": "È richiesto un ID del playbook.", "previewFailed": "Impossibile generare il playbook. Verificare la presenza di errori nel file YAML.", "saveFailed": "Impossibile salvare il playbook. Verificare la presenza di errori nel file YAML." }, + "loadDefault": "Carica predefinito integrato", + "loadingDefault": "Caricamento predefinito integrato…", + "meta": { + "allowedTools": "Strumenti consentiti", + "noTools": "Nessuno", + "outputContract": "Contratto di produzione", + "role": "Ruolo" + }, "name": "Nome", "namePlaceholder": "nome leggibile dall'uomo", "playbookId": "ID del playbook", @@ -346,4 +356,4 @@ "runs": "Corse" }, "title": "Risanamento della flotta" -} +} \ No newline at end of file diff --git a/frontend/public/locales/ja/remediation.json b/frontend/public/locales/ja/remediation.json index b9dbb00..4989a9d 100644 --- a/frontend/public/locales/ja/remediation.json +++ b/frontend/public/locales/ja/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "YAMLのプレイブックが登場…", "create": "新しいプレイブック", "description": "エージェントが使用する修復プロンプトをカスタマイズします。プレイブックを検証して、モデル呼び出しなしでレンダリングされたプロンプトをプレビューします。", + "duplicate": "複製してカスタマイズする", "empty": "プレイブックはまだ追加されていません。追加するまでは、組み込みのデフォルトプレイブックが使用されます。", "error": "プレイブックの読み込みに失敗しました。", "errors": { "contentRequired": "プレイブックの内容は必須です。", + "loadDefaultFailed": "組み込みのデフォルトプレイブックの読み込みに失敗しました。", "nameRequired": "名前は必須です。", "playbookIdRequired": "プレイブックIDが必要です。", "previewFailed": "プレイブックのレンダリングに失敗しました。YAMLファイルにエラーがないか確認してください。", "saveFailed": "プレイブックの保存に失敗しました。YAMLファイルにエラーがないか確認してください。" }, + "loadDefault": "組み込みのデフォルトを読み込む", + "loadingDefault": "組み込みのデフォルト設定を読み込んでいます…", + "meta": { + "allowedTools": "許可されているツール", + "noTools": "なし", + "outputContract": "出力契約", + "role": "役割" + }, "name": "名前", "namePlaceholder": "人間が読みやすい名前", "playbookId": "プレイブックID", @@ -346,4 +356,4 @@ "runs": "走る" }, "title": "車両整備" -} +} \ No newline at end of file diff --git a/frontend/public/locales/ko/remediation.json b/frontend/public/locales/ko/remediation.json index 0d191fe..44ad831 100644 --- a/frontend/public/locales/ko/remediation.json +++ b/frontend/public/locales/ko/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "플레이북 YAML 파일을 입력하세요…", "create": "새로운 플레이북", "description": "상담원이 사용하는 문제 해결 프롬프트를 사용자 지정합니다. 모델 호출 없이 렌더링된 프롬프트를 미리 보려면 플레이북을 검증합니다.", + "duplicate": "복제하여 사용자 정의하세요", "empty": "아직 플레이북이 없습니다. 플레이북을 추가하기 전까지는 기본 플레이북이 사용됩니다.", "error": "플레이북을 불러오는 데 실패했습니다.", "errors": { "contentRequired": "플레이북 콘텐츠가 필요합니다.", + "loadDefaultFailed": "내장된 기본 플레이북을 로드하는 데 실패했습니다.", "nameRequired": "이름은 필수 입력 사항입니다.", "playbookIdRequired": "플레이북 ID가 필요합니다.", "previewFailed": "플레이북 렌더링에 실패했습니다. YAML 파일에서 오류를 확인하세요.", "saveFailed": "플레이북 저장에 실패했습니다. YAML 파일에서 오류를 확인하세요." }, + "loadDefault": "내장 기본값을 불러오기", + "loadingDefault": "내장 기본 설정 불러오는 중…", + "meta": { + "allowedTools": "허용된 도구", + "noTools": "없음", + "outputContract": "생산 계약", + "role": "역할" + }, "name": "이름", "namePlaceholder": "사람이 읽을 수 있는 이름", "playbookId": "플레이북 ID", @@ -346,4 +356,4 @@ "runs": "실행" }, "title": "함대 정비" -} +} \ No newline at end of file diff --git a/frontend/public/locales/nl/remediation.json b/frontend/public/locales/nl/remediation.json index d319c08..f7bac0f 100644 --- a/frontend/public/locales/nl/remediation.json +++ b/frontend/public/locales/nl/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Voer het playbook in (YAML-formaat) in...", "create": "Nieuw draaiboek", "description": "Pas de herstelprompts aan die de agent gebruikt. Valideer een playbook om een voorbeeld van de weergegeven prompt te bekijken zonder modelaanroep.", + "duplicate": "Dupliceer om aan te passen", "empty": "Er zijn nog geen playbooks beschikbaar. Het ingebouwde standaard playbook wordt gebruikt totdat u er zelf een toevoegt.", "error": "Het laden van de playbooks is mislukt.", "errors": { "contentRequired": "De inhoud van het draaiboek is vereist.", + "loadDefaultFailed": "Het laden van het ingebouwde standaard playbook is mislukt.", "nameRequired": "Een naam is vereist.", "playbookIdRequired": "Een playbook-ID is vereist.", "previewFailed": "Het is niet gelukt om het playbook te laden. Controleer het YAML-bestand op fouten.", "saveFailed": "Het opslaan van de playbook is mislukt. Controleer het YAML-bestand op fouten." }, + "loadDefault": "Laad de ingebouwde standaard", + "loadingDefault": "De ingebouwde standaardinstellingen worden geladen…", + "meta": { + "allowedTools": "Toegestane gereedschappen", + "noTools": "Geen", + "outputContract": "Outputcontract", + "role": "Rol" + }, "name": "Naam", "namePlaceholder": "Menselijke leesbare naam", "playbookId": "Playbook-ID", @@ -346,4 +356,4 @@ "runs": "Loopt" }, "title": "Vlootherstel" -} +} \ No newline at end of file diff --git a/frontend/public/locales/no/remediation.json b/frontend/public/locales/no/remediation.json index 6cfe2ec..a330f08 100644 --- a/frontend/public/locales/no/remediation.json +++ b/frontend/public/locales/no/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Gå inn i YAML-håndboken…", "create": "Ny strategibok", "description": "Tilpass utbedringsforespørslene som agenten bruker. Valider en strategibok for å forhåndsvise den gjengitte forespørselen uten modellkall.", + "duplicate": "Dupliser for å tilpasse", "empty": "Ingen strategier ennå. Den innebygde standardstrategien brukes inntil du legger til en.", "error": "Kunne ikke laste inn spillbøkene.", "errors": { "contentRequired": "Innhold i spillboken er obligatorisk.", + "loadDefaultFailed": "Kunne ikke laste inn den innebygde standardspillboken.", "nameRequired": "Et navn er påkrevd.", "playbookIdRequired": "En playbook-ID er nødvendig.", "previewFailed": "Kunne ikke gjengi handlingsplanen. Sjekk YAML for feil.", "saveFailed": "Kunne ikke lagre handlingsplanen. Sjekk YAML for feil." }, + "loadDefault": "Last inn innebygd standard", + "loadingDefault": "Laster inn innebygd standard …", + "meta": { + "allowedTools": "Tillatte verktøy", + "noTools": "Ingen", + "outputContract": "Utgangskontrakt", + "role": "Rolle" + }, "name": "Navn", "namePlaceholder": "Menneskelig lesbart navn", "playbookId": "Playbook-ID", @@ -346,4 +356,4 @@ "runs": "Løper" }, "title": "Flåteopprydding" -} +} \ No newline at end of file diff --git a/frontend/public/locales/pl/remediation.json b/frontend/public/locales/pl/remediation.json index 90ee0de..657a186 100644 --- a/frontend/public/locales/pl/remediation.json +++ b/frontend/public/locales/pl/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Poznaj podręcznik YAML…", "create": "Nowy podręcznik", "description": "Dostosuj monity naprawcze używane przez agenta. Zweryfikuj playbook, aby wyświetlić podgląd wyrenderowanego monitu bez wywoływania modelu.", + "duplicate": "Duplikuj, aby dostosować", "empty": "Brak podręczników. Domyślny, wbudowany podręcznik będzie używany, dopóki go nie dodasz.", "error": "Nie udało się załadować podręczników.", "errors": { "contentRequired": "Treść podręcznika jest wymagana.", + "loadDefaultFailed": "Nie udało się załadować domyślnego, wbudowanego podręcznika.", "nameRequired": "Nazwa jest wymagana.", "playbookIdRequired": "Wymagany jest identyfikator podręcznika.", "previewFailed": "Nie udało się wyrenderować playbooka. Sprawdź plik YAML pod kątem błędów.", "saveFailed": "Nie udało się zapisać podręcznika. Sprawdź plik YAML pod kątem błędów." }, + "loadDefault": "Załaduj wbudowane domyślne", + "loadingDefault": "Ładowanie wbudowanego domyślnego…", + "meta": { + "allowedTools": "Dozwolone narzędzia", + "noTools": "Nic", + "outputContract": "Kontrakt wyjściowy", + "role": "Rola" + }, "name": "Nazwa", "namePlaceholder": "Nazwa czytelna dla człowieka", "playbookId": "Identyfikator podręcznika", @@ -346,4 +356,4 @@ "runs": "Biegi" }, "title": "Remediacja floty" -} +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/remediation.json b/frontend/public/locales/pt-BR/remediation.json index 96377e8..11d7793 100644 --- a/frontend/public/locales/pt-BR/remediation.json +++ b/frontend/public/locales/pt-BR/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Insira o playbook YAML…", "create": "Novo manual de estratégias", "description": "Personalize os prompts de correção que o agente utiliza. Valide um playbook para visualizar o prompt renderizado sem nenhuma chamada de modelo.", + "duplicate": "Duplique para personalizar", "empty": "Ainda não há playbooks. O playbook padrão integrado será usado até que você adicione um.", "error": "Falha ao carregar os playbooks.", "errors": { "contentRequired": "O conteúdo do manual é obrigatório.", + "loadDefaultFailed": "Falha ao carregar o playbook padrão integrado.", "nameRequired": "É necessário informar um nome.", "playbookIdRequired": "É necessário um ID de playbook.", "previewFailed": "Falha ao renderizar o playbook. Verifique o arquivo YAML em busca de erros.", "saveFailed": "Falha ao salvar o playbook. Verifique o arquivo YAML em busca de erros." }, + "loadDefault": "Carregar padrão integrado", + "loadingDefault": "Carregando configurações padrão integradas…", + "meta": { + "allowedTools": "Ferramentas permitidas", + "noTools": "Nenhum", + "outputContract": "Contrato de produção", + "role": "Papel" + }, "name": "Nome", "namePlaceholder": "Nome legível para humanos", "playbookId": "ID do Playbook", @@ -346,4 +356,4 @@ "runs": "Corridas" }, "title": "Remediação da frota" -} +} \ No newline at end of file diff --git a/frontend/public/locales/ru/remediation.json b/frontend/public/locales/ru/remediation.json index 3a458da..bde9505 100644 --- a/frontend/public/locales/ru/remediation.json +++ b/frontend/public/locales/ru/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Представляем вашему вниманию руководство по использованию YAML…", "create": "Новый план действий", "description": "Настройте подсказки для устранения неполадок, используемые агентом. Проверьте сценарий автоматизации, чтобы просмотреть отображаемую подсказку без вызова модели.", + "duplicate": "Дублировать для настройки", "empty": "Сценарии игровых действий пока отсутствуют. Пока не будет использоваться встроенный сценарий по умолчанию, пока вы его не добавите.", "error": "Не удалось загрузить сценарии игр.", "errors": { "contentRequired": "Содержание руководства обязательно.", + "loadDefaultFailed": "Не удалось загрузить встроенный сценарий автоматизации по умолчанию.", "nameRequired": "Необходимо указать имя.", "playbookIdRequired": "Требуется идентификатор сценария игры.", "previewFailed": "Не удалось отобразить сценарий автоматизации. Проверьте файл YAML на наличие ошибок.", "saveFailed": "Не удалось сохранить сценарий действий. Проверьте файл YAML на наличие ошибок." }, + "loadDefault": "Загрузить встроенные настройки по умолчанию", + "loadingDefault": "Загрузка встроенных настроек по умолчанию…", + "meta": { + "allowedTools": "Разрешенные инструменты", + "noTools": "Никто", + "outputContract": "Контракт на выпуск продукции", + "role": "Роль" + }, "name": "Имя", "namePlaceholder": "Имя, читаемое человеком", "playbookId": "Идентификатор плейбука", @@ -346,4 +356,4 @@ "runs": "Беги" }, "title": "Восстановление автопарка" -} +} \ No newline at end of file diff --git a/frontend/public/locales/sr/remediation.json b/frontend/public/locales/sr/remediation.json index ba9f51b..8103bc9 100644 --- a/frontend/public/locales/sr/remediation.json +++ b/frontend/public/locales/sr/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Уђите у приручник YAML…", "create": "Нови приручник", "description": "Прилагодите упите за санацију које агент користи. Валидирајте плејбук да бисте прегледали приказани упит без позива модела.", + "duplicate": "Дуплирајте да бисте прилагодили", "empty": "Још нема референтних приручника. Уграђени подразумевани референтни приручник се користи док га не додате.", "error": "Учитавање плејбукова није успело.", "errors": { "contentRequired": "Садржај приручника је обавезан.", + "loadDefaultFailed": "Није успело учитавање уграђеног подразумеваног плејбука.", "nameRequired": "Потребно је име.", "playbookIdRequired": "Потребан је ИД плејбука.", "previewFailed": "Није успело приказивање плејбука. Проверите YAML да ли има грешака.", "saveFailed": "Чување приручника није успело. Проверите YAML датотеку за грешке." }, + "loadDefault": "Учитај уграђене подразумеване вредности", + "loadingDefault": "Учитавање уграђених подразумеваних подешавања…", + "meta": { + "allowedTools": "Дозвољени алати", + "noTools": "Ниједан", + "outputContract": "Излазни уговор", + "role": "Улога" + }, "name": "Име", "namePlaceholder": "Име читљиво људима", "playbookId": "ИД приручника", @@ -346,4 +356,4 @@ "runs": "Трчи" }, "title": "Санација возног парка" -} +} \ No newline at end of file diff --git a/frontend/public/locales/sv/remediation.json b/frontend/public/locales/sv/remediation.json index 8045975..852b7f2 100644 --- a/frontend/public/locales/sv/remediation.json +++ b/frontend/public/locales/sv/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Gå in i YAML-spelboken…", "create": "Ny spelbok", "description": "Anpassa de åtgärdsfrågor som agenten använder. Validera en spelbok för att förhandsgranska den renderade frågan utan modellanrop.", + "duplicate": "Duplicera för att anpassa", "empty": "Inga spelböcker ännu. Den inbyggda standardspelboken används tills du lägger till en.", "error": "Misslyckades med att läsa in spelböcker.", "errors": { "contentRequired": "Innehåll i spelboken krävs.", + "loadDefaultFailed": "Det gick inte att läsa in den inbyggda standardspelboken.", "nameRequired": "Ett namn krävs.", "playbookIdRequired": "Ett playbook-ID krävs.", "previewFailed": "Misslyckades med att rendera spelboken. Kontrollera YAML för fel.", "saveFailed": "Det gick inte att spara spelboken. Kontrollera YAML för fel." }, + "loadDefault": "Ladda inbyggd standard", + "loadingDefault": "Läser inbyggd standard…", + "meta": { + "allowedTools": "Tillåtna verktyg", + "noTools": "Ingen", + "outputContract": "Utgångskontrakt", + "role": "Roll" + }, "name": "Namn", "namePlaceholder": "Läsbart namn", "playbookId": "Playbook-ID", @@ -346,4 +356,4 @@ "runs": "Löpningar" }, "title": "Sanering av flottan" -} +} \ No newline at end of file diff --git a/frontend/public/locales/th/remediation.json b/frontend/public/locales/th/remediation.json index 1e84c87..9e45ac0 100644 --- a/frontend/public/locales/th/remediation.json +++ b/frontend/public/locales/th/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "เข้าสู่คู่มือการใช้งาน YAML…", "create": "คู่มือฉบับใหม่", "description": "ปรับแต่งข้อความแจ้งเตือนการแก้ไขปัญหาที่เอเจนต์ใช้ ตรวจสอบความถูกต้องของเพลย์บุ๊กเพื่อดูตัวอย่างข้อความแจ้งเตือนที่แสดงโดยไม่ต้องเรียกใช้โมเดล", + "duplicate": "ทำซ้ำเพื่อปรับแต่ง", "empty": "ยังไม่มีเพลย์บุ๊กใดๆ ระบบจะใช้เพลย์บุ๊กเริ่มต้นที่สร้างไว้แล้วจนกว่าคุณจะเพิ่มเพลย์บุ๊กใหม่", "error": "ไม่สามารถโหลดเพลย์บุ๊กได้", "errors": { "contentRequired": "จำเป็นต้องมีเนื้อหาในคู่มือการปฏิบัติงาน", + "loadDefaultFailed": "ไม่สามารถโหลด playbook เริ่มต้นที่สร้างไว้ล่วงหน้าได้", "nameRequired": "ต้องระบุชื่อด้วย", "playbookIdRequired": "จำเป็นต้องระบุรหัส Playbook", "previewFailed": "ไม่สามารถแสดงผล playbook ได้ โปรดตรวจสอบไฟล์ YAML เพื่อหาข้อผิดพลาด", "saveFailed": "ไม่สามารถบันทึก playbook ได้ โปรดตรวจสอบไฟล์ YAML เพื่อหาข้อผิดพลาด" }, + "loadDefault": "โหลดค่าเริ่มต้นในตัว", + "loadingDefault": "กำลังโหลดค่าเริ่มต้นที่ติดตั้งมาในตัว…", + "meta": { + "allowedTools": "เครื่องมือที่อนุญาต", + "noTools": "ไม่มี", + "outputContract": "สัญญาผลผลิต", + "role": "บทบาท" + }, "name": "ชื่อ", "namePlaceholder": "ชื่อที่มนุษย์อ่านได้", "playbookId": "รหัสเพลย์บุ๊ก", @@ -346,4 +356,4 @@ "runs": "วิ่ง" }, "title": "การแก้ไขปัญหาฝูงเรือ" -} +} \ No newline at end of file diff --git a/frontend/public/locales/tr/remediation.json b/frontend/public/locales/tr/remediation.json index 2f647af..da2112f 100644 --- a/frontend/public/locales/tr/remediation.json +++ b/frontend/public/locales/tr/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "YAML oyun kılavuzuna girin…", "create": "Yeni strateji kitabı", "description": "Aracının kullandığı düzeltme istemlerini özelleştirin. Model çağrısı olmadan oluşturulan istemi önizlemek için bir playbook'u doğrulayın.", + "duplicate": "Özelleştirmek için çoğaltın", "empty": "Henüz hiçbir playbook yok. Siz bir playbook ekleyene kadar yerleşik varsayılan playbook kullanılır.", "error": "Oyun kitapçıkları yüklenemedi.", "errors": { "contentRequired": "Oyun planı içeriği gereklidir.", + "loadDefaultFailed": "Dahili varsayılan playbook yüklenemedi.", "nameRequired": "Bir isim gereklidir.", "playbookIdRequired": "Bir oyun kitabı kimliği gereklidir.", "previewFailed": "Playbook oluşturulamadı. Hata olup olmadığını kontrol etmek için YAML dosyasını inceleyin.", "saveFailed": "Oyun kitabı kaydedilemedi. Hata olup olmadığını kontrol etmek için YAML dosyasını inceleyin." }, + "loadDefault": "Dahili varsayılanı yükle", + "loadingDefault": "Dahili varsayılan ayarlar yükleniyor…", + "meta": { + "allowedTools": "İzin verilen araçlar", + "noTools": "Hiçbiri", + "outputContract": "Üretim sözleşmesi", + "role": "Rol" + }, "name": "İsim", "namePlaceholder": "İnsan tarafından okunabilir isim", "playbookId": "Oyun Kitabı Kimliği", @@ -346,4 +356,4 @@ "runs": "Koşular" }, "title": "Filo İyileştirme" -} +} \ No newline at end of file diff --git a/frontend/public/locales/vi/remediation.json b/frontend/public/locales/vi/remediation.json index 15b1d19..44dbb02 100644 --- a/frontend/public/locales/vi/remediation.json +++ b/frontend/public/locales/vi/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "Nhập tệp YAML của playbook…", "create": "Chiến lược mới", "description": "Tùy chỉnh các lời nhắc khắc phục sự cố mà tác nhân sử dụng. Xác thực một playbook để xem trước lời nhắc được hiển thị mà không cần gọi mô hình.", + "duplicate": "Sao chép để tùy chỉnh", "empty": "Hiện chưa có playbook nào. Playbook mặc định được tích hợp sẵn sẽ được sử dụng cho đến khi bạn thêm một playbook khác.", "error": "Không thể tải các tập lệnh chiến thuật.", "errors": { "contentRequired": "Nội dung trong cẩm nang là bắt buộc.", + "loadDefaultFailed": "Không thể tải tập lệnh mặc định tích hợp sẵn.", "nameRequired": "Cần phải nhập tên.", "playbookIdRequired": "Cần có mã định danh của sổ tay chiến thuật.", "previewFailed": "Không thể hiển thị playbook. Kiểm tra tệp YAML để tìm lỗi.", "saveFailed": "Không thể lưu tập lệnh. Kiểm tra tệp YAML để tìm lỗi." }, + "loadDefault": "Tải cài đặt mặc định tích hợp sẵn", + "loadingDefault": "Đang tải các cài đặt mặc định tích hợp sẵn…", + "meta": { + "allowedTools": "Các công cụ được phép", + "noTools": "Không có", + "outputContract": "Hợp đồng sản lượng", + "role": "Vai trò" + }, "name": "Tên", "namePlaceholder": "Tên dễ đọc đối với con người", "playbookId": "Mã số sổ tay", @@ -346,4 +356,4 @@ "runs": "Chạy" }, "title": "Khắc phục sự cố đội xe" -} +} \ No newline at end of file diff --git a/frontend/public/locales/zh-CN/remediation.json b/frontend/public/locales/zh-CN/remediation.json index 4cfc194..d8345fd 100644 --- a/frontend/public/locales/zh-CN/remediation.json +++ b/frontend/public/locales/zh-CN/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "输入 YAML 剧本……", "create": "新策略手册", "description": "自定义代理使用的修复提示。验证剧本以预览渲染后的提示,无需调用模型。", + "duplicate": "复制以进行自定义", "empty": "目前还没有剧本。在您添加剧本之前,将使用内置的默认剧本。", "error": "剧本加载失败。", "errors": { "contentRequired": "需要提供操作手册内容。", + "loadDefaultFailed": "无法加载内置的默认剧本。", "nameRequired": "必须填写姓名。", "playbookIdRequired": "需要剧本ID。", "previewFailed": "剧本渲染失败。请检查 YAML 文件是否存在错误。", "saveFailed": "剧本保存失败。请检查 YAML 文件是否存在错误。" }, + "loadDefault": "加载内置默认值", + "loadingDefault": "正在加载内置默认值…", + "meta": { + "allowedTools": "允许使用的工具", + "noTools": "没有任何", + "outputContract": "产出合同", + "role": "角色" + }, "name": "姓名", "namePlaceholder": "人类可读的名称", "playbookId": "剧本 ID", @@ -346,4 +356,4 @@ "runs": "跑" }, "title": "舰队整改" -} +} \ No newline at end of file diff --git a/frontend/public/locales/zh-TW/remediation.json b/frontend/public/locales/zh-TW/remediation.json index dd60b20..6f934d7 100644 --- a/frontend/public/locales/zh-TW/remediation.json +++ b/frontend/public/locales/zh-TW/remediation.json @@ -239,15 +239,25 @@ "contentPlaceholder": "輸入 YAML 劇本…", "create": "新策略手冊", "description": "自訂代理程式使用的修復提示。驗證劇本以預覽渲染後的提示,無需呼叫模型。", + "duplicate": "複製以進行自訂", "empty": "目前還沒有劇本。在您新增劇本之前,將使用內建的預設劇本。", "error": "劇本加載失敗。", "errors": { "contentRequired": "需提供操作手冊內容。", + "loadDefaultFailed": "無法載入內建的預設劇本。", "nameRequired": "必須填寫姓名。", "playbookIdRequired": "需要劇本ID。", "previewFailed": "劇本渲染失敗。請檢查 YAML 檔案是否有錯誤。", "saveFailed": "劇本保存失敗。請檢查 YAML 檔案是否有錯誤。" }, + "loadDefault": "載入內建預設值", + "loadingDefault": "正在載入內建預設值…", + "meta": { + "allowedTools": "允許使用的工具", + "noTools": "沒有任何", + "outputContract": "產出合約", + "role": "角色" + }, "name": "姓名", "namePlaceholder": "人類可讀的名稱", "playbookId": "劇本 ID", @@ -346,4 +356,4 @@ "runs": "跑" }, "title": "艦隊整改" -} +} \ No newline at end of file diff --git a/frontend/src/api/playbooks.ts b/frontend/src/api/playbooks.ts index d2266cf..ca137d4 100644 --- a/frontend/src/api/playbooks.ts +++ b/frontend/src/api/playbooks.ts @@ -22,6 +22,15 @@ export const playbooksApi = { return response.data.data!; }, + /** + * The built-in default playbook (ADR-006), read-only. Used as a documented + * starting point the editor can load and customize. + */ + async getEmbeddedPlaybook(): Promise { + const response = await apiClient.get>('/remediation/playbooks/embedded'); + return response.data.data!; + }, + async createPlaybook(data: CreatePlaybookRequest): Promise { const response = await apiClient.post>('/remediation/playbooks', data); return response.data.data!; diff --git a/frontend/src/components/remediation/PlaybookEditor.test.tsx b/frontend/src/components/remediation/PlaybookEditor.test.tsx index fc927fb..d7d9f7c 100644 --- a/frontend/src/components/remediation/PlaybookEditor.test.tsx +++ b/frontend/src/components/remediation/PlaybookEditor.test.tsx @@ -15,6 +15,7 @@ vi.mock('react-i18next', () => ({ const mockCreate = vi.fn(); const mockDelete = vi.fn(); const mockPreview = vi.fn(); +const mockLoadDefault = vi.fn(); let playbooksData: Playbook[] = []; vi.mock('@/hooks/usePlaybooks', () => ({ @@ -22,6 +23,7 @@ vi.mock('@/hooks/usePlaybooks', () => ({ useCreatePlaybook: () => ({ mutate: mockCreate, isPending: false }), useDeletePlaybook: () => ({ mutate: mockDelete, isPending: false }), usePreviewPlaybook: () => ({ mutate: mockPreview, isPending: false }), + useLoadEmbeddedPlaybook: () => ({ mutate: mockLoadDefault, isPending: false }), })); const samplePlaybook: Playbook = { @@ -75,6 +77,74 @@ describe('PlaybookEditor', () => { expect(await screen.findByText('You are a careful build-fixing agent.')).toBeInTheDocument(); }); + it('should_renderCapabilityPills_when_previewSucceeds', async () => { + playbooksData = [samplePlaybook]; + mockPreview.mockImplementation((_vars, options) => { + options.onSuccess({ + failureClass: 'build_error', + role: 'fixer', + systemInstruction: 'You are a careful build-fixing agent.', + outputContract: 'unified_diff', + allowedTools: ['read_file', 'apply_patch'], + }); + }); + const user = userEvent.setup(); + render(); + + await user.click(screen.getByRole('button', { name: 'remediation:playbooks.preview' })); + + // The output-contract value and each allowed tool render as their own pills. + expect(await screen.findByText(/unified_diff/)).toBeInTheDocument(); + expect(screen.getByText('read_file')).toBeInTheDocument(); + expect(screen.getByText('apply_patch')).toBeInTheDocument(); + }); + + it('should_prefillFormWithDefaultYaml_when_loadDefaultClicked', async () => { + mockLoadDefault.mockImplementation((_vars, options) => { + options.onSuccess({ + id: '00000000-0000-0000-0000-000000000000', + playbookId: 'default', + version: 1, + source: 'builtin', + name: 'Default remediation playbook', + description: 'builtin default', + content: 'role: You are a remediation engineer.\ntasks: {}', + enabled: true, + scopeType: 'global', + scopeId: null, + createdAt: '1970-01-01T00:00:00+00:00', + updatedAt: '1970-01-01T00:00:00+00:00', + }); + }); + const user = userEvent.setup(); + render(); + + await user.click(screen.getByRole('button', { name: 'remediation:playbooks.loadDefault' })); + + // The form opens prefilled with the default YAML but a blank id/name (a + // sanitized copy that never collides with the built-in). + const content = await screen.findByLabelText('remediation:playbooks.content'); + expect(content).toHaveValue('role: You are a remediation engineer.\ntasks: {}'); + expect(screen.getByLabelText('remediation:playbooks.playbookId')).toHaveValue(''); + expect(screen.getByLabelText('remediation:playbooks.name')).toHaveValue(''); + }); + + it('should_prefillFormFromRow_when_duplicateClicked', async () => { + playbooksData = [samplePlaybook]; + const user = userEvent.setup(); + render(); + + await user.click(screen.getByRole('button', { name: 'remediation:playbooks.duplicate' })); + + expect(await screen.findByLabelText('remediation:playbooks.content')).toHaveValue( + 'role: fixer' + ); + expect(screen.getByLabelText('remediation:playbooks.playbookId')).toHaveValue( + 'custom-remediation-copy' + ); + expect(screen.getByLabelText('remediation:playbooks.name')).toHaveValue('Custom Remediation'); + }); + it('should_showError_when_previewFailsWithYamlError', async () => { playbooksData = [samplePlaybook]; mockPreview.mockImplementation((_vars, options) => { diff --git a/frontend/src/components/remediation/PlaybookEditor.tsx b/frontend/src/components/remediation/PlaybookEditor.tsx index 2d022cc..b854b51 100644 --- a/frontend/src/components/remediation/PlaybookEditor.tsx +++ b/frontend/src/components/remediation/PlaybookEditor.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { FileCode, Plus, Trash2 } from 'lucide-react'; +import { Copy, FileCode, FileDown, Plus, Trash2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; @@ -15,6 +15,7 @@ import { import { useCreatePlaybook, useDeletePlaybook, + useLoadEmbeddedPlaybook, usePlaybooks, usePreviewPlaybook, } from '@/hooks/usePlaybooks'; @@ -24,24 +25,45 @@ import type { ScopeType } from '@/types/remediation'; const SCOPE_TYPES: ScopeType[] = ['user', 'team', 'org', 'repository']; +/** Initial values a form is opened with (blank create, loaded default, or duplicate). */ +interface PlaybookFormSeed { + playbookId: string; + name: string; + content: string; + scopeType: ScopeType; +} + +const BLANK_SEED: PlaybookFormSeed = { + playbookId: '', + name: '', + content: '', + scopeType: 'user', +}; + +/** Coerce an arbitrary stored `scopeType` string to a known form value. */ +function toScopeType(value: string): ScopeType { + return (SCOPE_TYPES as string[]).includes(value) ? (value as ScopeType) : 'user'; +} + interface PlaybookFormProps { + initial: PlaybookFormSeed; onClose: () => void; } -function PlaybookForm({ onClose }: PlaybookFormProps) { +function PlaybookForm({ initial, onClose }: PlaybookFormProps) { const { t } = useTranslation(['remediation', 'common']); const createMutation = useCreatePlaybook(); - const [playbookId, setPlaybookId] = useState(''); - const [name, setName] = useState(''); - const [scopeType, setScopeType] = useState('user'); + const [playbookId, setPlaybookId] = useState(initial.playbookId); + const [name, setName] = useState(initial.name); + const [scopeType, setScopeType] = useState(initial.scopeType); const [scopeId, setScopeId] = useState(''); - const [content, setContent] = useState(''); + const [content, setContent] = useState(initial.content); const [error, setError] = useState(null); // Validate/Preview renders a SAVED playbook (the API operates on a stored row), // so it lives on each list row below. The create form surfaces server-side YAML - // parse errors (422) inline on save. + // parse errors (422, now with a field path) inline on save. const handleSave = (e: React.FormEvent) => { e.preventDefault(); setError(null); @@ -162,8 +184,42 @@ function PlaybookForm({ onClose }: PlaybookFormProps) { ); } +const PILL = 'rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground'; + +/** Compact "what this playbook grants" pills, mirroring the model-catalog pills. */ +function PreviewMeta({ preview }: { preview: PlaybookPreviewResponse }) { + const { t } = useTranslation(['remediation']); + return ( +
+ + {t('remediation:playbooks.meta.role')}: {preview.role} + + + {t('remediation:playbooks.meta.outputContract')}: {preview.outputContract} + + + {t('remediation:playbooks.meta.allowedTools')}: + + {preview.allowedTools.length === 0 ? ( + {t('remediation:playbooks.meta.noTools')} + ) : ( + preview.allowedTools.map((tool) => ( + + {tool} + + )) + )} +
+ ); +} + +interface PlaybookRowProps { + playbook: Playbook; + onDuplicate: (playbook: Playbook) => void; +} + /** Per-row preview control: validates a SAVED playbook and shows the prompt. */ -function PlaybookRow({ playbook }: { playbook: Playbook }) { +function PlaybookRow({ playbook, onDuplicate }: PlaybookRowProps) { const { t } = useTranslation(['remediation', 'common']); const previewMutation = usePreviewPlaybook(); const deleteMutation = useDeletePlaybook(); @@ -206,6 +262,10 @@ function PlaybookRow({ playbook }: { playbook: Playbook }) { ? t('remediation:playbooks.previewing') : t('remediation:playbooks.preview')} + + )} - {creating && setCreating(false)} />} + {loadError && ( +

+ {loadError} +

+ )} + + {formSeed && ( + setFormSeed(null)} /> + )} {isLoading ? (
@@ -267,7 +379,7 @@ export function PlaybookEditor() { ) : (
    {playbooks.map((playbook) => ( - + ))}
)} diff --git a/frontend/src/hooks/usePlaybooks.ts b/frontend/src/hooks/usePlaybooks.ts index 00e2415..091b21c 100644 --- a/frontend/src/hooks/usePlaybooks.ts +++ b/frontend/src/hooks/usePlaybooks.ts @@ -26,6 +26,17 @@ export function usePlaybook(id: string) { }); } +/** + * On-demand fetch of the built-in default playbook (ADR-006). Modeled as a + * mutation so it fires on a user action (the editor's "Load built-in default"), + * not on mount. + */ +export function useLoadEmbeddedPlaybook() { + return useMutation({ + mutationFn: () => playbooksApi.getEmbeddedPlaybook(), + }); +} + export function useCreatePlaybook() { const queryClient = useQueryClient(); return useMutation({ diff --git a/frontend/src/i18n/types.ts b/frontend/src/i18n/types.ts index 6c3703a..130f8d1 100644 --- a/frontend/src/i18n/types.ts +++ b/frontend/src/i18n/types.ts @@ -1009,15 +1009,25 @@ export interface RemediationTranslations { contentPlaceholder: string; create: string; description: string; + duplicate: string; empty: string; error: string; errors: { contentRequired: string; + loadDefaultFailed: string; nameRequired: string; playbookIdRequired: string; previewFailed: string; saveFailed: string; }; + loadDefault: string; + loadingDefault: string; + meta: { + allowedTools: string; + noTools: string; + outputContract: string; + role: string; + }; name: string; namePlaceholder: string; playbookId: string;