From 9e47a11eb5761fc36d26273c9cebbd247acd3935 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Wed, 5 Aug 2026 20:04:13 +0530 Subject: [PATCH 1/3] docs: fix broken images in all 14 translated READMEs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The root README.md sits at the repo root, so it writes repo-root-relative image paths (assets/logos/claude.svg, readme-arch-hq.gif). The translator is prompt-forbidden from rewriting paths, so every copy inherited them verbatim into docs/i18n/, two directories down, where they resolved to nothing: GitHub 404'd on docs/i18n/assets/..., and Mintlify — which also serves these pages at /i18n/README. — 403'd from S3. Every CLI logo and the architecture GIF were missing in all 14 languages. rebaseReadmePaths now re-points them at generation time. Images become absolute raw.githubusercontent.com URLs, the only form that renders on both surfaces: a ../../ path fixes GitHub but leaves Mintlify with no assets/ tree to walk into. Document links (./LICENSE, ./CONTRIBUTING.md) get ../../ instead, since GitHub is the only place a link to a repo file resolves and a raw URL there would serve unrendered plaintext. Paths inside fenced code blocks stay literal, and the rebase runs on the model output only — the wrapper's language selector already points at docs/i18n/ siblings. The 14 committed files are repaired in place with the same function. Add a broken-image check to validate:mdx so the class cannot ship again. A bad image path is valid MDX and valid YAML, so mintlify validate and the existing MDX parse both passed it straight through to a reader's browser — nothing in CI was watching. findBrokenAssetRefs resolves every local image reference on every docs page (site-absolute against docs/, everything else against the page's own directory) and fails with the path it resolved to. It runs in the CI docs job, in each per-language auto-translation job before its artifact is uploaded so the failing language is named rather than surfacing across 14 logs, and twice more in consolidate. The root README.md is checked too, since a bad path there propagates into 14 files as an absolute URL the check would no longer follow. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Hnj5rFHSw86gGXZTP6JsPU --- .github/workflows/ci.yml | 6 +- .github/workflows/translate-docs.yml | 14 +- CHANGELOG.md | 2 + .../translate-docs/readme-translator.test.ts | 85 +++++++++- __tests__/scripts/validate-mdx.test.ts | 91 +++++++++++ docs/i18n/README.ar.md | 36 ++-- docs/i18n/README.de.md | 36 ++-- docs/i18n/README.es.md | 36 ++-- docs/i18n/README.fr.md | 36 ++-- docs/i18n/README.he.md | 36 ++-- docs/i18n/README.hi.md | 36 ++-- docs/i18n/README.it.md | 36 ++-- docs/i18n/README.ja.md | 36 ++-- docs/i18n/README.ko.md | 36 ++-- docs/i18n/README.pt-br.md | 36 ++-- docs/i18n/README.ru.md | 36 ++-- docs/i18n/README.tr.md | 36 ++-- docs/i18n/README.vi.md | 36 ++-- docs/i18n/README.zh.md | 36 ++-- scripts/translate-docs/readme-translator.ts | 120 +++++++++++++- scripts/validate-mdx.ts | 154 ++++++++++++++++-- 21 files changed, 703 insertions(+), 273 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23a5a8b6..159cfa7b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -185,8 +185,10 @@ jobs: # time. `mintlify validate` does NOT parse page content, so a syntax # error (e.g. a translation that breaks a JSX tag or injects a `{#id}` # heading anchor) passes that step but fails the post-merge deploy. - # This catches it on the PR instead. - - name: Validate MDX pages parse + # This catches it on the PR instead. It also verifies every image + # reference resolves on disk — that class breaks nothing at build time, + # it just renders as a broken image, so nothing else in CI watches it. + - name: Validate MDX pages parse and image references resolve run: bun run validate:mdx test-e2e: diff --git a/.github/workflows/translate-docs.yml b/.github/workflows/translate-docs.yml index 17453150..b732b2aa 100644 --- a/.github/workflows/translate-docs.yml +++ b/.github/workflows/translate-docs.yml @@ -90,6 +90,15 @@ jobs: - name: Translate ${{ matrix.lang }} run: bun run translate --languages ${{ matrix.lang }} ${{ inputs.force == true && '--force' || '' }} + # Fail the language that actually broke, before its artifact is uploaded. + # `consolidate` re-runs this on the merged tree, but only after every + # language finished — attributing a failure there means reading 14 logs. + # This also covers broken image paths (see findBrokenAssetRefs), the class + # that shipped every logo broken in all 14 translated READMEs: valid MDX, + # valid YAML, so neither `mintlify validate` nor the MDX parse saw it. + - name: Validate translated pages parse and images resolve + run: bun run validate:mdx + - name: Upload translated files uses: actions/upload-artifact@v7 with: @@ -161,7 +170,10 @@ jobs: working-directory: docs run: mintlify validate - - name: Validate translated MDX pages + # Parses every page AND checks that every image reference resolves on + # disk — a broken image path is valid MDX, so `mintlify validate` above + # passes it straight through to a reader's browser. + - name: Validate translated MDX pages and image references run: bun run validate:mdx - name: Download cache fragments diff --git a/CHANGELOG.md b/CHANGELOG.md index cc1f9e27..cf758a49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - Restrict stable releases to a maintainer allowlist while leaving prereleases open. `publish.yml`'s preflight now refuses any publish at dist-tag `latest`, or of a non-prerelease version at any dist-tag, unless both `github.actor` and `github.triggering_actor` are on the allowlist (`NiveditJain`) — the second identity matters because a re-run keeps `actor` as the original triggerer, so checking only it would make a maintainer's stable run a re-run button for everyone with write access. A stable version published under `next` is gated too: it claims that number on npm permanently and is one `npm dist-tag add` away from being the stable release. `beta` and `next` builds are untouched, so the branch-dispatch path stays open to anyone GitHub already trusts with write access. The check runs in preflight, which every other job depends on, so a refusal costs seconds rather than a 4-way cross-compile. (#651) ### Fixes +- Repair every image in the 14 translated READMEs, which had been broken since they were first generated. The root `README.md` sits at the repo root, so it writes repo-root-relative paths (`assets/logos/claude.svg`, `readme-arch-hq.gif`); the translator is prompt-forbidden from rewriting paths, so each copy inherited them verbatim into `docs/i18n/`, two directories down, where they resolved to nothing — GitHub 404'd on `docs/i18n/assets/...` and Mintlify, which also serves these pages at `/i18n/README.`, 403'd from S3. Every CLI logo and the architecture GIF were missing in all 14 languages. `rebaseReadmePaths` now re-points them at generation time: images become absolute `raw.githubusercontent.com` URLs (the only form that renders on both surfaces — a `../../` path fixes GitHub but leaves Mintlify with no `assets/` tree to walk into), while document links (`./LICENSE`, `./CONTRIBUTING.md`) get `../../`, since GitHub is the only place a link to a repo file resolves and a raw URL there would serve plaintext. Paths inside fenced code blocks stay literal. (#654) +- Add a broken-image check to `validate:mdx` so that class cannot ship again. A bad image path is valid MDX and valid YAML, so `mintlify validate` and the existing MDX parse both passed it straight through to a reader's browser — nothing in CI was watching. `findBrokenAssetRefs` now resolves every local image reference on every docs page (site-absolute `/…` against `docs/`, everything else against the page's own directory) and fails with the path it resolved to. It runs in the CI `docs` job, in each per-language auto-translation job before its artifact is uploaded, and twice more in `consolidate`. The root `README.md` is checked too, since a bad path there propagates into 14 files as an absolute URL the check would no longer follow. (#654) - Harden the release workflow against shell injection from ref names and generated outputs, align every Bun cache key with the tracked `bun.lock`, and discard the temporary publish-version edit before switching to `main` for the development-version bump. (#634) ### Dependencies diff --git a/__tests__/scripts/translate-docs/readme-translator.test.ts b/__tests__/scripts/translate-docs/readme-translator.test.ts index b87ad63c..c404b25a 100644 --- a/__tests__/scripts/translate-docs/readme-translator.test.ts +++ b/__tests__/scripts/translate-docs/readme-translator.test.ts @@ -1,8 +1,91 @@ // @vitest-environment node import { describe, it, expect } from "vitest"; -import { buildMainReadmeLanguageLinks } from "@/scripts/translate-docs/readme-translator"; +import { + buildMainReadmeLanguageLinks, + rebaseReadmePaths, +} from "@/scripts/translate-docs/readme-translator"; import { LANGUAGES } from "@/scripts/translate-docs/config"; +const RAW = "https://raw.githubusercontent.com/FailproofAI/failproofai/main"; + +describe("rebaseReadmePaths", () => { + // The root README sits AT the repo root, so it writes repo-root-relative + // paths. Its translations land in docs/i18n/, two levels down, where those + // paths resolve to nothing — GitHub 404s and Mintlify (which also serves + // these pages at /i18n/README.) 403s from S3. Every logo and the + // architecture GIF were broken in all 14 languages until this rewrite. + it("rewrites image paths to absolute raw URLs so both surfaces resolve", () => { + expect( + rebaseReadmePaths(''), + ).toBe(``); + expect(rebaseReadmePaths("![demo](readme-arch-hq.gif)")).toBe( + `![demo](${RAW}/readme-arch-hq.gif)`, + ); + }); + + it("rewrites document links to ../../ instead, where GitHub resolves them", () => { + // A raw URL for a .md would serve unrendered plaintext, so links get the + // relative form; GitHub is the only surface they work on either way. + expect(rebaseReadmePaths("[LICENSE](./LICENSE)")).toBe( + "[LICENSE](../../LICENSE)", + ); + expect(rebaseReadmePaths("[中文](./docs/i18n/README.zh.md)")).toBe( + "[中文](../../docs/i18n/README.zh.md)", + ); + }); + + it("preserves a fragment on a rewritten link", () => { + expect(rebaseReadmePaths("[build](./CONTRIBUTING.md#build-first)")).toBe( + "[build](../../CONTRIBUTING.md#build-first)", + ); + }); + + it("leaves absolute URLs, anchors, and other schemes alone", () => { + const untouched = + "[npm](https://www.npmjs.com/package/failproofai)\n" + + '\n' + + "[jump](#usage)\n" + + "[mail](mailto:hi@befailproof.ai)\n" + + "![inline](data:image/png;base64,iVBORw0KGgo=)\n" + + "![site](/agenteye/images/alerts.png)"; + expect(rebaseReadmePaths(untouched)).toBe(untouched); + }); + + it("is idempotent — a second pass changes nothing", () => { + const once = rebaseReadmePaths( + '\n[LICENSE](./LICENSE)', + ); + expect(rebaseReadmePaths(once)).toBe(once); + }); + + it("leaves paths inside fenced code blocks literal", () => { + // There a path is sample text a reader copies, not a reference to resolve. + const fenced = + "```html\n" + + '\n' + + "```\n" + + ''; + expect(rebaseReadmePaths(fenced)).toBe( + "```html\n" + + '\n' + + "```\n" + + ``, + ); + }); + + it("must run on the model output only, never on the assembled wrapper", () => { + // Documents the call-site contract. The language selector already points at + // docs/i18n/ siblings, so a bare `README.zh.md` there is CORRECT — running + // this over it would rewrite it to a path one directory above the file and + // break every selector link. `translateReadme` therefore rebases `raw` + // before wrapping, not the assembled page. + const selector = "[🇺🇸 English](../../README.md) | [🇨🇳 简体中文](README.zh.md)"; + expect(rebaseReadmePaths(selector)).toBe( + "[🇺🇸 English](../../README.md) | [🇨🇳 简体中文](../../README.zh.md)", + ); + }); +}); + describe("buildMainReadmeLanguageLinks", () => { it("returns a string starting with **Translations**:", () => { const result = buildMainReadmeLanguageLinks(); diff --git a/__tests__/scripts/validate-mdx.test.ts b/__tests__/scripts/validate-mdx.test.ts index d94fbd56..8215d477 100644 --- a/__tests__/scripts/validate-mdx.test.ts +++ b/__tests__/scripts/validate-mdx.test.ts @@ -6,6 +6,7 @@ import { tmpdir } from "node:os"; import { collectMdxFiles, encodeAnnotation, + findBrokenAssetRefs, findFrontmatterError, findMdxParseError, findPageError, @@ -247,3 +248,93 @@ describe("collectMdxFiles", () => { } }); }); + +describe("findBrokenAssetRefs", () => { + // Fixtures resolve against the real repo so the check is exercised with the + // same two path conventions the docs actually use. + const REPO = join(__dirname, "..", ".."); + const DOCS_PAGE = join(REPO, "docs", "agenteye", "alerts.mdx"); + const I18N_PAGE = join(REPO, "docs", "i18n", "README.ja.md"); + + it("flags the exact regression that broke every translated README", () => { + // The root README writes `assets/logos/claude.svg` because it sits AT the + // repo root. Copied verbatim into docs/i18n/ it resolves two levels too + // deep and 404s — this is the bug the check exists to prevent recurring. + const broken = findBrokenAssetRefs( + I18N_PAGE, + 'Claude Code\n', + ); + expect(broken).toHaveLength(1); + expect(broken[0].ref).toBe("assets/logos/claude.svg"); + expect(broken[0].resolved).toBe("docs/i18n/assets/logos/claude.svg"); + expect(broken[0].line).toBe(1); + }); + + it("accepts the rebased forms the translated READMEs now use", () => { + expect( + findBrokenAssetRefs( + I18N_PAGE, + '\n' + + "[link](../../CONTRIBUTING.md)\n", + ), + ).toEqual([]); + }); + + it("resolves a leading slash against docs/, not the page directory", () => { + // Mintlify site-absolute form, used by every agenteye page. + expect( + findBrokenAssetRefs( + DOCS_PAGE, + "![Alerts](/agenteye/images/alerts.png)\n", + ), + ).toEqual([]); + const broken = findBrokenAssetRefs( + DOCS_PAGE, + "![Nope](/agenteye/images/does-not-exist.png)\n", + ); + expect(broken).toHaveLength(1); + expect(broken[0].resolved).toBe("docs/agenteye/images/does-not-exist.png"); + }); + + it("accepts a page-relative path that exists", () => { + expect( + findBrokenAssetRefs(DOCS_PAGE, "![Alerts](images/alerts.png)\n"), + ).toEqual([]); + }); + + it("ignores external URLs, other schemes, and bare anchors", () => { + expect( + findBrokenAssetRefs( + DOCS_PAGE, + "![npm](https://img.shields.io/npm/dw/failproofai.svg)\n" + + "![inline](data:image/png;base64,iVBORw0KGgo=)\n" + + "![proto](//cdn.example.com/x.png)\n" + + "[jump](#section)\n", + ), + ).toEqual([]); + }); + + it("ignores non-asset links, which mintlify validate already covers", () => { + // Extensionless Mintlify routes and .md links must not false-positive. + expect( + findBrokenAssetRefs( + DOCS_PAGE, + "[Getting started](/getting-started)\n[Contributing](../../CONTRIBUTING.md)\n", + ), + ).toEqual([]); + }); + + it("strips a query or fragment before resolving", () => { + expect( + findBrokenAssetRefs(DOCS_PAGE, "![Alerts](images/alerts.png?v=2)\n"), + ).toEqual([]); + }); + + it("reports the line number of each broken reference", () => { + const broken = findBrokenAssetRefs( + DOCS_PAGE, + "# Title\n\n![One](images/nope-a.png)\n\n![Two](images/nope-b.png)\n", + ); + expect(broken.map((b) => b.line)).toEqual([3, 5]); + }); +}); diff --git a/docs/i18n/README.ar.md b/docs/i18n/README.ar.md index bb65a482..3edeafea 100644 --- a/docs/i18n/README.ar.md +++ b/docs/i18n/README.ar.md @@ -15,9 +15,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**الترجمات:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**الترجمات:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **حل أعطال وقت التشغيل لوكلاء البرمجة.** يتكامل مع Claude Code و Codex. يكتشف الحلقات والإجراءات الخطرة وتسريب الأسرار @@ -26,7 +26,7 @@

- Failproof AI in action + Failproof AI in action

--- @@ -40,14 +40,14 @@ - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -55,7 +55,7 @@ - GitHub Copilot + GitHub Copilot @@ -63,7 +63,7 @@ - Cursor Agent + Cursor Agent @@ -71,7 +71,7 @@ - OpenCode + OpenCode @@ -79,7 +79,7 @@ - Pi + Pi @@ -89,38 +89,38 @@ - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -207,19 +207,19 @@ customPolicies.add({ ## الترخيص -MIT مع [Commons Clause](https://commonsclause.com/) — مجاني للاستخدام الداخلي والشخصي؛ إعادة بيع failproofai نفسه بشكل تجاري يتطلب اتفاقية منفصلة. انظر [LICENSE](./LICENSE) للنص الكامل. +MIT مع [Commons Clause](https://commonsclause.com/) — مجاني للاستخدام الداخلي والشخصي؛ إعادة بيع failproofai نفسه بشكل تجاري يتطلب اتفاقية منفصلة. انظر [LICENSE](../../LICENSE) للنص الكامل. --- ## المساهمة -انظر [CONTRIBUTING.md](./CONTRIBUTING.md). السياسات الجديدة وحالات الحدود والترجمات كلها موضع ترحيب. +انظر [CONTRIBUTING.md](../../CONTRIBUTING.md). السياسات الجديدة وحالات الحدود والترجمات كلها موضع ترحيب. > **الإنشاء قبل البدء.** قم بتشغيل `bun install && bun run build` أولاً. يعمل هذا المستودع > على خطافات failproofai الخاصة به، ويقوم بحل استيراد failproofai مقابل > حزمة `dist/` المجمعة — بدون إنشاء ستواجه أخطاء خطافات `Cannot find package 'failproofai'` > انقر مجددًا بعد تغيير `src/`. انظر -> [الإنشاء قبل أن تعمل خطافات المستودع المضمن](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> [الإنشاء قبل أن تعمل خطافات المستودع المضمن](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). --- diff --git a/docs/i18n/README.de.md b/docs/i18n/README.de.md index a6017164..7cd37b9d 100644 --- a/docs/i18n/README.de.md +++ b/docs/i18n/README.de.md @@ -13,9 +13,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**Übersetzungen:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**Übersetzungen:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **Laufzeit-Fehlerbehebung für Coding-Agenten.** Klinkt sich in Claude Code und Codex ein. Erkennt Endlosschleifen, gefährliche Aktionen und geheime Datenlecks, @@ -24,7 +24,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal.

- Failproof AI in action + Failproof AI in action

--- @@ -38,14 +38,14 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -53,7 +53,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - GitHub Copilot + GitHub Copilot @@ -61,7 +61,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - Cursor Agent + Cursor Agent @@ -69,7 +69,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - OpenCode + OpenCode @@ -77,7 +77,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - Pi + Pi @@ -87,38 +87,38 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -205,19 +205,19 @@ wenn etwas schiefläuft. → [Dashboard-Leitfaden](https://docs.befailproof.ai/d ## Lizenz -MIT mit [Commons Clause](https://commonsclause.com/) — kostenlos für den internen und persönlichen Gebrauch; der kommerzielle Weiterverkauf von failproofai selbst erfordert eine gesonderte Vereinbarung. Den vollständigen Text findest du in [LICENSE](./LICENSE). +MIT mit [Commons Clause](https://commonsclause.com/) — kostenlos für den internen und persönlichen Gebrauch; der kommerzielle Weiterverkauf von failproofai selbst erfordert eine gesonderte Vereinbarung. Den vollständigen Text findest du in [LICENSE](../../LICENSE). --- ## Mitwirken -Siehe [CONTRIBUTING.md](./CONTRIBUTING.md). Neue Richtlinien, Randfälle und Übersetzungen sind herzlich willkommen. +Siehe [CONTRIBUTING.md](../../CONTRIBUTING.md). Neue Richtlinien, Randfälle und Übersetzungen sind herzlich willkommen. > **Erst bauen, dann starten.** Führe zunächst `bun install && bun run build` aus. Dieses Repository verwendet > failproofais eigene Hooks auf sich selbst, und diese lösen den `failproofai`-Import gegen das > kompilierte `dist/`-Bundle auf — ohne einen Build kommt es zu `Cannot find package 'failproofai'` > Hook-Fehlern. Nach Änderungen an `src/` neu bauen. Siehe -> [Build before the in-repo dev hooks will work](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> [Build before the in-repo dev hooks will work](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). --- diff --git a/docs/i18n/README.es.md b/docs/i18n/README.es.md index 734d224d..78b372cf 100644 --- a/docs/i18n/README.es.md +++ b/docs/i18n/README.es.md @@ -13,9 +13,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**Traducciones:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**Traducciones:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **Resolución de fallos en tiempo de ejecución para agentes de codificación.** Se integra con Claude Code y Codex. Detecta bucles, acciones peligrosas y fugas de secretos @@ -24,7 +24,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente.

- Failproof AI in action + Failproof AI in action

--- @@ -38,14 +38,14 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -53,7 +53,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - GitHub Copilot + GitHub Copilot @@ -61,7 +61,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - Cursor Agent + Cursor Agent @@ -69,7 +69,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - OpenCode + OpenCode @@ -77,7 +77,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - Pi + Pi @@ -87,38 +87,38 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -205,19 +205,19 @@ cuando algo sale mal. → [Guía del panel de control](https://docs.befailproof. ## Licencia -MIT con [Commons Clause](https://commonsclause.com/) — libre para uso interno y personal; la reventa comercial de failproofai en sí requiere un acuerdo aparte. Consulta [LICENSE](./LICENSE) para el texto completo. +MIT con [Commons Clause](https://commonsclause.com/) — libre para uso interno y personal; la reventa comercial de failproofai en sí requiere un acuerdo aparte. Consulta [LICENSE](../../LICENSE) para el texto completo. --- ## Contribuir -Consulta [CONTRIBUTING.md](./CONTRIBUTING.md). Se aceptan con gusto nuevas políticas, casos límite y traducciones. +Consulta [CONTRIBUTING.md](../../CONTRIBUTING.md). Se aceptan con gusto nuevas políticas, casos límite y traducciones. > **Compila antes de empezar.** Ejecuta `bun install && bun run build` primero. Este repositorio ejecuta > los propios hooks de failproofai sobre sí mismo, y resuelven la importación de `failproofai` contra el > bundle compilado en `dist/` — sin una compilación previa obtendrás errores de hook del tipo `Cannot find package 'failproofai'`. > Vuelve a compilar tras modificar `src/`. Consulta -> [Build before the in-repo dev hooks will work](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> [Build before the in-repo dev hooks will work](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). --- diff --git a/docs/i18n/README.fr.md b/docs/i18n/README.fr.md index 6d7ff320..4222e0c4 100644 --- a/docs/i18n/README.fr.md +++ b/docs/i18n/README.fr.md @@ -13,9 +13,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**Traductions :** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**Traductions :** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **Résolution des échecs d'exécution pour les agents de codage.** S'intègre à Claude Code et Codex. Détecte les boucles, les actions dangereuses et les fuites de secrets @@ -24,7 +24,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local.

- Failproof AI in action + Failproof AI in action

--- @@ -38,14 +38,14 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -53,7 +53,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - GitHub Copilot + GitHub Copilot @@ -61,7 +61,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - Cursor Agent + Cursor Agent @@ -69,7 +69,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - OpenCode + OpenCode @@ -77,7 +77,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - Pi + Pi @@ -87,38 +87,38 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -203,16 +203,16 @@ Chaque appel d'outil effectué par votre agent est journalisé localement. Le ta ## Licence -MIT avec [Commons Clause](https://commonsclause.com/) — gratuit pour un usage interne et personnel ; la revente commerciale de failproofai lui-même nécessite un accord séparé. Consultez [LICENSE](./LICENSE) pour le texte complet. +MIT avec [Commons Clause](https://commonsclause.com/) — gratuit pour un usage interne et personnel ; la revente commerciale de failproofai lui-même nécessite un accord séparé. Consultez [LICENSE](../../LICENSE) pour le texte complet. --- ## Contribuer -Voir [CONTRIBUTING.md](./CONTRIBUTING.md). Les nouvelles politiques, cas limites et traductions sont les bienvenus. +Voir [CONTRIBUTING.md](../../CONTRIBUTING.md). Les nouvelles politiques, cas limites et traductions sont les bienvenus. > **Compilez avant de commencer.** Exécutez `bun install && bun run build` en premier. Ce dépôt exécute ses propres hooks failproofai sur lui-même, et ceux-ci résolvent l'import `failproofai` depuis le bundle compilé `dist/` — sans compilation vous obtiendrez des erreurs de hook `Cannot find package 'failproofai'`. Recompilez après avoir modifié `src/`. Voir -> [Build before the in-repo dev hooks will work](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> [Build before the in-repo dev hooks will work](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). --- diff --git a/docs/i18n/README.he.md b/docs/i18n/README.he.md index 2083e0d0..da2e3b41 100644 --- a/docs/i18n/README.he.md +++ b/docs/i18n/README.he.md @@ -15,9 +15,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**תרגומים:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**תרגומים:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **פתרון כשלי זמן ריצה עבור סוכני קידוד.** חוטפים Claude Code ו-Codex. תופסים לולאות, פעולות מסוכנות, וניצולי סודות @@ -26,7 +26,7 @@

- Failproof AI in action + Failproof AI in action

--- @@ -40,14 +40,14 @@ - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -55,7 +55,7 @@ - GitHub Copilot + GitHub Copilot @@ -63,7 +63,7 @@ - Cursor Agent + Cursor Agent @@ -71,7 +71,7 @@ - OpenCode + OpenCode @@ -79,7 +79,7 @@ - Pi + Pi @@ -89,38 +89,38 @@ - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -207,16 +207,16 @@ customPolicies.add({ ## רישיון -MIT עם [Commons Clause](https://commonsclause.com/) — חינם לשימוש פנימי ואישי; מכירה מסחרית מחדש של failproofai עצמו דורשת הסכם נפרד. ראה [LICENSE](./LICENSE) לטקסט המלא. +MIT עם [Commons Clause](https://commonsclause.com/) — חינם לשימוש פנימי ואישי; מכירה מסחרית מחדש של failproofai עצמו דורשת הסכם נפרד. ראה [LICENSE](../../LICENSE) לטקסט המלא. --- ## תרומה -ראה [CONTRIBUTING.md](./CONTRIBUTING.md). מדיניות חדשות, מקרים קצה, ותרגומים בברכה. +ראה [CONTRIBUTING.md](../../CONTRIBUTING.md). מדיניות חדשות, מקרים קצה, ותרגומים בברכה. > **בנה לפני שתתחיל.** הרץ `bun install && bun run build` ראשון. ריפוזיטורי זה מריץ את הוקיים שלו על עצמו, והם פותרים את ייבוא ה-`failproofai` נגד הקבוצה `dist/` המקומפלת — בלי בנייה תוכל להיתקל בשגיאות `Cannot find package 'failproofai'` מהוק. בנה מחדש לאחר שינוי `src/`. ראה -> [בנה לפני שההוקים להתפתח בריפוזיטורי יעבדו](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> [בנה לפני שההוקים להתפתח בריפוזיטורי יעבדו](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). --- diff --git a/docs/i18n/README.hi.md b/docs/i18n/README.hi.md index b29b9c2d..ff874615 100644 --- a/docs/i18n/README.hi.md +++ b/docs/i18n/README.hi.md @@ -13,9 +13,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**अनुवाद:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**अनुवाद:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **कोडिंग एजेंटों के लिए रनटाइम विफलता समाधान।** Claude Code और Codex में हुक करता है। लूप्स, खतरनाक कार्यों, और गुप्त रिसाव को @@ -24,7 +24,7 @@ Claude Code और Codex में हुक करता है। लूप्

- Failproof AI in action + Failproof AI in action

--- @@ -38,14 +38,14 @@ Claude Code और Codex में हुक करता है। लूप् - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -53,7 +53,7 @@ Claude Code और Codex में हुक करता है। लूप् - GitHub Copilot + GitHub Copilot @@ -61,7 +61,7 @@ Claude Code और Codex में हुक करता है। लूप् - Cursor Agent + Cursor Agent @@ -69,7 +69,7 @@ Claude Code और Codex में हुक करता है। लूप् - OpenCode + OpenCode @@ -77,7 +77,7 @@ Claude Code और Codex में हुक करता है। लूप् - Pi + Pi @@ -87,38 +87,38 @@ Claude Code और Codex में हुक करता है। लूप् - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -205,18 +205,18 @@ customPolicies.add({ ## लाइसेंस -[Commons Clause](https://commonsclause.com/) के साथ MIT — आंतरिक और व्यक्तिगत उपयोग के लिए मुक्त; failproofai का वाणिज्यिक पुनर्विक्रय एक अलग समझौते की आवश्यकता है। पूर्ण पाठ के लिए [LICENSE](./LICENSE) देखें। +[Commons Clause](https://commonsclause.com/) के साथ MIT — आंतरिक और व्यक्तिगत उपयोग के लिए मुक्त; failproofai का वाणिज्यिक पुनर्विक्रय एक अलग समझौते की आवश्यकता है। पूर्ण पाठ के लिए [LICENSE](../../LICENSE) देखें। --- ## योगदान -[CONTRIBUTING.md](./CONTRIBUTING.md) देखें। नई नीतियां, किनारे के मामले, और अनुवाद स्वागत है। +[CONTRIBUTING.md](../../CONTRIBUTING.md) देखें। नई नीतियां, किनारे के मामले, और अनुवाद स्वागत है। > **शुरू करने से पहले बिल्ड करें।** पहले `bun install && bun run build` चलाएं। यह रेपो > failproofai की अपनी हुक को स्वयं पर चलाता है, और वे `failproofai` आयात को संकलित > `dist/` बंडल के विरुद्ध हल करते हैं — बिल्ड के बिना आपको `Cannot find package 'failproofai'` -> हुक त्रुटियां मिलेंगी। `src/` बदलने के बाद पुनर्निर्माण करें। [Build before the in-repo dev hooks will work](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work) देखें। +> हुक त्रुटियां मिलेंगी। `src/` बदलने के बाद पुनर्निर्माण करें। [Build before the in-repo dev hooks will work](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work) देखें। --- diff --git a/docs/i18n/README.it.md b/docs/i18n/README.it.md index 6fe02afb..279556f3 100644 --- a/docs/i18n/README.it.md +++ b/docs/i18n/README.it.md @@ -13,9 +13,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**Traduzioni:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**Traduzioni:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **Risoluzione degli errori di runtime per agenti di codifica.** Si integra con Claude Code e Codex. Intercetta cicli infiniti, azioni pericolose e fughe di segreti @@ -24,7 +24,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente.

- Failproof AI in action + Failproof AI in action

--- @@ -38,14 +38,14 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -53,7 +53,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - GitHub Copilot + GitHub Copilot @@ -61,7 +61,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - Cursor Agent + Cursor Agent @@ -69,7 +69,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - OpenCode + OpenCode @@ -77,7 +77,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - Pi + Pi @@ -87,38 +87,38 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -205,19 +205,19 @@ quando qualcosa va storto. → [Guida al dashboard](https://docs.befailproof.ai/ ## Licenza -MIT con [Commons Clause](https://commonsclause.com/) — gratuito per uso interno e personale; la rivendita commerciale di failproofai stesso richiede un accordo separato. Vedi [LICENSE](./LICENSE) per il testo completo. +MIT con [Commons Clause](https://commonsclause.com/) — gratuito per uso interno e personale; la rivendita commerciale di failproofai stesso richiede un accordo separato. Vedi [LICENSE](../../LICENSE) per il testo completo. --- ## Contribuire -Vedi [CONTRIBUTING.md](./CONTRIBUTING.md). Nuove politiche, casi limite e traduzioni sono tutti benvenuti. +Vedi [CONTRIBUTING.md](../../CONTRIBUTING.md). Nuove politiche, casi limite e traduzioni sono tutti benvenuti. > **Compila prima di iniziare.** Esegui `bun install && bun run build` prima. Questo repository esegue > i propri hook di failproofai su se stesso, e risolvono l'importazione di `failproofai` rispetto al > bundle compilato `dist/` — senza una compilazione riceverai errori di hook `Cannot find package 'failproofai'`. > Ricompila dopo aver modificato `src/`. Vedi -> [Compila prima che i dev hook nel repository funzionino](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> [Compila prima che i dev hook nel repository funzionino](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). --- diff --git a/docs/i18n/README.ja.md b/docs/i18n/README.ja.md index 7a8ef970..196348de 100644 --- a/docs/i18n/README.ja.md +++ b/docs/i18n/README.ja.md @@ -13,9 +13,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**翻訳:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**翻訳:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **コーディングエージェントのランタイム障害解決ツール。** Claude Code および Codex にフックし、ループ・危険な操作・シークレットの漏洩を @@ -24,7 +24,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ

- Failproof AI in action + Failproof AI in action

--- @@ -38,14 +38,14 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -53,7 +53,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - GitHub Copilot + GitHub Copilot @@ -61,7 +61,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - Cursor Agent + Cursor Agent @@ -69,7 +69,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - OpenCode + OpenCode @@ -77,7 +77,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - Pi + Pi @@ -87,38 +87,38 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -203,15 +203,15 @@ customPolicies.add({ ## ライセンス -MIT に [Commons Clause](https://commonsclause.com/) を追加 — 社内利用および個人利用は無償。failproofai 自体の商業的な再販には別途契約が必要です。全文は [LICENSE](./LICENSE) を参照してください。 +MIT に [Commons Clause](https://commonsclause.com/) を追加 — 社内利用および個人利用は無償。failproofai 自体の商業的な再販には別途契約が必要です。全文は [LICENSE](../../LICENSE) を参照してください。 --- ## コントリビュート -[CONTRIBUTING.md](./CONTRIBUTING.md) を参照してください。新しいポリシー、エッジケース、翻訳はいずれも歓迎します。 +[CONTRIBUTING.md](../../CONTRIBUTING.md) を参照してください。新しいポリシー、エッジケース、翻訳はいずれも歓迎します。 -> **開始前にビルドしてください。** まず `bun install && bun run build` を実行してください。このリポジトリは failproofai 自身のフックを自分自身に適用しており、`failproofai` のインポートはコンパイル済みの `dist/` バンドルに対して解決されます。ビルドなしで実行すると `Cannot find package 'failproofai'` というフックエラーが発生します。`src/` を変更した後は必ず再ビルドしてください。詳細は [リポジトリ内の開発用フックを動作させるためのビルド](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work) を参照してください。 +> **開始前にビルドしてください。** まず `bun install && bun run build` を実行してください。このリポジトリは failproofai 自身のフックを自分自身に適用しており、`failproofai` のインポートはコンパイル済みの `dist/` バンドルに対して解決されます。ビルドなしで実行すると `Cannot find package 'failproofai'` というフックエラーが発生します。`src/` を変更した後は必ず再ビルドしてください。詳細は [リポジトリ内の開発用フックを動作させるためのビルド](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work) を参照してください。 --- diff --git a/docs/i18n/README.ko.md b/docs/i18n/README.ko.md index 8b389ec8..6c0094b3 100644 --- a/docs/i18n/README.ko.md +++ b/docs/i18n/README.ko.md @@ -13,9 +13,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**번역:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**번역:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **코딩 에이전트를 위한 런타임 장애 해결 도구.** Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 유출을 @@ -24,7 +24,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿

- Failproof AI in action + Failproof AI in action

--- @@ -38,14 +38,14 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -53,7 +53,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - GitHub Copilot + GitHub Copilot @@ -61,7 +61,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - Cursor Agent + Cursor Agent @@ -69,7 +69,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - OpenCode + OpenCode @@ -77,7 +77,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - Pi + Pi @@ -87,38 +87,38 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -205,19 +205,19 @@ customPolicies.add({ ## 라이선스 -[Commons Clause](https://commonsclause.com/)가 포함된 MIT 라이선스 — 내부 및 개인 사용은 무료이며, failproofai 자체의 상업적 재판매는 별도 계약이 필요합니다. 전체 내용은 [LICENSE](./LICENSE)를 참조하세요. +[Commons Clause](https://commonsclause.com/)가 포함된 MIT 라이선스 — 내부 및 개인 사용은 무료이며, failproofai 자체의 상업적 재판매는 별도 계약이 필요합니다. 전체 내용은 [LICENSE](../../LICENSE)를 참조하세요. --- ## 기여 -[CONTRIBUTING.md](./CONTRIBUTING.md)를 참조하세요. 새로운 정책, 엣지 케이스, 번역 모두 환영합니다. +[CONTRIBUTING.md](../../CONTRIBUTING.md)를 참조하세요. 새로운 정책, 엣지 케이스, 번역 모두 환영합니다. > **시작하기 전에 빌드하세요.** 먼저 `bun install && bun run build`를 실행하세요. 이 저장소는 > failproofai 자체 훅을 자신에게 적용하며, `failproofai` 임포트를 컴파일된 `dist/` 번들에서 > 해석합니다 — 빌드 없이는 `Cannot find package 'failproofai'` 훅 오류가 발생합니다. > `src/`를 변경한 후에는 다시 빌드하세요. 자세한 내용은 -> [Build before the in-repo dev hooks will work](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work)를 참조하세요. +> [Build before the in-repo dev hooks will work](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work)를 참조하세요. --- diff --git a/docs/i18n/README.pt-br.md b/docs/i18n/README.pt-br.md index 5e729c28..351124a2 100644 --- a/docs/i18n/README.pt-br.md +++ b/docs/i18n/README.pt-br.md @@ -13,9 +13,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**Traduções:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**Traduções:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **Resolução de falhas em tempo de execução para agentes de codificação.** Integra-se ao Claude Code e ao Codex. Detecta loops, ações perigosas e vazamentos de segredos @@ -24,7 +24,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente.

- Failproof AI in action + Failproof AI in action

--- @@ -38,14 +38,14 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -53,7 +53,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - GitHub Copilot + GitHub Copilot @@ -61,7 +61,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - Cursor Agent + Cursor Agent @@ -69,7 +69,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - OpenCode + OpenCode @@ -77,7 +77,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - Pi + Pi @@ -87,38 +87,38 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -205,19 +205,19 @@ quando algo der errado. → [Guia do painel](https://docs.befailproof.ai/dashboa ## Licença -MIT com [Commons Clause](https://commonsclause.com/) — uso interno e pessoal é gratuito; a revenda comercial do failproofai em si requer um acordo separado. Veja [LICENSE](./LICENSE) para o texto completo. +MIT com [Commons Clause](https://commonsclause.com/) — uso interno e pessoal é gratuito; a revenda comercial do failproofai em si requer um acordo separado. Veja [LICENSE](../../LICENSE) para o texto completo. --- ## Contribuindo -Consulte [CONTRIBUTING.md](./CONTRIBUTING.md). Novas políticas, casos extremos e traduções são bem-vindos. +Consulte [CONTRIBUTING.md](../../CONTRIBUTING.md). Novas políticas, casos extremos e traduções são bem-vindos. > **Faça o build antes de começar.** Execute `bun install && bun run build` primeiro. Este repositório executa > os próprios hooks do failproofai sobre si mesmo, e eles resolvem a importação do `failproofai` contra o > bundle compilado em `dist/` — sem um build você encontrará erros de hook `Cannot find package 'failproofai'`. > Refaça o build após alterar `src/`. Veja -> [Build before the in-repo dev hooks will work](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> [Build before the in-repo dev hooks will work](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). --- diff --git a/docs/i18n/README.ru.md b/docs/i18n/README.ru.md index d4ba525b..e45b4e1f 100644 --- a/docs/i18n/README.ru.md +++ b/docs/i18n/README.ru.md @@ -13,9 +13,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**Переводы:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**Переводы:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **Разрешение проблем во время выполнения для кодирующих агентов.** Интегрируется с Claude Code и Codex. Перехватывает зацикливания, опасные действия и утечки секретов @@ -24,7 +24,7 @@

- Failproof AI in action + Failproof AI in action

--- @@ -38,14 +38,14 @@ - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -53,7 +53,7 @@ - GitHub Copilot + GitHub Copilot @@ -61,7 +61,7 @@ - Cursor Agent + Cursor Agent @@ -69,7 +69,7 @@ - OpenCode + OpenCode @@ -77,7 +77,7 @@ - Pi + Pi @@ -87,38 +87,38 @@ - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -205,16 +205,16 @@ customPolicies.add({ ## Лицензия -MIT с [Commons Clause](https://commonsclause.com/) — бесплатно для внутреннего и личного использования; коммерческая перепродажа самого failproofai требует отдельного соглашения. Полный текст см. в [LICENSE](./LICENSE). +MIT с [Commons Clause](https://commonsclause.com/) — бесплатно для внутреннего и личного использования; коммерческая перепродажа самого failproofai требует отдельного соглашения. Полный текст см. в [LICENSE](../../LICENSE). --- ## Внесение вклада -См. [CONTRIBUTING.md](./CONTRIBUTING.md). Новые политики, граничные случаи и переводы приветствуются. +См. [CONTRIBUTING.md](../../CONTRIBUTING.md). Новые политики, граничные случаи и переводы приветствуются. > **Собирайте перед началом.** Сначала запустите `bun install && bun run build`. Этот репозиторий запускает собственные перехватчики failproofai на себе, и они разрешают импорт `failproofai` для скомпилированного пакета `dist/` — без сборки вы столкнетесь с ошибками перехватчиков `Cannot find package 'failproofai'`. Пересобирайте после изменения `src/`. См. -> [Сборка перед работой встроенных перехватчиков в репозитории](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> [Сборка перед работой встроенных перехватчиков в репозитории](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). --- diff --git a/docs/i18n/README.tr.md b/docs/i18n/README.tr.md index 817ca2b3..2a247b7c 100644 --- a/docs/i18n/README.tr.md +++ b/docs/i18n/README.tr.md @@ -13,9 +13,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**Çeviriler:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**Çeviriler:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **Kodlama ajanları için çalışma zamanı hata çözümü.** Claude Code ve Codex'e bağlanır. Döngüleri, tehlikeli eylemleri ve gizli denemeleri @@ -24,7 +24,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır

- Failproof AI in action + Failproof AI in action

--- @@ -38,14 +38,14 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -53,7 +53,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - GitHub Copilot + GitHub Copilot @@ -61,7 +61,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - Cursor Agent + Cursor Agent @@ -69,7 +69,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - OpenCode + OpenCode @@ -77,7 +77,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - Pi + Pi @@ -87,38 +87,38 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -205,15 +205,15 @@ bir şey ters gittiğinde tahmin etmek zorunda kalmıyorsunuz. → [Pano kılavu ## Lisans -[Commons Clause](https://commonsclause.com/) ile MIT — dahili ve kişisel kullanım için ücretsiz; failproofai'nin kendisinin ticari satışı ayrı bir anlaşma gerektirir. Tam metin için [LICENSE](./LICENSE) dosyasına bakın. +[Commons Clause](https://commonsclause.com/) ile MIT — dahili ve kişisel kullanım için ücretsiz; failproofai'nin kendisinin ticari satışı ayrı bir anlaşma gerektirir. Tam metin için [LICENSE](../../LICENSE) dosyasına bakın. --- ## Katkıda bulunma -[CONTRIBUTING.md](./CONTRIBUTING.md) dosyasına bakın. Yeni politikalar, uç durumlar ve çeviriler hepsine hoş geldiniz. +[CONTRIBUTING.md](../../CONTRIBUTING.md) dosyasına bakın. Yeni politikalar, uç durumlar ve çeviriler hepsine hoş geldiniz. -> **Başlamadan önce inşa edin.** Önce `bun install && bun run build` komutunu çalıştırın. Bu depo failproofai'nin kendi kancalarını kendisine uygular ve `failproofai` içe aktarımını derlenmiş `dist/` paketi karşısında çözer — inşa olmadan `Cannot find package 'failproofai'` kanca hataları alırsınız. `src/` değiştirdikten sonra yeniden derleyin. Bkz. [In-repo dev kancaları çalışması için inşa etme](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> **Başlamadan önce inşa edin.** Önce `bun install && bun run build` komutunu çalıştırın. Bu depo failproofai'nin kendi kancalarını kendisine uygular ve `failproofai` içe aktarımını derlenmiş `dist/` paketi karşısında çözer — inşa olmadan `Cannot find package 'failproofai'` kanca hataları alırsınız. `src/` değiştirdikten sonra yeniden derleyin. Bkz. [In-repo dev kancaları çalışması için inşa etme](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). --- diff --git a/docs/i18n/README.vi.md b/docs/i18n/README.vi.md index 488571fd..441e0bb9 100644 --- a/docs/i18n/README.vi.md +++ b/docs/i18n/README.vi.md @@ -13,9 +13,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**Bản dịch:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**Bản dịch:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **Xử lý sự cố khi chạy cho các agents lập trình.** Tích hợp với Claude Code và Codex. Phát hiện vòng lặp, hành động nguy hiểm và rò rỉ bí mật @@ -24,7 +24,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c

- Failproof AI in action + Failproof AI in action

--- @@ -38,14 +38,14 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -53,7 +53,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - GitHub Copilot + GitHub Copilot @@ -61,7 +61,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - Cursor Agent + Cursor Agent @@ -69,7 +69,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - OpenCode + OpenCode @@ -77,7 +77,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - Pi + Pi @@ -87,38 +87,38 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -205,19 +205,19 @@ khi có gì đó sai. → [Hướng dẫn bảng điều khiển](https://docs.b ## Giấy phép -MIT với [Commons Clause](https://commonsclause.com/) — miễn phí cho việc sử dụng nội bộ và cá nhân; việc bán lại thương mại của failproofai yêu cầu một thỏa thuận riêng. Xem [LICENSE](./LICENSE) để biết toàn bộ nội dung. +MIT với [Commons Clause](https://commonsclause.com/) — miễn phí cho việc sử dụng nội bộ và cá nhân; việc bán lại thương mại của failproofai yêu cầu một thỏa thuận riêng. Xem [LICENSE](../../LICENSE) để biết toàn bộ nội dung. --- ## Đóng góp -Xem [CONTRIBUTING.md](./CONTRIBUTING.md). Chính sách mới, trường hợp cạnh và bản dịch đều được chào đón. +Xem [CONTRIBUTING.md](../../CONTRIBUTING.md). Chính sách mới, trường hợp cạnh và bản dịch đều được chào đón. > **Xây dựng trước khi bắt đầu.** Chạy `bun install && bun run build` trước. Kho lưu trữ này chạy > các hook của riêng failproofai trên chính nó, và chúng giải quyết nhập `failproofai` dựa trên > bundle `dist/` đã biên dịch — nếu không xây dựng, bạn sẽ gặp lỗi hook `Cannot find package 'failproofai'` > . Xây dựng lại sau khi thay đổi `src/`. Xem -> [Xây dựng trước khi các hook dev trong kho sẽ hoạt động](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> [Xây dựng trước khi các hook dev trong kho sẽ hoạt động](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). --- diff --git a/docs/i18n/README.zh.md b/docs/i18n/README.zh.md index 61aaff5b..d0d65e40 100644 --- a/docs/i18n/README.zh.md +++ b/docs/i18n/README.zh.md @@ -13,9 +13,9 @@ [![Supply Chain](https://img.shields.io/badge/supply%20chain-secure-brightgreen?style=flat-square)](https://github.com/failproofai/failproofai/actions/workflows/osv-scanner.yml) [![Discord](https://img.shields.io/badge/Discord-join%20us-5865F2?style=flat-square&logo=discord)](https://discord.befailproof.ai/) [![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/introduction) -[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE) +[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](../../LICENSE) -**翻译版本:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Русский](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md) +**翻译版本:** [简体中文](../../docs/i18n/README.zh.md) · [日本語](../../docs/i18n/README.ja.md) · [한국어](../../docs/i18n/README.ko.md) · [Español](../../docs/i18n/README.es.md) · [Português](../../docs/i18n/README.pt-br.md) · [Deutsch](../../docs/i18n/README.de.md) · [Français](../../docs/i18n/README.fr.md) · [Русский](../../docs/i18n/README.ru.md) · [हिन्दी](../../docs/i18n/README.hi.md) · [Türkçe](../../docs/i18n/README.tr.md) · [Tiếng Việt](../../docs/i18n/README.vi.md) · [Italiano](../../docs/i18n/README.it.md) · [العربية](../../docs/i18n/README.ar.md) · [עברית](../../docs/i18n/README.he.md) **为编码智能体提供运行时故障处理能力。** 深度集成 Claude Code 与 Codex,在循环调用、危险操作和密钥泄漏演变为事故之前将其拦截。零延迟,本地运行。 @@ -23,7 +23,7 @@

- Failproof AI in action + Failproof AI in action

--- @@ -37,14 +37,14 @@ - Claude Code + Claude Code - OpenAI Codex + OpenAI Codex @@ -52,7 +52,7 @@ - GitHub Copilot + GitHub Copilot @@ -60,7 +60,7 @@ - Cursor Agent + Cursor Agent @@ -68,7 +68,7 @@ - OpenCode + OpenCode @@ -76,7 +76,7 @@ - Pi + Pi @@ -86,38 +86,38 @@ - Hermes + Hermes - OpenClaw + OpenClaw - Factory Droid + Factory Droid - Devin CLI + Devin CLI - Antigravity CLI + Antigravity CLI - Goose + Goose @@ -201,16 +201,16 @@ customPolicies.add({ ## 许可证 -MIT 附加 [Commons Clause](https://commonsclause.com/) — 可免费用于内部及个人用途;将 failproofai 本身进行商业转售需另行签订协议。完整条款请参阅 [LICENSE](./LICENSE)。 +MIT 附加 [Commons Clause](https://commonsclause.com/) — 可免费用于内部及个人用途;将 failproofai 本身进行商业转售需另行签订协议。完整条款请参阅 [LICENSE](../../LICENSE)。 --- ## 参与贡献 -请参阅 [CONTRIBUTING.md](./CONTRIBUTING.md)。欢迎提交新策略、边缘案例处理以及翻译内容。 +请参阅 [CONTRIBUTING.md](../../CONTRIBUTING.md)。欢迎提交新策略、边缘案例处理以及翻译内容。 > **开始前请先构建项目。** 请先运行 `bun install && bun run build`。本仓库会对自身运行 failproofai 的 hook,这些 hook 会从编译后的 `dist/` 包中解析 `failproofai` 导入——若未完成构建,将触发 `Cannot find package 'failproofai'` hook 错误。修改 `src/` 后需重新构建。详见 -> [构建项目以使仓库内开发 hook 正常工作](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work)。 +> [构建项目以使仓库内开发 hook 正常工作](../../CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work)。 --- diff --git a/scripts/translate-docs/readme-translator.ts b/scripts/translate-docs/readme-translator.ts index 93be8b97..fc015f29 100644 --- a/scripts/translate-docs/readme-translator.ts +++ b/scripts/translate-docs/readme-translator.ts @@ -17,6 +17,111 @@ const ROOT_DIR = join(__dirname, "..", ".."); const README_PATH = join(ROOT_DIR, "README.md"); const I18N_DIR = join(ROOT_DIR, "docs", "i18n"); +/** + * Prefix that walks from `docs/i18n/` back to the repo root. Keep in sync with + * I18N_DIR — the disclaimer and language selector already hard-code the same + * two levels in their `../../README.md` links. + */ +const TO_REPO_ROOT = "../../"; + +/** Raw-content base for repo files that must resolve off-GitHub too. */ +const RAW_BASE = "https://raw.githubusercontent.com/FailproofAI/failproofai/main/"; + +const ASSET_RE = /\.(?:png|jpe?g|gif|svg|webp|ico|mp4|webm)$/i; + +/** + * Re-point the root README's repo-root-relative paths so they still resolve + * from `docs/i18n/README..md`, two directories deeper. + * + * The root README lives AT the repo root, so it writes `readme-arch-hq.gif` and + * `assets/logos/claude.svg` — correct there. The translator is prompt-forbidden + * from touching paths ("Preserve all URLs and paths", translator.ts), and + * rightly so, but that means every translated copy inherited those paths + * verbatim into a directory two levels down, where they resolve against + * `docs/i18n/`. Both consumers 404'd: GitHub asked for + * `docs/i18n/assets/logos/claude.svg` and Mintlify (which also serves these + * pages, unlisted, at `/i18n/README.`) asked S3 for `exosphere/i18n/...`. + * Every logo and the architecture GIF were broken in all 14 languages. + * + * The two ref kinds get different treatment because they resolve in different + * places: + * - IMAGES become absolute raw.githubusercontent URLs. A `../../` relative + * path would fix GitHub but not Mintlify, whose copy of the page has no + * `assets/` tree above it to walk into — an absolute URL is the only form + * that renders on BOTH surfaces. + * - DOCUMENT links (`./LICENSE`, `./CONTRIBUTING.md`, the translations row's + * `./docs/i18n/README.*.md`) get the `../../` prefix instead. GitHub is the + * only surface where a link to a repo file resolves at all, and a raw URL + * there would serve unrendered plaintext. + * + * Left alone: absolute URLs, anchors, `mailto:`, protocol-relative `//`, + * site-absolute `/`, anything already starting with `../`, and everything + * inside a fenced code block (where a path is literal sample text, not a ref). + */ +export function rebaseReadmePaths(content: string): string { + const fenceRanges = findFenceRanges(content); + const insideFence = (offset: number): boolean => + fenceRanges.some(([start, end]) => offset >= start && offset < end); + + const rebase = (path: string): string | null => { + if (path === "" || /^[a-z][a-z0-9+.-]*:/i.test(path)) return null; // scheme + if (path.startsWith("#") || path.startsWith("/")) return null; // anchor, site-absolute + if (path.startsWith("../")) return null; // already rebased + const bare = path.replace(/^\.\//, ""); + if (bare === "" || bare.startsWith("../")) return null; + return ASSET_RE.test(bare.split(/[?#]/)[0]) + ? `${RAW_BASE}${bare}` + : `${TO_REPO_ROOT}${bare}`; + }; + + // Markdown links and images: `](path)` / `](path "title")`. + let out = content.replace( + /(\]\()([^)\s]+)/g, + (match, prefix: string, path: string, offset: number) => { + if (insideFence(offset)) return match; + const next = rebase(path); + return next === null ? match : `${prefix}${next}`; + }, + ); + + // HTML/JSX attributes: the README's logo table is a raw of . + out = out.replace( + /((?:src|href)=(["']))(.*?)\2/g, + (match, prefix: string, _quote: string, path: string, offset: number) => { + if (insideFence(offset)) return match; + const next = rebase(path); + return next === null ? match : `${prefix}${next}${_quote}`; + }, + ); + + return out; +} + +/** + * Byte ranges covered by fenced code blocks, per CommonMark: a fence opens with + * ≥3 backticks or tildes and closes only on a later line using the SAME + * character at ≥ the same length. Mirrors the scanner in + * `mdx-translator.convertHtmlComments`, which needs the identical guard. + */ +function findFenceRanges(content: string): Array<[number, number]> { + const ranges: Array<[number, number]> = []; + const fenceRe = /^[ \t]*(`{3,}|~{3,})/gm; + let match: RegExpExecArray | null; + let open: { char: string; length: number; start: number } | null = null; + while ((match = fenceRe.exec(content)) !== null) { + const marker = match[1]; + if (!open) { + open = { char: marker[0], length: marker.length, start: match.index }; + } else if (marker[0] === open.char && marker.length >= open.length) { + const lineEnd = content.indexOf("\n", fenceRe.lastIndex); + ranges.push([open.start, lineEnd === -1 ? content.length : lineEnd]); + open = null; + } + } + if (open) ranges.push([open.start, content.length]); + return ranges; +} + function buildLanguageSelector(currentLang: string): string { const flags: Record = { en: "\ud83c\uddfa\ud83c\uddf8", @@ -117,10 +222,17 @@ export async function translateReadme( // Same MDX sanitizers as translateMdxPage — the README emits JSX (the // logo table), so strip stray attribute quotes, drop any unmatched // trailing code fence (which would swallow the RTL ``), and - // convert HTML comments to MDX — then wrap in disclaimer + selector + - // RTL div. - const cleaned = convertHtmlComments( - stripStrayTrailingFence(sanitizeJsxAttributes(raw)), + // convert HTML comments to MDX — then re-point the root README's + // repo-root-relative paths for this file's depth, and wrap in + // disclaimer + selector + RTL div. + // + // The rebase runs on the model output ONLY, never on the wrapper: the + // disclaimer's `../../README.md` and the selector's sibling + // `README..md` links are already written for `docs/i18n/`. + const cleaned = rebaseReadmePaths( + convertHtmlComments( + stripStrayTrailingFence(sanitizeJsxAttributes(raw)), + ), ); return `${disclaimer}\n\n${langSelector}\n\n---\n${rtlOpen}\n${cleaned}\n${rtlClose}`; }, diff --git a/scripts/validate-mdx.ts b/scripts/validate-mdx.ts index 592b2d8a..91e9a488 100644 --- a/scripts/validate-mdx.ts +++ b/scripts/validate-mdx.ts @@ -25,15 +25,22 @@ * `findPageError`), so this net is a strict superset of `mintlify validate`: * it catches both the frontmatter YAML class that fails `mintlify validate` * and the body-MDX class that `mintlify validate` lets through to deploy. + * + * It also covers a third class neither tool sees: image references whose target + * does not exist (`findBrokenAssetRefs`). Those are valid MDX and valid YAML — + * nothing errors, the reader just gets a broken image — which is how all 14 + * translated READMEs shipped with every logo and the architecture GIF broken. + * See that function for the mechanism. */ -import { readdirSync, statSync, readFileSync } from "node:fs"; -import { dirname, join, relative } from "node:path"; +import { readdirSync, statSync, readFileSync, existsSync } from "node:fs"; +import { dirname, join, relative, resolve, posix } from "node:path"; import { fileURLToPath } from "node:url"; import { compile } from "@mdx-js/mdx"; import YAML from "yaml"; const __dirname = dirname(fileURLToPath(import.meta.url)); -const DOCS_DIR = join(__dirname, "..", "docs"); +const ROOT_DIR = join(__dirname, ".."); +const DOCS_DIR = join(ROOT_DIR, "docs"); export interface MdxParseError { message: string; @@ -178,34 +185,155 @@ export function collectMdxFiles(dir: string): string[] { return out; } +/** File extensions treated as bundled media rather than a link to a page. */ +const ASSET_RE = /\.(?:png|jpe?g|gif|svg|webp|ico|mp4|webm)$/i; + +export interface BrokenAssetRef { + /** The reference exactly as written in the page. */ + ref: string; + /** Repo-relative path the reference resolves to, which does not exist. */ + resolved: string; + /** 1-based line the reference appears on. */ + line: number; +} + +/** + * Report every local image reference on a page whose target does not exist on + * disk. + * + * Why this is a separate net from the MDX parse above: a broken image path is + * perfectly valid MDX and perfectly valid YAML, so `mintlify validate` and + * `findPageError` both pass it — it only surfaces as a missing image in a + * reader's browser, which nothing in CI was watching. That is exactly how all + * 14 translated READMEs shipped with every logo and the architecture GIF + * broken: the translator faithfully copies the root README's repo-root-relative + * `assets/logos/*.svg` into `docs/i18n/`, two directories deeper, where they + * resolve to nothing (GitHub 404, Mintlify S3 403). The auto-translation + * workflow regenerates these pages unattended, so only a deterministic check + * keeps that class from coming back. + * + * Resolution follows the two conventions in this repo: + * - A leading `/` is Mintlify site-absolute → resolve against `docs/` + * (`/agenteye/images/x.png` → `docs/agenteye/images/x.png`). + * - Anything else is relative to the page's own directory, the way GitHub and + * Mintlify both resolve it. + * + * Skipped: absolute URLs and any other scheme (`https:`, `mailto:`, `data:`), + * protocol-relative `//`, bare anchors, and non-asset references — a link to a + * `.md`/`.mdx` page or a bare doc slug is nav, already covered by + * `mintlify validate`, and would false-positive on extensionless Mintlify + * routes. + */ +export function findBrokenAssetRefs( + file: string, + source: string, +): BrokenAssetRef[] { + const pageDir = dirname(file); + const out: BrokenAssetRef[] = []; + const seen = new Set(); + + const lines = source.split("\n"); + for (let i = 0; i < lines.length; i++) { + const refs = [ + ...lines[i].matchAll(/\]\(([^)\s]+)/g), + ...lines[i].matchAll(/(?:src|href)=["']([^"']+)["']/g), + ].map((m) => m[1]); + + for (const ref of refs) { + if (/^[a-z][a-z0-9+.-]*:/i.test(ref)) continue; // https:, mailto:, data: + if (ref.startsWith("//") || ref.startsWith("#")) continue; + // Strip the query/fragment before testing the extension so a versioned + // `x.png?v=2` is still recognised as an asset. + const path = ref.split(/[?#]/)[0]; + if (!ASSET_RE.test(path)) continue; + + const target = path.startsWith("/") + ? join(DOCS_DIR, path.slice(1)) + : resolve(pageDir, path); + if (existsSync(target)) continue; + + const key = `${i}:${ref}`; + if (seen.has(key)) continue; + seen.add(key); + out.push({ + ref, + resolved: relative(ROOT_DIR, target).split(/[\\/]/).join(posix.sep), + line: i + 1, + }); + } + } + return out; +} + async function main(): Promise { const files = collectMdxFiles(DOCS_DIR).sort(); - const failures: Array<{ file: string; error: MdxParseError }> = []; + const failures: Array<{ + file: string; + error: MdxParseError; + kind: "MDX parse error" | "Broken image"; + }> = []; + + const collectAssetFailures = (file: string, source: string): void => { + for (const broken of findBrokenAssetRefs(file, source)) { + failures.push({ + file: relative(process.cwd(), file), + kind: "Broken image", + error: { + message: + `Image \`${broken.ref}\` does not exist — it resolves to ` + + `\`${broken.resolved}\`. Paths are relative to the page's own ` + + "directory (a leading `/` is relative to `docs/`), so a path " + + "copied from a file at a different depth has to be re-pointed.", + line: broken.line, + }, + }); + } + }; for (const file of files) { - const error = await findPageError(readFileSync(file, "utf-8")); - if (error) failures.push({ file: relative(process.cwd(), file), error }); + const source = readFileSync(file, "utf-8"); + const error = await findPageError(source); + if (error) + failures.push({ + file: relative(process.cwd(), file), + error, + kind: "MDX parse error", + }); + + // A page can carry a broken image and still parse, so collect these + // independently rather than only when the parse succeeded. + collectAssetFailures(file, source); + } + + // The root README is not a docs page (it is GitHub-only, and its HTML + // comments are illegal MDX, so findPageError would reject it) — but it IS + // the source every docs/i18n/README..md is translated from. A bad + // image path here propagates into 14 files as an absolute raw URL, which + // findBrokenAssetRefs deliberately does not follow. Check it at the source. + const rootReadme = join(ROOT_DIR, "README.md"); + if (existsSync(rootReadme)) { + collectAssetFailures(rootReadme, readFileSync(rootReadme, "utf-8")); } if (failures.length === 0) { - console.log(`✓ ${files.length} MDX page(s) parsed cleanly`); + console.log( + `✓ ${files.length} MDX page(s) parsed cleanly with no broken images`, + ); return; } - console.error( - `✗ ${failures.length} of ${files.length} MDX page(s) failed to parse:\n`, - ); - for (const { file, error } of failures) { + console.error(`✗ ${failures.length} problem(s) in ${files.length} page(s):\n`); + for (const { file, error, kind } of failures) { const pos = error.line ? `:${error.line}${error.column ? `:${error.column}` : ""}` : ""; - console.error(` ${file}${pos}\n ${error.message}\n`); + console.error(` ${file}${pos}\n ${kind}: ${error.message}\n`); // GitHub Actions inline annotation. const loc = (error.line ? `,line=${error.line}` : "") + (error.column ? `,col=${error.column}` : ""); console.log( - `::error file=${encodeAnnotation(file)}${loc}::MDX parse error: ${encodeAnnotation(error.message)}`, + `::error file=${encodeAnnotation(file)}${loc}::${kind}: ${encodeAnnotation(error.message)}`, ); } process.exitCode = 1; From de8bfdbcbb5a9cf39b34ece9f089ee343fe72225 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Wed, 5 Aug 2026 20:17:24 +0530 Subject: [PATCH 2/3] docs: rebase srcset too, and teach the guard to see it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeRabbit caught a real gap in the previous commit. Each logo cell in the README is a pairing an with a dark-mode . The rebase handled src and href only, so 8 dark-mode logos per file — 112 across the 14 translated READMEs — stayed broken, and stayed broken for dark-theme readers only, the half least likely to be caught by eye. findBrokenAssetRefs had the same blind spot, which is worse: the guard added to stop exactly this class from shipping would have gone green over it. Both now parse srcset, splitting the comma-separated candidate list and stripping each density/width descriptor. Adding it to the guard first turned the 112 broken paths into failures, which the repair then cleared. Also correct the closing-fence rule in findFenceRanges: CommonMark permits an info string on an opening fence only, so treating ```ts as a close ended a nested block early and exposed the sample paths after it to rewriting. Add a translateReadme call-site test. rebaseReadmePaths is only correct if it runs on the model output BEFORE the wrapper is attached — rebasing the assembled bytes would rewrite the language selector's sibling README..md links to one directory too high. The unit tests pinned the function; this pins the ordering. Verified non-vacuous by mutation: moving the rebase to the assembled bytes fails it. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Hnj5rFHSw86gGXZTP6JsPU --- CHANGELOG.md | 4 +- .../translate-docs/readme-translator.test.ts | 132 +++++++++++++++++- __tests__/scripts/validate-mdx.test.ts | 19 +++ docs/i18n/README.ar.md | 16 +-- docs/i18n/README.de.md | 16 +-- docs/i18n/README.es.md | 16 +-- docs/i18n/README.fr.md | 16 +-- docs/i18n/README.he.md | 16 +-- docs/i18n/README.hi.md | 16 +-- docs/i18n/README.it.md | 16 +-- docs/i18n/README.ja.md | 16 +-- docs/i18n/README.ko.md | 16 +-- docs/i18n/README.pt-br.md | 16 +-- docs/i18n/README.ru.md | 16 +-- docs/i18n/README.tr.md | 16 +-- docs/i18n/README.vi.md | 16 +-- docs/i18n/README.zh.md | 16 +-- scripts/translate-docs/readme-translator.ts | 53 ++++++- scripts/validate-mdx.ts | 12 ++ 19 files changed, 322 insertions(+), 122 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf758a49..90df3c25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,8 @@ - Restrict stable releases to a maintainer allowlist while leaving prereleases open. `publish.yml`'s preflight now refuses any publish at dist-tag `latest`, or of a non-prerelease version at any dist-tag, unless both `github.actor` and `github.triggering_actor` are on the allowlist (`NiveditJain`) — the second identity matters because a re-run keeps `actor` as the original triggerer, so checking only it would make a maintainer's stable run a re-run button for everyone with write access. A stable version published under `next` is gated too: it claims that number on npm permanently and is one `npm dist-tag add` away from being the stable release. `beta` and `next` builds are untouched, so the branch-dispatch path stays open to anyone GitHub already trusts with write access. The check runs in preflight, which every other job depends on, so a refusal costs seconds rather than a 4-way cross-compile. (#651) ### Fixes -- Repair every image in the 14 translated READMEs, which had been broken since they were first generated. The root `README.md` sits at the repo root, so it writes repo-root-relative paths (`assets/logos/claude.svg`, `readme-arch-hq.gif`); the translator is prompt-forbidden from rewriting paths, so each copy inherited them verbatim into `docs/i18n/`, two directories down, where they resolved to nothing — GitHub 404'd on `docs/i18n/assets/...` and Mintlify, which also serves these pages at `/i18n/README.`, 403'd from S3. Every CLI logo and the architecture GIF were missing in all 14 languages. `rebaseReadmePaths` now re-points them at generation time: images become absolute `raw.githubusercontent.com` URLs (the only form that renders on both surfaces — a `../../` path fixes GitHub but leaves Mintlify with no `assets/` tree to walk into), while document links (`./LICENSE`, `./CONTRIBUTING.md`) get `../../`, since GitHub is the only place a link to a repo file resolves and a raw URL there would serve plaintext. Paths inside fenced code blocks stay literal. (#654) -- Add a broken-image check to `validate:mdx` so that class cannot ship again. A bad image path is valid MDX and valid YAML, so `mintlify validate` and the existing MDX parse both passed it straight through to a reader's browser — nothing in CI was watching. `findBrokenAssetRefs` now resolves every local image reference on every docs page (site-absolute `/…` against `docs/`, everything else against the page's own directory) and fails with the path it resolved to. It runs in the CI `docs` job, in each per-language auto-translation job before its artifact is uploaded, and twice more in `consolidate`. The root `README.md` is checked too, since a bad path there propagates into 14 files as an absolute URL the check would no longer follow. (#654) +- Repair every image in the 14 translated READMEs, which had been broken since they were first generated. The root `README.md` sits at the repo root, so it writes repo-root-relative paths (`assets/logos/claude.svg`, `readme-arch-hq.gif`); the translator is prompt-forbidden from rewriting paths, so each copy inherited them verbatim into `docs/i18n/`, two directories down, where they resolved to nothing — GitHub 404'd on `docs/i18n/assets/...` and Mintlify, which also serves these pages at `/i18n/README.`, 403'd from S3. Every CLI logo and the architecture GIF were missing in all 14 languages. `rebaseReadmePaths` now re-points them at generation time: images become absolute `raw.githubusercontent.com` URLs (the only form that renders on both surfaces — a `../../` path fixes GitHub but leaves Mintlify with no `assets/` tree to walk into), while document links (`./LICENSE`, `./CONTRIBUTING.md`) get `../../`, since GitHub is the only place a link to a repo file resolves and a raw URL there would serve plaintext. `srcset` is rewritten alongside `src`, descriptors preserved — each logo cell is a `` whose dark-mode `` would otherwise have stayed broken for dark-theme readers only. Paths inside fenced code blocks stay literal. (#654) +- Add a broken-image check to `validate:mdx` so that class cannot ship again. A bad image path is valid MDX and valid YAML, so `mintlify validate` and the existing MDX parse both passed it straight through to a reader's browser — nothing in CI was watching. `findBrokenAssetRefs` now resolves every local image reference on every docs page — `src`, `href`, Markdown `![…](…)`, and each `srcset` candidate — against `docs/` for a site-absolute `/…` and against the page's own directory otherwise, failing with the path it resolved to. It runs in the CI `docs` job, in each per-language auto-translation job before its artifact is uploaded, and twice more in `consolidate`. The root `README.md` is checked too, since a bad path there propagates into 14 files as an absolute URL the check would no longer follow. (#654) - Harden the release workflow against shell injection from ref names and generated outputs, align every Bun cache key with the tracked `bun.lock`, and discard the temporary publish-version edit before switching to `main` for the development-version bump. (#634) ### Dependencies diff --git a/__tests__/scripts/translate-docs/readme-translator.test.ts b/__tests__/scripts/translate-docs/readme-translator.test.ts index c404b25a..e771092f 100644 --- a/__tests__/scripts/translate-docs/readme-translator.test.ts +++ b/__tests__/scripts/translate-docs/readme-translator.test.ts @@ -1,5 +1,43 @@ // @vitest-environment node -import { describe, it, expect } from "vitest"; +import { describe, it, expect, vi } from "vitest"; + +// Stub the model call so `translateReadme` runs its real render pipeline over a +// fixed "translation", and stub the writes so the test never touches the repo's +// own docs/i18n/ files. Everything between — the sanitizers, the rebase, the +// wrapper assembly, and the real validator — runs unmocked. +vi.mock("@/scripts/translate-docs/translator", () => ({ + translateValidated: vi.fn( + async (opts: { + render: (raw: string) => string; + validate: (rendered: string) => Promise; + }) => { + const rendered = opts.render(RAW_TRANSLATION); + const error = await opts.validate(rendered); + if (error) throw new Error(`fixture failed validation: ${error}`); + return { rendered, inputTokens: 0, outputTokens: 0, attempts: 1 }; + }, + ), +})); + +vi.mock("node:fs", async (importOriginal) => { + const actual = await importOriginal(); + return { ...actual, writeFileSync: vi.fn(), mkdirSync: vi.fn() }; +}); + +/** Stands in for the model's output: the shapes the real README emits. */ +const RAW_TRANSLATION = [ + "# 失败保护 AI", + "", + "", + ' ', + ' OpenAI Codex', + "", + "", + "详情见 [LICENSE](./LICENSE)。", +].join("\n"); + +import { writeFileSync } from "node:fs"; +import { translateReadme } from "@/scripts/translate-docs/readme-translator"; import { buildMainReadmeLanguageLinks, rebaseReadmePaths, @@ -23,6 +61,34 @@ describe("rebaseReadmePaths", () => { ); }); + it("rewrites srcset, where the dark-mode logo of every lives", () => { + // Each logo cell pairs an with a dark-mode . + // Rewriting only `src` leaves the table half-broken for dark-theme readers + // — the half least likely to be caught by eye in review. + expect( + rebaseReadmePaths( + '', + ), + ).toBe( + ``, + ); + }); + + it("rebases every srcset candidate, keeping its descriptor and spacing", () => { + expect( + rebaseReadmePaths( + '', + ), + ).toBe( + ``, + ); + }); + + it("leaves an already-absolute srcset candidate alone", () => { + const abs = ''; + expect(rebaseReadmePaths(abs)).toBe(abs); + }); + it("rewrites document links to ../../ instead, where GitHub resolves them", () => { // A raw URL for a .md would serve unrendered plaintext, so links get the // relative form; GitHub is the only surface they work on either way. @@ -58,6 +124,27 @@ describe("rebaseReadmePaths", () => { expect(rebaseReadmePaths(once)).toBe(once); }); + it("does not close a fence on a line carrying an info string", () => { + // CommonMark allows an info string on an OPENING fence only. Treating + // ```` ```ts ```` as a close would end the block early and expose the + // sample paths after it to rewriting. + const fenced = + "````md\n" + + "```ts\n" + + '\n' + + "```\n" + + "````\n" + + ''; + expect(rebaseReadmePaths(fenced)).toBe( + "````md\n" + + "```ts\n" + + '\n' + + "```\n" + + "````\n" + + ``, + ); + }); + it("leaves paths inside fenced code blocks literal", () => { // There a path is sample text a reader copies, not a reference to resolve. const fenced = @@ -119,3 +206,46 @@ describe("buildMainReadmeLanguageLinks", () => { expect(result).toContain(" | "); }); }); + +describe("translateReadme — rebase call site", () => { + // rebaseReadmePaths is only correct if it runs on the model output BEFORE the + // wrapper is attached. The unit tests above pin the function; these pin the + // ordering, which is what a future refactor would silently get wrong. + const write = vi.mocked(writeFileSync); + + const renderOnce = async (): Promise => { + write.mockClear(); + // A caller-supplied cache keeps translateReadme off the on-disk one. + await translateReadme("zh", { + force: true, + cache: { sourceHash: "", lastUpdated: "", translations: {} }, + }); + expect(write).toHaveBeenCalledTimes(1); + return write.mock.calls[0][1] as string; + }; + + it("rebases the body's src, srcset, and document links", async () => { + const out = await renderOnce(); + expect(out).toContain(`src="${RAW}/assets/logos/openai-light.svg"`); + expect(out).toContain(`srcset="${RAW}/assets/logos/openai-dark.svg"`); + expect(out).toContain("[LICENSE](../../LICENSE)"); + expect(out).not.toContain('src="assets/logos/'); + expect(out).not.toContain('srcset="assets/logos/'); + }); + + it("leaves the language selector's sibling links untouched", async () => { + const out = await renderOnce(); + // Written by buildLanguageSelector AFTER the rebase, already relative to + // docs/i18n/. A `../../README.ja.md` here would point one level too high. + expect(out).toContain("](README.ja.md)"); + expect(out).toContain("](../../README.md)"); + expect(out).not.toContain("](../../README.ja.md)"); + }); + + it("writes to docs/i18n/README..md", async () => { + await renderOnce(); + expect(String(write.mock.calls[0][0])).toMatch( + /docs[/\\]i18n[/\\]README\.zh\.md$/, + ); + }); +}); diff --git a/__tests__/scripts/validate-mdx.test.ts b/__tests__/scripts/validate-mdx.test.ts index 8215d477..ece62123 100644 --- a/__tests__/scripts/validate-mdx.test.ts +++ b/__tests__/scripts/validate-mdx.test.ts @@ -296,6 +296,25 @@ describe("findBrokenAssetRefs", () => { expect(broken[0].resolved).toBe("docs/agenteye/images/does-not-exist.png"); }); + it("checks srcset candidates, not just src", () => { + // The README's logo table pairs every with a dark-mode + // . Extracting only `src` passed a half-broken table. + const broken = findBrokenAssetRefs( + I18N_PAGE, + '\n', + ); + expect(broken).toHaveLength(1); + expect(broken[0].resolved).toBe("docs/i18n/assets/logos/openai-dark.svg"); + }); + + it("splits a multi-candidate srcset and strips each descriptor", () => { + const broken = findBrokenAssetRefs( + DOCS_PAGE, + '\n', + ); + expect(broken.map((b) => b.ref)).toEqual(["images/missing@2x.png"]); + }); + it("accepts a page-relative path that exists", () => { expect( findBrokenAssetRefs(DOCS_PAGE, "![Alerts](images/alerts.png)\n"), diff --git a/docs/i18n/README.ar.md b/docs/i18n/README.ar.md index 3edeafea..8b98c82a 100644 --- a/docs/i18n/README.ar.md +++ b/docs/i18n/README.ar.md @@ -46,7 +46,7 @@
- + OpenAI Codex @@ -54,7 +54,7 @@ - + GitHub Copilot @@ -62,7 +62,7 @@ - + Cursor Agent @@ -70,7 +70,7 @@ - + OpenCode @@ -78,7 +78,7 @@ - + Pi @@ -88,7 +88,7 @@ - + Hermes @@ -101,7 +101,7 @@ - + Factory Droid @@ -119,7 +119,7 @@ - + Goose diff --git a/docs/i18n/README.de.md b/docs/i18n/README.de.md index 7cd37b9d..33f28d84 100644 --- a/docs/i18n/README.de.md +++ b/docs/i18n/README.de.md @@ -44,7 +44,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - + OpenAI Codex @@ -52,7 +52,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - + GitHub Copilot @@ -60,7 +60,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - + Cursor Agent @@ -68,7 +68,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - + OpenCode @@ -76,7 +76,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - + Pi @@ -86,7 +86,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - + Hermes @@ -99,7 +99,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - + Factory Droid @@ -117,7 +117,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - + Goose diff --git a/docs/i18n/README.es.md b/docs/i18n/README.es.md index 78b372cf..b617e1b0 100644 --- a/docs/i18n/README.es.md +++ b/docs/i18n/README.es.md @@ -44,7 +44,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - + OpenAI Codex @@ -52,7 +52,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - + GitHub Copilot @@ -60,7 +60,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - + Cursor Agent @@ -68,7 +68,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - + OpenCode @@ -76,7 +76,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - + Pi @@ -86,7 +86,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - + Hermes @@ -99,7 +99,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - + Factory Droid @@ -117,7 +117,7 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - + Goose diff --git a/docs/i18n/README.fr.md b/docs/i18n/README.fr.md index 4222e0c4..8b900fce 100644 --- a/docs/i18n/README.fr.md +++ b/docs/i18n/README.fr.md @@ -44,7 +44,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - + OpenAI Codex @@ -52,7 +52,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - + GitHub Copilot @@ -60,7 +60,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - + Cursor Agent @@ -68,7 +68,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - + OpenCode @@ -76,7 +76,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - + Pi @@ -86,7 +86,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - + Hermes @@ -99,7 +99,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - + Factory Droid @@ -117,7 +117,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - + Goose diff --git a/docs/i18n/README.he.md b/docs/i18n/README.he.md index da2e3b41..7a8f09c7 100644 --- a/docs/i18n/README.he.md +++ b/docs/i18n/README.he.md @@ -46,7 +46,7 @@ - + OpenAI Codex @@ -54,7 +54,7 @@ - + GitHub Copilot @@ -62,7 +62,7 @@ - + Cursor Agent @@ -70,7 +70,7 @@ - + OpenCode @@ -78,7 +78,7 @@ - + Pi @@ -88,7 +88,7 @@ - + Hermes @@ -101,7 +101,7 @@ - + Factory Droid @@ -119,7 +119,7 @@ - + Goose diff --git a/docs/i18n/README.hi.md b/docs/i18n/README.hi.md index ff874615..d6235f1e 100644 --- a/docs/i18n/README.hi.md +++ b/docs/i18n/README.hi.md @@ -44,7 +44,7 @@ Claude Code और Codex में हुक करता है। लूप् - + OpenAI Codex @@ -52,7 +52,7 @@ Claude Code और Codex में हुक करता है। लूप् - + GitHub Copilot @@ -60,7 +60,7 @@ Claude Code और Codex में हुक करता है। लूप् - + Cursor Agent @@ -68,7 +68,7 @@ Claude Code और Codex में हुक करता है। लूप् - + OpenCode @@ -76,7 +76,7 @@ Claude Code और Codex में हुक करता है। लूप् - + Pi @@ -86,7 +86,7 @@ Claude Code और Codex में हुक करता है। लूप् - + Hermes @@ -99,7 +99,7 @@ Claude Code और Codex में हुक करता है। लूप् - + Factory Droid @@ -117,7 +117,7 @@ Claude Code और Codex में हुक करता है। लूप् - + Goose diff --git a/docs/i18n/README.it.md b/docs/i18n/README.it.md index 279556f3..90b2eb0e 100644 --- a/docs/i18n/README.it.md +++ b/docs/i18n/README.it.md @@ -44,7 +44,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - + OpenAI Codex @@ -52,7 +52,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - + GitHub Copilot @@ -60,7 +60,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - + Cursor Agent @@ -68,7 +68,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - + OpenCode @@ -76,7 +76,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - + Pi @@ -86,7 +86,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - + Hermes @@ -99,7 +99,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - + Factory Droid @@ -117,7 +117,7 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - + Goose diff --git a/docs/i18n/README.ja.md b/docs/i18n/README.ja.md index 196348de..7df7a15e 100644 --- a/docs/i18n/README.ja.md +++ b/docs/i18n/README.ja.md @@ -44,7 +44,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - + OpenAI Codex @@ -52,7 +52,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - + GitHub Copilot @@ -60,7 +60,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - + Cursor Agent @@ -68,7 +68,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - + OpenCode @@ -76,7 +76,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - + Pi @@ -86,7 +86,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - + Hermes @@ -99,7 +99,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - + Factory Droid @@ -117,7 +117,7 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - + Goose diff --git a/docs/i18n/README.ko.md b/docs/i18n/README.ko.md index 6c0094b3..d82a9d4d 100644 --- a/docs/i18n/README.ko.md +++ b/docs/i18n/README.ko.md @@ -44,7 +44,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - + OpenAI Codex @@ -52,7 +52,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - + GitHub Copilot @@ -60,7 +60,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - + Cursor Agent @@ -68,7 +68,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - + OpenCode @@ -76,7 +76,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - + Pi @@ -86,7 +86,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - + Hermes @@ -99,7 +99,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - + Factory Droid @@ -117,7 +117,7 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - + Goose diff --git a/docs/i18n/README.pt-br.md b/docs/i18n/README.pt-br.md index 351124a2..ec7516b5 100644 --- a/docs/i18n/README.pt-br.md +++ b/docs/i18n/README.pt-br.md @@ -44,7 +44,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - + OpenAI Codex @@ -52,7 +52,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - + GitHub Copilot @@ -60,7 +60,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - + Cursor Agent @@ -68,7 +68,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - + OpenCode @@ -76,7 +76,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - + Pi @@ -86,7 +86,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - + Hermes @@ -99,7 +99,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - + Factory Droid @@ -117,7 +117,7 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - + Goose diff --git a/docs/i18n/README.ru.md b/docs/i18n/README.ru.md index e45b4e1f..fe58f3a6 100644 --- a/docs/i18n/README.ru.md +++ b/docs/i18n/README.ru.md @@ -44,7 +44,7 @@ - + OpenAI Codex @@ -52,7 +52,7 @@ - + GitHub Copilot @@ -60,7 +60,7 @@ - + Cursor Agent @@ -68,7 +68,7 @@ - + OpenCode @@ -76,7 +76,7 @@ - + Pi @@ -86,7 +86,7 @@ - + Hermes @@ -99,7 +99,7 @@ - + Factory Droid @@ -117,7 +117,7 @@ - + Goose diff --git a/docs/i18n/README.tr.md b/docs/i18n/README.tr.md index 2a247b7c..2a3923c3 100644 --- a/docs/i18n/README.tr.md +++ b/docs/i18n/README.tr.md @@ -44,7 +44,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - + OpenAI Codex @@ -52,7 +52,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - + GitHub Copilot @@ -60,7 +60,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - + Cursor Agent @@ -68,7 +68,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - + OpenCode @@ -76,7 +76,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - + Pi @@ -86,7 +86,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - + Hermes @@ -99,7 +99,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - + Factory Droid @@ -117,7 +117,7 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - + Goose diff --git a/docs/i18n/README.vi.md b/docs/i18n/README.vi.md index 441e0bb9..adc684cc 100644 --- a/docs/i18n/README.vi.md +++ b/docs/i18n/README.vi.md @@ -44,7 +44,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - + OpenAI Codex @@ -52,7 +52,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - + GitHub Copilot @@ -60,7 +60,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - + Cursor Agent @@ -68,7 +68,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - + OpenCode @@ -76,7 +76,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - + Pi @@ -86,7 +86,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - + Hermes @@ -99,7 +99,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - + Factory Droid @@ -117,7 +117,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c - + Goose diff --git a/docs/i18n/README.zh.md b/docs/i18n/README.zh.md index d0d65e40..c61f641f 100644 --- a/docs/i18n/README.zh.md +++ b/docs/i18n/README.zh.md @@ -43,7 +43,7 @@ - + OpenAI Codex @@ -51,7 +51,7 @@ - + GitHub Copilot @@ -59,7 +59,7 @@ - + Cursor Agent @@ -67,7 +67,7 @@ - + OpenCode @@ -75,7 +75,7 @@ - + Pi @@ -85,7 +85,7 @@ - + Hermes @@ -98,7 +98,7 @@ - + Factory Droid @@ -116,7 +116,7 @@ - + Goose diff --git a/scripts/translate-docs/readme-translator.ts b/scripts/translate-docs/readme-translator.ts index fc015f29..502bf0b7 100644 --- a/scripts/translate-docs/readme-translator.ts +++ b/scripts/translate-docs/readme-translator.ts @@ -87,32 +87,71 @@ export function rebaseReadmePaths(content: string): string { // HTML/JSX attributes: the README's logo table is a raw of . out = out.replace( /((?:src|href)=(["']))(.*?)\2/g, - (match, prefix: string, _quote: string, path: string, offset: number) => { + (match, prefix: string, quote: string, path: string, offset: number) => { if (insideFence(offset)) return match; const next = rebase(path); - return next === null ? match : `${prefix}${next}${_quote}`; + return next === null ? match : `${prefix}${next}${quote}`; + }, + ); + + // `srcset` needs its own pass: each logo cell is a whose dark-mode + // sits beside the . Miss + // it and half the table stays broken for dark-theme readers only — the half + // least likely to be noticed in review. + out = out.replace( + /(srcset=(["']))(.*?)\2/g, + (match, prefix: string, quote: string, value: string, offset: number) => { + if (insideFence(offset)) return match; + return `${prefix}${rebaseSrcset(value)}${quote}`; }, ); return out; + + /** + * Rebase every candidate in a `srcset` value, preserving each one's optional + * density/width descriptor (`logo.svg 2x`, `wide.png 800w`) and the original + * comma spacing. + */ + function rebaseSrcset(value: string): string { + return value + .split(",") + .map((candidate) => { + const [, lead, url, descriptor] = + /^(\s*)(\S+)(.*)$/.exec(candidate) ?? []; + if (url === undefined) return candidate; // whitespace-only candidate + const next = rebase(url); + return `${lead}${next ?? url}${descriptor}`; + }) + .join(","); + } } /** * Byte ranges covered by fenced code blocks, per CommonMark: a fence opens with * ≥3 backticks or tildes and closes only on a later line using the SAME - * character at ≥ the same length. Mirrors the scanner in - * `mdx-translator.convertHtmlComments`, which needs the identical guard. + * character at ≥ the same length. + * + * Follows the scanner in `mdx-translator.convertHtmlComments`, with one + * correction: a CLOSING fence may carry only trailing whitespace, never an info + * string. Accepting ```` ```ts ```` as a close would end the block at the first + * *nested* opener inside it and leave the real code that follows looking like + * prose — whose sample paths this function exists to protect. */ function findFenceRanges(content: string): Array<[number, number]> { const ranges: Array<[number, number]> = []; - const fenceRe = /^[ \t]*(`{3,}|~{3,})/gm; + const fenceRe = /^[ \t]*(`{3,}|~{3,})([^\n]*)$/gm; let match: RegExpExecArray | null; let open: { char: string; length: number; start: number } | null = null; while ((match = fenceRe.exec(content)) !== null) { - const marker = match[1]; + const [, marker, rest] = match; if (!open) { open = { char: marker[0], length: marker.length, start: match.index }; - } else if (marker[0] === open.char && marker.length >= open.length) { + } else if ( + marker[0] === open.char && + marker.length >= open.length && + rest.trim() === "" + ) { const lineEnd = content.indexOf("\n", fenceRe.lastIndex); ranges.push([open.start, lineEnd === -1 ? content.length : lineEnd]); open = null; diff --git a/scripts/validate-mdx.ts b/scripts/validate-mdx.ts index 91e9a488..4ffbacba 100644 --- a/scripts/validate-mdx.ts +++ b/scripts/validate-mdx.ts @@ -239,6 +239,18 @@ export function findBrokenAssetRefs( ...lines[i].matchAll(/(?:src|href)=["']([^"']+)["']/g), ].map((m) => m[1]); + // `srcset` carries a comma-separated candidate list, each optionally + // followed by a density/width descriptor (`logo.svg 2x`). The README's + // logo table pairs every with a dark-mode , so + // extracting only `src` would pass a table half-broken — and only for + // dark-theme readers, the half least likely to be caught by eye. + for (const m of lines[i].matchAll(/srcset=["']([^"']+)["']/g)) { + for (const candidate of m[1].split(",")) { + const url = candidate.trim().split(/\s+/)[0]; + if (url) refs.push(url); + } + } + for (const ref of refs) { if (/^[a-z][a-z0-9+.-]*:/i.test(ref)) continue; // https:, mailto:, data: if (ref.startsWith("//") || ref.startsWith("#")) continue; From 1f6ee049686cf1d2636a60ed37c8f27a3639efff Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Wed, 5 Aug 2026 20:25:13 +0530 Subject: [PATCH 3/3] docs: recompute the fence map between rebase passes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Third real find from CodeRabbit. rebaseReadmePaths computed fence ranges once from the input, but String.replace reports offsets into the string it is scanning — so once the markdown pass rewrote a path AHEAD of a fence, the text lengthened and that fence moved. The later src and srcset passes then tested offsets in the longer string against a map built from the shorter one, concluded a literal `` inside a ```html block was ordinary markup, and rewrote the sample path the fence guard exists to protect. Reproduced with a rebased GIF link above an html fence: the fenced src was rewritten. The map is now rebuilt from the current string before each pass — within a pass it stays valid, since every offset comes from the same input. The 14 committed READMEs are unaffected (verified stable under the fixed function); this guards the sample-bearing pages a future English README will have. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Hnj5rFHSw86gGXZTP6JsPU --- .../translate-docs/readme-translator.test.ts | 22 +++++++++++++++++++ scripts/translate-docs/readme-translator.ts | 10 ++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/__tests__/scripts/translate-docs/readme-translator.test.ts b/__tests__/scripts/translate-docs/readme-translator.test.ts index e771092f..b4803c8d 100644 --- a/__tests__/scripts/translate-docs/readme-translator.test.ts +++ b/__tests__/scripts/translate-docs/readme-translator.test.ts @@ -145,6 +145,28 @@ describe("rebaseReadmePaths", () => { ); }); + it("keeps a fence intact after an earlier pass lengthened the text", () => { + // The markdown pass rewrites the GIF to a much longer absolute URL, pushing + // the fence forward. A fence map computed once from the input would leave + // the later src/srcset passes reading stale offsets and rewriting the + // literal sample paths inside the block. + const fenced = + "![arch](readme-arch-hq.gif)\n" + + "\n" + + "```html\n" + + '\n' + + '\n' + + "```"; + expect(rebaseReadmePaths(fenced)).toBe( + `![arch](${RAW}/readme-arch-hq.gif)\n` + + "\n" + + "```html\n" + + '\n' + + '\n' + + "```", + ); + }); + it("leaves paths inside fenced code blocks literal", () => { // There a path is sample text a reader copies, not a reference to resolve. const fenced = diff --git a/scripts/translate-docs/readme-translator.ts b/scripts/translate-docs/readme-translator.ts index 502bf0b7..681fd165 100644 --- a/scripts/translate-docs/readme-translator.ts +++ b/scripts/translate-docs/readme-translator.ts @@ -59,7 +59,13 @@ const ASSET_RE = /\.(?:png|jpe?g|gif|svg|webp|ico|mp4|webm)$/i; * inside a fenced code block (where a path is literal sample text, not a ref). */ export function rebaseReadmePaths(content: string): string { - const fenceRanges = findFenceRanges(content); + // Recomputed before each pass. `String.replace` reports offsets into the + // string it is scanning, so one map is valid for a whole pass — but a pass + // that rewrites a path AHEAD of a fence lengthens the text and shifts that + // fence, leaving offsets from the previous string pointing short. The next + // pass would then read a literal `` inside a fence as ordinary + // markup and rewrite the sample path this guard exists to protect. + let fenceRanges = findFenceRanges(content); const insideFence = (offset: number): boolean => fenceRanges.some(([start, end]) => offset >= start && offset < end); @@ -85,6 +91,7 @@ export function rebaseReadmePaths(content: string): string { ); // HTML/JSX attributes: the README's logo table is a raw
of . + fenceRanges = findFenceRanges(out); out = out.replace( /((?:src|href)=(["']))(.*?)\2/g, (match, prefix: string, quote: string, path: string, offset: number) => { @@ -98,6 +105,7 @@ export function rebaseReadmePaths(content: string): string { // sits beside the . Miss // it and half the table stays broken for dark-theme readers only — the half // least likely to be noticed in review. + fenceRanges = findFenceRanges(out); out = out.replace( /(srcset=(["']))(.*?)\2/g, (match, prefix: string, quote: string, value: string, offset: number) => {