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..90df3c25 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. `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 b87ad63c..b4803c8d 100644 --- a/__tests__/scripts/translate-docs/readme-translator.test.ts +++ b/__tests__/scripts/translate-docs/readme-translator.test.ts @@ -1,8 +1,200 @@ // @vitest-environment node -import { describe, it, expect } from "vitest"; -import { buildMainReadmeLanguageLinks } from "@/scripts/translate-docs/readme-translator"; +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, +} 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 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. + 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("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("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 = + "```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(); @@ -36,3 +228,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 d94fbd56..ece62123 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,112 @@ 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("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"), + ).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..8b98c82a 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,46 +40,46 @@ - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -88,39 +88,39 @@ - - 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..33f28d84 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,46 +38,46 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -86,39 +86,39 @@ 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..b617e1b0 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,46 +38,46 @@ antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente. - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -86,39 +86,39 @@ 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..8b900fce 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,46 +38,46 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -86,39 +86,39 @@ 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..7a8f09c7 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,46 +40,46 @@ - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -88,39 +88,39 @@ - - 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..d6235f1e 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,46 +38,46 @@ Claude Code और Codex में हुक करता है। लूप् - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -86,39 +86,39 @@ 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..90b2eb0e 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,46 +38,46 @@ prima che diventino incidenti. Zero latenza. Eseguito localmente. - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -86,39 +86,39 @@ 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..7df7a15e 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,46 +38,46 @@ Claude Code および Codex にフックし、ループ・危険な操作・シ - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -86,39 +86,39 @@ 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..d82a9d4d 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,46 +38,46 @@ Claude Code 및 Codex에 연결됩니다. 루프, 위험한 동작, 시크릿 - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -86,39 +86,39 @@ 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..ec7516b5 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,46 +38,46 @@ antes que se tornem incidentes. Latência zero. Executa localmente. - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -86,39 +86,39 @@ 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..fe58f3a6 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,46 +38,46 @@ - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -86,39 +86,39 @@ - - 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..2a3923c3 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,46 +38,46 @@ bir olaya dönüşmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -86,39 +86,39 @@ 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..adc684cc 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,46 +38,46 @@ 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 - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -86,39 +86,39 @@ 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..c61f641f 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,46 +37,46 @@ - Claude Code + Claude Code - - OpenAI Codex + + OpenAI Codex - - GitHub Copilot + + GitHub Copilot - - Cursor Agent + + Cursor Agent - - OpenCode + + OpenCode - - Pi + + Pi @@ -85,39 +85,39 @@ - - 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..681fd165 100644 --- a/scripts/translate-docs/readme-translator.ts +++ b/scripts/translate-docs/readme-translator.ts @@ -17,6 +17,158 @@ 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 { + // 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); + + 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 . + fenceRanges = findFenceRanges(out); + 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}`; + }, + ); + + // `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. + fenceRanges = findFenceRanges(out); + 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. + * + * 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,})([^\n]*)$/gm; + let match: RegExpExecArray | null; + let open: { char: string; length: number; start: number } | null = null; + while ((match = fenceRe.exec(content)) !== null) { + 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 && + rest.trim() === "" + ) { + 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 +269,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..4ffbacba 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,167 @@ 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]); + + // `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; + // 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;